changeset 7 | cf61fcea0001 |
parent 5 | 5e2f62d02dcd |
child 9 | 177826044cd9 |
6:490d5cc509ed | 7:cf61fcea0001 |
---|---|
1 <?php |
1 <?php |
2 /** |
2 /** |
3 * Taxonomy API |
3 * Core Taxonomy API |
4 * |
4 * |
5 * @package WordPress |
5 * @package WordPress |
6 * @subpackage Taxonomy |
6 * @subpackage Taxonomy |
7 * @since 2.3.0 |
|
8 */ |
7 */ |
9 |
8 |
10 // |
9 // |
11 // Taxonomy Registration |
10 // Taxonomy Registration |
12 // |
11 // |
13 |
12 |
14 /** |
13 /** |
15 * Creates the initial taxonomies. |
14 * Creates the initial taxonomies. |
16 * |
15 * |
17 * This function fires twice: in wp-settings.php before plugins are loaded (for |
16 * This function fires twice: in wp-settings.php before plugins are loaded (for |
18 * backwards compatibility reasons), and again on the 'init' action. We must avoid |
17 * backward compatibility reasons), and again on the {@see 'init'} action. We must |
19 * registering rewrite rules before the 'init' action. |
18 * avoid registering rewrite rules before the {@see 'init'} action. |
19 * |
|
20 * @since 2.8.0 |
|
21 * |
|
22 * @global WP_Rewrite $wp_rewrite The WordPress rewrite class. |
|
20 */ |
23 */ |
21 function create_initial_taxonomies() { |
24 function create_initial_taxonomies() { |
22 global $wp_rewrite; |
25 global $wp_rewrite; |
23 |
26 |
24 if ( ! did_action( 'init' ) ) { |
27 if ( ! did_action( 'init' ) ) { |
25 $rewrite = array( 'category' => false, 'post_tag' => false, 'post_format' => false ); |
28 $rewrite = array( 'category' => false, 'post_tag' => false, 'post_format' => false ); |
26 } else { |
29 } else { |
27 |
30 |
28 /** |
31 /** |
29 * Filter the post formats rewrite base. |
32 * Filters the post formats rewrite base. |
30 * |
33 * |
31 * @since 3.1.0 |
34 * @since 3.1.0 |
32 * |
35 * |
33 * @param string $context Context of the rewrite base. Default 'type'. |
36 * @param string $context Context of the rewrite base. Default 'type'. |
34 */ |
37 */ |
56 'rewrite' => $rewrite['category'], |
59 'rewrite' => $rewrite['category'], |
57 'public' => true, |
60 'public' => true, |
58 'show_ui' => true, |
61 'show_ui' => true, |
59 'show_admin_column' => true, |
62 'show_admin_column' => true, |
60 '_builtin' => true, |
63 '_builtin' => true, |
64 'capabilities' => array( |
|
65 'manage_terms' => 'manage_categories', |
|
66 'edit_terms' => 'edit_categories', |
|
67 'delete_terms' => 'delete_categories', |
|
68 'assign_terms' => 'assign_categories', |
|
69 ), |
|
70 'show_in_rest' => true, |
|
71 'rest_base' => 'categories', |
|
72 'rest_controller_class' => 'WP_REST_Terms_Controller', |
|
61 ) ); |
73 ) ); |
62 |
74 |
63 register_taxonomy( 'post_tag', 'post', array( |
75 register_taxonomy( 'post_tag', 'post', array( |
64 'hierarchical' => false, |
76 'hierarchical' => false, |
65 'query_var' => 'tag', |
77 'query_var' => 'tag', |
66 'rewrite' => $rewrite['post_tag'], |
78 'rewrite' => $rewrite['post_tag'], |
67 'public' => true, |
79 'public' => true, |
68 'show_ui' => true, |
80 'show_ui' => true, |
69 'show_admin_column' => true, |
81 'show_admin_column' => true, |
70 '_builtin' => true, |
82 '_builtin' => true, |
83 'capabilities' => array( |
|
84 'manage_terms' => 'manage_post_tags', |
|
85 'edit_terms' => 'edit_post_tags', |
|
86 'delete_terms' => 'delete_post_tags', |
|
87 'assign_terms' => 'assign_post_tags', |
|
88 ), |
|
89 'show_in_rest' => true, |
|
90 'rest_base' => 'tags', |
|
91 'rest_controller_class' => 'WP_REST_Terms_Controller', |
|
71 ) ); |
92 ) ); |
72 |
93 |
73 register_taxonomy( 'nav_menu', 'nav_menu_item', array( |
94 register_taxonomy( 'nav_menu', 'nav_menu_item', array( |
74 'public' => false, |
95 'public' => false, |
75 'hierarchical' => false, |
96 'hierarchical' => false, |
97 'add_new_item' => __( 'Add New Link Category' ), |
118 'add_new_item' => __( 'Add New Link Category' ), |
98 'new_item_name' => __( 'New Link Category Name' ), |
119 'new_item_name' => __( 'New Link Category Name' ), |
99 'separate_items_with_commas' => null, |
120 'separate_items_with_commas' => null, |
100 'add_or_remove_items' => null, |
121 'add_or_remove_items' => null, |
101 'choose_from_most_used' => null, |
122 'choose_from_most_used' => null, |
123 'back_to_items' => __( '← Back to Link Categories' ), |
|
102 ), |
124 ), |
103 'capabilities' => array( |
125 'capabilities' => array( |
104 'manage_terms' => 'manage_links', |
126 'manage_terms' => 'manage_links', |
105 'edit_terms' => 'manage_links', |
127 'edit_terms' => 'manage_links', |
106 'delete_terms' => 'manage_links', |
128 'delete_terms' => 'manage_links', |
107 'assign_terms' => 'manage_links', |
129 'assign_terms' => 'manage_links', |
108 ), |
130 ), |
109 'query_var' => false, |
131 'query_var' => false, |
110 'rewrite' => false, |
132 'rewrite' => false, |
111 'public' => false, |
133 'public' => false, |
112 'show_ui' => false, |
134 'show_ui' => true, |
113 '_builtin' => true, |
135 '_builtin' => true, |
114 ) ); |
136 ) ); |
115 |
137 |
116 register_taxonomy( 'post_format', 'post', array( |
138 register_taxonomy( 'post_format', 'post', array( |
117 'public' => true, |
139 'public' => true, |
127 'show_in_nav_menus' => current_theme_supports( 'post-formats' ), |
149 'show_in_nav_menus' => current_theme_supports( 'post-formats' ), |
128 ) ); |
150 ) ); |
129 } |
151 } |
130 |
152 |
131 /** |
153 /** |
132 * Get a list of registered taxonomy objects. |
154 * Retrieves a list of registered taxonomy names or objects. |
133 * |
155 * |
134 * @since 3.0.0 |
156 * @since 3.0.0 |
135 * @uses $wp_taxonomies |
157 * |
136 * |
158 * @global array $wp_taxonomies The registered taxonomies. |
137 * @param array $args An array of key => value arguments to match against the taxonomy objects. |
159 * |
138 * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default. |
160 * @param array $args Optional. An array of `key => value` arguments to match against the taxonomy objects. |
139 * @param string $operator The logical operation to perform. 'or' means only one element |
161 * Default empty array. |
140 * from the array needs to match; 'and' means all elements must match. The default is 'and'. |
162 * @param string $output Optional. The type of output to return in the array. Accepts either taxonomy 'names' |
141 * @return array A list of taxonomy names or objects |
163 * or 'objects'. Default 'names'. |
164 * @param string $operator Optional. The logical operation to perform. Accepts 'and' or 'or'. 'or' means only |
|
165 * one element from the array needs to match; 'and' means all elements must match. |
|
166 * Default 'and'. |
|
167 * @return array A list of taxonomy names or objects. |
|
142 */ |
168 */ |
143 function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) { |
169 function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) { |
144 global $wp_taxonomies; |
170 global $wp_taxonomies; |
145 |
171 |
146 $field = ('names' == $output) ? 'name' : false; |
172 $field = ('names' == $output) ? 'name' : false; |
147 |
173 |
148 return wp_filter_object_list($wp_taxonomies, $args, $operator, $field); |
174 return wp_filter_object_list($wp_taxonomies, $args, $operator, $field); |
149 } |
175 } |
150 |
176 |
151 /** |
177 /** |
152 * Return all of the taxonomy names that are of $object_type. |
178 * Return the names or objects of the taxonomies which are registered for the requested object or object type, such as |
153 * |
179 * a post object or post type name. |
154 * It appears that this function can be used to find all of the names inside of |
180 * |
155 * $wp_taxonomies global variable. |
181 * Example: |
156 * |
182 * |
157 * `<?php $taxonomies = get_object_taxonomies('post'); ?>` Should |
183 * $taxonomies = get_object_taxonomies( 'post' ); |
158 * result in `Array( 'category', 'post_tag' )` |
184 * |
185 * This results in: |
|
186 * |
|
187 * Array( 'category', 'post_tag' ) |
|
159 * |
188 * |
160 * @since 2.3.0 |
189 * @since 2.3.0 |
161 * |
190 * |
162 * @uses $wp_taxonomies |
191 * @global array $wp_taxonomies The registered taxonomies. |
163 * |
192 * |
164 * @param array|string|object $object Name of the type of taxonomy object, or an object (row from posts) |
193 * @param array|string|WP_Post $object Name of the type of taxonomy object, or an object (row from posts) |
165 * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default. |
194 * @param string $output Optional. The type of output to return in the array. Accepts either |
195 * taxonomy 'names' or 'objects'. Default 'names'. |
|
166 * @return array The names of all taxonomy of $object_type. |
196 * @return array The names of all taxonomy of $object_type. |
167 */ |
197 */ |
168 function get_object_taxonomies($object, $output = 'names') { |
198 function get_object_taxonomies( $object, $output = 'names' ) { |
169 global $wp_taxonomies; |
199 global $wp_taxonomies; |
170 |
200 |
171 if ( is_object($object) ) { |
201 if ( is_object($object) ) { |
172 if ( $object->post_type == 'attachment' ) |
202 if ( $object->post_type == 'attachment' ) |
173 return get_attachment_taxonomies($object); |
203 return get_attachment_taxonomies( $object, $output ); |
174 $object = $object->post_type; |
204 $object = $object->post_type; |
175 } |
205 } |
176 |
206 |
177 $object = (array) $object; |
207 $object = (array) $object; |
178 |
208 |
195 * The get_taxonomy function will first check that the parameter string given |
225 * The get_taxonomy function will first check that the parameter string given |
196 * is a taxonomy object and if it is, it will return it. |
226 * is a taxonomy object and if it is, it will return it. |
197 * |
227 * |
198 * @since 2.3.0 |
228 * @since 2.3.0 |
199 * |
229 * |
200 * @uses $wp_taxonomies |
230 * @global array $wp_taxonomies The registered taxonomies. |
201 * |
231 * |
202 * @param string $taxonomy Name of taxonomy object to return |
232 * @param string $taxonomy Name of taxonomy object to return. |
203 * @return object|bool The Taxonomy Object or false if $taxonomy doesn't exist |
233 * @return WP_Taxonomy|false The Taxonomy Object or false if $taxonomy doesn't exist. |
204 */ |
234 */ |
205 function get_taxonomy( $taxonomy ) { |
235 function get_taxonomy( $taxonomy ) { |
206 global $wp_taxonomies; |
236 global $wp_taxonomies; |
207 |
237 |
208 if ( ! taxonomy_exists( $taxonomy ) ) |
238 if ( ! taxonomy_exists( $taxonomy ) ) |
216 * |
246 * |
217 * Formerly is_taxonomy(), introduced in 2.3.0. |
247 * Formerly is_taxonomy(), introduced in 2.3.0. |
218 * |
248 * |
219 * @since 3.0.0 |
249 * @since 3.0.0 |
220 * |
250 * |
221 * @uses $wp_taxonomies |
251 * @global array $wp_taxonomies The registered taxonomies. |
222 * |
252 * |
223 * @param string $taxonomy Name of taxonomy object |
253 * @param string $taxonomy Name of taxonomy object. |
224 * @return bool Whether the taxonomy exists. |
254 * @return bool Whether the taxonomy exists. |
225 */ |
255 */ |
226 function taxonomy_exists( $taxonomy ) { |
256 function taxonomy_exists( $taxonomy ) { |
227 global $wp_taxonomies; |
257 global $wp_taxonomies; |
228 |
258 |
237 * |
267 * |
238 * A false return value might also mean that the taxonomy does not exist. |
268 * A false return value might also mean that the taxonomy does not exist. |
239 * |
269 * |
240 * @since 2.3.0 |
270 * @since 2.3.0 |
241 * |
271 * |
242 * @param string $taxonomy Name of taxonomy object |
272 * @param string $taxonomy Name of taxonomy object. |
243 * @return bool Whether the taxonomy is hierarchical |
273 * @return bool Whether the taxonomy is hierarchical. |
244 */ |
274 */ |
245 function is_taxonomy_hierarchical($taxonomy) { |
275 function is_taxonomy_hierarchical($taxonomy) { |
246 if ( ! taxonomy_exists($taxonomy) ) |
276 if ( ! taxonomy_exists($taxonomy) ) |
247 return false; |
277 return false; |
248 |
278 |
249 $taxonomy = get_taxonomy($taxonomy); |
279 $taxonomy = get_taxonomy($taxonomy); |
250 return $taxonomy->hierarchical; |
280 return $taxonomy->hierarchical; |
251 } |
281 } |
252 |
282 |
253 /** |
283 /** |
254 * Create or modify a taxonomy object. Do not use before init. |
284 * Creates or modifies a taxonomy object. |
255 * |
285 * |
256 * A simple function for creating or modifying a taxonomy object based on the |
286 * Note: Do not use before the {@see 'init'} hook. |
257 * parameters given. The function will accept an array (third optional |
287 * |
258 * parameter), along with strings for the taxonomy name and another string for |
288 * A simple function for creating or modifying a taxonomy object based on |
259 * the object type. |
289 * the parameters given. If modifying an existing taxonomy object, note |
260 * |
290 * that the `$object_type` value from the original registration will be |
261 * Nothing is returned, so expect error maybe or use taxonomy_exists() to check |
291 * overwritten. |
262 * whether taxonomy exists. |
|
263 * |
|
264 * Optional $args contents: |
|
265 * |
|
266 * - label - Name of the taxonomy shown in the menu. Usually plural. If not set, labels['name'] will be used. |
|
267 * - labels - An array of labels for this taxonomy. |
|
268 * * By default tag labels are used for non-hierarchical types and category labels for hierarchical ones. |
|
269 * * You can see accepted values in {@link get_taxonomy_labels()}. |
|
270 * - description - A short descriptive summary of what the taxonomy is for. Defaults to blank. |
|
271 * - public - If the taxonomy should be publicly queryable; //@TODO not implemented. |
|
272 * * Defaults to true. |
|
273 * - hierarchical - Whether the taxonomy is hierarchical (e.g. category). Defaults to false. |
|
274 * - show_ui - Whether to generate a default UI for managing this taxonomy in the admin. |
|
275 * * If not set, the default is inherited from public. |
|
276 * - show_in_menu - Whether to show the taxonomy in the admin menu. |
|
277 * * If true, the taxonomy is shown as a submenu of the object type menu. |
|
278 * * If false, no menu is shown. |
|
279 * * show_ui must be true. |
|
280 * * If not set, the default is inherited from show_ui. |
|
281 * - show_in_nav_menus - Makes this taxonomy available for selection in navigation menus. |
|
282 * * If not set, the default is inherited from public. |
|
283 * - show_tagcloud - Whether to list the taxonomy in the Tag Cloud Widget. |
|
284 * * If not set, the default is inherited from show_ui. |
|
285 * - show_in_quick_edit - Whether to show the taxonomy in the quick/bulk edit panel. |
|
286 * * It not set, the default is inherited from show_ui. |
|
287 * - show_admin_column - Whether to display a column for the taxonomy on its post type listing screens. |
|
288 * * Defaults to false. |
|
289 * - meta_box_cb - Provide a callback function for the meta box display. |
|
290 * * If not set, defaults to post_categories_meta_box for hierarchical taxonomies |
|
291 * and post_tags_meta_box for non-hierarchical. |
|
292 * * If false, no meta box is shown. |
|
293 * - capabilities - Array of capabilities for this taxonomy. |
|
294 * * You can see accepted values in this function. |
|
295 * - rewrite - Triggers the handling of rewrites for this taxonomy. Defaults to true, using $taxonomy as slug. |
|
296 * * To prevent rewrite, set to false. |
|
297 * * To specify rewrite rules, an array can be passed with any of these keys |
|
298 * * 'slug' => string Customize the permastruct slug. Defaults to $taxonomy key |
|
299 * * 'with_front' => bool Should the permastruct be prepended with WP_Rewrite::$front. Defaults to true. |
|
300 * * 'hierarchical' => bool Either hierarchical rewrite tag or not. Defaults to false. |
|
301 * * 'ep_mask' => const Assign an endpoint mask. |
|
302 * * If not specified, defaults to EP_NONE. |
|
303 * - query_var - Sets the query_var key for this taxonomy. Defaults to $taxonomy key |
|
304 * * If false, a taxonomy cannot be loaded at ?{query_var}={term_slug} |
|
305 * * If specified as a string, the query ?{query_var_string}={term_slug} will be valid. |
|
306 * - update_count_callback - Works much like a hook, in that it will be called when the count is updated. |
|
307 * * Defaults to _update_post_term_count() for taxonomies attached to post types, which then confirms |
|
308 * that the objects are published before counting them. |
|
309 * * Defaults to _update_generic_term_count() for taxonomies attached to other object types, such as links. |
|
310 * - _builtin - true if this taxonomy is a native or "built-in" taxonomy. THIS IS FOR INTERNAL USE ONLY! |
|
311 * |
292 * |
312 * @since 2.3.0 |
293 * @since 2.3.0 |
313 * @since 4.2.0 Introduced `show_in_quick_edit` argument. |
294 * @since 4.2.0 Introduced `show_in_quick_edit` argument. |
295 * @since 4.4.0 The `show_ui` argument is now enforced on the term editing screen. |
|
296 * @since 4.4.0 The `public` argument now controls whether the taxonomy can be queried on the front end. |
|
297 * @since 4.5.0 Introduced `publicly_queryable` argument. |
|
298 * @since 4.7.0 Introduced `show_in_rest`, 'rest_base' and 'rest_controller_class' |
|
299 * arguments to register the Taxonomy in REST API. |
|
314 * |
300 * |
315 * @global array $wp_taxonomies Registered taxonomies. |
301 * @global array $wp_taxonomies Registered taxonomies. |
316 * @global WP $wp WP instance. |
302 * |
317 * |
303 * @param string $taxonomy Taxonomy key, must not exceed 32 characters. |
318 * @param string $taxonomy Taxonomy key, must not exceed 32 characters. |
304 * @param array|string $object_type Object type or array of object types with which the taxonomy should be associated. |
319 * @param array|string $object_type Name of the object type for the taxonomy object. |
305 * @param array|string $args { |
320 * @param array|string $args See optional args description above. |
306 * Optional. Array or query string of arguments for registering a taxonomy. |
321 * @return null|WP_Error WP_Error if errors, otherwise null. |
307 * |
308 * @type array $labels An array of labels for this taxonomy. By default, Tag labels are |
|
309 * used for non-hierarchical taxonomies, and Category labels are used |
|
310 * for hierarchical taxonomies. See accepted values in |
|
311 * get_taxonomy_labels(). Default empty array. |
|
312 * @type string $description A short descriptive summary of what the taxonomy is for. Default empty. |
|
313 * @type bool $public Whether a taxonomy is intended for use publicly either via |
|
314 * the admin interface or by front-end users. The default settings |
|
315 * of `$publicly_queryable`, `$show_ui`, and `$show_in_nav_menus` |
|
316 * are inherited from `$public`. |
|
317 * @type bool $publicly_queryable Whether the taxonomy is publicly queryable. |
|
318 * If not set, the default is inherited from `$public` |
|
319 * @type bool $hierarchical Whether the taxonomy is hierarchical. Default false. |
|
320 * @type bool $show_ui Whether to generate and allow a UI for managing terms in this taxonomy in |
|
321 * the admin. If not set, the default is inherited from `$public` |
|
322 * (default true). |
|
323 * @type bool $show_in_menu Whether to show the taxonomy in the admin menu. If true, the taxonomy is |
|
324 * shown as a submenu of the object type menu. If false, no menu is shown. |
|
325 * `$show_ui` must be true. If not set, default is inherited from `$show_ui` |
|
326 * (default true). |
|
327 * @type bool $show_in_nav_menus Makes this taxonomy available for selection in navigation menus. If not |
|
328 * set, the default is inherited from `$public` (default true). |
|
329 * @type bool $show_in_rest Whether to include the taxonomy in the REST API. |
|
330 * @type string $rest_base To change the base url of REST API route. Default is $taxonomy. |
|
331 * @type string $rest_controller_class REST API Controller class name. Default is 'WP_REST_Terms_Controller'. |
|
332 * @type bool $show_tagcloud Whether to list the taxonomy in the Tag Cloud Widget controls. If not set, |
|
333 * the default is inherited from `$show_ui` (default true). |
|
334 * @type bool $show_in_quick_edit Whether to show the taxonomy in the quick/bulk edit panel. It not set, |
|
335 * the default is inherited from `$show_ui` (default true). |
|
336 * @type bool $show_admin_column Whether to display a column for the taxonomy on its post type listing |
|
337 * screens. Default false. |
|
338 * @type bool|callable $meta_box_cb Provide a callback function for the meta box display. If not set, |
|
339 * post_categories_meta_box() is used for hierarchical taxonomies, and |
|
340 * post_tags_meta_box() is used for non-hierarchical. If false, no meta |
|
341 * box is shown. |
|
342 * @type array $capabilities { |
|
343 * Array of capabilities for this taxonomy. |
|
344 * |
|
345 * @type string $manage_terms Default 'manage_categories'. |
|
346 * @type string $edit_terms Default 'manage_categories'. |
|
347 * @type string $delete_terms Default 'manage_categories'. |
|
348 * @type string $assign_terms Default 'edit_posts'. |
|
349 * } |
|
350 * @type bool|array $rewrite { |
|
351 * Triggers the handling of rewrites for this taxonomy. Default true, using $taxonomy as slug. To prevent |
|
352 * rewrite, set to false. To specify rewrite rules, an array can be passed with any of these keys: |
|
353 * |
|
354 * @type string $slug Customize the permastruct slug. Default `$taxonomy` key. |
|
355 * @type bool $with_front Should the permastruct be prepended with WP_Rewrite::$front. Default true. |
|
356 * @type bool $hierarchical Either hierarchical rewrite tag or not. Default false. |
|
357 * @type int $ep_mask Assign an endpoint mask. Default `EP_NONE`. |
|
358 * } |
|
359 * @type string $query_var Sets the query var key for this taxonomy. Default `$taxonomy` key. If |
|
360 * false, a taxonomy cannot be loaded at `?{query_var}={term_slug}`. If a |
|
361 * string, the query `?{query_var}={term_slug}` will be valid. |
|
362 * @type callable $update_count_callback Works much like a hook, in that it will be called when the count is |
|
363 * updated. Default _update_post_term_count() for taxonomies attached |
|
364 * to post types, which confirms that the objects are published before |
|
365 * counting them. Default _update_generic_term_count() for taxonomies |
|
366 * attached to other object types, such as users. |
|
367 * @type bool $_builtin This taxonomy is a "built-in" taxonomy. INTERNAL USE ONLY! |
|
368 * Default false. |
|
369 * } |
|
370 * @return WP_Error|void WP_Error, if errors. |
|
322 */ |
371 */ |
323 function register_taxonomy( $taxonomy, $object_type, $args = array() ) { |
372 function register_taxonomy( $taxonomy, $object_type, $args = array() ) { |
324 global $wp_taxonomies, $wp; |
373 global $wp_taxonomies; |
325 |
374 |
326 if ( ! is_array( $wp_taxonomies ) ) |
375 if ( ! is_array( $wp_taxonomies ) ) |
327 $wp_taxonomies = array(); |
376 $wp_taxonomies = array(); |
328 |
377 |
329 $defaults = array( |
378 $args = wp_parse_args( $args ); |
330 'labels' => array(), |
|
331 'description' => '', |
|
332 'public' => true, |
|
333 'hierarchical' => false, |
|
334 'show_ui' => null, |
|
335 'show_in_menu' => null, |
|
336 'show_in_nav_menus' => null, |
|
337 'show_tagcloud' => null, |
|
338 'show_in_quick_edit' => null, |
|
339 'show_admin_column' => false, |
|
340 'meta_box_cb' => null, |
|
341 'capabilities' => array(), |
|
342 'rewrite' => true, |
|
343 'query_var' => $taxonomy, |
|
344 'update_count_callback' => '', |
|
345 '_builtin' => false, |
|
346 ); |
|
347 $args = wp_parse_args( $args, $defaults ); |
|
348 |
379 |
349 if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) { |
380 if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) { |
350 _doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2' ); |
381 _doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2.0' ); |
351 return new WP_Error( 'taxonomy_length_invalid', __( 'Taxonomy names must be between 1 and 32 characters in length.' ) ); |
382 return new WP_Error( 'taxonomy_length_invalid', __( 'Taxonomy names must be between 1 and 32 characters in length.' ) ); |
352 } |
383 } |
353 |
384 |
354 if ( false !== $args['query_var'] && ! empty( $wp ) ) { |
385 $taxonomy_object = new WP_Taxonomy( $taxonomy, $object_type, $args ); |
355 if ( true === $args['query_var'] ) |
386 $taxonomy_object->add_rewrite_rules(); |
356 $args['query_var'] = $taxonomy; |
387 |
357 else |
388 $wp_taxonomies[ $taxonomy ] = $taxonomy_object; |
358 $args['query_var'] = sanitize_title_with_dashes( $args['query_var'] ); |
389 |
359 $wp->add_query_var( $args['query_var'] ); |
390 $taxonomy_object->add_hooks(); |
360 } |
391 |
361 |
|
362 if ( false !== $args['rewrite'] && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) { |
|
363 $args['rewrite'] = wp_parse_args( $args['rewrite'], array( |
|
364 'with_front' => true, |
|
365 'hierarchical' => false, |
|
366 'ep_mask' => EP_NONE, |
|
367 ) ); |
|
368 |
|
369 if ( empty( $args['rewrite']['slug'] ) ) |
|
370 $args['rewrite']['slug'] = sanitize_title_with_dashes( $taxonomy ); |
|
371 |
|
372 if ( $args['hierarchical'] && $args['rewrite']['hierarchical'] ) |
|
373 $tag = '(.+?)'; |
|
374 else |
|
375 $tag = '([^/]+)'; |
|
376 |
|
377 add_rewrite_tag( "%$taxonomy%", $tag, $args['query_var'] ? "{$args['query_var']}=" : "taxonomy=$taxonomy&term=" ); |
|
378 add_permastruct( $taxonomy, "{$args['rewrite']['slug']}/%$taxonomy%", $args['rewrite'] ); |
|
379 } |
|
380 |
|
381 // If not set, default to the setting for public. |
|
382 if ( null === $args['show_ui'] ) |
|
383 $args['show_ui'] = $args['public']; |
|
384 |
|
385 // If not set, default to the setting for show_ui. |
|
386 if ( null === $args['show_in_menu' ] || ! $args['show_ui'] ) |
|
387 $args['show_in_menu' ] = $args['show_ui']; |
|
388 |
|
389 // If not set, default to the setting for public. |
|
390 if ( null === $args['show_in_nav_menus'] ) |
|
391 $args['show_in_nav_menus'] = $args['public']; |
|
392 |
|
393 // If not set, default to the setting for show_ui. |
|
394 if ( null === $args['show_tagcloud'] ) |
|
395 $args['show_tagcloud'] = $args['show_ui']; |
|
396 |
|
397 // If not set, default to the setting for show_ui. |
|
398 if ( null === $args['show_in_quick_edit'] ) { |
|
399 $args['show_in_quick_edit'] = $args['show_ui']; |
|
400 } |
|
401 |
|
402 $default_caps = array( |
|
403 'manage_terms' => 'manage_categories', |
|
404 'edit_terms' => 'manage_categories', |
|
405 'delete_terms' => 'manage_categories', |
|
406 'assign_terms' => 'edit_posts', |
|
407 ); |
|
408 $args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] ); |
|
409 unset( $args['capabilities'] ); |
|
410 |
|
411 $args['name'] = $taxonomy; |
|
412 $args['object_type'] = array_unique( (array) $object_type ); |
|
413 |
|
414 $args['labels'] = get_taxonomy_labels( (object) $args ); |
|
415 $args['label'] = $args['labels']->name; |
|
416 |
|
417 // If not set, use the default meta box |
|
418 if ( null === $args['meta_box_cb'] ) { |
|
419 if ( $args['hierarchical'] ) |
|
420 $args['meta_box_cb'] = 'post_categories_meta_box'; |
|
421 else |
|
422 $args['meta_box_cb'] = 'post_tags_meta_box'; |
|
423 } |
|
424 |
|
425 $wp_taxonomies[ $taxonomy ] = (object) $args; |
|
426 |
|
427 // register callback handling for metabox |
|
428 add_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' ); |
|
429 |
392 |
430 /** |
393 /** |
431 * Fires after a taxonomy is registered. |
394 * Fires after a taxonomy is registered. |
432 * |
395 * |
433 * @since 3.3.0 |
396 * @since 3.3.0 |
434 * |
397 * |
435 * @param string $taxonomy Taxonomy slug. |
398 * @param string $taxonomy Taxonomy slug. |
436 * @param array|string $object_type Object type or array of object types. |
399 * @param array|string $object_type Object type or array of object types. |
437 * @param array $args Array of taxonomy registration arguments. |
400 * @param array $args Array of taxonomy registration arguments. |
438 */ |
401 */ |
439 do_action( 'registered_taxonomy', $taxonomy, $object_type, $args ); |
402 do_action( 'registered_taxonomy', $taxonomy, $object_type, (array) $taxonomy_object ); |
440 } |
403 } |
441 |
404 |
442 /** |
405 /** |
443 * Builds an object with all taxonomy labels out of a taxonomy object |
406 * Unregisters a taxonomy. |
444 * |
407 * |
445 * Accepted keys of the label array in the taxonomy object: |
408 * Can not be used to unregister built-in taxonomies. |
446 * |
409 * |
447 * - name - general name for the taxonomy, usually plural. The same as and overridden by $tax->label. Default is Tags/Categories |
410 * @since 4.5.0 |
448 * - singular_name - name for one object of this taxonomy. Default is Tag/Category |
411 * |
449 * - search_items - Default is Search Tags/Search Categories |
412 * @global WP $wp Current WordPress environment instance. |
450 * - popular_items - This string isn't used on hierarchical taxonomies. Default is Popular Tags |
413 * @global array $wp_taxonomies List of taxonomies. |
451 * - all_items - Default is All Tags/All Categories |
414 * |
452 * - parent_item - This string isn't used on non-hierarchical taxonomies. In hierarchical ones the default is Parent Category |
415 * @param string $taxonomy Taxonomy name. |
453 * - parent_item_colon - The same as `parent_item`, but with colon `:` in the end |
416 * @return bool|WP_Error True on success, WP_Error on failure or if the taxonomy doesn't exist. |
454 * - edit_item - Default is Edit Tag/Edit Category |
417 */ |
455 * - view_item - Default is View Tag/View Category |
418 function unregister_taxonomy( $taxonomy ) { |
456 * - update_item - Default is Update Tag/Update Category |
419 if ( ! taxonomy_exists( $taxonomy ) ) { |
457 * - add_new_item - Default is Add New Tag/Add New Category |
420 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
458 * - new_item_name - Default is New Tag Name/New Category Name |
421 } |
459 * - separate_items_with_commas - This string isn't used on hierarchical taxonomies. Default is "Separate tags with commas", used in the meta box. |
422 |
460 * - add_or_remove_items - This string isn't used on hierarchical taxonomies. Default is "Add or remove tags", used in the meta box when JavaScript is disabled. |
423 $taxonomy_object = get_taxonomy( $taxonomy ); |
461 * - choose_from_most_used - This string isn't used on hierarchical taxonomies. Default is "Choose from the most used tags", used in the meta box. |
424 |
462 * - not_found - Default is "No tags found"/"No categories found", used in the meta box and taxonomy list table. |
425 // Do not allow unregistering internal taxonomies. |
463 * |
426 if ( $taxonomy_object->_builtin ) { |
464 * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories). |
427 return new WP_Error( 'invalid_taxonomy', __( 'Unregistering a built-in taxonomy is not allowed.' ) ); |
428 } |
|
429 |
|
430 global $wp_taxonomies; |
|
431 |
|
432 $taxonomy_object->remove_rewrite_rules(); |
|
433 $taxonomy_object->remove_hooks(); |
|
434 |
|
435 // Remove the taxonomy. |
|
436 unset( $wp_taxonomies[ $taxonomy ] ); |
|
437 |
|
438 /** |
|
439 * Fires after a taxonomy is unregistered. |
|
440 * |
|
441 * @since 4.5.0 |
|
442 * |
|
443 * @param string $taxonomy Taxonomy name. |
|
444 */ |
|
445 do_action( 'unregistered_taxonomy', $taxonomy ); |
|
446 |
|
447 return true; |
|
448 } |
|
449 |
|
450 /** |
|
451 * Builds an object with all taxonomy labels out of a taxonomy object. |
|
465 * |
452 * |
466 * @since 3.0.0 |
453 * @since 3.0.0 |
467 * @param object $tax Taxonomy object |
454 * @since 4.3.0 Added the `no_terms` label. |
468 * @return object object with all the labels as member variables |
455 * @since 4.4.0 Added the `items_list_navigation` and `items_list` labels. |
469 */ |
456 * @since 4.9.0 Added the `most_used` and `back_to_items` labels. |
470 |
457 * |
458 * @param WP_Taxonomy $tax Taxonomy object. |
|
459 * @return object { |
|
460 * Taxonomy labels object. The first default value is for non-hierarchical taxonomies |
|
461 * (like tags) and the second one is for hierarchical taxonomies (like categories). |
|
462 * |
|
463 * @type string $name General name for the taxonomy, usually plural. The same |
|
464 * as and overridden by `$tax->label`. Default 'Tags'/'Categories'. |
|
465 * @type string $singular_name Name for one object of this taxonomy. Default 'Tag'/'Category'. |
|
466 * @type string $search_items Default 'Search Tags'/'Search Categories'. |
|
467 * @type string $popular_items This label is only used for non-hierarchical taxonomies. |
|
468 * Default 'Popular Tags'. |
|
469 * @type string $all_items Default 'All Tags'/'All Categories'. |
|
470 * @type string $parent_item This label is only used for hierarchical taxonomies. Default |
|
471 * 'Parent Category'. |
|
472 * @type string $parent_item_colon The same as `parent_item`, but with colon `:` in the end. |
|
473 * @type string $edit_item Default 'Edit Tag'/'Edit Category'. |
|
474 * @type string $view_item Default 'View Tag'/'View Category'. |
|
475 * @type string $update_item Default 'Update Tag'/'Update Category'. |
|
476 * @type string $add_new_item Default 'Add New Tag'/'Add New Category'. |
|
477 * @type string $new_item_name Default 'New Tag Name'/'New Category Name'. |
|
478 * @type string $separate_items_with_commas This label is only used for non-hierarchical taxonomies. Default |
|
479 * 'Separate tags with commas', used in the meta box. |
|
480 * @type string $add_or_remove_items This label is only used for non-hierarchical taxonomies. Default |
|
481 * 'Add or remove tags', used in the meta box when JavaScript |
|
482 * is disabled. |
|
483 * @type string $choose_from_most_used This label is only used on non-hierarchical taxonomies. Default |
|
484 * 'Choose from the most used tags', used in the meta box. |
|
485 * @type string $not_found Default 'No tags found'/'No categories found', used in |
|
486 * the meta box and taxonomy list table. |
|
487 * @type string $no_terms Default 'No tags'/'No categories', used in the posts and media |
|
488 * list tables. |
|
489 * @type string $items_list_navigation Label for the table pagination hidden heading. |
|
490 * @type string $items_list Label for the table hidden heading. |
|
491 * @type string $most_used Title for the Most Used tab. Default 'Most Used'. |
|
492 * @type string $back_to_items Label displayed after a term has been updated. |
|
493 * } |
|
494 */ |
|
471 function get_taxonomy_labels( $tax ) { |
495 function get_taxonomy_labels( $tax ) { |
472 $tax->labels = (array) $tax->labels; |
496 $tax->labels = (array) $tax->labels; |
473 |
497 |
474 if ( isset( $tax->helps ) && empty( $tax->labels['separate_items_with_commas'] ) ) |
498 if ( isset( $tax->helps ) && empty( $tax->labels['separate_items_with_commas'] ) ) |
475 $tax->labels['separate_items_with_commas'] = $tax->helps; |
499 $tax->labels['separate_items_with_commas'] = $tax->helps; |
492 'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ), |
516 'new_item_name' => array( __( 'New Tag Name' ), __( 'New Category Name' ) ), |
493 'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ), |
517 'separate_items_with_commas' => array( __( 'Separate tags with commas' ), null ), |
494 'add_or_remove_items' => array( __( 'Add or remove tags' ), null ), |
518 'add_or_remove_items' => array( __( 'Add or remove tags' ), null ), |
495 'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ), |
519 'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ), |
496 'not_found' => array( __( 'No tags found.' ), __( 'No categories found.' ) ), |
520 'not_found' => array( __( 'No tags found.' ), __( 'No categories found.' ) ), |
521 'no_terms' => array( __( 'No tags' ), __( 'No categories' ) ), |
|
522 'items_list_navigation' => array( __( 'Tags list navigation' ), __( 'Categories list navigation' ) ), |
|
523 'items_list' => array( __( 'Tags list' ), __( 'Categories list' ) ), |
|
524 /* translators: Tab heading when selecting from the most used terms */ |
|
525 'most_used' => array( _x( 'Most Used', 'tags' ), _x( 'Most Used', 'categories' ) ), |
|
526 'back_to_items' => array( __( '← Back to Tags' ), __( '← Back to Categories' ) ), |
|
497 ); |
527 ); |
498 $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name']; |
528 $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name']; |
499 |
529 |
500 return _get_custom_object_labels( $tax, $nohier_vs_hier_defaults ); |
530 $labels = _get_custom_object_labels( $tax, $nohier_vs_hier_defaults ); |
531 |
|
532 $taxonomy = $tax->name; |
|
533 |
|
534 $default_labels = clone $labels; |
|
535 |
|
536 /** |
|
537 * Filters the labels of a specific taxonomy. |
|
538 * |
|
539 * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. |
|
540 * |
|
541 * @since 4.4.0 |
|
542 * |
|
543 * @see get_taxonomy_labels() for the full list of taxonomy labels. |
|
544 * |
|
545 * @param object $labels Object with labels for the taxonomy as member variables. |
|
546 */ |
|
547 $labels = apply_filters( "taxonomy_labels_{$taxonomy}", $labels ); |
|
548 |
|
549 // Ensure that the filtered labels contain all required default values. |
|
550 $labels = (object) array_merge( (array) $default_labels, (array) $labels ); |
|
551 |
|
552 return $labels; |
|
501 } |
553 } |
502 |
554 |
503 /** |
555 /** |
504 * Add an already registered taxonomy to an object type. |
556 * Add an already registered taxonomy to an object type. |
505 * |
557 * |
506 * @since 3.0.0 |
558 * @since 3.0.0 |
507 * @uses $wp_taxonomies Modifies taxonomy object |
559 * |
508 * |
560 * @global array $wp_taxonomies The registered taxonomies. |
509 * @param string $taxonomy Name of taxonomy object |
561 * |
510 * @param string $object_type Name of the object type |
562 * @param string $taxonomy Name of taxonomy object. |
511 * @return bool True if successful, false if not |
563 * @param string $object_type Name of the object type. |
564 * @return bool True if successful, false if not. |
|
512 */ |
565 */ |
513 function register_taxonomy_for_object_type( $taxonomy, $object_type) { |
566 function register_taxonomy_for_object_type( $taxonomy, $object_type) { |
514 global $wp_taxonomies; |
567 global $wp_taxonomies; |
515 |
568 |
516 if ( !isset($wp_taxonomies[$taxonomy]) ) |
569 if ( !isset($wp_taxonomies[$taxonomy]) ) |
520 return false; |
573 return false; |
521 |
574 |
522 if ( ! in_array( $object_type, $wp_taxonomies[$taxonomy]->object_type ) ) |
575 if ( ! in_array( $object_type, $wp_taxonomies[$taxonomy]->object_type ) ) |
523 $wp_taxonomies[$taxonomy]->object_type[] = $object_type; |
576 $wp_taxonomies[$taxonomy]->object_type[] = $object_type; |
524 |
577 |
578 // Filter out empties. |
|
579 $wp_taxonomies[ $taxonomy ]->object_type = array_filter( $wp_taxonomies[ $taxonomy ]->object_type ); |
|
580 |
|
525 return true; |
581 return true; |
526 } |
582 } |
527 |
583 |
528 /** |
584 /** |
529 * Remove an already registered taxonomy from an object type. |
585 * Remove an already registered taxonomy from an object type. |
530 * |
586 * |
531 * @since 3.7.0 |
587 * @since 3.7.0 |
588 * |
|
589 * @global array $wp_taxonomies The registered taxonomies. |
|
532 * |
590 * |
533 * @param string $taxonomy Name of taxonomy object. |
591 * @param string $taxonomy Name of taxonomy object. |
534 * @param string $object_type Name of the object type. |
592 * @param string $object_type Name of the object type. |
535 * @return bool True if successful, false if not. |
593 * @return bool True if successful, false if not. |
536 */ |
594 */ |
572 * |
630 * |
573 * @since 2.3.0 |
631 * @since 2.3.0 |
574 * |
632 * |
575 * @global wpdb $wpdb WordPress database abstraction object. |
633 * @global wpdb $wpdb WordPress database abstraction object. |
576 * |
634 * |
577 * @param int|array $term_ids Term id or array of term ids of terms that will be used |
635 * @param int|array $term_ids Term id or array of term ids of terms that will be used. |
578 * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names |
636 * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names. |
579 * @param array|string $args Change the order of the object_ids, either ASC or DESC |
637 * @param array|string $args Change the order of the object_ids, either ASC or DESC. |
580 * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success |
638 * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success. |
581 * the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found. |
639 * the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found. |
582 */ |
640 */ |
583 function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) { |
641 function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) { |
584 global $wpdb; |
642 global $wpdb; |
585 |
643 |
589 if ( ! is_array( $taxonomies ) ) { |
647 if ( ! is_array( $taxonomies ) ) { |
590 $taxonomies = array( $taxonomies ); |
648 $taxonomies = array( $taxonomies ); |
591 } |
649 } |
592 foreach ( (array) $taxonomies as $taxonomy ) { |
650 foreach ( (array) $taxonomies as $taxonomy ) { |
593 if ( ! taxonomy_exists( $taxonomy ) ) { |
651 if ( ! taxonomy_exists( $taxonomy ) ) { |
594 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) ); |
652 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
595 } |
653 } |
596 } |
654 } |
597 |
655 |
598 $defaults = array( 'order' => 'ASC' ); |
656 $defaults = array( 'order' => 'ASC' ); |
599 $args = wp_parse_args( $args, $defaults ); |
657 $args = wp_parse_args( $args, $defaults ); |
600 |
658 |
601 $order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC'; |
659 $order = ( 'desc' == strtolower( $args['order'] ) ) ? 'DESC' : 'ASC'; |
602 |
660 |
603 $term_ids = array_map('intval', $term_ids ); |
661 $term_ids = array_map('intval', $term_ids ); |
604 |
662 |
605 $taxonomies = "'" . implode( "', '", $taxonomies ) . "'"; |
663 $taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'"; |
606 $term_ids = "'" . implode( "', '", $term_ids ) . "'"; |
664 $term_ids = "'" . implode( "', '", $term_ids ) . "'"; |
607 |
665 |
608 $object_ids = $wpdb->get_col("SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order"); |
666 $sql = "SELECT tr.object_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tt.term_id IN ($term_ids) ORDER BY tr.object_id $order"; |
667 |
|
668 $last_changed = wp_cache_get_last_changed( 'terms' ); |
|
669 $cache_key = 'get_objects_in_term:' . md5( $sql ) . ":$last_changed"; |
|
670 $cache = wp_cache_get( $cache_key, 'terms' ); |
|
671 if ( false === $cache ) { |
|
672 $object_ids = $wpdb->get_col( $sql ); |
|
673 wp_cache_set( $cache_key, $object_ids, 'terms' ); |
|
674 } else { |
|
675 $object_ids = (array) $cache; |
|
676 } |
|
609 |
677 |
610 if ( ! $object_ids ){ |
678 if ( ! $object_ids ){ |
611 return array(); |
679 return array(); |
612 } |
680 } |
613 return $object_ids; |
681 return $object_ids; |
618 * |
686 * |
619 * @since 3.1.0 |
687 * @since 3.1.0 |
620 * |
688 * |
621 * @see WP_Tax_Query |
689 * @see WP_Tax_Query |
622 * |
690 * |
623 * @param array $tax_query A compact tax query |
691 * @param array $tax_query A compact tax query |
624 * @param string $primary_table |
692 * @param string $primary_table |
625 * @param string $primary_id_column |
693 * @param string $primary_id_column |
626 * @return array |
694 * @return array |
627 */ |
695 */ |
628 function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) { |
696 function get_tax_sql( $tax_query, $primary_table, $primary_id_column ) { |
629 $tax_query_obj = new WP_Tax_Query( $tax_query ); |
697 $tax_query_obj = new WP_Tax_Query( $tax_query ); |
630 return $tax_query_obj->get_sql( $primary_table, $primary_id_column ); |
698 return $tax_query_obj->get_sql( $primary_table, $primary_id_column ); |
631 } |
|
632 |
|
633 /** |
|
634 * Class for generating SQL clauses that filter a primary query according to object taxonomy terms. |
|
635 * |
|
636 * `WP_Tax_Query` is a helper that allows primary query classes, such as {@see WP_Query}, to filter |
|
637 * their results by object metadata, by generating `JOIN` and `WHERE` subclauses to be attached |
|
638 * to the primary SQL query string. |
|
639 * |
|
640 * @since 3.1.0 |
|
641 */ |
|
642 class WP_Tax_Query { |
|
643 |
|
644 /** |
|
645 * Array of taxonomy queries. |
|
646 * |
|
647 * See {@see WP_Tax_Query::__construct()} for information on tax query arguments. |
|
648 * |
|
649 * @since 3.1.0 |
|
650 * @access public |
|
651 * @var array |
|
652 */ |
|
653 public $queries = array(); |
|
654 |
|
655 /** |
|
656 * The relation between the queries. Can be one of 'AND' or 'OR'. |
|
657 * |
|
658 * @since 3.1.0 |
|
659 * @access public |
|
660 * @var string |
|
661 */ |
|
662 public $relation; |
|
663 |
|
664 /** |
|
665 * Standard response when the query should not return any rows. |
|
666 * |
|
667 * @since 3.2.0 |
|
668 * @access private |
|
669 * @var string |
|
670 */ |
|
671 private static $no_results = array( 'join' => array( '' ), 'where' => array( '0 = 1' ) ); |
|
672 |
|
673 /** |
|
674 * A flat list of table aliases used in the JOIN clauses. |
|
675 * |
|
676 * @since 4.1.0 |
|
677 * @access protected |
|
678 * @var array |
|
679 */ |
|
680 protected $table_aliases = array(); |
|
681 |
|
682 /** |
|
683 * Terms and taxonomies fetched by this query. |
|
684 * |
|
685 * We store this data in a flat array because they are referenced in a |
|
686 * number of places by {@see WP_Query}. |
|
687 * |
|
688 * @since 4.1.0 |
|
689 * @access public |
|
690 * @var array |
|
691 */ |
|
692 public $queried_terms = array(); |
|
693 |
|
694 /** |
|
695 * Database table that where the metadata's objects are stored (eg $wpdb->users). |
|
696 * |
|
697 * @since 4.1.0 |
|
698 * @access public |
|
699 * @var string |
|
700 */ |
|
701 public $primary_table; |
|
702 |
|
703 /** |
|
704 * Column in 'primary_table' that represents the ID of the object. |
|
705 * |
|
706 * @since 4.1.0 |
|
707 * @access public |
|
708 * @var string |
|
709 */ |
|
710 public $primary_id_column; |
|
711 |
|
712 /** |
|
713 * Constructor. |
|
714 * |
|
715 * @since 3.1.0 |
|
716 * @since 4.1.0 Added support for `$operator` 'NOT EXISTS' and 'EXISTS' values. |
|
717 * @access public |
|
718 * |
|
719 * @param array $tax_query { |
|
720 * Array of taxonomy query clauses. |
|
721 * |
|
722 * @type string $relation Optional. The MySQL keyword used to join |
|
723 * the clauses of the query. Accepts 'AND', or 'OR'. Default 'AND'. |
|
724 * @type array { |
|
725 * Optional. An array of first-order clause parameters, or another fully-formed tax query. |
|
726 * |
|
727 * @type string $taxonomy Taxonomy being queried. Optional when field=term_taxonomy_id. |
|
728 * @type string|int|array $terms Term or terms to filter by. |
|
729 * @type string $field Field to match $terms against. Accepts 'term_id', 'slug', |
|
730 * 'name', or 'term_taxonomy_id'. Default: 'term_id'. |
|
731 * @type string $operator MySQL operator to be used with $terms in the WHERE clause. |
|
732 * Accepts 'AND', 'IN', 'NOT IN', 'EXISTS', 'NOT EXISTS'. |
|
733 * Default: 'IN'. |
|
734 * @type bool $include_children Optional. Whether to include child terms. |
|
735 * Requires a $taxonomy. Default: true. |
|
736 * } |
|
737 * } |
|
738 */ |
|
739 public function __construct( $tax_query ) { |
|
740 if ( isset( $tax_query['relation'] ) ) { |
|
741 $this->relation = $this->sanitize_relation( $tax_query['relation'] ); |
|
742 } else { |
|
743 $this->relation = 'AND'; |
|
744 } |
|
745 |
|
746 $this->queries = $this->sanitize_query( $tax_query ); |
|
747 } |
|
748 |
|
749 /** |
|
750 * Ensure the 'tax_query' argument passed to the class constructor is well-formed. |
|
751 * |
|
752 * Ensures that each query-level clause has a 'relation' key, and that |
|
753 * each first-order clause contains all the necessary keys from `$defaults`. |
|
754 * |
|
755 * @since 4.1.0 |
|
756 * @access public |
|
757 * |
|
758 * @param array $queries Array of queries clauses. |
|
759 * @return array Sanitized array of query clauses. |
|
760 */ |
|
761 public function sanitize_query( $queries ) { |
|
762 $cleaned_query = array(); |
|
763 |
|
764 $defaults = array( |
|
765 'taxonomy' => '', |
|
766 'terms' => array(), |
|
767 'field' => 'term_id', |
|
768 'operator' => 'IN', |
|
769 'include_children' => true, |
|
770 ); |
|
771 |
|
772 foreach ( $queries as $key => $query ) { |
|
773 if ( 'relation' === $key ) { |
|
774 $cleaned_query['relation'] = $this->sanitize_relation( $query ); |
|
775 |
|
776 // First-order clause. |
|
777 } elseif ( self::is_first_order_clause( $query ) ) { |
|
778 |
|
779 $cleaned_clause = array_merge( $defaults, $query ); |
|
780 $cleaned_clause['terms'] = (array) $cleaned_clause['terms']; |
|
781 $cleaned_query[] = $cleaned_clause; |
|
782 |
|
783 /* |
|
784 * Keep a copy of the clause in the flate |
|
785 * $queried_terms array, for use in WP_Query. |
|
786 */ |
|
787 if ( ! empty( $cleaned_clause['taxonomy'] ) && 'NOT IN' !== $cleaned_clause['operator'] ) { |
|
788 $taxonomy = $cleaned_clause['taxonomy']; |
|
789 if ( ! isset( $this->queried_terms[ $taxonomy ] ) ) { |
|
790 $this->queried_terms[ $taxonomy ] = array(); |
|
791 } |
|
792 |
|
793 /* |
|
794 * Backward compatibility: Only store the first |
|
795 * 'terms' and 'field' found for a given taxonomy. |
|
796 */ |
|
797 if ( ! empty( $cleaned_clause['terms'] ) && ! isset( $this->queried_terms[ $taxonomy ]['terms'] ) ) { |
|
798 $this->queried_terms[ $taxonomy ]['terms'] = $cleaned_clause['terms']; |
|
799 } |
|
800 |
|
801 if ( ! empty( $cleaned_clause['field'] ) && ! isset( $this->queried_terms[ $taxonomy ]['field'] ) ) { |
|
802 $this->queried_terms[ $taxonomy ]['field'] = $cleaned_clause['field']; |
|
803 } |
|
804 } |
|
805 |
|
806 // Otherwise, it's a nested query, so we recurse. |
|
807 } elseif ( is_array( $query ) ) { |
|
808 $cleaned_subquery = $this->sanitize_query( $query ); |
|
809 |
|
810 if ( ! empty( $cleaned_subquery ) ) { |
|
811 // All queries with children must have a relation. |
|
812 if ( ! isset( $cleaned_subquery['relation'] ) ) { |
|
813 $cleaned_subquery['relation'] = 'AND'; |
|
814 } |
|
815 |
|
816 $cleaned_query[] = $cleaned_subquery; |
|
817 } |
|
818 } |
|
819 } |
|
820 |
|
821 return $cleaned_query; |
|
822 } |
|
823 |
|
824 /** |
|
825 * Sanitize a 'relation' operator. |
|
826 * |
|
827 * @since 4.1.0 |
|
828 * @access public |
|
829 * |
|
830 * @param string $relation Raw relation key from the query argument. |
|
831 * @return string Sanitized relation ('AND' or 'OR'). |
|
832 */ |
|
833 public function sanitize_relation( $relation ) { |
|
834 if ( 'OR' === strtoupper( $relation ) ) { |
|
835 return 'OR'; |
|
836 } else { |
|
837 return 'AND'; |
|
838 } |
|
839 } |
|
840 |
|
841 /** |
|
842 * Determine whether a clause is first-order. |
|
843 * |
|
844 * A "first-order" clause is one that contains any of the first-order |
|
845 * clause keys ('terms', 'taxonomy', 'include_children', 'field', |
|
846 * 'operator'). An empty clause also counts as a first-order clause, |
|
847 * for backward compatibility. Any clause that doesn't meet this is |
|
848 * determined, by process of elimination, to be a higher-order query. |
|
849 * |
|
850 * @since 4.1.0 |
|
851 * @access protected |
|
852 * |
|
853 * @param array $query Tax query arguments. |
|
854 * @return bool Whether the query clause is a first-order clause. |
|
855 */ |
|
856 protected static function is_first_order_clause( $query ) { |
|
857 return is_array( $query ) && ( empty( $query ) || array_key_exists( 'terms', $query ) || array_key_exists( 'taxonomy', $query ) || array_key_exists( 'include_children', $query ) || array_key_exists( 'field', $query ) || array_key_exists( 'operator', $query ) ); |
|
858 } |
|
859 |
|
860 /** |
|
861 * Generates SQL clauses to be appended to a main query. |
|
862 * |
|
863 * @since 3.1.0 |
|
864 * @access public |
|
865 * |
|
866 * @param string $primary_table Database table where the object being filtered is stored (eg wp_users). |
|
867 * @param string $primary_id_column ID column for the filtered object in $primary_table. |
|
868 * @return array { |
|
869 * Array containing JOIN and WHERE SQL clauses to append to the main query. |
|
870 * |
|
871 * @type string $join SQL fragment to append to the main JOIN clause. |
|
872 * @type string $where SQL fragment to append to the main WHERE clause. |
|
873 * } |
|
874 */ |
|
875 public function get_sql( $primary_table, $primary_id_column ) { |
|
876 $this->primary_table = $primary_table; |
|
877 $this->primary_id_column = $primary_id_column; |
|
878 |
|
879 return $this->get_sql_clauses(); |
|
880 } |
|
881 |
|
882 /** |
|
883 * Generate SQL clauses to be appended to a main query. |
|
884 * |
|
885 * Called by the public {@see WP_Tax_Query::get_sql()}, this method |
|
886 * is abstracted out to maintain parity with the other Query classes. |
|
887 * |
|
888 * @since 4.1.0 |
|
889 * @access protected |
|
890 * |
|
891 * @return array { |
|
892 * Array containing JOIN and WHERE SQL clauses to append to the main query. |
|
893 * |
|
894 * @type string $join SQL fragment to append to the main JOIN clause. |
|
895 * @type string $where SQL fragment to append to the main WHERE clause. |
|
896 * } |
|
897 */ |
|
898 protected function get_sql_clauses() { |
|
899 /* |
|
900 * $queries are passed by reference to get_sql_for_query() for recursion. |
|
901 * To keep $this->queries unaltered, pass a copy. |
|
902 */ |
|
903 $queries = $this->queries; |
|
904 $sql = $this->get_sql_for_query( $queries ); |
|
905 |
|
906 if ( ! empty( $sql['where'] ) ) { |
|
907 $sql['where'] = ' AND ' . $sql['where']; |
|
908 } |
|
909 |
|
910 return $sql; |
|
911 } |
|
912 |
|
913 /** |
|
914 * Generate SQL clauses for a single query array. |
|
915 * |
|
916 * If nested subqueries are found, this method recurses the tree to |
|
917 * produce the properly nested SQL. |
|
918 * |
|
919 * @since 4.1.0 |
|
920 * @access protected |
|
921 * |
|
922 * @param array $query Query to parse, passed by reference. |
|
923 * @param int $depth Optional. Number of tree levels deep we currently are. |
|
924 * Used to calculate indentation. Default 0. |
|
925 * @return array { |
|
926 * Array containing JOIN and WHERE SQL clauses to append to a single query array. |
|
927 * |
|
928 * @type string $join SQL fragment to append to the main JOIN clause. |
|
929 * @type string $where SQL fragment to append to the main WHERE clause. |
|
930 * } |
|
931 */ |
|
932 protected function get_sql_for_query( &$query, $depth = 0 ) { |
|
933 $sql_chunks = array( |
|
934 'join' => array(), |
|
935 'where' => array(), |
|
936 ); |
|
937 |
|
938 $sql = array( |
|
939 'join' => '', |
|
940 'where' => '', |
|
941 ); |
|
942 |
|
943 $indent = ''; |
|
944 for ( $i = 0; $i < $depth; $i++ ) { |
|
945 $indent .= " "; |
|
946 } |
|
947 |
|
948 foreach ( $query as $key => &$clause ) { |
|
949 if ( 'relation' === $key ) { |
|
950 $relation = $query['relation']; |
|
951 } elseif ( is_array( $clause ) ) { |
|
952 |
|
953 // This is a first-order clause. |
|
954 if ( $this->is_first_order_clause( $clause ) ) { |
|
955 $clause_sql = $this->get_sql_for_clause( $clause, $query ); |
|
956 |
|
957 $where_count = count( $clause_sql['where'] ); |
|
958 if ( ! $where_count ) { |
|
959 $sql_chunks['where'][] = ''; |
|
960 } elseif ( 1 === $where_count ) { |
|
961 $sql_chunks['where'][] = $clause_sql['where'][0]; |
|
962 } else { |
|
963 $sql_chunks['where'][] = '( ' . implode( ' AND ', $clause_sql['where'] ) . ' )'; |
|
964 } |
|
965 |
|
966 $sql_chunks['join'] = array_merge( $sql_chunks['join'], $clause_sql['join'] ); |
|
967 // This is a subquery, so we recurse. |
|
968 } else { |
|
969 $clause_sql = $this->get_sql_for_query( $clause, $depth + 1 ); |
|
970 |
|
971 $sql_chunks['where'][] = $clause_sql['where']; |
|
972 $sql_chunks['join'][] = $clause_sql['join']; |
|
973 } |
|
974 } |
|
975 } |
|
976 |
|
977 // Filter to remove empties. |
|
978 $sql_chunks['join'] = array_filter( $sql_chunks['join'] ); |
|
979 $sql_chunks['where'] = array_filter( $sql_chunks['where'] ); |
|
980 |
|
981 if ( empty( $relation ) ) { |
|
982 $relation = 'AND'; |
|
983 } |
|
984 |
|
985 // Filter duplicate JOIN clauses and combine into a single string. |
|
986 if ( ! empty( $sql_chunks['join'] ) ) { |
|
987 $sql['join'] = implode( ' ', array_unique( $sql_chunks['join'] ) ); |
|
988 } |
|
989 |
|
990 // Generate a single WHERE clause with proper brackets and indentation. |
|
991 if ( ! empty( $sql_chunks['where'] ) ) { |
|
992 $sql['where'] = '( ' . "\n " . $indent . implode( ' ' . "\n " . $indent . $relation . ' ' . "\n " . $indent, $sql_chunks['where'] ) . "\n" . $indent . ')'; |
|
993 } |
|
994 |
|
995 return $sql; |
|
996 } |
|
997 |
|
998 /** |
|
999 * Generate SQL JOIN and WHERE clauses for a "first-order" query clause. |
|
1000 * |
|
1001 * @since 4.1.0 |
|
1002 * @access public |
|
1003 * |
|
1004 * @param array $clause Query clause, passed by reference |
|
1005 * @param array $parent_query Parent query array. |
|
1006 * @return array { |
|
1007 * Array containing JOIN and WHERE SQL clauses to append to a first-order query. |
|
1008 * |
|
1009 * @type string $join SQL fragment to append to the main JOIN clause. |
|
1010 * @type string $where SQL fragment to append to the main WHERE clause. |
|
1011 * } |
|
1012 */ |
|
1013 public function get_sql_for_clause( &$clause, $parent_query ) { |
|
1014 global $wpdb; |
|
1015 |
|
1016 $sql = array( |
|
1017 'where' => array(), |
|
1018 'join' => array(), |
|
1019 ); |
|
1020 |
|
1021 $join = ''; |
|
1022 |
|
1023 $this->clean_query( $clause ); |
|
1024 |
|
1025 if ( is_wp_error( $clause ) ) { |
|
1026 return self::$no_results; |
|
1027 } |
|
1028 |
|
1029 $terms = $clause['terms']; |
|
1030 $operator = strtoupper( $clause['operator'] ); |
|
1031 |
|
1032 if ( 'IN' == $operator ) { |
|
1033 |
|
1034 if ( empty( $terms ) ) { |
|
1035 return self::$no_results; |
|
1036 } |
|
1037 |
|
1038 $terms = implode( ',', $terms ); |
|
1039 |
|
1040 /* |
|
1041 * Before creating another table join, see if this clause has a |
|
1042 * sibling with an existing join that can be shared. |
|
1043 */ |
|
1044 $alias = $this->find_compatible_table_alias( $clause, $parent_query ); |
|
1045 if ( false === $alias ) { |
|
1046 $i = count( $this->table_aliases ); |
|
1047 $alias = $i ? 'tt' . $i : $wpdb->term_relationships; |
|
1048 |
|
1049 // Store the alias as part of a flat array to build future iterators. |
|
1050 $this->table_aliases[] = $alias; |
|
1051 |
|
1052 // Store the alias with this clause, so later siblings can use it. |
|
1053 $clause['alias'] = $alias; |
|
1054 |
|
1055 $join .= " INNER JOIN $wpdb->term_relationships"; |
|
1056 $join .= $i ? " AS $alias" : ''; |
|
1057 $join .= " ON ($this->primary_table.$this->primary_id_column = $alias.object_id)"; |
|
1058 } |
|
1059 |
|
1060 |
|
1061 $where = "$alias.term_taxonomy_id $operator ($terms)"; |
|
1062 |
|
1063 } elseif ( 'NOT IN' == $operator ) { |
|
1064 |
|
1065 if ( empty( $terms ) ) { |
|
1066 return $sql; |
|
1067 } |
|
1068 |
|
1069 $terms = implode( ',', $terms ); |
|
1070 |
|
1071 $where = "$this->primary_table.$this->primary_id_column NOT IN ( |
|
1072 SELECT object_id |
|
1073 FROM $wpdb->term_relationships |
|
1074 WHERE term_taxonomy_id IN ($terms) |
|
1075 )"; |
|
1076 |
|
1077 } elseif ( 'AND' == $operator ) { |
|
1078 |
|
1079 if ( empty( $terms ) ) { |
|
1080 return $sql; |
|
1081 } |
|
1082 |
|
1083 $num_terms = count( $terms ); |
|
1084 |
|
1085 $terms = implode( ',', $terms ); |
|
1086 |
|
1087 $where = "( |
|
1088 SELECT COUNT(1) |
|
1089 FROM $wpdb->term_relationships |
|
1090 WHERE term_taxonomy_id IN ($terms) |
|
1091 AND object_id = $this->primary_table.$this->primary_id_column |
|
1092 ) = $num_terms"; |
|
1093 |
|
1094 } elseif ( 'NOT EXISTS' === $operator || 'EXISTS' === $operator ) { |
|
1095 |
|
1096 $where = $wpdb->prepare( "$operator ( |
|
1097 SELECT 1 |
|
1098 FROM $wpdb->term_relationships |
|
1099 INNER JOIN $wpdb->term_taxonomy |
|
1100 ON $wpdb->term_taxonomy.term_taxonomy_id = $wpdb->term_relationships.term_taxonomy_id |
|
1101 WHERE $wpdb->term_taxonomy.taxonomy = %s |
|
1102 AND $wpdb->term_relationships.object_id = $this->primary_table.$this->primary_id_column |
|
1103 )", $clause['taxonomy'] ); |
|
1104 |
|
1105 } |
|
1106 |
|
1107 $sql['join'][] = $join; |
|
1108 $sql['where'][] = $where; |
|
1109 return $sql; |
|
1110 } |
|
1111 |
|
1112 /** |
|
1113 * Identify an existing table alias that is compatible with the current query clause. |
|
1114 * |
|
1115 * We avoid unnecessary table joins by allowing each clause to look for |
|
1116 * an existing table alias that is compatible with the query that it |
|
1117 * needs to perform. |
|
1118 * |
|
1119 * An existing alias is compatible if (a) it is a sibling of `$clause` |
|
1120 * (ie, it's under the scope of the same relation), and (b) the combination |
|
1121 * of operator and relation between the clauses allows for a shared table |
|
1122 * join. In the case of {@see WP_Tax_Query}, this only applies to 'IN' |
|
1123 * clauses that are connected by the relation 'OR'. |
|
1124 * |
|
1125 * @since 4.1.0 |
|
1126 * @access protected |
|
1127 * |
|
1128 * @param array $clause Query clause. |
|
1129 * @param array $parent_query Parent query of $clause. |
|
1130 * @return string|bool Table alias if found, otherwise false. |
|
1131 */ |
|
1132 protected function find_compatible_table_alias( $clause, $parent_query ) { |
|
1133 $alias = false; |
|
1134 |
|
1135 // Sanity check. Only IN queries use the JOIN syntax . |
|
1136 if ( ! isset( $clause['operator'] ) || 'IN' !== $clause['operator'] ) { |
|
1137 return $alias; |
|
1138 } |
|
1139 |
|
1140 // Since we're only checking IN queries, we're only concerned with OR relations. |
|
1141 if ( ! isset( $parent_query['relation'] ) || 'OR' !== $parent_query['relation'] ) { |
|
1142 return $alias; |
|
1143 } |
|
1144 |
|
1145 $compatible_operators = array( 'IN' ); |
|
1146 |
|
1147 foreach ( $parent_query as $sibling ) { |
|
1148 if ( ! is_array( $sibling ) || ! $this->is_first_order_clause( $sibling ) ) { |
|
1149 continue; |
|
1150 } |
|
1151 |
|
1152 if ( empty( $sibling['alias'] ) || empty( $sibling['operator'] ) ) { |
|
1153 continue; |
|
1154 } |
|
1155 |
|
1156 // The sibling must both have compatible operator to share its alias. |
|
1157 if ( in_array( strtoupper( $sibling['operator'] ), $compatible_operators ) ) { |
|
1158 $alias = $sibling['alias']; |
|
1159 break; |
|
1160 } |
|
1161 } |
|
1162 |
|
1163 return $alias; |
|
1164 } |
|
1165 |
|
1166 /** |
|
1167 * Validates a single query. |
|
1168 * |
|
1169 * @since 3.2.0 |
|
1170 * @access private |
|
1171 * |
|
1172 * @param array &$query The single query. |
|
1173 */ |
|
1174 private function clean_query( &$query ) { |
|
1175 if ( empty( $query['taxonomy'] ) ) { |
|
1176 if ( 'term_taxonomy_id' !== $query['field'] ) { |
|
1177 $query = new WP_Error( 'Invalid taxonomy' ); |
|
1178 return; |
|
1179 } |
|
1180 |
|
1181 // so long as there are shared terms, include_children requires that a taxonomy is set |
|
1182 $query['include_children'] = false; |
|
1183 } elseif ( ! taxonomy_exists( $query['taxonomy'] ) ) { |
|
1184 $query = new WP_Error( 'Invalid taxonomy' ); |
|
1185 return; |
|
1186 } |
|
1187 |
|
1188 $query['terms'] = array_unique( (array) $query['terms'] ); |
|
1189 |
|
1190 if ( is_taxonomy_hierarchical( $query['taxonomy'] ) && $query['include_children'] ) { |
|
1191 $this->transform_query( $query, 'term_id' ); |
|
1192 |
|
1193 if ( is_wp_error( $query ) ) |
|
1194 return; |
|
1195 |
|
1196 $children = array(); |
|
1197 foreach ( $query['terms'] as $term ) { |
|
1198 $children = array_merge( $children, get_term_children( $term, $query['taxonomy'] ) ); |
|
1199 $children[] = $term; |
|
1200 } |
|
1201 $query['terms'] = $children; |
|
1202 } |
|
1203 |
|
1204 $this->transform_query( $query, 'term_taxonomy_id' ); |
|
1205 } |
|
1206 |
|
1207 /** |
|
1208 * Transforms a single query, from one field to another. |
|
1209 * |
|
1210 * @since 3.2.0 |
|
1211 * |
|
1212 * @param array &$query The single query. |
|
1213 * @param string $resulting_field The resulting field. Accepts 'slug', 'name', 'term_taxonomy_id', |
|
1214 * or 'term_id'. Default: 'term_id'. |
|
1215 */ |
|
1216 public function transform_query( &$query, $resulting_field ) { |
|
1217 global $wpdb; |
|
1218 |
|
1219 if ( empty( $query['terms'] ) ) |
|
1220 return; |
|
1221 |
|
1222 if ( $query['field'] == $resulting_field ) |
|
1223 return; |
|
1224 |
|
1225 $resulting_field = sanitize_key( $resulting_field ); |
|
1226 |
|
1227 switch ( $query['field'] ) { |
|
1228 case 'slug': |
|
1229 case 'name': |
|
1230 foreach ( $query['terms'] as &$term ) { |
|
1231 /* |
|
1232 * 0 is the $term_id parameter. We don't have a term ID yet, but it doesn't |
|
1233 * matter because `sanitize_term_field()` ignores the $term_id param when the |
|
1234 * context is 'db'. |
|
1235 */ |
|
1236 $term = "'" . esc_sql( sanitize_term_field( $query['field'], $term, 0, $query['taxonomy'], 'db' ) ) . "'"; |
|
1237 } |
|
1238 |
|
1239 $terms = implode( ",", $query['terms'] ); |
|
1240 |
|
1241 $terms = $wpdb->get_col( " |
|
1242 SELECT $wpdb->term_taxonomy.$resulting_field |
|
1243 FROM $wpdb->term_taxonomy |
|
1244 INNER JOIN $wpdb->terms USING (term_id) |
|
1245 WHERE taxonomy = '{$query['taxonomy']}' |
|
1246 AND $wpdb->terms.{$query['field']} IN ($terms) |
|
1247 " ); |
|
1248 break; |
|
1249 case 'term_taxonomy_id': |
|
1250 $terms = implode( ',', array_map( 'intval', $query['terms'] ) ); |
|
1251 $terms = $wpdb->get_col( " |
|
1252 SELECT $resulting_field |
|
1253 FROM $wpdb->term_taxonomy |
|
1254 WHERE term_taxonomy_id IN ($terms) |
|
1255 " ); |
|
1256 break; |
|
1257 default: |
|
1258 $terms = implode( ',', array_map( 'intval', $query['terms'] ) ); |
|
1259 $terms = $wpdb->get_col( " |
|
1260 SELECT $resulting_field |
|
1261 FROM $wpdb->term_taxonomy |
|
1262 WHERE taxonomy = '{$query['taxonomy']}' |
|
1263 AND term_id IN ($terms) |
|
1264 " ); |
|
1265 } |
|
1266 |
|
1267 if ( 'AND' == $query['operator'] && count( $terms ) < count( $query['terms'] ) ) { |
|
1268 $query = new WP_Error( 'Inexistent terms' ); |
|
1269 return; |
|
1270 } |
|
1271 |
|
1272 $query['terms'] = $terms; |
|
1273 $query['field'] = $resulting_field; |
|
1274 } |
|
1275 } |
699 } |
1276 |
700 |
1277 /** |
701 /** |
1278 * Get all Term data from database by Term ID. |
702 * Get all Term data from database by Term ID. |
1279 * |
703 * |
1288 * There are two hooks, one is specifically for each term, named 'get_term', and |
712 * There are two hooks, one is specifically for each term, named 'get_term', and |
1289 * the second is for the taxonomy name, 'term_$taxonomy'. Both hooks gets the |
713 * the second is for the taxonomy name, 'term_$taxonomy'. Both hooks gets the |
1290 * term object, and the taxonomy name as parameters. Both hooks are expected to |
714 * term object, and the taxonomy name as parameters. Both hooks are expected to |
1291 * return a Term object. |
715 * return a Term object. |
1292 * |
716 * |
1293 * 'get_term' hook - Takes two parameters the term Object and the taxonomy name. |
717 * {@see 'get_term'} hook - Takes two parameters the term Object and the taxonomy name. |
1294 * Must return term object. Used in get_term() as a catch-all filter for every |
718 * Must return term object. Used in get_term() as a catch-all filter for every |
1295 * $term. |
719 * $term. |
1296 * |
720 * |
1297 * 'get_$taxonomy' hook - Takes two parameters the term Object and the taxonomy |
721 * {@see 'get_$taxonomy'} hook - Takes two parameters the term Object and the taxonomy |
1298 * name. Must return term object. $taxonomy will be the taxonomy name, so for |
722 * name. Must return term object. $taxonomy will be the taxonomy name, so for |
1299 * example, if 'category', it would be 'get_category' as the filter name. Useful |
723 * example, if 'category', it would be 'get_category' as the filter name. Useful |
1300 * for custom taxonomies or plugging into default taxonomies. |
724 * for custom taxonomies or plugging into default taxonomies. |
1301 * |
725 * |
726 * @todo Better formatting for DocBlock |
|
727 * |
|
1302 * @since 2.3.0 |
728 * @since 2.3.0 |
1303 * |
729 * @since 4.4.0 Converted to return a WP_Term object if `$output` is `OBJECT`. |
1304 * @global wpdb $wpdb WordPress database abstraction object. |
730 * The `$taxonomy` parameter was made optional. |
731 * |
|
1305 * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param. |
732 * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param. |
1306 * |
733 * |
1307 * @param int|object $term If integer, will get from database. If object will apply filters and return $term. |
734 * @param int|WP_Term|object $term If integer, term data will be fetched from the database, or from the cache if |
1308 * @param string $taxonomy Taxonomy name that $term is part of. |
735 * available. If stdClass object (as in the results of a database query), will apply |
1309 * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N |
736 * filters and return a `WP_Term` object corresponding to the `$term` data. If `WP_Term`, |
1310 * @param string $filter Optional, default is raw or no WordPress defined filter will applied. |
737 * will return `$term`. |
1311 * @return mixed|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not |
738 * @param string $taxonomy Optional. Taxonomy name that $term is part of. |
1312 * exist then WP_Error will be returned. |
739 * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to |
1313 */ |
740 * a WP_Term object, an associative array, or a numeric array, respectively. Default OBJECT. |
1314 function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') { |
741 * @param string $filter Optional, default is raw or no WordPress defined filter will applied. |
1315 global $wpdb; |
742 * @return array|WP_Term|WP_Error|null Object of the type specified by `$output` on success. When `$output` is 'OBJECT', |
1316 |
743 * a WP_Term instance is returned. If taxonomy does not exist, a WP_Error is |
1317 if ( empty($term) ) { |
744 * returned. Returns null for miscellaneous failure. |
1318 $error = new WP_Error('invalid_term', __('Empty Term')); |
745 */ |
1319 return $error; |
746 function get_term( $term, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) { |
1320 } |
747 if ( empty( $term ) ) { |
1321 |
748 return new WP_Error( 'invalid_term', __( 'Empty Term.' ) ); |
1322 if ( ! taxonomy_exists($taxonomy) ) { |
749 } |
1323 $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
750 |
1324 return $error; |
751 if ( $taxonomy && ! taxonomy_exists( $taxonomy ) ) { |
1325 } |
752 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
1326 |
753 } |
1327 if ( is_object($term) && empty($term->filter) ) { |
754 |
1328 wp_cache_add( $term->term_id, $term, $taxonomy ); |
755 if ( $term instanceof WP_Term ) { |
1329 $_term = $term; |
756 $_term = $term; |
757 } elseif ( is_object( $term ) ) { |
|
758 if ( empty( $term->filter ) || 'raw' === $term->filter ) { |
|
759 $_term = sanitize_term( $term, $taxonomy, 'raw' ); |
|
760 $_term = new WP_Term( $_term ); |
|
761 } else { |
|
762 $_term = WP_Term::get_instance( $term->term_id ); |
|
763 } |
|
1330 } else { |
764 } else { |
1331 if ( is_object($term) ) |
765 $_term = WP_Term::get_instance( $term, $taxonomy ); |
1332 $term = $term->term_id; |
766 } |
1333 if ( !$term = (int) $term ) |
767 |
1334 return null; |
768 if ( is_wp_error( $_term ) ) { |
1335 if ( ! $_term = wp_cache_get( $term, $taxonomy ) ) { |
769 return $_term; |
1336 $_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND t.term_id = %d LIMIT 1", $taxonomy, $term) ); |
770 } elseif ( ! $_term ) { |
1337 if ( ! $_term ) |
771 return null; |
1338 return null; |
|
1339 wp_cache_add( $term, $_term, $taxonomy ); |
|
1340 } |
|
1341 } |
772 } |
1342 |
773 |
1343 /** |
774 /** |
1344 * Filter a term. |
775 * Filters a term. |
1345 * |
776 * |
1346 * @since 2.3.0 |
777 * @since 2.3.0 |
1347 * |
778 * @since 4.4.0 `$_term` can now also be a WP_Term object. |
1348 * @param int|object $_term Term object or ID. |
779 * |
1349 * @param string $taxonomy The taxonomy slug. |
780 * @param int|WP_Term $_term Term object or ID. |
781 * @param string $taxonomy The taxonomy slug. |
|
1350 */ |
782 */ |
1351 $_term = apply_filters( 'get_term', $_term, $taxonomy ); |
783 $_term = apply_filters( 'get_term', $_term, $taxonomy ); |
1352 |
784 |
1353 /** |
785 /** |
1354 * Filter a taxonomy. |
786 * Filters a taxonomy. |
1355 * |
787 * |
1356 * The dynamic portion of the filter name, `$taxonomy`, refers |
788 * The dynamic portion of the filter name, `$taxonomy`, refers |
1357 * to the taxonomy slug. |
789 * to the taxonomy slug. |
1358 * |
790 * |
1359 * @since 2.3.0 |
791 * @since 2.3.0 |
1360 * |
792 * @since 4.4.0 `$_term` can now also be a WP_Term object. |
1361 * @param int|object $_term Term object or ID. |
793 * |
1362 * @param string $taxonomy The taxonomy slug. |
794 * @param int|WP_Term $_term Term object or ID. |
1363 */ |
795 * @param string $taxonomy The taxonomy slug. |
1364 $_term = apply_filters( "get_$taxonomy", $_term, $taxonomy ); |
796 */ |
1365 $_term = sanitize_term($_term, $taxonomy, $filter); |
797 $_term = apply_filters( "get_{$taxonomy}", $_term, $taxonomy ); |
1366 |
798 |
1367 if ( $output == OBJECT ) { |
799 // Bail if a filter callback has changed the type of the `$_term` object. |
800 if ( ! ( $_term instanceof WP_Term ) ) { |
|
1368 return $_term; |
801 return $_term; |
1369 } elseif ( $output == ARRAY_A ) { |
802 } |
1370 $__term = get_object_vars($_term); |
803 |
1371 return $__term; |
804 // Sanitize term, according to the specified filter. |
805 $_term->filter( $filter ); |
|
806 |
|
807 if ( $output == ARRAY_A ) { |
|
808 return $_term->to_array(); |
|
1372 } elseif ( $output == ARRAY_N ) { |
809 } elseif ( $output == ARRAY_N ) { |
1373 $__term = array_values(get_object_vars($_term)); |
810 return array_values( $_term->to_array() ); |
1374 return $__term; |
811 } |
1375 } else { |
812 |
1376 return $_term; |
813 return $_term; |
1377 } |
|
1378 } |
814 } |
1379 |
815 |
1380 /** |
816 /** |
1381 * Get all Term data from database by Term field and data. |
817 * Get all Term data from database by Term field and data. |
1382 * |
818 * |
1387 * field, but not recommended that you do so. |
823 * field, but not recommended that you do so. |
1388 * |
824 * |
1389 * If $value does not exist, the return value will be false. If $taxonomy exists |
825 * If $value does not exist, the return value will be false. If $taxonomy exists |
1390 * and $field and $value combinations exist, the Term will be returned. |
826 * and $field and $value combinations exist, the Term will be returned. |
1391 * |
827 * |
828 * This function will always return the first term that matches the `$field`- |
|
829 * `$value`-`$taxonomy` combination specified in the parameters. If your query |
|
830 * is likely to match more than one term (as is likely to be the case when |
|
831 * `$field` is 'name', for example), consider using get_terms() instead; that |
|
832 * way, you will get all matching terms, and can provide your own logic for |
|
833 * deciding which one was intended. |
|
834 * |
|
835 * @todo Better formatting for DocBlock. |
|
836 * |
|
1392 * @since 2.3.0 |
837 * @since 2.3.0 |
1393 * |
838 * @since 4.4.0 `$taxonomy` is optional if `$field` is 'term_taxonomy_id'. Converted to return |
1394 * @global wpdb $wpdb WordPress database abstraction object. |
839 * a WP_Term object if `$output` is `OBJECT`. |
840 * |
|
1395 * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param. |
841 * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param. |
1396 * |
842 * |
1397 * @param string $field Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id' |
843 * @param string $field Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id' |
1398 * @param string|int $value Search for this term value |
844 * @param string|int $value Search for this term value |
1399 * @param string $taxonomy Taxonomy Name |
845 * @param string $taxonomy Taxonomy name. Optional, if `$field` is 'term_taxonomy_id'. |
1400 * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N |
846 * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to |
1401 * @param string $filter Optional, default is raw or no WordPress defined filter will applied. |
847 * a WP_Term object, an associative array, or a numeric array, respectively. Default OBJECT. |
1402 * @return mixed Term Row from database. Will return false if $taxonomy does not exist or $term was not found. |
848 * @param string $filter Optional, default is raw or no WordPress defined filter will applied. |
1403 */ |
849 * @return WP_Term|array|false WP_Term instance (or array) on success. Will return false if `$taxonomy` does not exist |
1404 function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') { |
850 * or `$term` was not found. |
1405 global $wpdb; |
851 */ |
1406 |
852 function get_term_by( $field, $value, $taxonomy = '', $output = OBJECT, $filter = 'raw' ) { |
1407 if ( ! taxonomy_exists($taxonomy) ) |
853 |
854 // 'term_taxonomy_id' lookups don't require taxonomy checks. |
|
855 if ( 'term_taxonomy_id' !== $field && ! taxonomy_exists( $taxonomy ) ) { |
|
1408 return false; |
856 return false; |
1409 |
857 } |
1410 if ( 'slug' == $field ) { |
858 |
1411 $field = 't.slug'; |
859 // No need to perform a query for empty 'slug' or 'name'. |
1412 $value = sanitize_title($value); |
860 if ( 'slug' === $field || 'name' === $field ) { |
1413 if ( empty($value) ) |
861 $value = (string) $value; |
862 |
|
863 if ( 0 === strlen( $value ) ) { |
|
1414 return false; |
864 return false; |
1415 } elseif ( 'name' == $field ) { |
865 } |
1416 // Assume already escaped |
866 } |
1417 $value = wp_unslash($value); |
867 |
1418 $field = 't.name'; |
868 if ( 'id' === $field || 'term_id' === $field ) { |
1419 } elseif ( 'term_taxonomy_id' == $field ) { |
|
1420 $value = (int) $value; |
|
1421 $field = 'tt.term_taxonomy_id'; |
|
1422 } else { |
|
1423 $term = get_term( (int) $value, $taxonomy, $output, $filter ); |
869 $term = get_term( (int) $value, $taxonomy, $output, $filter ); |
1424 if ( is_wp_error( $term ) ) |
870 if ( is_wp_error( $term ) || null === $term ) { |
1425 $term = false; |
871 $term = false; |
872 } |
|
1426 return $term; |
873 return $term; |
1427 } |
874 } |
1428 |
875 |
1429 $term = $wpdb->get_row( $wpdb->prepare( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s AND $field = %s LIMIT 1", $taxonomy, $value ) ); |
876 $args = array( |
1430 if ( ! $term ) |
877 'get' => 'all', |
878 'number' => 1, |
|
879 'taxonomy' => $taxonomy, |
|
880 'update_term_meta_cache' => false, |
|
881 'orderby' => 'none', |
|
882 'suppress_filter' => true, |
|
883 ); |
|
884 |
|
885 switch ( $field ) { |
|
886 case 'slug' : |
|
887 $args['slug'] = $value; |
|
888 break; |
|
889 case 'name' : |
|
890 $args['name'] = $value; |
|
891 break; |
|
892 case 'term_taxonomy_id' : |
|
893 $args['term_taxonomy_id'] = $value; |
|
894 unset( $args[ 'taxonomy' ] ); |
|
895 break; |
|
896 default : |
|
897 return false; |
|
898 } |
|
899 |
|
900 $terms = get_terms( $args ); |
|
901 if ( is_wp_error( $terms ) || empty( $terms ) ) { |
|
1431 return false; |
902 return false; |
1432 |
903 } |
1433 wp_cache_add( $term->term_id, $term, $taxonomy ); |
904 |
1434 |
905 $term = array_shift( $terms ); |
1435 /** This filter is documented in wp-includes/taxonomy.php */ |
906 |
1436 $term = apply_filters( 'get_term', $term, $taxonomy ); |
907 // In the case of 'term_taxonomy_id', override the provided `$taxonomy` with whatever we find in the db. |
1437 |
908 if ( 'term_taxonomy_id' === $field ) { |
1438 /** This filter is documented in wp-includes/taxonomy.php */ |
909 $taxonomy = $term->taxonomy; |
1439 $term = apply_filters( "get_$taxonomy", $term, $taxonomy ); |
910 } |
1440 |
911 |
1441 $term = sanitize_term($term, $taxonomy, $filter); |
912 return get_term( $term, $taxonomy, $output, $filter ); |
1442 |
|
1443 if ( $output == OBJECT ) { |
|
1444 return $term; |
|
1445 } elseif ( $output == ARRAY_A ) { |
|
1446 return get_object_vars($term); |
|
1447 } elseif ( $output == ARRAY_N ) { |
|
1448 return array_values(get_object_vars($term)); |
|
1449 } else { |
|
1450 return $term; |
|
1451 } |
|
1452 } |
913 } |
1453 |
914 |
1454 /** |
915 /** |
1455 * Merge all term children into a single array of their IDs. |
916 * Merge all term children into a single array of their IDs. |
1456 * |
917 * |
1459 * |
920 * |
1460 * Will return an empty array if $term does not exist in $taxonomy. |
921 * Will return an empty array if $term does not exist in $taxonomy. |
1461 * |
922 * |
1462 * @since 2.3.0 |
923 * @since 2.3.0 |
1463 * |
924 * |
1464 * @global wpdb $wpdb WordPress database abstraction object. |
925 * @param int $term_id ID of Term to get children. |
1465 * |
926 * @param string $taxonomy Taxonomy Name. |
1466 * @param string $term_id ID of Term to get children |
927 * @return array|WP_Error List of Term IDs. WP_Error returned if `$taxonomy` does not exist. |
1467 * @param string $taxonomy Taxonomy Name |
|
1468 * @return array|WP_Error List of Term IDs. WP_Error returned if $taxonomy does not exist |
|
1469 */ |
928 */ |
1470 function get_term_children( $term_id, $taxonomy ) { |
929 function get_term_children( $term_id, $taxonomy ) { |
1471 if ( ! taxonomy_exists($taxonomy) ) |
930 if ( ! taxonomy_exists( $taxonomy ) ) { |
1472 return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
931 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
932 } |
|
1473 |
933 |
1474 $term_id = intval( $term_id ); |
934 $term_id = intval( $term_id ); |
1475 |
935 |
1476 $terms = _get_term_hierarchy($taxonomy); |
936 $terms = _get_term_hierarchy($taxonomy); |
1477 |
937 |
1493 } |
953 } |
1494 |
954 |
1495 /** |
955 /** |
1496 * Get sanitized Term field. |
956 * Get sanitized Term field. |
1497 * |
957 * |
1498 * Does checks for $term, based on the $taxonomy. The function is for contextual |
958 * The function is for contextual reasons and for simplicity of usage. |
1499 * reasons and for simplicity of usage. See sanitize_term_field() for more |
|
1500 * information. |
|
1501 * |
959 * |
1502 * @since 2.3.0 |
960 * @since 2.3.0 |
1503 * |
961 * @since 4.4.0 The `$taxonomy` parameter was made optional. `$term` can also now accept a WP_Term object. |
1504 * @param string $field Term field to fetch |
962 * |
1505 * @param int $term Term ID |
963 * @see sanitize_term_field() |
1506 * @param string $taxonomy Taxonomy Name |
964 * |
1507 * @param string $context Optional, default is display. Look at sanitize_term_field() for available options. |
965 * @param string $field Term field to fetch. |
1508 * @return mixed Will return an empty string if $term is not an object or if $field is not set in $term. |
966 * @param int|WP_Term $term Term ID or object. |
1509 */ |
967 * @param string $taxonomy Optional. Taxonomy Name. Default empty. |
1510 function get_term_field( $field, $term, $taxonomy, $context = 'display' ) { |
968 * @param string $context Optional, default is display. Look at sanitize_term_field() for available options. |
1511 $term = (int) $term; |
969 * @return string|int|null|WP_Error Will return an empty string if $term is not an object or if $field is not set in $term. |
970 */ |
|
971 function get_term_field( $field, $term, $taxonomy = '', $context = 'display' ) { |
|
1512 $term = get_term( $term, $taxonomy ); |
972 $term = get_term( $term, $taxonomy ); |
1513 if ( is_wp_error($term) ) |
973 if ( is_wp_error($term) ) |
1514 return $term; |
974 return $term; |
1515 |
975 |
1516 if ( !is_object($term) ) |
976 if ( !is_object($term) ) |
1517 return ''; |
977 return ''; |
1518 |
978 |
1519 if ( !isset($term->$field) ) |
979 if ( !isset($term->$field) ) |
1520 return ''; |
980 return ''; |
1521 |
981 |
1522 return sanitize_term_field($field, $term->$field, $term->term_id, $taxonomy, $context); |
982 return sanitize_term_field( $field, $term->$field, $term->term_id, $term->taxonomy, $context ); |
1523 } |
983 } |
1524 |
984 |
1525 /** |
985 /** |
1526 * Sanitizes Term for editing. |
986 * Sanitizes Term for editing. |
1527 * |
987 * |
1528 * Return value is sanitize_term() and usage is for sanitizing the term for |
988 * Return value is sanitize_term() and usage is for sanitizing the term for |
1529 * editing. Function is for contextual and simplicity. |
989 * editing. Function is for contextual and simplicity. |
1530 * |
990 * |
1531 * @since 2.3.0 |
991 * @since 2.3.0 |
1532 * |
992 * |
1533 * @param int|object $id Term ID or Object |
993 * @param int|object $id Term ID or object. |
1534 * @param string $taxonomy Taxonomy Name |
994 * @param string $taxonomy Taxonomy name. |
1535 * @return mixed|null|WP_Error Will return empty string if $term is not an object. |
995 * @return string|int|null|WP_Error Will return empty string if $term is not an object. |
1536 */ |
996 */ |
1537 function get_term_to_edit( $id, $taxonomy ) { |
997 function get_term_to_edit( $id, $taxonomy ) { |
1538 $term = get_term( $id, $taxonomy ); |
998 $term = get_term( $id, $taxonomy ); |
1539 |
999 |
1540 if ( is_wp_error($term) ) |
1000 if ( is_wp_error($term) ) |
1550 * Retrieve the terms in a given taxonomy or list of taxonomies. |
1010 * Retrieve the terms in a given taxonomy or list of taxonomies. |
1551 * |
1011 * |
1552 * You can fully inject any customizations to the query before it is sent, as |
1012 * You can fully inject any customizations to the query before it is sent, as |
1553 * well as control the output with a filter. |
1013 * well as control the output with a filter. |
1554 * |
1014 * |
1555 * The 'get_terms' filter will be called when the cache has the term and will |
1015 * The {@see 'get_terms'} filter will be called when the cache has the term and will |
1556 * pass the found term along with the array of $taxonomies and array of $args. |
1016 * pass the found term along with the array of $taxonomies and array of $args. |
1557 * This filter is also called before the array of terms is passed and will pass |
1017 * This filter is also called before the array of terms is passed and will pass |
1558 * the array of terms, along with the $taxonomies and $args. |
1018 * the array of terms, along with the $taxonomies and $args. |
1559 * |
1019 * |
1560 * The 'list_terms_exclusions' filter passes the compiled exclusions along with |
1020 * The {@see 'list_terms_exclusions'} filter passes the compiled exclusions along with |
1561 * the $args. |
1021 * the $args. |
1562 * |
1022 * |
1563 * The 'get_terms_orderby' filter passes the ORDER BY clause for the query |
1023 * The {@see 'get_terms_orderby'} filter passes the `ORDER BY` clause for the query |
1564 * along with the $args array. |
1024 * along with the $args array. |
1025 * |
|
1026 * Prior to 4.5.0, the first parameter of `get_terms()` was a taxonomy or list of taxonomies: |
|
1027 * |
|
1028 * $terms = get_terms( 'post_tag', array( |
|
1029 * 'hide_empty' => false, |
|
1030 * ) ); |
|
1031 * |
|
1032 * Since 4.5.0, taxonomies should be passed via the 'taxonomy' argument in the `$args` array: |
|
1033 * |
|
1034 * $terms = get_terms( array( |
|
1035 * 'taxonomy' => 'post_tag', |
|
1036 * 'hide_empty' => false, |
|
1037 * ) ); |
|
1565 * |
1038 * |
1566 * @since 2.3.0 |
1039 * @since 2.3.0 |
1567 * @since 4.2.0 Introduced 'name' and 'childless' parameters. |
1040 * @since 4.2.0 Introduced 'name' and 'childless' parameters. |
1041 * @since 4.4.0 Introduced the ability to pass 'term_id' as an alias of 'id' for the `orderby` parameter. |
|
1042 * Introduced the 'meta_query' and 'update_term_meta_cache' parameters. Converted to return |
|
1043 * a list of WP_Term objects. |
|
1044 * @since 4.5.0 Changed the function signature so that the `$args` array can be provided as the first parameter. |
|
1045 * Introduced 'meta_key' and 'meta_value' parameters. Introduced the ability to order results by metadata. |
|
1046 * @since 4.8.0 Introduced 'suppress_filter' parameter. |
|
1047 * |
|
1048 * @internal The `$deprecated` parameter is parsed for backward compatibility only. |
|
1049 * |
|
1050 * @param string|array $args Optional. Array or string of arguments. See WP_Term_Query::__construct() |
|
1051 * for information on accepted arguments. Default empty. |
|
1052 * @param array $deprecated Argument array, when using the legacy function parameter format. If present, this |
|
1053 * parameter will be interpreted as `$args`, and the first function parameter will |
|
1054 * be parsed as a taxonomy or array of taxonomies. |
|
1055 * @return array|int|WP_Error List of WP_Term instances and their children. Will return WP_Error, if any of $taxonomies |
|
1056 * do not exist. |
|
1057 */ |
|
1058 function get_terms( $args = array(), $deprecated = '' ) { |
|
1059 $term_query = new WP_Term_Query(); |
|
1060 |
|
1061 $defaults = array( |
|
1062 'suppress_filter' => false, |
|
1063 ); |
|
1064 |
|
1065 /* |
|
1066 * Legacy argument format ($taxonomy, $args) takes precedence. |
|
1067 * |
|
1068 * We detect legacy argument format by checking if |
|
1069 * (a) a second non-empty parameter is passed, or |
|
1070 * (b) the first parameter shares no keys with the default array (ie, it's a list of taxonomies) |
|
1071 */ |
|
1072 $_args = wp_parse_args( $args ); |
|
1073 $key_intersect = array_intersect_key( $term_query->query_var_defaults, (array) $_args ); |
|
1074 $do_legacy_args = $deprecated || empty( $key_intersect ); |
|
1075 |
|
1076 if ( $do_legacy_args ) { |
|
1077 $taxonomies = (array) $args; |
|
1078 $args = wp_parse_args( $deprecated, $defaults ); |
|
1079 $args['taxonomy'] = $taxonomies; |
|
1080 } else { |
|
1081 $args = wp_parse_args( $args, $defaults ); |
|
1082 if ( isset( $args['taxonomy'] ) && null !== $args['taxonomy'] ) { |
|
1083 $args['taxonomy'] = (array) $args['taxonomy']; |
|
1084 } |
|
1085 } |
|
1086 |
|
1087 if ( ! empty( $args['taxonomy'] ) ) { |
|
1088 foreach ( $args['taxonomy'] as $taxonomy ) { |
|
1089 if ( ! taxonomy_exists( $taxonomy ) ) { |
|
1090 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
|
1091 } |
|
1092 } |
|
1093 } |
|
1094 |
|
1095 // Don't pass suppress_filter to WP_Term_Query. |
|
1096 $suppress_filter = $args['suppress_filter']; |
|
1097 unset( $args['suppress_filter'] ); |
|
1098 |
|
1099 $terms = $term_query->query( $args ); |
|
1100 |
|
1101 // Count queries are not filtered, for legacy reasons. |
|
1102 if ( ! is_array( $terms ) ) { |
|
1103 return $terms; |
|
1104 } |
|
1105 |
|
1106 if ( $suppress_filter ) { |
|
1107 return $terms; |
|
1108 } |
|
1109 |
|
1110 /** |
|
1111 * Filters the found terms. |
|
1112 * |
|
1113 * @since 2.3.0 |
|
1114 * @since 4.6.0 Added the `$term_query` parameter. |
|
1115 * |
|
1116 * @param array $terms Array of found terms. |
|
1117 * @param array $taxonomies An array of taxonomies. |
|
1118 * @param array $args An array of get_terms() arguments. |
|
1119 * @param WP_Term_Query $term_query The WP_Term_Query object. |
|
1120 */ |
|
1121 return apply_filters( 'get_terms', $terms, $term_query->query_vars['taxonomy'], $term_query->query_vars, $term_query ); |
|
1122 } |
|
1123 |
|
1124 /** |
|
1125 * Adds metadata to a term. |
|
1126 * |
|
1127 * @since 4.4.0 |
|
1128 * |
|
1129 * @param int $term_id Term ID. |
|
1130 * @param string $meta_key Metadata name. |
|
1131 * @param mixed $meta_value Metadata value. |
|
1132 * @param bool $unique Optional. Whether to bail if an entry with the same key is found for the term. |
|
1133 * Default false. |
|
1134 * @return int|WP_Error|bool Meta ID on success. WP_Error when term_id is ambiguous between taxonomies. |
|
1135 * False on failure. |
|
1136 */ |
|
1137 function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) { |
|
1138 // Bail if term meta table is not installed. |
|
1139 if ( get_option( 'db_version' ) < 34370 ) { |
|
1140 return false; |
|
1141 } |
|
1142 |
|
1143 if ( wp_term_is_shared( $term_id ) ) { |
|
1144 return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.'), $term_id ); |
|
1145 } |
|
1146 |
|
1147 $added = add_metadata( 'term', $term_id, $meta_key, $meta_value, $unique ); |
|
1148 |
|
1149 // Bust term query cache. |
|
1150 if ( $added ) { |
|
1151 wp_cache_set( 'last_changed', microtime(), 'terms' ); |
|
1152 } |
|
1153 |
|
1154 return $added; |
|
1155 } |
|
1156 |
|
1157 /** |
|
1158 * Removes metadata matching criteria from a term. |
|
1159 * |
|
1160 * @since 4.4.0 |
|
1161 * |
|
1162 * @param int $term_id Term ID. |
|
1163 * @param string $meta_key Metadata name. |
|
1164 * @param mixed $meta_value Optional. Metadata value. If provided, rows will only be removed that match the value. |
|
1165 * @return bool True on success, false on failure. |
|
1166 */ |
|
1167 function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) { |
|
1168 // Bail if term meta table is not installed. |
|
1169 if ( get_option( 'db_version' ) < 34370 ) { |
|
1170 return false; |
|
1171 } |
|
1172 |
|
1173 $deleted = delete_metadata( 'term', $term_id, $meta_key, $meta_value ); |
|
1174 |
|
1175 // Bust term query cache. |
|
1176 if ( $deleted ) { |
|
1177 wp_cache_set( 'last_changed', microtime(), 'terms' ); |
|
1178 } |
|
1179 |
|
1180 return $deleted; |
|
1181 } |
|
1182 |
|
1183 /** |
|
1184 * Retrieves metadata for a term. |
|
1185 * |
|
1186 * @since 4.4.0 |
|
1187 * |
|
1188 * @param int $term_id Term ID. |
|
1189 * @param string $key Optional. The meta key to retrieve. If no key is provided, fetches all metadata for the term. |
|
1190 * @param bool $single Whether to return a single value. If false, an array of all values matching the |
|
1191 * `$term_id`/`$key` pair will be returned. Default: false. |
|
1192 * @return mixed If `$single` is false, an array of metadata values. If `$single` is true, a single metadata value. |
|
1193 */ |
|
1194 function get_term_meta( $term_id, $key = '', $single = false ) { |
|
1195 // Bail if term meta table is not installed. |
|
1196 if ( get_option( 'db_version' ) < 34370 ) { |
|
1197 return false; |
|
1198 } |
|
1199 |
|
1200 return get_metadata( 'term', $term_id, $key, $single ); |
|
1201 } |
|
1202 |
|
1203 /** |
|
1204 * Updates term metadata. |
|
1205 * |
|
1206 * Use the `$prev_value` parameter to differentiate between meta fields with the same key and term ID. |
|
1207 * |
|
1208 * If the meta field for the term does not exist, it will be added. |
|
1209 * |
|
1210 * @since 4.4.0 |
|
1211 * |
|
1212 * @param int $term_id Term ID. |
|
1213 * @param string $meta_key Metadata key. |
|
1214 * @param mixed $meta_value Metadata value. |
|
1215 * @param mixed $prev_value Optional. Previous value to check before removing. |
|
1216 * @return int|WP_Error|bool Meta ID if the key didn't previously exist. True on successful update. |
|
1217 * WP_Error when term_id is ambiguous between taxonomies. False on failure. |
|
1218 */ |
|
1219 function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) { |
|
1220 // Bail if term meta table is not installed. |
|
1221 if ( get_option( 'db_version' ) < 34370 ) { |
|
1222 return false; |
|
1223 } |
|
1224 |
|
1225 if ( wp_term_is_shared( $term_id ) ) { |
|
1226 return new WP_Error( 'ambiguous_term_id', __( 'Term meta cannot be added to terms that are shared between taxonomies.'), $term_id ); |
|
1227 } |
|
1228 |
|
1229 $updated = update_metadata( 'term', $term_id, $meta_key, $meta_value, $prev_value ); |
|
1230 |
|
1231 // Bust term query cache. |
|
1232 if ( $updated ) { |
|
1233 wp_cache_set( 'last_changed', microtime(), 'terms' ); |
|
1234 } |
|
1235 |
|
1236 return $updated; |
|
1237 } |
|
1238 |
|
1239 /** |
|
1240 * Updates metadata cache for list of term IDs. |
|
1241 * |
|
1242 * Performs SQL query to retrieve all metadata for the terms matching `$term_ids` and stores them in the cache. |
|
1243 * Subsequent calls to `get_term_meta()` will not need to query the database. |
|
1244 * |
|
1245 * @since 4.4.0 |
|
1246 * |
|
1247 * @param array $term_ids List of term IDs. |
|
1248 * @return array|false Returns false if there is nothing to update. Returns an array of metadata on success. |
|
1249 */ |
|
1250 function update_termmeta_cache( $term_ids ) { |
|
1251 // Bail if term meta table is not installed. |
|
1252 if ( get_option( 'db_version' ) < 34370 ) { |
|
1253 return; |
|
1254 } |
|
1255 |
|
1256 return update_meta_cache( 'term', $term_ids ); |
|
1257 } |
|
1258 |
|
1259 /** |
|
1260 * Get all meta data, including meta IDs, for the given term ID. |
|
1261 * |
|
1262 * @since 4.9.0 |
|
1568 * |
1263 * |
1569 * @global wpdb $wpdb WordPress database abstraction object. |
1264 * @global wpdb $wpdb WordPress database abstraction object. |
1570 * |
1265 * |
1571 * @param string|array $taxonomies Taxonomy name or list of Taxonomy names. |
1266 * @param int $term_id Term ID. |
1572 * @param array|string $args { |
1267 * @return array|false Array with meta data, or false when the meta table is not installed. |
1573 * Optional. Array or string of arguments to get terms. |
1268 */ |
1574 * |
1269 function has_term_meta( $term_id ) { |
1575 * @type string $orderby Field(s) to order terms by. Accepts term fields ('name', 'slug', |
1270 // Bail if term meta table is not installed. |
1576 * 'term_group', 'term_id', 'id', 'description'), 'count' for term |
1271 if ( get_option( 'db_version' ) < 34370 ) { |
1577 * taxonomy count, 'include' to match the 'order' of the $include param, |
1272 return false; |
1578 * or 'none' to skip ORDER BY. Defaults to 'name'. |
1273 } |
1579 * @type string $order Whether to order terms in ascending or descending order. |
1274 |
1580 * Accepts 'ASC' (ascending) or 'DESC' (descending). |
|
1581 * Default 'ASC'. |
|
1582 * @type bool|int $hide_empty Whether to hide terms not assigned to any posts. Accepts |
|
1583 * 1|true or 0|false. Default 1|true. |
|
1584 * @type array|string $include Array or comma/space-separated string of term ids to include. |
|
1585 * Default empty array. |
|
1586 * @type array|string $exclude Array or comma/space-separated string of term ids to exclude. |
|
1587 * If $include is non-empty, $exclude is ignored. |
|
1588 * Default empty array. |
|
1589 * @type array|string $exclude_tree Array or comma/space-separated string of term ids to exclude |
|
1590 * along with all of their descendant terms. If $include is |
|
1591 * non-empty, $exclude_tree is ignored. Default empty array. |
|
1592 * @type int|string $number Maximum number of terms to return. Accepts ''|0 (all) or any |
|
1593 * positive number. Default ''|0 (all). |
|
1594 * @type int $offset The number by which to offset the terms query. Default empty. |
|
1595 * @type string $fields Term fields to query for. Accepts 'all' (returns an array of |
|
1596 * term objects), 'ids' or 'names' (returns an array of integers |
|
1597 * or strings, respectively. Default 'all'. |
|
1598 * @type string|array $name Optional. Name or array of names to return term(s) for. Default empty. |
|
1599 * @type string|array $slug Optional. Slug or array of slugs to return term(s) for. Default empty. |
|
1600 * @type bool $hierarchical Whether to include terms that have non-empty descendants (even |
|
1601 * if $hide_empty is set to true). Default true. |
|
1602 * @type string $search Search criteria to match terms. Will be SQL-formatted with |
|
1603 * wildcards before and after. Default empty. |
|
1604 * @type string $name__like Retrieve terms with criteria by which a term is LIKE $name__like. |
|
1605 * Default empty. |
|
1606 * @type string $description__like Retrieve terms where the description is LIKE $description__like. |
|
1607 * Default empty. |
|
1608 * @type bool $pad_counts Whether to pad the quantity of a term's children in the quantity |
|
1609 * of each term's "count" object variable. Default false. |
|
1610 * @type string $get Whether to return terms regardless of ancestry or whether the terms |
|
1611 * are empty. Accepts 'all' or empty (disabled). Default empty. |
|
1612 * @type int $child_of Term ID to retrieve child terms of. If multiple taxonomies |
|
1613 * are passed, $child_of is ignored. Default 0. |
|
1614 * @type int|string $parent Parent term ID to retrieve direct-child terms of. Default empty. |
|
1615 * @type bool $childless True to limit results to terms that have no children. This parameter has |
|
1616 * no effect on non-hierarchical taxonomies. Default false. |
|
1617 * @type string $cache_domain Unique cache key to be produced when this query is stored in an |
|
1618 * object cache. Default is 'core'. |
|
1619 * } |
|
1620 * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies |
|
1621 * do not exist. |
|
1622 */ |
|
1623 function get_terms( $taxonomies, $args = '' ) { |
|
1624 global $wpdb; |
1275 global $wpdb; |
1625 $empty_array = array(); |
1276 |
1626 |
1277 return $wpdb->get_results( $wpdb->prepare( "SELECT meta_key, meta_value, meta_id, term_id FROM $wpdb->termmeta WHERE term_id = %d ORDER BY meta_key,meta_id", $term_id ), ARRAY_A ); |
1627 $single_taxonomy = ! is_array( $taxonomies ) || 1 === count( $taxonomies ); |
1278 } |
1628 if ( ! is_array( $taxonomies ) ) { |
1279 |
1629 $taxonomies = array( $taxonomies ); |
1280 /** |
1630 } |
1281 * Registers a meta key for terms. |
1631 |
1282 * |
1632 foreach ( $taxonomies as $taxonomy ) { |
1283 * @since 4.9.8 |
1633 if ( ! taxonomy_exists($taxonomy) ) { |
1284 * |
1634 $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
1285 * @param string $taxonomy Taxonomy to register a meta key for. Pass an empty string |
1635 return $error; |
1286 * to register the meta key across all existing taxonomies. |
1636 } |
1287 * @param string $meta_key The meta key to register. |
1637 } |
1288 * @param array $args Data used to describe the meta key when registered. See |
1638 |
1289 * {@see register_meta()} for a list of supported arguments. |
1639 $defaults = array('orderby' => 'name', 'order' => 'ASC', |
1290 * @return bool True if the meta key was successfully registered, false if not. |
1640 'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(), |
1291 */ |
1641 'number' => '', 'fields' => 'all', 'name' => '', 'slug' => '', 'parent' => '', 'childless' => false, |
1292 function register_term_meta( $taxonomy, $meta_key, array $args ) { |
1642 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '', |
1293 $args['object_subtype'] = $taxonomy; |
1643 'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' ); |
1294 |
1644 $args = wp_parse_args( $args, $defaults ); |
1295 return register_meta( 'term', $meta_key, $args ); |
1645 $args['number'] = absint( $args['number'] ); |
1296 } |
1646 $args['offset'] = absint( $args['offset'] ); |
1297 |
1647 |
1298 /** |
1648 // Save queries by not crawling the tree in the case of multiple taxes or a flat tax. |
1299 * Unregisters a meta key for terms. |
1649 $has_hierarchical_tax = false; |
1300 * |
1650 foreach ( $taxonomies as $_tax ) { |
1301 * @since 4.9.8 |
1651 if ( is_taxonomy_hierarchical( $_tax ) ) { |
1302 * |
1652 $has_hierarchical_tax = true; |
1303 * @param string $taxonomy Taxonomy the meta key is currently registered for. Pass |
1653 } |
1304 * an empty string if the meta key is registered across all |
1654 } |
1305 * existing taxonomies. |
1655 |
1306 * @param string $meta_key The meta key to unregister. |
1656 if ( ! $has_hierarchical_tax ) { |
1307 * @return bool True on success, false if the meta key was not previously registered. |
1657 $args['hierarchical'] = false; |
1308 */ |
1658 $args['pad_counts'] = false; |
1309 function unregister_term_meta( $taxonomy, $meta_key ) { |
1659 } |
1310 return unregister_meta_key( 'term', $meta_key, $taxonomy ); |
1660 |
|
1661 // 'parent' overrides 'child_of'. |
|
1662 if ( 0 < intval( $args['parent'] ) ) { |
|
1663 $args['child_of'] = false; |
|
1664 } |
|
1665 |
|
1666 if ( 'all' == $args['get'] ) { |
|
1667 $args['childless'] = false; |
|
1668 $args['child_of'] = 0; |
|
1669 $args['hide_empty'] = 0; |
|
1670 $args['hierarchical'] = false; |
|
1671 $args['pad_counts'] = false; |
|
1672 } |
|
1673 |
|
1674 /** |
|
1675 * Filter the terms query arguments. |
|
1676 * |
|
1677 * @since 3.1.0 |
|
1678 * |
|
1679 * @param array $args An array of arguments. |
|
1680 * @param array $taxonomies An array of taxonomies. |
|
1681 */ |
|
1682 $args = apply_filters( 'get_terms_args', $args, $taxonomies ); |
|
1683 |
|
1684 // Avoid the query if the queried parent/child_of term has no descendants. |
|
1685 $child_of = $args['child_of']; |
|
1686 $parent = $args['parent']; |
|
1687 |
|
1688 if ( $child_of ) { |
|
1689 $_parent = $child_of; |
|
1690 } elseif ( $parent ) { |
|
1691 $_parent = $parent; |
|
1692 } else { |
|
1693 $_parent = false; |
|
1694 } |
|
1695 |
|
1696 if ( $_parent ) { |
|
1697 $in_hierarchy = false; |
|
1698 foreach ( $taxonomies as $_tax ) { |
|
1699 $hierarchy = _get_term_hierarchy( $_tax ); |
|
1700 |
|
1701 if ( isset( $hierarchy[ $_parent ] ) ) { |
|
1702 $in_hierarchy = true; |
|
1703 } |
|
1704 } |
|
1705 |
|
1706 if ( ! $in_hierarchy ) { |
|
1707 return $empty_array; |
|
1708 } |
|
1709 } |
|
1710 |
|
1711 // $args can be whatever, only use the args defined in defaults to compute the key |
|
1712 $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; |
|
1713 $key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $filter_key ); |
|
1714 $last_changed = wp_cache_get( 'last_changed', 'terms' ); |
|
1715 if ( ! $last_changed ) { |
|
1716 $last_changed = microtime(); |
|
1717 wp_cache_set( 'last_changed', $last_changed, 'terms' ); |
|
1718 } |
|
1719 $cache_key = "get_terms:$key:$last_changed"; |
|
1720 $cache = wp_cache_get( $cache_key, 'terms' ); |
|
1721 if ( false !== $cache ) { |
|
1722 |
|
1723 /** |
|
1724 * Filter the given taxonomy's terms cache. |
|
1725 * |
|
1726 * @since 2.3.0 |
|
1727 * |
|
1728 * @param array $cache Cached array of terms for the given taxonomy. |
|
1729 * @param array $taxonomies An array of taxonomies. |
|
1730 * @param array $args An array of arguments to get terms. |
|
1731 */ |
|
1732 $cache = apply_filters( 'get_terms', $cache, $taxonomies, $args ); |
|
1733 return $cache; |
|
1734 } |
|
1735 |
|
1736 $_orderby = strtolower( $args['orderby'] ); |
|
1737 if ( 'count' == $_orderby ) { |
|
1738 $orderby = 'tt.count'; |
|
1739 } elseif ( 'name' == $_orderby ) { |
|
1740 $orderby = 't.name'; |
|
1741 } elseif ( 'slug' == $_orderby ) { |
|
1742 $orderby = 't.slug'; |
|
1743 } elseif ( 'include' == $_orderby && ! empty( $args['include'] ) ) { |
|
1744 $include = implode( ',', array_map( 'absint', $args['include'] ) ); |
|
1745 $orderby = "FIELD( t.term_id, $include )"; |
|
1746 } elseif ( 'term_group' == $_orderby ) { |
|
1747 $orderby = 't.term_group'; |
|
1748 } elseif ( 'description' == $_orderby ) { |
|
1749 $orderby = 'tt.description'; |
|
1750 } elseif ( 'none' == $_orderby ) { |
|
1751 $orderby = ''; |
|
1752 } elseif ( empty($_orderby) || 'id' == $_orderby ) { |
|
1753 $orderby = 't.term_id'; |
|
1754 } else { |
|
1755 $orderby = 't.name'; |
|
1756 } |
|
1757 /** |
|
1758 * Filter the ORDERBY clause of the terms query. |
|
1759 * |
|
1760 * @since 2.8.0 |
|
1761 * |
|
1762 * @param string $orderby ORDERBY clause of the terms query. |
|
1763 * @param array $args An array of terms query arguments. |
|
1764 * @param array $taxonomies An array of taxonomies. |
|
1765 */ |
|
1766 $orderby = apply_filters( 'get_terms_orderby', $orderby, $args, $taxonomies ); |
|
1767 |
|
1768 $order = strtoupper( $args['order'] ); |
|
1769 if ( ! empty( $orderby ) ) { |
|
1770 $orderby = "ORDER BY $orderby"; |
|
1771 } else { |
|
1772 $order = ''; |
|
1773 } |
|
1774 |
|
1775 if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) ) { |
|
1776 $order = 'ASC'; |
|
1777 } |
|
1778 |
|
1779 $where = "tt.taxonomy IN ('" . implode("', '", $taxonomies) . "')"; |
|
1780 |
|
1781 $exclude = $args['exclude']; |
|
1782 $exclude_tree = $args['exclude_tree']; |
|
1783 $include = $args['include']; |
|
1784 |
|
1785 $inclusions = ''; |
|
1786 if ( ! empty( $include ) ) { |
|
1787 $exclude = ''; |
|
1788 $exclude_tree = ''; |
|
1789 $inclusions = implode( ',', wp_parse_id_list( $include ) ); |
|
1790 } |
|
1791 |
|
1792 if ( ! empty( $inclusions ) ) { |
|
1793 $inclusions = ' AND t.term_id IN ( ' . $inclusions . ' )'; |
|
1794 $where .= $inclusions; |
|
1795 } |
|
1796 |
|
1797 $exclusions = array(); |
|
1798 if ( ! empty( $exclude_tree ) ) { |
|
1799 $exclude_tree = wp_parse_id_list( $exclude_tree ); |
|
1800 $excluded_children = $exclude_tree; |
|
1801 foreach ( $exclude_tree as $extrunk ) { |
|
1802 $excluded_children = array_merge( |
|
1803 $excluded_children, |
|
1804 (array) get_terms( $taxonomies[0], array( 'child_of' => intval( $extrunk ), 'fields' => 'ids', 'hide_empty' => 0 ) ) |
|
1805 ); |
|
1806 } |
|
1807 $exclusions = array_merge( $excluded_children, $exclusions ); |
|
1808 } |
|
1809 |
|
1810 if ( ! empty( $exclude ) ) { |
|
1811 $exclusions = array_merge( wp_parse_id_list( $exclude ), $exclusions ); |
|
1812 } |
|
1813 |
|
1814 // 'childless' terms are those without an entry in the flattened term hierarchy. |
|
1815 $childless = (bool) $args['childless']; |
|
1816 if ( $childless ) { |
|
1817 foreach ( $taxonomies as $_tax ) { |
|
1818 $term_hierarchy = _get_term_hierarchy( $_tax ); |
|
1819 $exclusions = array_merge( array_keys( $term_hierarchy ), $exclusions ); |
|
1820 } |
|
1821 } |
|
1822 |
|
1823 if ( ! empty( $exclusions ) ) { |
|
1824 $exclusions = ' AND t.term_id NOT IN (' . implode( ',', array_map( 'intval', $exclusions ) ) . ')'; |
|
1825 } else { |
|
1826 $exclusions = ''; |
|
1827 } |
|
1828 |
|
1829 /** |
|
1830 * Filter the terms to exclude from the terms query. |
|
1831 * |
|
1832 * @since 2.3.0 |
|
1833 * |
|
1834 * @param string $exclusions NOT IN clause of the terms query. |
|
1835 * @param array $args An array of terms query arguments. |
|
1836 * @param array $taxonomies An array of taxonomies. |
|
1837 */ |
|
1838 $exclusions = apply_filters( 'list_terms_exclusions', $exclusions, $args, $taxonomies ); |
|
1839 |
|
1840 if ( ! empty( $exclusions ) ) { |
|
1841 $where .= $exclusions; |
|
1842 } |
|
1843 |
|
1844 if ( ! empty( $args['name'] ) ) { |
|
1845 if ( is_array( $args['name'] ) ) { |
|
1846 $name = array_map( 'sanitize_text_field', $args['name'] ); |
|
1847 $where .= " AND t.name IN ('" . implode( "', '", array_map( 'esc_sql', $name ) ) . "')"; |
|
1848 } else { |
|
1849 $name = sanitize_text_field( $args['name'] ); |
|
1850 $where .= $wpdb->prepare( " AND t.name = %s", $name ); |
|
1851 } |
|
1852 } |
|
1853 |
|
1854 if ( ! empty( $args['slug'] ) ) { |
|
1855 if ( is_array( $args['slug'] ) ) { |
|
1856 $slug = array_map( 'sanitize_title', $args['slug'] ); |
|
1857 $where .= " AND t.slug IN ('" . implode( "', '", $slug ) . "')"; |
|
1858 } else { |
|
1859 $slug = sanitize_title( $args['slug'] ); |
|
1860 $where .= " AND t.slug = '$slug'"; |
|
1861 } |
|
1862 } |
|
1863 |
|
1864 if ( ! empty( $args['name__like'] ) ) { |
|
1865 $where .= $wpdb->prepare( " AND t.name LIKE %s", '%' . $wpdb->esc_like( $args['name__like'] ) . '%' ); |
|
1866 } |
|
1867 |
|
1868 if ( ! empty( $args['description__like'] ) ) { |
|
1869 $where .= $wpdb->prepare( " AND tt.description LIKE %s", '%' . $wpdb->esc_like( $args['description__like'] ) . '%' ); |
|
1870 } |
|
1871 |
|
1872 if ( '' !== $parent ) { |
|
1873 $parent = (int) $parent; |
|
1874 $where .= " AND tt.parent = '$parent'"; |
|
1875 } |
|
1876 |
|
1877 $hierarchical = $args['hierarchical']; |
|
1878 if ( 'count' == $args['fields'] ) { |
|
1879 $hierarchical = false; |
|
1880 } |
|
1881 if ( $args['hide_empty'] && !$hierarchical ) { |
|
1882 $where .= ' AND tt.count > 0'; |
|
1883 } |
|
1884 |
|
1885 $number = $args['number']; |
|
1886 $offset = $args['offset']; |
|
1887 |
|
1888 // don't limit the query results when we have to descend the family tree |
|
1889 if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) { |
|
1890 if ( $offset ) { |
|
1891 $limits = 'LIMIT ' . $offset . ',' . $number; |
|
1892 } else { |
|
1893 $limits = 'LIMIT ' . $number; |
|
1894 } |
|
1895 } else { |
|
1896 $limits = ''; |
|
1897 } |
|
1898 |
|
1899 if ( ! empty( $args['search'] ) ) { |
|
1900 $like = '%' . $wpdb->esc_like( $args['search'] ) . '%'; |
|
1901 $where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', $like, $like ); |
|
1902 } |
|
1903 |
|
1904 $selects = array(); |
|
1905 switch ( $args['fields'] ) { |
|
1906 case 'all': |
|
1907 $selects = array( 't.*', 'tt.*' ); |
|
1908 break; |
|
1909 case 'ids': |
|
1910 case 'id=>parent': |
|
1911 $selects = array( 't.term_id', 'tt.parent', 'tt.count', 'tt.taxonomy' ); |
|
1912 break; |
|
1913 case 'names': |
|
1914 $selects = array( 't.term_id', 'tt.parent', 'tt.count', 't.name', 'tt.taxonomy' ); |
|
1915 break; |
|
1916 case 'count': |
|
1917 $orderby = ''; |
|
1918 $order = ''; |
|
1919 $selects = array( 'COUNT(*)' ); |
|
1920 break; |
|
1921 case 'id=>name': |
|
1922 $selects = array( 't.term_id', 't.name', 'tt.count', 'tt.taxonomy' ); |
|
1923 break; |
|
1924 case 'id=>slug': |
|
1925 $selects = array( 't.term_id', 't.slug', 'tt.count', 'tt.taxonomy' ); |
|
1926 break; |
|
1927 } |
|
1928 |
|
1929 $_fields = $args['fields']; |
|
1930 |
|
1931 /** |
|
1932 * Filter the fields to select in the terms query. |
|
1933 * |
|
1934 * Field lists modified using this filter will only modify the term fields returned |
|
1935 * by the function when the `$fields` parameter set to 'count' or 'all'. In all other |
|
1936 * cases, the term fields in the results array will be determined by the `$fields` |
|
1937 * parameter alone. |
|
1938 * |
|
1939 * Use of this filter can result in unpredictable behavior, and is not recommended. |
|
1940 * |
|
1941 * @since 2.8.0 |
|
1942 * |
|
1943 * @param array $selects An array of fields to select for the terms query. |
|
1944 * @param array $args An array of term query arguments. |
|
1945 * @param array $taxonomies An array of taxonomies. |
|
1946 */ |
|
1947 $fields = implode( ', ', apply_filters( 'get_terms_fields', $selects, $args, $taxonomies ) ); |
|
1948 |
|
1949 $join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id"; |
|
1950 |
|
1951 $pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' ); |
|
1952 |
|
1953 /** |
|
1954 * Filter the terms query SQL clauses. |
|
1955 * |
|
1956 * @since 3.1.0 |
|
1957 * |
|
1958 * @param array $pieces Terms query SQL clauses. |
|
1959 * @param array $taxonomies An array of taxonomies. |
|
1960 * @param array $args An array of terms query arguments. |
|
1961 */ |
|
1962 $clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args ); |
|
1963 $fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : ''; |
|
1964 $join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : ''; |
|
1965 $where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : ''; |
|
1966 $orderby = isset( $clauses[ 'orderby' ] ) ? $clauses[ 'orderby' ] : ''; |
|
1967 $order = isset( $clauses[ 'order' ] ) ? $clauses[ 'order' ] : ''; |
|
1968 $limits = isset( $clauses[ 'limits' ] ) ? $clauses[ 'limits' ] : ''; |
|
1969 |
|
1970 $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits"; |
|
1971 |
|
1972 if ( 'count' == $_fields ) { |
|
1973 $term_count = $wpdb->get_var($query); |
|
1974 return $term_count; |
|
1975 } |
|
1976 |
|
1977 $terms = $wpdb->get_results($query); |
|
1978 if ( 'all' == $_fields ) { |
|
1979 update_term_cache( $terms ); |
|
1980 } |
|
1981 |
|
1982 if ( empty($terms) ) { |
|
1983 wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS ); |
|
1984 |
|
1985 /** This filter is documented in wp-includes/taxonomy.php */ |
|
1986 $terms = apply_filters( 'get_terms', array(), $taxonomies, $args ); |
|
1987 return $terms; |
|
1988 } |
|
1989 |
|
1990 if ( $child_of ) { |
|
1991 foreach ( $taxonomies as $_tax ) { |
|
1992 $children = _get_term_hierarchy( $_tax ); |
|
1993 if ( ! empty( $children ) ) { |
|
1994 $terms = _get_term_children( $child_of, $terms, $_tax ); |
|
1995 } |
|
1996 } |
|
1997 } |
|
1998 |
|
1999 // Update term counts to include children. |
|
2000 if ( $args['pad_counts'] && 'all' == $_fields ) { |
|
2001 foreach ( $taxonomies as $_tax ) { |
|
2002 _pad_term_counts( $terms, $_tax ); |
|
2003 } |
|
2004 } |
|
2005 |
|
2006 // Make sure we show empty categories that have children. |
|
2007 if ( $hierarchical && $args['hide_empty'] && is_array( $terms ) ) { |
|
2008 foreach ( $terms as $k => $term ) { |
|
2009 if ( ! $term->count ) { |
|
2010 $children = get_term_children( $term->term_id, $term->taxonomy ); |
|
2011 if ( is_array( $children ) ) { |
|
2012 foreach ( $children as $child_id ) { |
|
2013 $child = get_term( $child_id, $term->taxonomy ); |
|
2014 if ( $child->count ) { |
|
2015 continue 2; |
|
2016 } |
|
2017 } |
|
2018 } |
|
2019 |
|
2020 // It really is empty |
|
2021 unset($terms[$k]); |
|
2022 } |
|
2023 } |
|
2024 } |
|
2025 |
|
2026 $_terms = array(); |
|
2027 if ( 'id=>parent' == $_fields ) { |
|
2028 foreach ( $terms as $term ) { |
|
2029 $_terms[ $term->term_id ] = $term->parent; |
|
2030 } |
|
2031 } elseif ( 'ids' == $_fields ) { |
|
2032 foreach ( $terms as $term ) { |
|
2033 $_terms[] = $term->term_id; |
|
2034 } |
|
2035 } elseif ( 'names' == $_fields ) { |
|
2036 foreach ( $terms as $term ) { |
|
2037 $_terms[] = $term->name; |
|
2038 } |
|
2039 } elseif ( 'id=>name' == $_fields ) { |
|
2040 foreach ( $terms as $term ) { |
|
2041 $_terms[ $term->term_id ] = $term->name; |
|
2042 } |
|
2043 } elseif ( 'id=>slug' == $_fields ) { |
|
2044 foreach ( $terms as $term ) { |
|
2045 $_terms[ $term->term_id ] = $term->slug; |
|
2046 } |
|
2047 } |
|
2048 |
|
2049 if ( ! empty( $_terms ) ) { |
|
2050 $terms = $_terms; |
|
2051 } |
|
2052 |
|
2053 if ( $number && is_array( $terms ) && count( $terms ) > $number ) { |
|
2054 $terms = array_slice( $terms, $offset, $number ); |
|
2055 } |
|
2056 |
|
2057 wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS ); |
|
2058 |
|
2059 /** This filter is documented in wp-includes/taxonomy */ |
|
2060 $terms = apply_filters( 'get_terms', $terms, $taxonomies, $args ); |
|
2061 return $terms; |
|
2062 } |
1311 } |
2063 |
1312 |
2064 /** |
1313 /** |
2065 * Check if Term exists. |
1314 * Check if Term exists. |
2066 * |
1315 * |
2068 * |
1317 * |
2069 * @since 3.0.0 |
1318 * @since 3.0.0 |
2070 * |
1319 * |
2071 * @global wpdb $wpdb WordPress database abstraction object. |
1320 * @global wpdb $wpdb WordPress database abstraction object. |
2072 * |
1321 * |
2073 * @param int|string $term The term to check |
1322 * @param int|string $term The term to check. Accepts term ID, slug, or name. |
2074 * @param string $taxonomy The taxonomy name to use |
1323 * @param string $taxonomy The taxonomy name to use |
2075 * @param int $parent Optional. ID of parent term under which to confine the exists search. |
1324 * @param int $parent Optional. ID of parent term under which to confine the exists search. |
2076 * @return mixed Returns null if the term does not exist. Returns the term ID |
1325 * @return mixed Returns null if the term does not exist. Returns the term ID |
2077 * if no taxonomy is specified and the term ID exists. Returns |
1326 * if no taxonomy is specified and the term ID exists. Returns |
2078 * an array of the term ID and the term taxonomy ID the taxonomy |
1327 * an array of the term ID and the term taxonomy ID the taxonomy |
2079 * is specified and the pairing exists. |
1328 * is specified and the pairing exists. |
2080 */ |
1329 */ |
2132 * |
1381 * |
2133 * You can use either an id or the term object for both parameters. |
1382 * You can use either an id or the term object for both parameters. |
2134 * |
1383 * |
2135 * @since 3.4.0 |
1384 * @since 3.4.0 |
2136 * |
1385 * |
2137 * @param int|object $term1 ID or object to check if this is the parent term. |
1386 * @param int|object $term1 ID or object to check if this is the parent term. |
2138 * @param int|object $term2 The child term. |
1387 * @param int|object $term2 The child term. |
2139 * @param string $taxonomy Taxonomy name that $term1 and $term2 belong to. |
1388 * @param string $taxonomy Taxonomy name that $term1 and `$term2` belong to. |
2140 * @return bool Whether $term2 is child of $term1 |
1389 * @return bool Whether `$term2` is a child of `$term1`. |
2141 */ |
1390 */ |
2142 function term_is_ancestor_of( $term1, $term2, $taxonomy ) { |
1391 function term_is_ancestor_of( $term1, $term2, $taxonomy ) { |
2143 if ( ! isset( $term1->term_id ) ) |
1392 if ( ! isset( $term1->term_id ) ) |
2144 $term1 = get_term( $term1, $taxonomy ); |
1393 $term1 = get_term( $term1, $taxonomy ); |
2145 if ( ! isset( $term2->parent ) ) |
1394 if ( ! isset( $term2->parent ) ) |
2162 * |
1411 * |
2163 * The $term is expected to be either an array or an object. |
1412 * The $term is expected to be either an array or an object. |
2164 * |
1413 * |
2165 * @since 2.3.0 |
1414 * @since 2.3.0 |
2166 * |
1415 * |
2167 * @param array|object $term The term to check |
1416 * @param array|object $term The term to check. |
2168 * @param string $taxonomy The taxonomy name to use |
1417 * @param string $taxonomy The taxonomy name to use. |
2169 * @param string $context Default is 'display'. |
1418 * @param string $context Optional. Context in which to sanitize the term. Accepts 'edit', 'db', |
2170 * @return array|object Term with all fields sanitized |
1419 * 'display', 'attribute', or 'js'. Default 'display'. |
1420 * @return array|object Term with all fields sanitized. |
|
2171 */ |
1421 */ |
2172 function sanitize_term($term, $taxonomy, $context = 'display') { |
1422 function sanitize_term($term, $taxonomy, $context = 'display') { |
2173 |
|
2174 $fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' ); |
1423 $fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' ); |
2175 |
1424 |
2176 $do_object = is_object( $term ); |
1425 $do_object = is_object( $term ); |
2177 |
1426 |
2178 $term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0); |
1427 $term_id = $do_object ? $term->term_id : (isset($term['term_id']) ? $term['term_id'] : 0); |
2208 * without creating your own filter function. Simply create a function that |
1457 * without creating your own filter function. Simply create a function that |
2209 * hooks into the filter you need. |
1458 * hooks into the filter you need. |
2210 * |
1459 * |
2211 * @since 2.3.0 |
1460 * @since 2.3.0 |
2212 * |
1461 * |
2213 * @global wpdb $wpdb WordPress database abstraction object. |
1462 * @param string $field Term field to sanitize. |
2214 * |
1463 * @param string $value Search for this term value. |
2215 * @param string $field Term field to sanitize |
1464 * @param int $term_id Term ID. |
2216 * @param string $value Search for this term value |
1465 * @param string $taxonomy Taxonomy Name. |
2217 * @param int $term_id Term ID |
1466 * @param string $context Context in which to sanitize the term field. Accepts 'edit', 'db', 'display', |
2218 * @param string $taxonomy Taxonomy Name |
1467 * 'attribute', or 'js'. |
2219 * @param string $context Either edit, db, display, attribute, or js. |
1468 * @return mixed Sanitized field. |
2220 * @return mixed sanitized field |
|
2221 */ |
1469 */ |
2222 function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) { |
1470 function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) { |
2223 $int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' ); |
1471 $int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' ); |
2224 if ( in_array( $field, $int_fields ) ) { |
1472 if ( in_array( $field, $int_fields ) ) { |
2225 $value = (int) $value; |
1473 $value = (int) $value; |
2231 return $value; |
1479 return $value; |
2232 |
1480 |
2233 if ( 'edit' == $context ) { |
1481 if ( 'edit' == $context ) { |
2234 |
1482 |
2235 /** |
1483 /** |
2236 * Filter a term field to edit before it is sanitized. |
1484 * Filters a term field to edit before it is sanitized. |
2237 * |
1485 * |
2238 * The dynamic portion of the filter name, `$field`, refers to the term field. |
1486 * The dynamic portion of the filter name, `$field`, refers to the term field. |
2239 * |
1487 * |
2240 * @since 2.3.0 |
1488 * @since 2.3.0 |
2241 * |
1489 * |
2244 * @param string $taxonomy Taxonomy slug. |
1492 * @param string $taxonomy Taxonomy slug. |
2245 */ |
1493 */ |
2246 $value = apply_filters( "edit_term_{$field}", $value, $term_id, $taxonomy ); |
1494 $value = apply_filters( "edit_term_{$field}", $value, $term_id, $taxonomy ); |
2247 |
1495 |
2248 /** |
1496 /** |
2249 * Filter the taxonomy field to edit before it is sanitized. |
1497 * Filters the taxonomy field to edit before it is sanitized. |
2250 * |
1498 * |
2251 * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer |
1499 * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer |
2252 * to the taxonomy slug and taxonomy field, respectively. |
1500 * to the taxonomy slug and taxonomy field, respectively. |
2253 * |
1501 * |
2254 * @since 2.3.0 |
1502 * @since 2.3.0 |
2255 * |
1503 * |
2256 * @param mixed $value Value of the taxonomy field to edit. |
1504 * @param mixed $value Value of the taxonomy field to edit. |
2257 * @param int $term_id Term ID. |
1505 * @param int $term_id Term ID. |
2258 */ |
1506 */ |
2259 $value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id ); |
1507 $value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id ); |
1508 |
|
2260 if ( 'description' == $field ) |
1509 if ( 'description' == $field ) |
2261 $value = esc_html($value); // textarea_escaped |
1510 $value = esc_html($value); // textarea_escaped |
2262 else |
1511 else |
2263 $value = esc_attr($value); |
1512 $value = esc_attr($value); |
2264 } elseif ( 'db' == $context ) { |
1513 } elseif ( 'db' == $context ) { |
2265 |
1514 |
2266 /** |
1515 /** |
2267 * Filter a term field value before it is sanitized. |
1516 * Filters a term field value before it is sanitized. |
2268 * |
1517 * |
2269 * The dynamic portion of the filter name, `$field`, refers to the term field. |
1518 * The dynamic portion of the filter name, `$field`, refers to the term field. |
2270 * |
1519 * |
2271 * @since 2.3.0 |
1520 * @since 2.3.0 |
2272 * |
1521 * |
2274 * @param string $taxonomy Taxonomy slug. |
1523 * @param string $taxonomy Taxonomy slug. |
2275 */ |
1524 */ |
2276 $value = apply_filters( "pre_term_{$field}", $value, $taxonomy ); |
1525 $value = apply_filters( "pre_term_{$field}", $value, $taxonomy ); |
2277 |
1526 |
2278 /** |
1527 /** |
2279 * Filter a taxonomy field before it is sanitized. |
1528 * Filters a taxonomy field before it is sanitized. |
2280 * |
1529 * |
2281 * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer |
1530 * The dynamic portions of the filter name, `$taxonomy` and `$field`, refer |
2282 * to the taxonomy slug and field name, respectively. |
1531 * to the taxonomy slug and field name, respectively. |
2283 * |
1532 * |
2284 * @since 2.3.0 |
1533 * @since 2.3.0 |
2285 * |
1534 * |
2286 * @param mixed $value Value of the taxonomy field. |
1535 * @param mixed $value Value of the taxonomy field. |
2287 */ |
1536 */ |
2288 $value = apply_filters( "pre_{$taxonomy}_{$field}", $value ); |
1537 $value = apply_filters( "pre_{$taxonomy}_{$field}", $value ); |
1538 |
|
2289 // Back compat filters |
1539 // Back compat filters |
2290 if ( 'slug' == $field ) { |
1540 if ( 'slug' == $field ) { |
2291 /** |
1541 /** |
2292 * Filter the category nicename before it is sanitized. |
1542 * Filters the category nicename before it is sanitized. |
2293 * |
1543 * |
2294 * Use the pre_{$taxonomy}_{$field} hook instead. |
1544 * Use the {@see 'pre_$taxonomy_$field'} hook instead. |
2295 * |
1545 * |
2296 * @since 2.0.3 |
1546 * @since 2.0.3 |
2297 * |
1547 * |
2298 * @param string $value The category nicename. |
1548 * @param string $value The category nicename. |
2299 */ |
1549 */ |
2301 } |
1551 } |
2302 |
1552 |
2303 } elseif ( 'rss' == $context ) { |
1553 } elseif ( 'rss' == $context ) { |
2304 |
1554 |
2305 /** |
1555 /** |
2306 * Filter the term field for use in RSS. |
1556 * Filters the term field for use in RSS. |
2307 * |
1557 * |
2308 * The dynamic portion of the filter name, `$field`, refers to the term field. |
1558 * The dynamic portion of the filter name, `$field`, refers to the term field. |
2309 * |
1559 * |
2310 * @since 2.3.0 |
1560 * @since 2.3.0 |
2311 * |
1561 * |
2313 * @param string $taxonomy Taxonomy slug. |
1563 * @param string $taxonomy Taxonomy slug. |
2314 */ |
1564 */ |
2315 $value = apply_filters( "term_{$field}_rss", $value, $taxonomy ); |
1565 $value = apply_filters( "term_{$field}_rss", $value, $taxonomy ); |
2316 |
1566 |
2317 /** |
1567 /** |
2318 * Filter the taxonomy field for use in RSS. |
1568 * Filters the taxonomy field for use in RSS. |
2319 * |
1569 * |
2320 * The dynamic portions of the hook name, `$taxonomy`, and $field, refer |
1570 * The dynamic portions of the hook name, `$taxonomy`, and `$field`, refer |
2321 * to the taxonomy slug and field name, respectively. |
1571 * to the taxonomy slug and field name, respectively. |
2322 * |
1572 * |
2323 * @since 2.3.0 |
1573 * @since 2.3.0 |
2324 * |
1574 * |
2325 * @param mixed $value Value of the taxonomy field. |
1575 * @param mixed $value Value of the taxonomy field. |
2327 $value = apply_filters( "{$taxonomy}_{$field}_rss", $value ); |
1577 $value = apply_filters( "{$taxonomy}_{$field}_rss", $value ); |
2328 } else { |
1578 } else { |
2329 // Use display filters by default. |
1579 // Use display filters by default. |
2330 |
1580 |
2331 /** |
1581 /** |
2332 * Filter the term field sanitized for display. |
1582 * Filters the term field sanitized for display. |
2333 * |
1583 * |
2334 * The dynamic portion of the filter name, `$field`, refers to the term field name. |
1584 * The dynamic portion of the filter name, `$field`, refers to the term field name. |
2335 * |
1585 * |
2336 * @since 2.3.0 |
1586 * @since 2.3.0 |
2337 * |
1587 * |
2341 * @param string $context Context to retrieve the term field value. |
1591 * @param string $context Context to retrieve the term field value. |
2342 */ |
1592 */ |
2343 $value = apply_filters( "term_{$field}", $value, $term_id, $taxonomy, $context ); |
1593 $value = apply_filters( "term_{$field}", $value, $term_id, $taxonomy, $context ); |
2344 |
1594 |
2345 /** |
1595 /** |
2346 * Filter the taxonomy field sanitized for display. |
1596 * Filters the taxonomy field sanitized for display. |
2347 * |
1597 * |
2348 * The dynamic portions of the filter name, `$taxonomy`, and $field, refer |
1598 * The dynamic portions of the filter name, `$taxonomy`, and `$field`, refer |
2349 * to the taxonomy slug and taxonomy field, respectively. |
1599 * to the taxonomy slug and taxonomy field, respectively. |
2350 * |
1600 * |
2351 * @since 2.3.0 |
1601 * @since 2.3.0 |
2352 * |
1602 * |
2353 * @param mixed $value Value of the taxonomy field. |
1603 * @param mixed $value Value of the taxonomy field. |
2370 * |
1620 * |
2371 * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true). |
1621 * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true). |
2372 * |
1622 * |
2373 * @since 2.3.0 |
1623 * @since 2.3.0 |
2374 * |
1624 * |
2375 * @param string $taxonomy Taxonomy name |
1625 * @param string $taxonomy Taxonomy name. |
2376 * @param array|string $args Overwrite defaults. See get_terms() |
1626 * @param array|string $args Optional. Array of arguments that get passed to get_terms(). |
2377 * @return int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist. |
1627 * Default empty array. |
1628 * @return array|int|WP_Error Number of terms in that taxonomy or WP_Error if the taxonomy does not exist. |
|
2378 */ |
1629 */ |
2379 function wp_count_terms( $taxonomy, $args = array() ) { |
1630 function wp_count_terms( $taxonomy, $args = array() ) { |
2380 $defaults = array('hide_empty' => false); |
1631 $defaults = array('hide_empty' => false); |
2381 $args = wp_parse_args($args, $defaults); |
1632 $args = wp_parse_args($args, $defaults); |
2382 |
1633 |
2383 // backwards compatibility |
1634 // backward compatibility |
2384 if ( isset($args['ignore_empty']) ) { |
1635 if ( isset($args['ignore_empty']) ) { |
2385 $args['hide_empty'] = $args['ignore_empty']; |
1636 $args['hide_empty'] = $args['ignore_empty']; |
2386 unset($args['ignore_empty']); |
1637 unset($args['ignore_empty']); |
2387 } |
1638 } |
2388 |
1639 |
2398 * a particular taxonomy or taxonomies. Does not remove the term or |
1649 * a particular taxonomy or taxonomies. Does not remove the term or |
2399 * taxonomy itself. |
1650 * taxonomy itself. |
2400 * |
1651 * |
2401 * @since 2.3.0 |
1652 * @since 2.3.0 |
2402 * |
1653 * |
2403 * @param int $object_id The term Object Id that refers to the term |
1654 * @param int $object_id The term Object Id that refers to the term. |
2404 * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name. |
1655 * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name. |
2405 */ |
1656 */ |
2406 function wp_delete_object_term_relationships( $object_id, $taxonomies ) { |
1657 function wp_delete_object_term_relationships( $object_id, $taxonomies ) { |
2407 $object_id = (int) $object_id; |
1658 $object_id = (int) $object_id; |
2408 |
1659 |
2420 * Removes a term from the database. |
1671 * Removes a term from the database. |
2421 * |
1672 * |
2422 * If the term is a parent of other terms, then the children will be updated to |
1673 * If the term is a parent of other terms, then the children will be updated to |
2423 * that term's parent. |
1674 * that term's parent. |
2424 * |
1675 * |
2425 * The $args 'default' will only override the terms found, if there is only one |
1676 * Metadata associated with the term will be deleted. |
2426 * term found. Any other and the found terms are used. |
|
2427 * |
|
2428 * The $args 'force_default' will force the term supplied as default to be |
|
2429 * assigned even if the object was not going to be termless |
|
2430 * |
1677 * |
2431 * @since 2.3.0 |
1678 * @since 2.3.0 |
2432 * |
1679 * |
2433 * @global wpdb $wpdb WordPress database abstraction object. |
1680 * @global wpdb $wpdb WordPress database abstraction object. |
2434 * |
1681 * |
2435 * @param int $term Term ID |
1682 * @param int $term Term ID. |
2436 * @param string $taxonomy Taxonomy Name |
1683 * @param string $taxonomy Taxonomy Name. |
2437 * @param array|string $args Optional. Change 'default' term id and override found term ids. |
1684 * @param array|string $args { |
2438 * @return bool|WP_Error Returns false if not term; true if completes delete action. |
1685 * Optional. Array of arguments to override the default term ID. Default empty array. |
1686 * |
|
1687 * @type int $default The term ID to make the default term. This will only override |
|
1688 * the terms found if there is only one term found. Any other and |
|
1689 * the found terms are used. |
|
1690 * @type bool $force_default Optional. Whether to force the supplied term as default to be |
|
1691 * assigned even if the object was not going to be term-less. |
|
1692 * Default false. |
|
1693 * } |
|
1694 * @return bool|int|WP_Error True on success, false if term does not exist. Zero on attempted |
|
1695 * deletion of default Category. WP_Error if the taxonomy does not exist. |
|
2439 */ |
1696 */ |
2440 function wp_delete_term( $term, $taxonomy, $args = array() ) { |
1697 function wp_delete_term( $term, $taxonomy, $args = array() ) { |
2441 global $wpdb; |
1698 global $wpdb; |
2442 |
1699 |
2443 $term = (int) $term; |
1700 $term = (int) $term; |
2496 * @since 2.9.0 |
1753 * @since 2.9.0 |
2497 * |
1754 * |
2498 * @param array $edit_tt_ids An array of term taxonomy IDs for the given term. |
1755 * @param array $edit_tt_ids An array of term taxonomy IDs for the given term. |
2499 */ |
1756 */ |
2500 do_action( 'edit_term_taxonomies', $edit_tt_ids ); |
1757 do_action( 'edit_term_taxonomies', $edit_tt_ids ); |
1758 |
|
2501 $wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) ); |
1759 $wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) ); |
2502 |
1760 |
2503 // Clean the cache for all child terms. |
1761 // Clean the cache for all child terms. |
2504 $edit_term_ids = wp_list_pluck( $edit_ids, 'term_id' ); |
1762 $edit_term_ids = wp_list_pluck( $edit_ids, 'term_id' ); |
2505 clean_term_cache( $edit_term_ids, $taxonomy ); |
1763 clean_term_cache( $edit_term_ids, $taxonomy ); |
2512 * @param array $edit_tt_ids An array of term taxonomy IDs for the given term. |
1770 * @param array $edit_tt_ids An array of term taxonomy IDs for the given term. |
2513 */ |
1771 */ |
2514 do_action( 'edited_term_taxonomies', $edit_tt_ids ); |
1772 do_action( 'edited_term_taxonomies', $edit_tt_ids ); |
2515 } |
1773 } |
2516 |
1774 |
2517 $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) ); |
1775 // Get the term before deleting it or its term relationships so we can pass to actions below. |
2518 |
1776 $deleted_term = get_term( $term, $taxonomy ); |
2519 foreach ( (array) $objects as $object ) { |
1777 |
2520 $terms = wp_get_object_terms($object, $taxonomy, array('fields' => 'ids', 'orderby' => 'none')); |
1778 $object_ids = (array) $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) ); |
1779 |
|
1780 foreach ( $object_ids as $object_id ) { |
|
1781 $terms = wp_get_object_terms( $object_id, $taxonomy, array( 'fields' => 'ids', 'orderby' => 'none' ) ); |
|
2521 if ( 1 == count($terms) && isset($default) ) { |
1782 if ( 1 == count($terms) && isset($default) ) { |
2522 $terms = array($default); |
1783 $terms = array($default); |
2523 } else { |
1784 } else { |
2524 $terms = array_diff($terms, array($term)); |
1785 $terms = array_diff($terms, array($term)); |
2525 if (isset($default) && isset($force_default) && $force_default) |
1786 if (isset($default) && isset($force_default) && $force_default) |
2526 $terms = array_merge($terms, array($default)); |
1787 $terms = array_merge($terms, array($default)); |
2527 } |
1788 } |
2528 $terms = array_map('intval', $terms); |
1789 $terms = array_map('intval', $terms); |
2529 wp_set_object_terms($object, $terms, $taxonomy); |
1790 wp_set_object_terms( $object_id, $terms, $taxonomy ); |
2530 } |
1791 } |
2531 |
1792 |
2532 // Clean the relationship caches for all object types using this term |
1793 // Clean the relationship caches for all object types using this term. |
2533 $tax_object = get_taxonomy( $taxonomy ); |
1794 $tax_object = get_taxonomy( $taxonomy ); |
2534 foreach ( $tax_object->object_type as $object_type ) |
1795 foreach ( $tax_object->object_type as $object_type ) |
2535 clean_object_term_cache( $objects, $object_type ); |
1796 clean_object_term_cache( $object_ids, $object_type ); |
2536 |
1797 |
2537 // Get the object before deletion so we can pass to actions below |
1798 $term_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->termmeta WHERE term_id = %d ", $term ) ); |
2538 $deleted_term = get_term( $term, $taxonomy ); |
1799 foreach ( $term_meta_ids as $mid ) { |
1800 delete_metadata_by_mid( 'term', $mid ); |
|
1801 } |
|
2539 |
1802 |
2540 /** |
1803 /** |
2541 * Fires immediately before a term taxonomy ID is deleted. |
1804 * Fires immediately before a term taxonomy ID is deleted. |
2542 * |
1805 * |
2543 * @since 2.9.0 |
1806 * @since 2.9.0 |
2564 |
1827 |
2565 /** |
1828 /** |
2566 * Fires after a term is deleted from the database and the cache is cleaned. |
1829 * Fires after a term is deleted from the database and the cache is cleaned. |
2567 * |
1830 * |
2568 * @since 2.5.0 |
1831 * @since 2.5.0 |
1832 * @since 4.5.0 Introduced the `$object_ids` argument. |
|
2569 * |
1833 * |
2570 * @param int $term Term ID. |
1834 * @param int $term Term ID. |
2571 * @param int $tt_id Term taxonomy ID. |
1835 * @param int $tt_id Term taxonomy ID. |
2572 * @param string $taxonomy Taxonomy slug. |
1836 * @param string $taxonomy Taxonomy slug. |
2573 * @param mixed $deleted_term Copy of the already-deleted term, in the form specified |
1837 * @param mixed $deleted_term Copy of the already-deleted term, in the form specified |
2574 * by the parent function. WP_Error otherwise. |
1838 * by the parent function. WP_Error otherwise. |
2575 */ |
1839 * @param array $object_ids List of term object IDs. |
2576 do_action( 'delete_term', $term, $tt_id, $taxonomy, $deleted_term ); |
1840 */ |
1841 do_action( 'delete_term', $term, $tt_id, $taxonomy, $deleted_term, $object_ids ); |
|
2577 |
1842 |
2578 /** |
1843 /** |
2579 * Fires after a term in a specific taxonomy is deleted. |
1844 * Fires after a term in a specific taxonomy is deleted. |
2580 * |
1845 * |
2581 * The dynamic portion of the hook name, `$taxonomy`, refers to the specific |
1846 * The dynamic portion of the hook name, `$taxonomy`, refers to the specific |
2582 * taxonomy the term belonged to. |
1847 * taxonomy the term belonged to. |
2583 * |
1848 * |
2584 * @since 2.3.0 |
1849 * @since 2.3.0 |
1850 * @since 4.5.0 Introduced the `$object_ids` argument. |
|
2585 * |
1851 * |
2586 * @param int $term Term ID. |
1852 * @param int $term Term ID. |
2587 * @param int $tt_id Term taxonomy ID. |
1853 * @param int $tt_id Term taxonomy ID. |
2588 * @param mixed $deleted_term Copy of the already-deleted term, in the form specified |
1854 * @param mixed $deleted_term Copy of the already-deleted term, in the form specified |
2589 * by the parent function. {@see WP_Error} otherwise. |
1855 * by the parent function. WP_Error otherwise. |
2590 */ |
1856 * @param array $object_ids List of term object IDs. |
2591 do_action( "delete_$taxonomy", $term, $tt_id, $deleted_term ); |
1857 */ |
1858 do_action( "delete_{$taxonomy}", $term, $tt_id, $deleted_term, $object_ids ); |
|
2592 |
1859 |
2593 return true; |
1860 return true; |
2594 } |
1861 } |
2595 |
1862 |
2596 /** |
1863 /** |
2597 * Deletes one existing category. |
1864 * Deletes one existing category. |
2598 * |
1865 * |
2599 * @since 2.0.0 |
1866 * @since 2.0.0 |
2600 * |
1867 * |
2601 * @param int $cat_ID |
1868 * @param int $cat_ID Category term ID. |
2602 * @return mixed Returns true if completes delete action; false if term doesn't exist; |
1869 * @return bool|int|WP_Error Returns true if completes delete action; false if term doesn't exist; |
2603 * Zero on attempted deletion of default Category; WP_Error object is also a possibility. |
1870 * Zero on attempted deletion of default Category; WP_Error object is also a possibility. |
2604 */ |
1871 */ |
2605 function wp_delete_category( $cat_ID ) { |
1872 function wp_delete_category( $cat_ID ) { |
2606 return wp_delete_term( $cat_ID, 'category' ); |
1873 return wp_delete_term( $cat_ID, 'category' ); |
2607 } |
1874 } |
2610 * Retrieves the terms associated with the given object(s), in the supplied taxonomies. |
1877 * Retrieves the terms associated with the given object(s), in the supplied taxonomies. |
2611 * |
1878 * |
2612 * @since 2.3.0 |
1879 * @since 2.3.0 |
2613 * @since 4.2.0 Added support for 'taxonomy', 'parent', and 'term_taxonomy_id' values of `$orderby`. |
1880 * @since 4.2.0 Added support for 'taxonomy', 'parent', and 'term_taxonomy_id' values of `$orderby`. |
2614 * Introduced `$parent` argument. |
1881 * Introduced `$parent` argument. |
2615 * |
1882 * @since 4.4.0 Introduced `$meta_query` and `$update_term_meta_cache` arguments. When `$fields` is 'all' or |
2616 * @global wpdb $wpdb WordPress database abstraction object. |
1883 * 'all_with_object_id', an array of `WP_Term` objects will be returned. |
1884 * @since 4.7.0 Refactored to use WP_Term_Query, and to support any WP_Term_Query arguments. |
|
2617 * |
1885 * |
2618 * @param int|array $object_ids The ID(s) of the object(s) to retrieve. |
1886 * @param int|array $object_ids The ID(s) of the object(s) to retrieve. |
2619 * @param string|array $taxonomies The taxonomies to retrieve terms from. |
1887 * @param string|array $taxonomies The taxonomies to retrieve terms from. |
2620 * @param array|string $args { |
1888 * @param array|string $args See WP_Term_Query::__construct() for supported arguments. |
2621 * Array of arguments. |
|
2622 * @type string $orderby Field by which results should be sorted. Accepts 'name', 'count', 'slug', 'term_group', |
|
2623 * 'term_order', 'taxonomy', 'parent', or 'term_taxonomy_id'. Default 'name'. |
|
2624 * @type string $order Sort order. Accepts 'ASC' or 'DESC'. Default 'ASC'. |
|
2625 * @type string $fields Fields to return for matched terms. Accepts 'all', 'ids', 'names', and |
|
2626 * 'all_with_object_id'. Note that 'all' or 'all_with_object_id' will result in an array of |
|
2627 * term objects being returned, 'ids' will return an array of integers, and 'names' an array |
|
2628 * of strings. |
|
2629 * @type int $parent Optional. Limit results to the direct children of a given term ID. |
|
2630 * } |
|
2631 * @return array|WP_Error The requested term data or empty array if no terms found. |
1889 * @return array|WP_Error The requested term data or empty array if no terms found. |
2632 * WP_Error if any of the $taxonomies don't exist. |
1890 * WP_Error if any of the $taxonomies don't exist. |
2633 */ |
1891 */ |
2634 function wp_get_object_terms($object_ids, $taxonomies, $args = array()) { |
1892 function wp_get_object_terms($object_ids, $taxonomies, $args = array()) { |
2635 global $wpdb; |
|
2636 |
|
2637 if ( empty( $object_ids ) || empty( $taxonomies ) ) |
1893 if ( empty( $object_ids ) || empty( $taxonomies ) ) |
2638 return array(); |
1894 return array(); |
2639 |
1895 |
2640 if ( !is_array($taxonomies) ) |
1896 if ( !is_array($taxonomies) ) |
2641 $taxonomies = array($taxonomies); |
1897 $taxonomies = array($taxonomies); |
2642 |
1898 |
2643 foreach ( $taxonomies as $taxonomy ) { |
1899 foreach ( $taxonomies as $taxonomy ) { |
2644 if ( ! taxonomy_exists($taxonomy) ) |
1900 if ( ! taxonomy_exists($taxonomy) ) |
2645 return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
1901 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
2646 } |
1902 } |
2647 |
1903 |
2648 if ( !is_array($object_ids) ) |
1904 if ( !is_array($object_ids) ) |
2649 $object_ids = array($object_ids); |
1905 $object_ids = array($object_ids); |
2650 $object_ids = array_map('intval', $object_ids); |
1906 $object_ids = array_map('intval', $object_ids); |
2651 |
1907 |
2652 $defaults = array( |
1908 $args = wp_parse_args( $args ); |
2653 'orderby' => 'name', |
1909 |
2654 'order' => 'ASC', |
1910 /** |
2655 'fields' => 'all', |
1911 * Filter arguments for retrieving object terms. |
2656 'parent' => '', |
1912 * |
2657 ); |
1913 * @since 4.9.0 |
2658 $args = wp_parse_args( $args, $defaults ); |
1914 * |
2659 |
1915 * @param array $args An array of arguments for retrieving terms for the given object(s). |
1916 * See {@see wp_get_object_terms()} for details. |
|
1917 * @param int|array $object_ids Object ID or array of IDs. |
|
1918 * @param string|array $taxonomies The taxonomies to retrieve terms from. |
|
1919 */ |
|
1920 $args = apply_filters( 'wp_get_object_terms_args', $args, $object_ids, $taxonomies ); |
|
1921 |
|
1922 /* |
|
1923 * When one or more queried taxonomies is registered with an 'args' array, |
|
1924 * those params override the `$args` passed to this function. |
|
1925 */ |
|
2660 $terms = array(); |
1926 $terms = array(); |
2661 if ( count($taxonomies) > 1 ) { |
1927 if ( count( $taxonomies ) > 1 ) { |
2662 foreach ( $taxonomies as $index => $taxonomy ) { |
1928 foreach ( $taxonomies as $index => $taxonomy ) { |
2663 $t = get_taxonomy($taxonomy); |
1929 $t = get_taxonomy( $taxonomy ); |
2664 if ( isset($t->args) && is_array($t->args) && $args != array_merge($args, $t->args) ) { |
1930 if ( isset( $t->args ) && is_array( $t->args ) && $args != array_merge( $args, $t->args ) ) { |
2665 unset($taxonomies[$index]); |
1931 unset( $taxonomies[ $index ] ); |
2666 $terms = array_merge($terms, wp_get_object_terms($object_ids, $taxonomy, array_merge($args, $t->args))); |
1932 $terms = array_merge( $terms, wp_get_object_terms( $object_ids, $taxonomy, array_merge( $args, $t->args ) ) ); |
2667 } |
1933 } |
2668 } |
1934 } |
2669 } else { |
1935 } else { |
2670 $t = get_taxonomy($taxonomies[0]); |
1936 $t = get_taxonomy( $taxonomies[0] ); |
2671 if ( isset($t->args) && is_array($t->args) ) |
1937 if ( isset( $t->args ) && is_array( $t->args ) ) { |
2672 $args = array_merge($args, $t->args); |
1938 $args = array_merge( $args, $t->args ); |
2673 } |
1939 } |
2674 |
1940 } |
2675 $orderby = $args['orderby']; |
1941 |
2676 $order = $args['order']; |
1942 $args['taxonomy'] = $taxonomies; |
2677 $fields = $args['fields']; |
1943 $args['object_ids'] = $object_ids; |
2678 |
1944 |
2679 if ( in_array( $orderby, array( 'term_id', 'name', 'slug', 'term_group' ) ) ) { |
1945 // Taxonomies registered without an 'args' param are handled here. |
2680 $orderby = "t.$orderby"; |
1946 if ( ! empty( $taxonomies ) ) { |
2681 } else if ( in_array( $orderby, array( 'count', 'parent', 'taxonomy', 'term_taxonomy_id' ) ) ) { |
1947 $terms_from_remaining_taxonomies = get_terms( $args ); |
2682 $orderby = "tt.$orderby"; |
1948 |
2683 } else if ( 'term_order' === $orderby ) { |
1949 // Array keys should be preserved for values of $fields that use term_id for keys. |
2684 $orderby = 'tr.term_order'; |
1950 if ( ! empty( $args['fields'] ) && 0 === strpos( $args['fields'], 'id=>' ) ) { |
2685 } else if ( 'none' === $orderby ) { |
1951 $terms = $terms + $terms_from_remaining_taxonomies; |
2686 $orderby = ''; |
1952 } else { |
2687 $order = ''; |
1953 $terms = array_merge( $terms, $terms_from_remaining_taxonomies ); |
2688 } else { |
1954 } |
2689 $orderby = 't.term_id'; |
|
2690 } |
|
2691 |
|
2692 // tt_ids queries can only be none or tr.term_taxonomy_id |
|
2693 if ( ('tt_ids' == $fields) && !empty($orderby) ) |
|
2694 $orderby = 'tr.term_taxonomy_id'; |
|
2695 |
|
2696 if ( !empty($orderby) ) |
|
2697 $orderby = "ORDER BY $orderby"; |
|
2698 |
|
2699 $order = strtoupper( $order ); |
|
2700 if ( '' !== $order && ! in_array( $order, array( 'ASC', 'DESC' ) ) ) |
|
2701 $order = 'ASC'; |
|
2702 |
|
2703 $taxonomy_array = $taxonomies; |
|
2704 $object_id_array = $object_ids; |
|
2705 $taxonomies = "'" . implode("', '", $taxonomies) . "'"; |
|
2706 $object_ids = implode(', ', $object_ids); |
|
2707 |
|
2708 $select_this = ''; |
|
2709 if ( 'all' == $fields ) { |
|
2710 $select_this = 't.*, tt.*'; |
|
2711 } elseif ( 'ids' == $fields ) { |
|
2712 $select_this = 't.term_id'; |
|
2713 } elseif ( 'names' == $fields ) { |
|
2714 $select_this = 't.name'; |
|
2715 } elseif ( 'slugs' == $fields ) { |
|
2716 $select_this = 't.slug'; |
|
2717 } elseif ( 'all_with_object_id' == $fields ) { |
|
2718 $select_this = 't.*, tt.*, tr.object_id'; |
|
2719 } |
|
2720 |
|
2721 $where = array( |
|
2722 "tt.taxonomy IN ($taxonomies)", |
|
2723 "tr.object_id IN ($object_ids)", |
|
2724 ); |
|
2725 |
|
2726 if ( '' !== $args['parent'] ) { |
|
2727 $where[] = $wpdb->prepare( 'tt.parent = %d', $args['parent'] ); |
|
2728 } |
|
2729 |
|
2730 $where = implode( ' AND ', $where ); |
|
2731 |
|
2732 $query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE $where $orderby $order"; |
|
2733 |
|
2734 $objects = false; |
|
2735 if ( 'all' == $fields || 'all_with_object_id' == $fields ) { |
|
2736 $_terms = $wpdb->get_results( $query ); |
|
2737 foreach ( $_terms as $key => $term ) { |
|
2738 $_terms[$key] = sanitize_term( $term, $taxonomy, 'raw' ); |
|
2739 } |
|
2740 $terms = array_merge( $terms, $_terms ); |
|
2741 update_term_cache( $terms ); |
|
2742 $objects = true; |
|
2743 } elseif ( 'ids' == $fields || 'names' == $fields || 'slugs' == $fields ) { |
|
2744 $_terms = $wpdb->get_col( $query ); |
|
2745 $_field = ( 'ids' == $fields ) ? 'term_id' : 'name'; |
|
2746 foreach ( $_terms as $key => $term ) { |
|
2747 $_terms[$key] = sanitize_term_field( $_field, $term, $term, $taxonomy, 'raw' ); |
|
2748 } |
|
2749 $terms = array_merge( $terms, $_terms ); |
|
2750 } elseif ( 'tt_ids' == $fields ) { |
|
2751 $terms = $wpdb->get_col("SELECT tr.term_taxonomy_id FROM $wpdb->term_relationships AS tr INNER JOIN $wpdb->term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tr.object_id IN ($object_ids) AND tt.taxonomy IN ($taxonomies) $orderby $order"); |
|
2752 foreach ( $terms as $key => $tt_id ) { |
|
2753 $terms[$key] = sanitize_term_field( 'term_taxonomy_id', $tt_id, 0, $taxonomy, 'raw' ); // 0 should be the term id, however is not needed when using raw context. |
|
2754 } |
|
2755 } |
|
2756 |
|
2757 if ( ! $terms ) { |
|
2758 $terms = array(); |
|
2759 } elseif ( $objects && 'all_with_object_id' !== $fields ) { |
|
2760 $_tt_ids = array(); |
|
2761 $_terms = array(); |
|
2762 foreach ( $terms as $term ) { |
|
2763 if ( in_array( $term->term_taxonomy_id, $_tt_ids ) ) { |
|
2764 continue; |
|
2765 } |
|
2766 |
|
2767 $_tt_ids[] = $term->term_taxonomy_id; |
|
2768 $_terms[] = $term; |
|
2769 } |
|
2770 $terms = $_terms; |
|
2771 } elseif ( ! $objects ) { |
|
2772 $terms = array_values( array_unique( $terms ) ); |
|
2773 } |
1955 } |
2774 |
1956 |
2775 /** |
1957 /** |
2776 * Filter the terms for a given object or objects. |
1958 * Filters the terms for a given object or objects. |
2777 * |
1959 * |
2778 * @since 4.2.0 |
1960 * @since 4.2.0 |
2779 * |
1961 * |
2780 * @param array $terms An array of terms for the given object or objects. |
1962 * @param array $terms An array of terms for the given object or objects. |
2781 * @param array $object_id_array Array of object IDs for which `$terms` were retrieved. |
1963 * @param array $object_ids Array of object IDs for which `$terms` were retrieved. |
2782 * @param array $taxonomy_array Array of taxonomies from which `$terms` were retrieved. |
1964 * @param array $taxonomies Array of taxonomies from which `$terms` were retrieved. |
2783 * @param array $args An array of arguments for retrieving terms for the given |
1965 * @param array $args An array of arguments for retrieving terms for the given |
2784 * object(s). See wp_get_object_terms() for details. |
1966 * object(s). See wp_get_object_terms() for details. |
2785 */ |
1967 */ |
2786 $terms = apply_filters( 'get_object_terms', $terms, $object_id_array, $taxonomy_array, $args ); |
1968 $terms = apply_filters( 'get_object_terms', $terms, $object_ids, $taxonomies, $args ); |
1969 |
|
1970 $object_ids = implode( ',', $object_ids ); |
|
1971 $taxonomies = "'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "'"; |
|
2787 |
1972 |
2788 /** |
1973 /** |
2789 * Filter the terms for a given object or objects. |
1974 * Filters the terms for a given object or objects. |
2790 * |
1975 * |
2791 * The `$taxonomies` parameter passed to this filter is formatted as a SQL fragment. The |
1976 * The `$taxonomies` parameter passed to this filter is formatted as a SQL fragment. The |
2792 * {@see 'get_object_terms'} filter is recommended as an alternative. |
1977 * {@see 'get_object_terms'} filter is recommended as an alternative. |
2793 * |
1978 * |
2794 * @since 2.8.0 |
1979 * @since 2.8.0 |
2795 * |
1980 * |
2796 * @param array $terms An array of terms for the given object or objects. |
1981 * @param array $terms An array of terms for the given object or objects. |
2797 * @param int|array $object_ids Object ID or array of IDs. |
1982 * @param int|array $object_ids Object ID or array of IDs. |
2798 * @param string $taxonomies SQL-formatted (comma-separated and quoted) list of taxonomy names. |
1983 * @param string $taxonomies SQL-formatted (comma-separated and quoted) list of taxonomy names. |
2799 * @param array $args An array of arguments for retrieving terms for the given object(s). |
1984 * @param array $args An array of arguments for retrieving terms for the given object(s). |
2800 * See {@see wp_get_object_terms()} for details. |
1985 * See wp_get_object_terms() for details. |
2801 */ |
1986 */ |
2802 return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args ); |
1987 return apply_filters( 'wp_get_object_terms', $terms, $object_ids, $taxonomies, $args ); |
2803 } |
1988 } |
2804 |
1989 |
2805 /** |
1990 /** |
2817 * is invalid. If it is not a valid, existing term, it is added and the term_id |
2002 * is invalid. If it is not a valid, existing term, it is added and the term_id |
2818 * is given. |
2003 * is given. |
2819 * |
2004 * |
2820 * If the taxonomy is hierarchical, and the 'parent' argument is not empty, |
2005 * If the taxonomy is hierarchical, and the 'parent' argument is not empty, |
2821 * the term is inserted and the term_id will be given. |
2006 * the term is inserted and the term_id will be given. |
2822 |
2007 * |
2823 * Error handling: |
2008 * Error handling: |
2824 * If $taxonomy does not exist or $term is empty, |
2009 * If $taxonomy does not exist or $term is empty, |
2825 * a WP_Error object will be returned. |
2010 * a WP_Error object will be returned. |
2826 * |
2011 * |
2827 * If the term already exists on the same hierarchical level, |
2012 * If the term already exists on the same hierarchical level, |
2828 * or the term slug and name are not unique, a WP_Error object will be returned. |
2013 * or the term slug and name are not unique, a WP_Error object will be returned. |
2829 * |
2014 * |
2830 * @global wpdb $wpdb WordPress database abstraction object. |
2015 * @global wpdb $wpdb WordPress database abstraction object. |
2831 |
2016 * |
2832 * @since 2.3.0 |
2017 * @since 2.3.0 |
2833 * |
2018 * |
2834 * @param string $term The term to add or update. |
2019 * @param string $term The term to add or update. |
2835 * @param string $taxonomy The taxonomy to which to add the term. |
2020 * @param string $taxonomy The taxonomy to which to add the term. |
2836 * @param array|string $args { |
2021 * @param array|string $args { |
2841 * @type string $description The term description. Default empty string. |
2026 * @type string $description The term description. Default empty string. |
2842 * @type int $parent The id of the parent term. Default 0. |
2027 * @type int $parent The id of the parent term. Default 0. |
2843 * @type string $slug The term slug to use. Default empty string. |
2028 * @type string $slug The term slug to use. Default empty string. |
2844 * } |
2029 * } |
2845 * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`, |
2030 * @return array|WP_Error An array containing the `term_id` and `term_taxonomy_id`, |
2846 * {@see WP_Error} otherwise. |
2031 * WP_Error otherwise. |
2847 */ |
2032 */ |
2848 function wp_insert_term( $term, $taxonomy, $args = array() ) { |
2033 function wp_insert_term( $term, $taxonomy, $args = array() ) { |
2849 global $wpdb; |
2034 global $wpdb; |
2850 |
2035 |
2851 if ( ! taxonomy_exists($taxonomy) ) { |
2036 if ( ! taxonomy_exists($taxonomy) ) { |
2852 return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
2037 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
2853 } |
2038 } |
2854 /** |
2039 /** |
2855 * Filter a term before it is sanitized and inserted into the database. |
2040 * Filters a term before it is sanitized and inserted into the database. |
2856 * |
2041 * |
2857 * @since 3.0.0 |
2042 * @since 3.0.0 |
2858 * |
2043 * |
2859 * @param string $term The term to add or update. |
2044 * @param string $term The term to add or update. |
2860 * @param string $taxonomy Taxonomy slug. |
2045 * @param string $taxonomy Taxonomy slug. |
2861 */ |
2046 */ |
2862 $term = apply_filters( 'pre_insert_term', $term, $taxonomy ); |
2047 $term = apply_filters( 'pre_insert_term', $term, $taxonomy ); |
2863 if ( is_wp_error( $term ) ) { |
2048 if ( is_wp_error( $term ) ) { |
2864 return $term; |
2049 return $term; |
2865 } |
2050 } |
2866 if ( is_int($term) && 0 == $term ) { |
2051 if ( is_int( $term ) && 0 == $term ) { |
2867 return new WP_Error('invalid_term_id', __('Invalid term ID')); |
2052 return new WP_Error( 'invalid_term_id', __( 'Invalid term ID.' ) ); |
2868 } |
2053 } |
2869 if ( '' == trim($term) ) { |
2054 if ( '' == trim( $term ) ) { |
2870 return new WP_Error('empty_term_name', __('A name is required for this term')); |
2055 return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) ); |
2871 } |
2056 } |
2872 $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => ''); |
2057 $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => ''); |
2873 $args = wp_parse_args( $args, $defaults ); |
2058 $args = wp_parse_args( $args, $defaults ); |
2874 |
2059 |
2875 if ( $args['parent'] > 0 && ! term_exists( (int) $args['parent'] ) ) { |
2060 if ( $args['parent'] > 0 && ! term_exists( (int) $args['parent'] ) ) { |
2876 return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) ); |
2061 return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) ); |
2877 } |
2062 } |
2063 |
|
2878 $args['name'] = $term; |
2064 $args['name'] = $term; |
2879 $args['taxonomy'] = $taxonomy; |
2065 $args['taxonomy'] = $taxonomy; |
2066 |
|
2067 // Coerce null description to strings, to avoid database errors. |
|
2068 $args['description'] = (string) $args['description']; |
|
2069 |
|
2880 $args = sanitize_term($args, $taxonomy, 'db'); |
2070 $args = sanitize_term($args, $taxonomy, 'db'); |
2881 |
2071 |
2882 // expected_slashed ($name) |
2072 // expected_slashed ($name) |
2883 $name = wp_unslash( $args['name'] ); |
2073 $name = wp_unslash( $args['name'] ); |
2884 $description = wp_unslash( $args['description'] ); |
2074 $description = wp_unslash( $args['description'] ); |
2912 |
2102 |
2913 /* |
2103 /* |
2914 * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy, |
2104 * Prevent the creation of terms with duplicate names at the same level of a taxonomy hierarchy, |
2915 * unless a unique slug has been explicitly provided. |
2105 * unless a unique slug has been explicitly provided. |
2916 */ |
2106 */ |
2917 if ( $name_match = get_term_by( 'name', $name, $taxonomy ) ) { |
2107 $name_matches = get_terms( $taxonomy, array( |
2108 'name' => $name, |
|
2109 'hide_empty' => false, |
|
2110 'parent' => $args['parent'], |
|
2111 ) ); |
|
2112 |
|
2113 /* |
|
2114 * The `name` match in `get_terms()` doesn't differentiate accented characters, |
|
2115 * so we do a stricter comparison here. |
|
2116 */ |
|
2117 $name_match = null; |
|
2118 if ( $name_matches ) { |
|
2119 foreach ( $name_matches as $_match ) { |
|
2120 if ( strtolower( $name ) === strtolower( $_match->name ) ) { |
|
2121 $name_match = $_match; |
|
2122 break; |
|
2123 } |
|
2124 } |
|
2125 } |
|
2126 |
|
2127 if ( $name_match ) { |
|
2918 $slug_match = get_term_by( 'slug', $slug, $taxonomy ); |
2128 $slug_match = get_term_by( 'slug', $slug, $taxonomy ); |
2919 if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) { |
2129 if ( ! $slug_provided || $name_match->slug === $slug || $slug_match ) { |
2920 if ( is_taxonomy_hierarchical( $taxonomy ) ) { |
2130 if ( is_taxonomy_hierarchical( $taxonomy ) ) { |
2921 $siblings = get_terms( $taxonomy, array( 'get' => 'all', 'parent' => $parent ) ); |
2131 $siblings = get_terms( $taxonomy, array( 'get' => 'all', 'parent' => $parent ) ); |
2922 |
2132 |
2923 $existing_term = null; |
2133 $existing_term = null; |
2924 if ( $name_match->slug === $slug && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) { |
2134 if ( ( ! $slug_provided || $name_match->slug === $slug ) && in_array( $name, wp_list_pluck( $siblings, 'name' ) ) ) { |
2925 $existing_term = $name_match; |
2135 $existing_term = $name_match; |
2926 } elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) { |
2136 } elseif ( $slug_match && in_array( $slug, wp_list_pluck( $siblings, 'slug' ) ) ) { |
2927 $existing_term = $slug_match; |
2137 $existing_term = $slug_match; |
2928 } |
2138 } |
2929 |
2139 |
2930 if ( $existing_term ) { |
2140 if ( $existing_term ) { |
2931 return new WP_Error( 'term_exists', __( 'A term with the name already exists with this parent.' ), $existing_term->term_id ); |
2141 return new WP_Error( 'term_exists', __( 'A term with the name provided already exists with this parent.' ), $existing_term->term_id ); |
2932 } |
2142 } |
2933 } else { |
2143 } else { |
2934 return new WP_Error( 'term_exists', __( 'A term with the name already exists in this taxonomy.' ), $name_match->term_id ); |
2144 return new WP_Error( 'term_exists', __( 'A term with the name provided already exists in this taxonomy.' ), $name_match->term_id ); |
2935 } |
2145 } |
2936 } |
2146 } |
2937 } |
2147 } |
2938 |
2148 |
2939 $slug = wp_unique_term_slug( $slug, (object) $args ); |
2149 $slug = wp_unique_term_slug( $slug, (object) $args ); |
2940 |
2150 |
2941 if ( false === $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ) ) { |
2151 $data = compact( 'name', 'slug', 'term_group' ); |
2942 return new WP_Error( 'db_insert_error', __( 'Could not insert term into the database' ), $wpdb->last_error ); |
2152 |
2153 /** |
|
2154 * Filters term data before it is inserted into the database. |
|
2155 * |
|
2156 * @since 4.7.0 |
|
2157 * |
|
2158 * @param array $data Term data to be inserted. |
|
2159 * @param string $taxonomy Taxonomy slug. |
|
2160 * @param array $args Arguments passed to wp_insert_term(). |
|
2161 */ |
|
2162 $data = apply_filters( 'wp_insert_term_data', $data, $taxonomy, $args ); |
|
2163 |
|
2164 if ( false === $wpdb->insert( $wpdb->terms, $data ) ) { |
|
2165 return new WP_Error( 'db_insert_error', __( 'Could not insert term into the database.' ), $wpdb->last_error ); |
|
2943 } |
2166 } |
2944 |
2167 |
2945 $term_id = (int) $wpdb->insert_id; |
2168 $term_id = (int) $wpdb->insert_id; |
2946 |
2169 |
2947 // Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string. |
2170 // Seems unreachable, However, Is used in the case that a term name is provided, which sanitizes to an empty string. |
3002 * @since 2.3.0 |
2225 * @since 2.3.0 |
3003 * |
2226 * |
3004 * @param int $term_id Term ID. |
2227 * @param int $term_id Term ID. |
3005 * @param int $tt_id Term taxonomy ID. |
2228 * @param int $tt_id Term taxonomy ID. |
3006 */ |
2229 */ |
3007 do_action( "create_$taxonomy", $term_id, $tt_id ); |
2230 do_action( "create_{$taxonomy}", $term_id, $tt_id ); |
3008 |
2231 |
3009 /** |
2232 /** |
3010 * Filter the term ID after a new term is created. |
2233 * Filters the term ID after a new term is created. |
3011 * |
2234 * |
3012 * @since 2.3.0 |
2235 * @since 2.3.0 |
3013 * |
2236 * |
3014 * @param int $term_id Term ID. |
2237 * @param int $term_id Term ID. |
3015 * @param int $tt_id Taxonomy term ID. |
2238 * @param int $tt_id Taxonomy term ID. |
3020 |
2243 |
3021 /** |
2244 /** |
3022 * Fires after a new term is created, and after the term cache has been cleaned. |
2245 * Fires after a new term is created, and after the term cache has been cleaned. |
3023 * |
2246 * |
3024 * @since 2.3.0 |
2247 * @since 2.3.0 |
3025 */ |
2248 * |
3026 do_action( "created_term", $term_id, $tt_id, $taxonomy ); |
2249 * @param int $term_id Term ID. |
2250 * @param int $tt_id Term taxonomy ID. |
|
2251 * @param string $taxonomy Taxonomy slug. |
|
2252 */ |
|
2253 do_action( 'created_term', $term_id, $tt_id, $taxonomy ); |
|
3027 |
2254 |
3028 /** |
2255 /** |
3029 * Fires after a new term in a specific taxonomy is created, and after the term |
2256 * Fires after a new term in a specific taxonomy is created, and after the term |
3030 * cache has been cleaned. |
2257 * cache has been cleaned. |
3031 * |
2258 * |
2259 * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug. |
|
2260 * |
|
3032 * @since 2.3.0 |
2261 * @since 2.3.0 |
3033 * |
2262 * |
3034 * @param int $term_id Term ID. |
2263 * @param int $term_id Term ID. |
3035 * @param int $tt_id Term taxonomy ID. |
2264 * @param int $tt_id Term taxonomy ID. |
3036 */ |
2265 */ |
3037 do_action( "created_$taxonomy", $term_id, $tt_id ); |
2266 do_action( "created_{$taxonomy}", $term_id, $tt_id ); |
3038 |
2267 |
3039 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
2268 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
3040 } |
2269 } |
3041 |
2270 |
3042 /** |
2271 /** |
3050 * A term has no meaning until it is given context by defining which taxonomy it |
2279 * A term has no meaning until it is given context by defining which taxonomy it |
3051 * exists under. |
2280 * exists under. |
3052 * |
2281 * |
3053 * @since 2.3.0 |
2282 * @since 2.3.0 |
3054 * |
2283 * |
2284 * @global wpdb $wpdb The WordPress database abstraction object. |
|
2285 * |
|
3055 * @param int $object_id The object to relate to. |
2286 * @param int $object_id The object to relate to. |
3056 * @param array|int|string $terms A single term slug, single term id, or array of either term slugs or ids. |
2287 * @param string|int|array $terms A single term slug, single term id, or array of either term slugs or ids. |
3057 * Will replace all existing related terms in this taxonomy. |
2288 * Will replace all existing related terms in this taxonomy. Passing an |
2289 * empty value will remove all related terms. |
|
3058 * @param string $taxonomy The context in which to relate the term to the object. |
2290 * @param string $taxonomy The context in which to relate the term to the object. |
3059 * @param bool $append Optional. If false will delete difference of terms. Default false. |
2291 * @param bool $append Optional. If false will delete difference of terms. Default false. |
3060 * @return array|WP_Error Affected Term IDs. |
2292 * @return array|WP_Error Term taxonomy IDs of the affected terms. |
3061 */ |
2293 */ |
3062 function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) { |
2294 function wp_set_object_terms( $object_id, $terms, $taxonomy, $append = false ) { |
3063 global $wpdb; |
2295 global $wpdb; |
3064 |
2296 |
3065 $object_id = (int) $object_id; |
2297 $object_id = (int) $object_id; |
3066 |
2298 |
3067 if ( ! taxonomy_exists($taxonomy) ) |
2299 if ( ! taxonomy_exists( $taxonomy ) ) { |
3068 return new WP_Error('invalid_taxonomy', __('Invalid taxonomy')); |
2300 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
2301 } |
|
3069 |
2302 |
3070 if ( !is_array($terms) ) |
2303 if ( !is_array($terms) ) |
3071 $terms = array($terms); |
2304 $terms = array($terms); |
3072 |
2305 |
3073 if ( ! $append ) |
2306 if ( ! $append ) |
3100 |
2333 |
3101 /** |
2334 /** |
3102 * Fires immediately before an object-term relationship is added. |
2335 * Fires immediately before an object-term relationship is added. |
3103 * |
2336 * |
3104 * @since 2.9.0 |
2337 * @since 2.9.0 |
2338 * @since 4.7.0 Added the `$taxonomy` parameter. |
|
3105 * |
2339 * |
3106 * @param int $object_id Object ID. |
2340 * @param int $object_id Object ID. |
3107 * @param int $tt_id Term taxonomy ID. |
2341 * @param int $tt_id Term taxonomy ID. |
2342 * @param string $taxonomy Taxonomy slug. |
|
3108 */ |
2343 */ |
3109 do_action( 'add_term_relationship', $object_id, $tt_id ); |
2344 do_action( 'add_term_relationship', $object_id, $tt_id, $taxonomy ); |
3110 $wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) ); |
2345 $wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) ); |
3111 |
2346 |
3112 /** |
2347 /** |
3113 * Fires immediately after an object-term relationship is added. |
2348 * Fires immediately after an object-term relationship is added. |
3114 * |
2349 * |
3115 * @since 2.9.0 |
2350 * @since 2.9.0 |
2351 * @since 4.7.0 Added the `$taxonomy` parameter. |
|
3116 * |
2352 * |
3117 * @param int $object_id Object ID. |
2353 * @param int $object_id Object ID. |
3118 * @param int $tt_id Term taxonomy ID. |
2354 * @param int $tt_id Term taxonomy ID. |
2355 * @param string $taxonomy Taxonomy slug. |
|
3119 */ |
2356 */ |
3120 do_action( 'added_term_relationship', $object_id, $tt_id ); |
2357 do_action( 'added_term_relationship', $object_id, $tt_id, $taxonomy ); |
3121 $new_tt_ids[] = $tt_id; |
2358 $new_tt_ids[] = $tt_id; |
3122 } |
2359 } |
3123 |
2360 |
3124 if ( $new_tt_ids ) |
2361 if ( $new_tt_ids ) |
3125 wp_update_term_count( $new_tt_ids, $taxonomy ); |
2362 wp_update_term_count( $new_tt_ids, $taxonomy ); |
3147 foreach ( $tt_ids as $tt_id ) |
2384 foreach ( $tt_ids as $tt_id ) |
3148 if ( in_array($tt_id, $final_tt_ids) ) |
2385 if ( in_array($tt_id, $final_tt_ids) ) |
3149 $values[] = $wpdb->prepare( "(%d, %d, %d)", $object_id, $tt_id, ++$term_order); |
2386 $values[] = $wpdb->prepare( "(%d, %d, %d)", $object_id, $tt_id, ++$term_order); |
3150 if ( $values ) |
2387 if ( $values ) |
3151 if ( false === $wpdb->query( "INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES " . join( ',', $values ) . " ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)" ) ) |
2388 if ( false === $wpdb->query( "INSERT INTO $wpdb->term_relationships (object_id, term_taxonomy_id, term_order) VALUES " . join( ',', $values ) . " ON DUPLICATE KEY UPDATE term_order = VALUES(term_order)" ) ) |
3152 return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database' ), $wpdb->last_error ); |
2389 return new WP_Error( 'db_insert_error', __( 'Could not insert term relationship into the database.' ), $wpdb->last_error ); |
3153 } |
2390 } |
3154 |
2391 |
3155 wp_cache_delete( $object_id, $taxonomy . '_relationships' ); |
2392 wp_cache_delete( $object_id, $taxonomy . '_relationships' ); |
2393 wp_cache_delete( 'last_changed', 'terms' ); |
|
3156 |
2394 |
3157 /** |
2395 /** |
3158 * Fires after an object's terms have been set. |
2396 * Fires after an object's terms have been set. |
3159 * |
2397 * |
3160 * @since 2.8.0 |
2398 * @since 2.8.0 |
3173 /** |
2411 /** |
3174 * Add term(s) associated with a given object. |
2412 * Add term(s) associated with a given object. |
3175 * |
2413 * |
3176 * @since 3.6.0 |
2414 * @since 3.6.0 |
3177 * |
2415 * |
3178 * @param int $object_id The ID of the object to which the terms will be added. |
2416 * @param int $object_id The ID of the object to which the terms will be added. |
3179 * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to add. |
2417 * @param string|int|array $terms The slug(s) or ID(s) of the term(s) to add. |
3180 * @param array|string $taxonomy Taxonomy name. |
2418 * @param array|string $taxonomy Taxonomy name. |
3181 * @return array|WP_Error Affected Term IDs |
2419 * @return array|WP_Error Term taxonomy IDs of the affected terms. |
3182 */ |
2420 */ |
3183 function wp_add_object_terms( $object_id, $terms, $taxonomy ) { |
2421 function wp_add_object_terms( $object_id, $terms, $taxonomy ) { |
3184 return wp_set_object_terms( $object_id, $terms, $taxonomy, true ); |
2422 return wp_set_object_terms( $object_id, $terms, $taxonomy, true ); |
3185 } |
2423 } |
3186 |
2424 |
3189 * |
2427 * |
3190 * @since 3.6.0 |
2428 * @since 3.6.0 |
3191 * |
2429 * |
3192 * @global wpdb $wpdb WordPress database abstraction object. |
2430 * @global wpdb $wpdb WordPress database abstraction object. |
3193 * |
2431 * |
3194 * @param int $object_id The ID of the object from which the terms will be removed. |
2432 * @param int $object_id The ID of the object from which the terms will be removed. |
3195 * @param array|int|string $terms The slug(s) or ID(s) of the term(s) to remove. |
2433 * @param string|int|array $terms The slug(s) or ID(s) of the term(s) to remove. |
3196 * @param array|string $taxonomy Taxonomy name. |
2434 * @param array|string $taxonomy Taxonomy name. |
3197 * @return bool|WP_Error True on success, false or WP_Error on failure. |
2435 * @return bool|WP_Error True on success, false or WP_Error on failure. |
3198 */ |
2436 */ |
3199 function wp_remove_object_terms( $object_id, $terms, $taxonomy ) { |
2437 function wp_remove_object_terms( $object_id, $terms, $taxonomy ) { |
3200 global $wpdb; |
2438 global $wpdb; |
3201 |
2439 |
3202 $object_id = (int) $object_id; |
2440 $object_id = (int) $object_id; |
3203 |
2441 |
3204 if ( ! taxonomy_exists( $taxonomy ) ) { |
2442 if ( ! taxonomy_exists( $taxonomy ) ) { |
3205 return new WP_Error( 'invalid_taxonomy', __( 'Invalid Taxonomy' ) ); |
2443 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
3206 } |
2444 } |
3207 |
2445 |
3208 if ( ! is_array( $terms ) ) { |
2446 if ( ! is_array( $terms ) ) { |
3209 $terms = array( $terms ); |
2447 $terms = array( $terms ); |
3210 } |
2448 } |
3235 |
2473 |
3236 /** |
2474 /** |
3237 * Fires immediately before an object-term relationship is deleted. |
2475 * Fires immediately before an object-term relationship is deleted. |
3238 * |
2476 * |
3239 * @since 2.9.0 |
2477 * @since 2.9.0 |
2478 * @since 4.7.0 Added the `$taxonomy` parameter. |
|
3240 * |
2479 * |
3241 * @param int $object_id Object ID. |
2480 * @param int $object_id Object ID. |
3242 * @param array $tt_ids An array of term taxonomy IDs. |
2481 * @param array $tt_ids An array of term taxonomy IDs. |
2482 * @param string $taxonomy Taxonomy slug. |
|
3243 */ |
2483 */ |
3244 do_action( 'delete_term_relationships', $object_id, $tt_ids ); |
2484 do_action( 'delete_term_relationships', $object_id, $tt_ids, $taxonomy ); |
3245 $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) ); |
2485 $deleted = $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->term_relationships WHERE object_id = %d AND term_taxonomy_id IN ($in_tt_ids)", $object_id ) ); |
2486 |
|
2487 wp_cache_delete( $object_id, $taxonomy . '_relationships' ); |
|
2488 wp_cache_delete( 'last_changed', 'terms' ); |
|
3246 |
2489 |
3247 /** |
2490 /** |
3248 * Fires immediately after an object-term relationship is deleted. |
2491 * Fires immediately after an object-term relationship is deleted. |
3249 * |
2492 * |
3250 * @since 2.9.0 |
2493 * @since 2.9.0 |
2494 * @since 4.7.0 Added the `$taxonomy` parameter. |
|
3251 * |
2495 * |
3252 * @param int $object_id Object ID. |
2496 * @param int $object_id Object ID. |
3253 * @param array $tt_ids An array of term taxonomy IDs. |
2497 * @param array $tt_ids An array of term taxonomy IDs. |
2498 * @param string $taxonomy Taxonomy slug. |
|
3254 */ |
2499 */ |
3255 do_action( 'deleted_term_relationships', $object_id, $tt_ids ); |
2500 do_action( 'deleted_term_relationships', $object_id, $tt_ids, $taxonomy ); |
2501 |
|
3256 wp_update_term_count( $tt_ids, $taxonomy ); |
2502 wp_update_term_count( $tt_ids, $taxonomy ); |
3257 |
2503 |
3258 return (bool) $deleted; |
2504 return (bool) $deleted; |
3259 } |
2505 } |
3260 |
2506 |
3262 } |
2508 } |
3263 |
2509 |
3264 /** |
2510 /** |
3265 * Will make slug unique, if it isn't already. |
2511 * Will make slug unique, if it isn't already. |
3266 * |
2512 * |
3267 * The $slug has to be unique global to every taxonomy, meaning that one |
2513 * The `$slug` has to be unique global to every taxonomy, meaning that one |
3268 * taxonomy term can't have a matching slug with another taxonomy term. Each |
2514 * taxonomy term can't have a matching slug with another taxonomy term. Each |
3269 * slug has to be globally unique for every taxonomy. |
2515 * slug has to be globally unique for every taxonomy. |
3270 * |
2516 * |
3271 * The way this works is that if the taxonomy that the term belongs to is |
2517 * The way this works is that if the taxonomy that the term belongs to is |
3272 * hierarchical and has a parent, it will append that parent to the $slug. |
2518 * hierarchical and has a parent, it will append that parent to the $slug. |
3273 * |
2519 * |
3274 * If that still doesn't return an unique slug, then it try to append a number |
2520 * If that still doesn't return an unique slug, then it try to append a number |
3275 * until it finds a number that is truly unique. |
2521 * until it finds a number that is truly unique. |
3276 * |
2522 * |
3277 * The only purpose for $term is for appending a parent, if one exists. |
2523 * The only purpose for `$term` is for appending a parent, if one exists. |
3278 * |
2524 * |
3279 * @since 2.3.0 |
2525 * @since 2.3.0 |
3280 * |
2526 * |
3281 * @global wpdb $wpdb WordPress database abstraction object. |
2527 * @global wpdb $wpdb WordPress database abstraction object. |
3282 * |
2528 * |
3283 * @param string $slug The string that will be tried for a unique slug |
2529 * @param string $slug The string that will be tried for a unique slug. |
3284 * @param object $term The term object that the $slug will belong too |
2530 * @param object $term The term object that the `$slug` will belong to. |
3285 * @return string Will return a true unique slug. |
2531 * @return string Will return a true unique slug. |
3286 */ |
2532 */ |
3287 function wp_unique_term_slug($slug, $term) { |
2533 function wp_unique_term_slug( $slug, $term ) { |
3288 global $wpdb; |
2534 global $wpdb; |
3289 |
2535 |
3290 if ( ! term_exists( $slug ) ) |
2536 $needs_suffix = true; |
3291 return $slug; |
2537 $original_slug = $slug; |
3292 |
2538 |
3293 // As of 4.1, duplicate slugs are allowed as long as they're in different taxonomies. |
2539 // As of 4.1, duplicate slugs are allowed as long as they're in different taxonomies. |
3294 if ( get_option( 'db_version' ) >= 30133 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) { |
2540 if ( ! term_exists( $slug ) || get_option( 'db_version' ) >= 30133 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) { |
3295 return $slug; |
2541 $needs_suffix = false; |
3296 } |
2542 } |
3297 |
2543 |
3298 // If the taxonomy supports hierarchy and the term has a parent, make the slug unique |
2544 /* |
3299 // by incorporating parent slugs. |
2545 * If the taxonomy supports hierarchy and the term has a parent, make the slug unique |
3300 if ( is_taxonomy_hierarchical($term->taxonomy) && !empty($term->parent) ) { |
2546 * by incorporating parent slugs. |
2547 */ |
|
2548 $parent_suffix = ''; |
|
2549 if ( $needs_suffix && is_taxonomy_hierarchical( $term->taxonomy ) && ! empty( $term->parent ) ) { |
|
3301 $the_parent = $term->parent; |
2550 $the_parent = $term->parent; |
3302 while ( ! empty($the_parent) ) { |
2551 while ( ! empty($the_parent) ) { |
3303 $parent_term = get_term($the_parent, $term->taxonomy); |
2552 $parent_term = get_term($the_parent, $term->taxonomy); |
3304 if ( is_wp_error($parent_term) || empty($parent_term) ) |
2553 if ( is_wp_error($parent_term) || empty($parent_term) ) |
3305 break; |
2554 break; |
3306 $slug .= '-' . $parent_term->slug; |
2555 $parent_suffix .= '-' . $parent_term->slug; |
3307 if ( ! term_exists( $slug ) ) |
2556 if ( ! term_exists( $slug . $parent_suffix ) ) { |
3308 return $slug; |
2557 break; |
2558 } |
|
3309 |
2559 |
3310 if ( empty($parent_term->parent) ) |
2560 if ( empty($parent_term->parent) ) |
3311 break; |
2561 break; |
3312 $the_parent = $parent_term->parent; |
2562 $the_parent = $parent_term->parent; |
3313 } |
2563 } |
3314 } |
2564 } |
3315 |
2565 |
3316 // If we didn't get a unique slug, try appending a number to make it unique. |
2566 // If we didn't get a unique slug, try appending a number to make it unique. |
3317 if ( ! empty( $term->term_id ) ) |
2567 |
3318 $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id ); |
2568 /** |
3319 else |
2569 * Filters whether the proposed unique term slug is bad. |
3320 $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug ); |
2570 * |
3321 |
2571 * @since 4.3.0 |
3322 if ( $wpdb->get_var( $query ) ) { |
2572 * |
3323 $num = 2; |
2573 * @param bool $needs_suffix Whether the slug needs to be made unique with a suffix. |
3324 do { |
2574 * @param string $slug The slug. |
3325 $alt_slug = $slug . "-$num"; |
2575 * @param object $term Term object. |
3326 $num++; |
2576 */ |
3327 $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) ); |
2577 if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) { |
3328 } while ( $slug_check ); |
2578 if ( $parent_suffix ) { |
3329 $slug = $alt_slug; |
2579 $slug .= $parent_suffix; |
3330 } |
2580 } else { |
3331 |
2581 if ( ! empty( $term->term_id ) ) |
3332 return $slug; |
2582 $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id ); |
2583 else |
|
2584 $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug ); |
|
2585 |
|
2586 if ( $wpdb->get_var( $query ) ) { |
|
2587 $num = 2; |
|
2588 do { |
|
2589 $alt_slug = $slug . "-$num"; |
|
2590 $num++; |
|
2591 $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) ); |
|
2592 } while ( $slug_check ); |
|
2593 $slug = $alt_slug; |
|
2594 } |
|
2595 } |
|
2596 } |
|
2597 |
|
2598 /** |
|
2599 * Filters the unique term slug. |
|
2600 * |
|
2601 * @since 4.3.0 |
|
2602 * |
|
2603 * @param string $slug Unique term slug. |
|
2604 * @param object $term Term object. |
|
2605 * @param string $original_slug Slug originally passed to the function for testing. |
|
2606 */ |
|
2607 return apply_filters( 'wp_unique_term_slug', $slug, $term, $original_slug ); |
|
3333 } |
2608 } |
3334 |
2609 |
3335 /** |
2610 /** |
3336 * Update term based on arguments provided. |
2611 * Update term based on arguments provided. |
3337 * |
2612 * |
3348 * If the 'slug' argument in $args is missing, then the 'name' in $args will be |
2623 * If the 'slug' argument in $args is missing, then the 'name' in $args will be |
3349 * used. It should also be noted that if you set 'slug' and it isn't unique then |
2624 * used. It should also be noted that if you set 'slug' and it isn't unique then |
3350 * a WP_Error will be passed back. If you don't pass any slug, then a unique one |
2625 * a WP_Error will be passed back. If you don't pass any slug, then a unique one |
3351 * will be created for you. |
2626 * will be created for you. |
3352 * |
2627 * |
3353 * For what can be overrode in $args, check the term scheme can contain and stay |
2628 * For what can be overrode in `$args`, check the term scheme can contain and stay |
3354 * away from the term keys. |
2629 * away from the term keys. |
3355 * |
2630 * |
3356 * @since 2.3.0 |
2631 * @since 2.3.0 |
3357 * |
2632 * |
3358 * @global wpdb $wpdb WordPress database abstraction object. |
2633 * @global wpdb $wpdb WordPress database abstraction object. |
3359 * |
2634 * |
3360 * @param int $term_id The ID of the term |
2635 * @param int $term_id The ID of the term |
3361 * @param string $taxonomy The context in which to relate the term to the object. |
2636 * @param string $taxonomy The context in which to relate the term to the object. |
3362 * @param array|string $args Overwrite term field values |
2637 * @param array|string $args Optional. Array of get_terms() arguments. Default empty array. |
3363 * @return array|WP_Error Returns Term ID and Taxonomy Term ID |
2638 * @return array|WP_Error Returns Term ID and Taxonomy Term ID |
3364 */ |
2639 */ |
3365 function wp_update_term( $term_id, $taxonomy, $args = array() ) { |
2640 function wp_update_term( $term_id, $taxonomy, $args = array() ) { |
3366 global $wpdb; |
2641 global $wpdb; |
3367 |
2642 |
3368 if ( ! taxonomy_exists( $taxonomy ) ) { |
2643 if ( ! taxonomy_exists( $taxonomy ) ) { |
3369 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) ); |
2644 return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); |
3370 } |
2645 } |
3371 |
2646 |
3372 $term_id = (int) $term_id; |
2647 $term_id = (int) $term_id; |
3373 |
2648 |
3374 // First, get all of the original args |
2649 // First, get all of the original args |
3375 $term = get_term( $term_id, $taxonomy, ARRAY_A ); |
2650 $term = get_term( $term_id, $taxonomy ); |
3376 |
2651 |
3377 if ( is_wp_error( $term ) ) { |
2652 if ( is_wp_error( $term ) ) { |
3378 return $term; |
2653 return $term; |
3379 } |
2654 } |
3380 |
2655 |
3381 if ( ! $term ) { |
2656 if ( ! $term ) { |
3382 return new WP_Error( 'invalid_term', __( 'Empty Term' ) ); |
2657 return new WP_Error( 'invalid_term', __( 'Empty Term.' ) ); |
3383 } |
2658 } |
2659 |
|
2660 $term = (array) $term->data; |
|
3384 |
2661 |
3385 // Escape data pulled from DB. |
2662 // Escape data pulled from DB. |
3386 $term = wp_slash($term); |
2663 $term = wp_slash( $term ); |
3387 |
2664 |
3388 // Merge old and new args with new args overwriting old ones. |
2665 // Merge old and new args with new args overwriting old ones. |
3389 $args = array_merge($term, $args); |
2666 $args = array_merge($term, $args); |
3390 |
2667 |
3391 $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => ''); |
2668 $defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0, 'slug' => ''); |
3398 $description = wp_unslash( $args['description'] ); |
2675 $description = wp_unslash( $args['description'] ); |
3399 |
2676 |
3400 $parsed_args['name'] = $name; |
2677 $parsed_args['name'] = $name; |
3401 $parsed_args['description'] = $description; |
2678 $parsed_args['description'] = $description; |
3402 |
2679 |
3403 if ( '' == trim($name) ) |
2680 if ( '' == trim( $name ) ) { |
3404 return new WP_Error('empty_term_name', __('A name is required for this term')); |
2681 return new WP_Error( 'empty_term_name', __( 'A name is required for this term.' ) ); |
2682 } |
|
3405 |
2683 |
3406 if ( $parsed_args['parent'] > 0 && ! term_exists( (int) $parsed_args['parent'] ) ) { |
2684 if ( $parsed_args['parent'] > 0 && ! term_exists( (int) $parsed_args['parent'] ) ) { |
3407 return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) ); |
2685 return new WP_Error( 'missing_parent', __( 'Parent term does not exist.' ) ); |
3408 } |
2686 } |
3409 |
2687 |
3437 |
2715 |
3438 $parsed_args['term_group'] = $term_group; |
2716 $parsed_args['term_group'] = $term_group; |
3439 } |
2717 } |
3440 |
2718 |
3441 /** |
2719 /** |
3442 * Filter the term parent. |
2720 * Filters the term parent. |
3443 * |
2721 * |
3444 * Hook to this filter to see if it will cause a hierarchy loop. |
2722 * Hook to this filter to see if it will cause a hierarchy loop. |
3445 * |
2723 * |
3446 * @since 3.1.0 |
2724 * @since 3.1.0 |
3447 * |
2725 * |
3456 // Check for duplicate slug |
2734 // Check for duplicate slug |
3457 $duplicate = get_term_by( 'slug', $slug, $taxonomy ); |
2735 $duplicate = get_term_by( 'slug', $slug, $taxonomy ); |
3458 if ( $duplicate && $duplicate->term_id != $term_id ) { |
2736 if ( $duplicate && $duplicate->term_id != $term_id ) { |
3459 // If an empty slug was passed or the parent changed, reset the slug to something unique. |
2737 // If an empty slug was passed or the parent changed, reset the slug to something unique. |
3460 // Otherwise, bail. |
2738 // Otherwise, bail. |
3461 if ( $empty_slug || ( $parent != $term['parent']) ) |
2739 if ( $empty_slug || ( $parent != $term['parent']) ) { |
3462 $slug = wp_unique_term_slug($slug, (object) $args); |
2740 $slug = wp_unique_term_slug($slug, (object) $args); |
3463 else |
2741 } else { |
3464 return new WP_Error('duplicate_term_slug', sprintf(__('The slug “%s” is already in use by another term'), $slug)); |
2742 /* translators: 1: Taxonomy term slug */ |
3465 } |
2743 return new WP_Error( 'duplicate_term_slug', sprintf( __( 'The slug “%s” is already in use by another term.' ), $slug ) ); |
3466 |
2744 } |
3467 $tt_id = $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) ); |
2745 } |
2746 |
|
2747 $tt_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = %s AND t.term_id = %d", $taxonomy, $term_id) ); |
|
3468 |
2748 |
3469 // Check whether this is a shared term that needs splitting. |
2749 // Check whether this is a shared term that needs splitting. |
3470 $_term_id = _split_shared_term( $term_id, $tt_id ); |
2750 $_term_id = _split_shared_term( $term_id, $tt_id ); |
3471 if ( ! is_wp_error( $_term_id ) ) { |
2751 if ( ! is_wp_error( $_term_id ) ) { |
3472 $term_id = $_term_id; |
2752 $term_id = $_term_id; |
3479 * |
2759 * |
3480 * @param int $term_id Term ID. |
2760 * @param int $term_id Term ID. |
3481 * @param string $taxonomy Taxonomy slug. |
2761 * @param string $taxonomy Taxonomy slug. |
3482 */ |
2762 */ |
3483 do_action( 'edit_terms', $term_id, $taxonomy ); |
2763 do_action( 'edit_terms', $term_id, $taxonomy ); |
3484 $wpdb->update($wpdb->terms, compact( 'name', 'slug', 'term_group' ), compact( 'term_id' ) ); |
2764 |
2765 $data = compact( 'name', 'slug', 'term_group' ); |
|
2766 |
|
2767 /** |
|
2768 * Filters term data before it is updated in the database. |
|
2769 * |
|
2770 * @since 4.7.0 |
|
2771 * |
|
2772 * @param array $data Term data to be updated. |
|
2773 * @param int $term_id Term ID. |
|
2774 * @param string $taxonomy Taxonomy slug. |
|
2775 * @param array $args Arguments passed to wp_update_term(). |
|
2776 */ |
|
2777 $data = apply_filters( 'wp_update_term_data', $data, $term_id, $taxonomy, $args ); |
|
2778 |
|
2779 $wpdb->update( $wpdb->terms, $data, compact( 'term_id' ) ); |
|
3485 if ( empty($slug) ) { |
2780 if ( empty($slug) ) { |
3486 $slug = sanitize_title($name, $term_id); |
2781 $slug = sanitize_title($name, $term_id); |
3487 $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) ); |
2782 $wpdb->update( $wpdb->terms, compact( 'slug' ), compact( 'term_id' ) ); |
3488 } |
2783 } |
3489 |
2784 |
3504 * |
2799 * |
3505 * @param int $tt_id Term taxonomy ID. |
2800 * @param int $tt_id Term taxonomy ID. |
3506 * @param string $taxonomy Taxonomy slug. |
2801 * @param string $taxonomy Taxonomy slug. |
3507 */ |
2802 */ |
3508 do_action( 'edit_term_taxonomy', $tt_id, $taxonomy ); |
2803 do_action( 'edit_term_taxonomy', $tt_id, $taxonomy ); |
2804 |
|
3509 $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) ); |
2805 $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) ); |
3510 |
2806 |
3511 /** |
2807 /** |
3512 * Fires immediately after a term-taxonomy relationship is updated. |
2808 * Fires immediately after a term-taxonomy relationship is updated. |
3513 * |
2809 * |
3515 * |
2811 * |
3516 * @param int $tt_id Term taxonomy ID. |
2812 * @param int $tt_id Term taxonomy ID. |
3517 * @param string $taxonomy Taxonomy slug. |
2813 * @param string $taxonomy Taxonomy slug. |
3518 */ |
2814 */ |
3519 do_action( 'edited_term_taxonomy', $tt_id, $taxonomy ); |
2815 do_action( 'edited_term_taxonomy', $tt_id, $taxonomy ); |
3520 |
|
3521 // Clean the relationship caches for all object types using this term |
|
3522 $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) ); |
|
3523 $tax_object = get_taxonomy( $taxonomy ); |
|
3524 foreach ( $tax_object->object_type as $object_type ) { |
|
3525 clean_object_term_cache( $objects, $object_type ); |
|
3526 } |
|
3527 |
2816 |
3528 /** |
2817 /** |
3529 * Fires after a term has been updated, but before the term cache has been cleaned. |
2818 * Fires after a term has been updated, but before the term cache has been cleaned. |
3530 * |
2819 * |
3531 * @since 2.3.0 |
2820 * @since 2.3.0 |
3545 * @since 2.3.0 |
2834 * @since 2.3.0 |
3546 * |
2835 * |
3547 * @param int $term_id Term ID. |
2836 * @param int $term_id Term ID. |
3548 * @param int $tt_id Term taxonomy ID. |
2837 * @param int $tt_id Term taxonomy ID. |
3549 */ |
2838 */ |
3550 do_action( "edit_$taxonomy", $term_id, $tt_id ); |
2839 do_action( "edit_{$taxonomy}", $term_id, $tt_id ); |
3551 |
2840 |
3552 /** This filter is documented in wp-includes/taxonomy.php */ |
2841 /** This filter is documented in wp-includes/taxonomy.php */ |
3553 $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id ); |
2842 $term_id = apply_filters( 'term_id_filter', $term_id, $tt_id ); |
3554 |
2843 |
3555 clean_term_cache($term_id, $taxonomy); |
2844 clean_term_cache($term_id, $taxonomy); |
3574 * @since 2.3.0 |
2863 * @since 2.3.0 |
3575 * |
2864 * |
3576 * @param int $term_id Term ID. |
2865 * @param int $term_id Term ID. |
3577 * @param int $tt_id Term taxonomy ID. |
2866 * @param int $tt_id Term taxonomy ID. |
3578 */ |
2867 */ |
3579 do_action( "edited_$taxonomy", $term_id, $tt_id ); |
2868 do_action( "edited_{$taxonomy}", $term_id, $tt_id ); |
3580 |
2869 |
3581 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
2870 return array('term_id' => $term_id, 'term_taxonomy_id' => $tt_id); |
3582 } |
2871 } |
3583 |
2872 |
3584 /** |
2873 /** |
3585 * Enable or disable term counting. |
2874 * Enable or disable term counting. |
3586 * |
2875 * |
3587 * @since 2.5.0 |
2876 * @since 2.5.0 |
2877 * |
|
2878 * @staticvar bool $_defer |
|
3588 * |
2879 * |
3589 * @param bool $defer Optional. Enable if true, disable if false. |
2880 * @param bool $defer Optional. Enable if true, disable if false. |
3590 * @return bool Whether term counting is enabled or disabled. |
2881 * @return bool Whether term counting is enabled or disabled. |
3591 */ |
2882 */ |
3592 function wp_defer_term_counting($defer=null) { |
2883 function wp_defer_term_counting($defer=null) { |
3611 * The default action is to count what the amount of terms have the relationship |
2902 * The default action is to count what the amount of terms have the relationship |
3612 * of term ID. Once that is done, then update the database. |
2903 * of term ID. Once that is done, then update the database. |
3613 * |
2904 * |
3614 * @since 2.3.0 |
2905 * @since 2.3.0 |
3615 * |
2906 * |
3616 * @global wpdb $wpdb WordPress database abstraction object. |
2907 * @staticvar array $_deferred |
3617 * |
2908 * |
3618 * @param int|array $terms The term_taxonomy_id of the terms |
2909 * @param int|array $terms The term_taxonomy_id of the terms. |
3619 * @param string $taxonomy The context of the term. |
2910 * @param string $taxonomy The context of the term. |
2911 * @param bool $do_deferred Whether to flush the deferred term counts too. Default false. |
|
3620 * @return bool If no terms will return false, and if successful will return true. |
2912 * @return bool If no terms will return false, and if successful will return true. |
3621 */ |
2913 */ |
3622 function wp_update_term_count( $terms, $taxonomy, $do_deferred=false ) { |
2914 function wp_update_term_count( $terms, $taxonomy, $do_deferred = false ) { |
3623 static $_deferred = array(); |
2915 static $_deferred = array(); |
3624 |
2916 |
3625 if ( $do_deferred ) { |
2917 if ( $do_deferred ) { |
3626 foreach ( (array) array_keys($_deferred) as $tax ) { |
2918 foreach ( (array) array_keys($_deferred) as $tax ) { |
3627 wp_update_term_count_now( $_deferred[$tax], $tax ); |
2919 wp_update_term_count_now( $_deferred[$tax], $tax ); |
3648 /** |
2940 /** |
3649 * Perform term count update immediately. |
2941 * Perform term count update immediately. |
3650 * |
2942 * |
3651 * @since 2.5.0 |
2943 * @since 2.5.0 |
3652 * |
2944 * |
3653 * @param array $terms The term_taxonomy_id of terms to update. |
2945 * @param array $terms The term_taxonomy_id of terms to update. |
3654 * @param string $taxonomy The context of the term. |
2946 * @param string $taxonomy The context of the term. |
3655 * @return bool Always true when complete. |
2947 * @return true Always true when complete. |
3656 */ |
2948 */ |
3657 function wp_update_term_count_now( $terms, $taxonomy ) { |
2949 function wp_update_term_count_now( $terms, $taxonomy ) { |
3658 $terms = array_map('intval', $terms); |
2950 $terms = array_map('intval', $terms); |
3659 |
2951 |
3660 $taxonomy = get_taxonomy($taxonomy); |
2952 $taxonomy = get_taxonomy($taxonomy); |
3686 // |
2978 // |
3687 |
2979 |
3688 /** |
2980 /** |
3689 * Removes the taxonomy relationship to terms from the cache. |
2981 * Removes the taxonomy relationship to terms from the cache. |
3690 * |
2982 * |
3691 * Will remove the entire taxonomy relationship containing term $object_id. The |
2983 * Will remove the entire taxonomy relationship containing term `$object_id`. The |
3692 * term IDs have to exist within the taxonomy $object_type for the deletion to |
2984 * term IDs have to exist within the taxonomy `$object_type` for the deletion to |
3693 * take place. |
2985 * take place. |
3694 * |
2986 * |
3695 * @since 2.3.0 |
2987 * @since 2.3.0 |
3696 * |
2988 * |
3697 * @see get_object_taxonomies() for more on $object_type |
2989 * @global bool $_wp_suspend_cache_invalidation |
3698 * |
2990 * |
3699 * @param int|array $object_ids Single or list of term object ID(s) |
2991 * @see get_object_taxonomies() for more on $object_type. |
3700 * @param array|string $object_type The taxonomy object type |
2992 * |
2993 * @param int|array $object_ids Single or list of term object ID(s). |
|
2994 * @param array|string $object_type The taxonomy object type. |
|
3701 */ |
2995 */ |
3702 function clean_object_term_cache($object_ids, $object_type) { |
2996 function clean_object_term_cache($object_ids, $object_type) { |
2997 global $_wp_suspend_cache_invalidation; |
|
2998 |
|
2999 if ( ! empty( $_wp_suspend_cache_invalidation ) ) { |
|
3000 return; |
|
3001 } |
|
3002 |
|
3703 if ( !is_array($object_ids) ) |
3003 if ( !is_array($object_ids) ) |
3704 $object_ids = array($object_ids); |
3004 $object_ids = array($object_ids); |
3705 |
3005 |
3706 $taxonomies = get_object_taxonomies( $object_type ); |
3006 $taxonomies = get_object_taxonomies( $object_type ); |
3707 |
3007 |
3715 * Fires after the object term cache has been cleaned. |
3015 * Fires after the object term cache has been cleaned. |
3716 * |
3016 * |
3717 * @since 2.5.0 |
3017 * @since 2.5.0 |
3718 * |
3018 * |
3719 * @param array $object_ids An array of object IDs. |
3019 * @param array $object_ids An array of object IDs. |
3720 * @param string $objet_type Object type. |
3020 * @param string $object_type Object type. |
3721 */ |
3021 */ |
3722 do_action( 'clean_object_term_cache', $object_ids, $object_type ); |
3022 do_action( 'clean_object_term_cache', $object_ids, $object_type ); |
3723 } |
3023 } |
3724 |
3024 |
3725 /** |
3025 /** |
3726 * Will remove all of the term ids from the cache. |
3026 * Will remove all of the term ids from the cache. |
3727 * |
3027 * |
3728 * @since 2.3.0 |
3028 * @since 2.3.0 |
3729 * |
3029 * |
3730 * @global wpdb $wpdb WordPress database abstraction object. |
3030 * @global wpdb $wpdb WordPress database abstraction object. |
3731 * |
3031 * @global bool $_wp_suspend_cache_invalidation |
3732 * @param int|array $ids Single or list of Term IDs |
3032 * |
3733 * @param string $taxonomy Can be empty and will assume tt_ids, else will use for context. |
3033 * @param int|array $ids Single or list of Term IDs. |
3734 * @param bool $clean_taxonomy Whether to clean taxonomy wide caches (true), or just individual term object caches (false). Default is true. |
3034 * @param string $taxonomy Optional. Can be empty and will assume `tt_ids`, else will use for context. |
3035 * Default empty. |
|
3036 * @param bool $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual |
|
3037 * term object caches (false). Default true. |
|
3735 */ |
3038 */ |
3736 function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) { |
3039 function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) { |
3737 global $wpdb; |
3040 global $wpdb, $_wp_suspend_cache_invalidation; |
3041 |
|
3042 if ( ! empty( $_wp_suspend_cache_invalidation ) ) { |
|
3043 return; |
|
3044 } |
|
3738 |
3045 |
3739 if ( !is_array($ids) ) |
3046 if ( !is_array($ids) ) |
3740 $ids = array($ids); |
3047 $ids = array($ids); |
3741 |
3048 |
3742 $taxonomies = array(); |
3049 $taxonomies = array(); |
3747 $terms = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)"); |
3054 $terms = $wpdb->get_results("SELECT term_id, taxonomy FROM $wpdb->term_taxonomy WHERE term_taxonomy_id IN ($tt_ids)"); |
3748 $ids = array(); |
3055 $ids = array(); |
3749 foreach ( (array) $terms as $term ) { |
3056 foreach ( (array) $terms as $term ) { |
3750 $taxonomies[] = $term->taxonomy; |
3057 $taxonomies[] = $term->taxonomy; |
3751 $ids[] = $term->term_id; |
3058 $ids[] = $term->term_id; |
3752 wp_cache_delete($term->term_id, $term->taxonomy); |
3059 wp_cache_delete( $term->term_id, 'terms' ); |
3753 } |
3060 } |
3754 $taxonomies = array_unique($taxonomies); |
3061 $taxonomies = array_unique($taxonomies); |
3755 } else { |
3062 } else { |
3756 $taxonomies = array($taxonomy); |
3063 $taxonomies = array($taxonomy); |
3757 foreach ( $taxonomies as $taxonomy ) { |
3064 foreach ( $taxonomies as $taxonomy ) { |
3758 foreach ( $ids as $id ) { |
3065 foreach ( $ids as $id ) { |
3759 wp_cache_delete($id, $taxonomy); |
3066 wp_cache_delete( $id, 'terms' ); |
3760 } |
3067 } |
3761 } |
3068 } |
3762 } |
3069 } |
3763 |
3070 |
3764 foreach ( $taxonomies as $taxonomy ) { |
3071 foreach ( $taxonomies as $taxonomy ) { |
3765 if ( $clean_taxonomy ) { |
3072 if ( $clean_taxonomy ) { |
3766 wp_cache_delete('all_ids', $taxonomy); |
3073 clean_taxonomy_cache( $taxonomy ); |
3767 wp_cache_delete('get', $taxonomy); |
|
3768 delete_option("{$taxonomy}_children"); |
|
3769 // Regenerate {$taxonomy}_children |
|
3770 _get_term_hierarchy($taxonomy); |
|
3771 } |
3074 } |
3772 |
3075 |
3773 /** |
3076 /** |
3774 * Fires once after each taxonomy's term cache has been cleaned. |
3077 * Fires once after each taxonomy's term cache has been cleaned. |
3775 * |
3078 * |
3776 * @since 2.5.0 |
3079 * @since 2.5.0 |
3080 * @since 4.5.0 Added the `$clean_taxonomy` parameter. |
|
3777 * |
3081 * |
3778 * @param array $ids An array of term IDs. |
3082 * @param array $ids An array of term IDs. |
3779 * @param string $taxonomy Taxonomy slug. |
3083 * @param string $taxonomy Taxonomy slug. |
3084 * @param bool $clean_taxonomy Whether or not to clean taxonomy-wide caches |
|
3780 */ |
3085 */ |
3781 do_action( 'clean_term_cache', $ids, $taxonomy ); |
3086 do_action( 'clean_term_cache', $ids, $taxonomy, $clean_taxonomy ); |
3782 } |
3087 } |
3783 |
3088 |
3784 wp_cache_set( 'last_changed', microtime(), 'terms' ); |
3089 wp_cache_set( 'last_changed', microtime(), 'terms' ); |
3785 } |
3090 } |
3786 |
3091 |
3787 /** |
3092 /** |
3093 * Clean the caches for a taxonomy. |
|
3094 * |
|
3095 * @since 4.9.0 |
|
3096 * |
|
3097 * @param string $taxonomy Taxonomy slug. |
|
3098 */ |
|
3099 function clean_taxonomy_cache( $taxonomy ) { |
|
3100 wp_cache_delete( 'all_ids', $taxonomy ); |
|
3101 wp_cache_delete( 'get', $taxonomy ); |
|
3102 |
|
3103 // Regenerate cached hierarchy. |
|
3104 delete_option( "{$taxonomy}_children" ); |
|
3105 _get_term_hierarchy( $taxonomy ); |
|
3106 |
|
3107 /** |
|
3108 * Fires after a taxonomy's caches have been cleaned. |
|
3109 * |
|
3110 * @since 4.9.0 |
|
3111 * |
|
3112 * @param string $taxonomy Taxonomy slug. |
|
3113 */ |
|
3114 do_action( 'clean_taxonomy_cache', $taxonomy ); |
|
3115 } |
|
3116 |
|
3117 /** |
|
3788 * Retrieves the taxonomy relationship to the term object id. |
3118 * Retrieves the taxonomy relationship to the term object id. |
3789 * |
3119 * |
3120 * Upstream functions (like get_the_terms() and is_object_in_term()) are |
|
3121 * responsible for populating the object-term relationship cache. The current |
|
3122 * function only fetches relationship data that is already in the cache. |
|
3123 * |
|
3790 * @since 2.3.0 |
3124 * @since 2.3.0 |
3791 * |
3125 * @since 4.7.0 Returns a WP_Error object if get_term() returns an error for |
3792 * @param int $id Term object ID |
3126 * any of the matched terms. |
3793 * @param string $taxonomy Taxonomy Name |
3127 * |
3794 * @return bool|array Empty array if $terms found, but not $taxonomy. False if nothing is in cache for $taxonomy and $id. |
3128 * @param int $id Term object ID. |
3795 */ |
3129 * @param string $taxonomy Taxonomy name. |
3796 function get_object_term_cache($id, $taxonomy) { |
3130 * @return bool|array|WP_Error Array of `WP_Term` objects, if cached. |
3797 $cache = wp_cache_get($id, "{$taxonomy}_relationships"); |
3131 * False if cache is empty for `$taxonomy` and `$id`. |
3798 return $cache; |
3132 * WP_Error if get_term() returns an error object for any term. |
3133 */ |
|
3134 function get_object_term_cache( $id, $taxonomy ) { |
|
3135 $_term_ids = wp_cache_get( $id, "{$taxonomy}_relationships" ); |
|
3136 |
|
3137 // We leave the priming of relationship caches to upstream functions. |
|
3138 if ( false === $_term_ids ) { |
|
3139 return false; |
|
3140 } |
|
3141 |
|
3142 // Backward compatibility for if a plugin is putting objects into the cache, rather than IDs. |
|
3143 $term_ids = array(); |
|
3144 foreach ( $_term_ids as $term_id ) { |
|
3145 if ( is_numeric( $term_id ) ) { |
|
3146 $term_ids[] = intval( $term_id ); |
|
3147 } elseif ( isset( $term_id->term_id ) ) { |
|
3148 $term_ids[] = intval( $term_id->term_id ); |
|
3149 } |
|
3150 } |
|
3151 |
|
3152 // Fill the term objects. |
|
3153 _prime_term_caches( $term_ids ); |
|
3154 |
|
3155 $terms = array(); |
|
3156 foreach ( $term_ids as $term_id ) { |
|
3157 $term = get_term( $term_id, $taxonomy ); |
|
3158 if ( is_wp_error( $term ) ) { |
|
3159 return $term; |
|
3160 } |
|
3161 |
|
3162 $terms[] = $term; |
|
3163 } |
|
3164 |
|
3165 return $terms; |
|
3799 } |
3166 } |
3800 |
3167 |
3801 /** |
3168 /** |
3802 * Updates the cache for the given term object ID(s). |
3169 * Updates the cache for the given term object ID(s). |
3803 * |
3170 * |
3808 * |
3175 * |
3809 * Caches will only be updated for terms not already cached. |
3176 * Caches will only be updated for terms not already cached. |
3810 * |
3177 * |
3811 * @since 2.3.0 |
3178 * @since 2.3.0 |
3812 * |
3179 * |
3813 * @param string|array $object_ids Comma-separated list or array of term object IDs.. |
3180 * @param string|array $object_ids Comma-separated list or array of term object IDs. |
3814 * @param array|string $object_type The taxonomy object type. |
3181 * @param array|string $object_type The taxonomy object type. |
3815 * @return null|false Null if `$object_ids` is empty, false if all of the terms in |
3182 * @return void|false False if all of the terms in `$object_ids` are already cached. |
3816 * `$object_ids` are already cached. |
|
3817 */ |
3183 */ |
3818 function update_object_term_cache($object_ids, $object_type) { |
3184 function update_object_term_cache($object_ids, $object_type) { |
3819 if ( empty($object_ids) ) |
3185 if ( empty($object_ids) ) |
3820 return; |
3186 return; |
3821 |
3187 |
3837 } |
3203 } |
3838 |
3204 |
3839 if ( empty( $ids ) ) |
3205 if ( empty( $ids ) ) |
3840 return false; |
3206 return false; |
3841 |
3207 |
3842 $terms = wp_get_object_terms($ids, $taxonomies, array('fields' => 'all_with_object_id')); |
3208 $terms = wp_get_object_terms( $ids, $taxonomies, array( |
3209 'fields' => 'all_with_object_id', |
|
3210 'orderby' => 'name', |
|
3211 'update_term_meta_cache' => false, |
|
3212 ) ); |
|
3843 |
3213 |
3844 $object_terms = array(); |
3214 $object_terms = array(); |
3845 foreach ( (array) $terms as $term ) |
3215 foreach ( (array) $terms as $term ) { |
3846 $object_terms[$term->object_id][$term->taxonomy][] = $term; |
3216 $object_terms[ $term->object_id ][ $term->taxonomy ][] = $term->term_id; |
3217 } |
|
3847 |
3218 |
3848 foreach ( $ids as $id ) { |
3219 foreach ( $ids as $id ) { |
3849 foreach ( $taxonomies as $taxonomy ) { |
3220 foreach ( $taxonomies as $taxonomy ) { |
3850 if ( ! isset($object_terms[$id][$taxonomy]) ) { |
3221 if ( ! isset($object_terms[$id][$taxonomy]) ) { |
3851 if ( !isset($object_terms[$id]) ) |
3222 if ( !isset($object_terms[$id]) ) |
3865 /** |
3236 /** |
3866 * Updates Terms to Taxonomy in cache. |
3237 * Updates Terms to Taxonomy in cache. |
3867 * |
3238 * |
3868 * @since 2.3.0 |
3239 * @since 2.3.0 |
3869 * |
3240 * |
3870 * @param array $terms List of Term objects to change |
3241 * @param array $terms List of term objects to change. |
3871 * @param string $taxonomy Optional. Update Term to this taxonomy in cache |
3242 * @param string $taxonomy Optional. Update Term to this taxonomy in cache. Default empty. |
3872 */ |
3243 */ |
3873 function update_term_cache($terms, $taxonomy = '') { |
3244 function update_term_cache( $terms, $taxonomy = '' ) { |
3874 foreach ( (array) $terms as $term ) { |
3245 foreach ( (array) $terms as $term ) { |
3875 $term_taxonomy = $taxonomy; |
3246 // Create a copy in case the array was passed by reference. |
3876 if ( empty($term_taxonomy) ) |
3247 $_term = clone $term; |
3877 $term_taxonomy = $term->taxonomy; |
3248 |
3878 |
3249 // Object ID should not be cached. |
3879 wp_cache_add( $term->term_id, $term, $term_taxonomy ); |
3250 unset( $_term->object_id ); |
3251 |
|
3252 wp_cache_add( $term->term_id, $_term, 'terms' ); |
|
3880 } |
3253 } |
3881 } |
3254 } |
3882 |
3255 |
3883 // |
3256 // |
3884 // Private |
3257 // Private |
3885 // |
3258 // |
3886 |
3259 |
3887 /** |
3260 /** |
3888 * Retrieves children of taxonomy as Term IDs. |
3261 * Retrieves children of taxonomy as Term IDs. |
3889 * |
3262 * |
3890 * @access private |
3263 * @ignore |
3891 * @since 2.3.0 |
3264 * @since 2.3.0 |
3892 * |
3265 * |
3893 * @param string $taxonomy Taxonomy Name |
3266 * @param string $taxonomy Taxonomy name. |
3894 * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs. |
3267 * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs. |
3895 */ |
3268 */ |
3896 function _get_term_hierarchy($taxonomy) { |
3269 function _get_term_hierarchy( $taxonomy ) { |
3897 if ( !is_taxonomy_hierarchical($taxonomy) ) |
3270 if ( !is_taxonomy_hierarchical($taxonomy) ) |
3898 return array(); |
3271 return array(); |
3899 $children = get_option("{$taxonomy}_children"); |
3272 $children = get_option("{$taxonomy}_children"); |
3900 |
3273 |
3901 if ( is_array($children) ) |
3274 if ( is_array($children) ) |
3912 } |
3285 } |
3913 |
3286 |
3914 /** |
3287 /** |
3915 * Get the subset of $terms that are descendants of $term_id. |
3288 * Get the subset of $terms that are descendants of $term_id. |
3916 * |
3289 * |
3917 * If $terms is an array of objects, then _get_term_children returns an array of objects. |
3290 * If `$terms` is an array of objects, then _get_term_children() returns an array of objects. |
3918 * If $terms is an array of IDs, then _get_term_children returns an array of IDs. |
3291 * If `$terms` is an array of IDs, then _get_term_children() returns an array of IDs. |
3919 * |
3292 * |
3920 * @access private |
3293 * @access private |
3921 * @since 2.3.0 |
3294 * @since 2.3.0 |
3922 * |
3295 * |
3923 * @param int $term_id The ancestor term: all returned terms should be descendants of $term_id. |
3296 * @param int $term_id The ancestor term: all returned terms should be descendants of `$term_id`. |
3924 * @param array $terms The set of terms - either an array of term objects or term IDs - from which those that |
3297 * @param array $terms The set of terms - either an array of term objects or term IDs - from which those that |
3925 * are descendants of $term_id will be chosen. |
3298 * are descendants of $term_id will be chosen. |
3926 * @param string $taxonomy The taxonomy which determines the hierarchy of the terms. |
3299 * @param string $taxonomy The taxonomy which determines the hierarchy of the terms. |
3927 * @param array $ancestors Term ancestors that have already been identified. Passed by reference, to keep track of |
3300 * @param array $ancestors Optional. Term ancestors that have already been identified. Passed by reference, to keep |
3928 * found terms when recursing the hierarchy. The array of located ancestors is used to prevent |
3301 * track of found terms when recursing the hierarchy. The array of located ancestors is used |
3929 * infinite recursion loops. For performance, term_ids are used as array keys, with 1 as value. |
3302 * to prevent infinite recursion loops. For performance, `term_ids` are used as array keys, |
3930 * @return array The subset of $terms that are descendants of $term_id. |
3303 * with 1 as value. Default empty array. |
3304 * @return array|WP_Error The subset of $terms that are descendants of $term_id. |
|
3931 */ |
3305 */ |
3932 function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) { |
3306 function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) { |
3933 $empty_array = array(); |
3307 $empty_array = array(); |
3934 if ( empty($terms) ) |
3308 if ( empty($terms) ) |
3935 return $empty_array; |
3309 return $empty_array; |
3987 * @access private |
3361 * @access private |
3988 * @since 2.3.0 |
3362 * @since 2.3.0 |
3989 * |
3363 * |
3990 * @global wpdb $wpdb WordPress database abstraction object. |
3364 * @global wpdb $wpdb WordPress database abstraction object. |
3991 * |
3365 * |
3992 * @param array $terms List of Term IDs |
3366 * @param array $terms List of term objects (passed by reference). |
3993 * @param string $taxonomy Term Context |
3367 * @param string $taxonomy Term context. |
3994 * @return null Will break from function if conditions are not met. |
3368 */ |
3995 */ |
3369 function _pad_term_counts( &$terms, $taxonomy ) { |
3996 function _pad_term_counts(&$terms, $taxonomy) { |
|
3997 global $wpdb; |
3370 global $wpdb; |
3998 |
3371 |
3999 // This function only works for hierarchical taxonomies like post categories. |
3372 // This function only works for hierarchical taxonomies like post categories. |
4000 if ( !is_taxonomy_hierarchical( $taxonomy ) ) |
3373 if ( !is_taxonomy_hierarchical( $taxonomy ) ) |
4001 return; |
3374 return; |
4012 foreach ( (array) $terms as $key => $term ) { |
3385 foreach ( (array) $terms as $key => $term ) { |
4013 $terms_by_id[$term->term_id] = & $terms[$key]; |
3386 $terms_by_id[$term->term_id] = & $terms[$key]; |
4014 $term_ids[$term->term_taxonomy_id] = $term->term_id; |
3387 $term_ids[$term->term_taxonomy_id] = $term->term_id; |
4015 } |
3388 } |
4016 |
3389 |
4017 // Get the object and term ids and stick them in a lookup table |
3390 // Get the object and term ids and stick them in a lookup table. |
4018 $tax_obj = get_taxonomy($taxonomy); |
3391 $tax_obj = get_taxonomy($taxonomy); |
4019 $object_types = esc_sql($tax_obj->object_type); |
3392 $object_types = esc_sql($tax_obj->object_type); |
4020 $results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode(',', array_keys($term_ids)) . ") AND post_type IN ('" . implode("', '", $object_types) . "') AND post_status = 'publish'"); |
3393 $results = $wpdb->get_results("SELECT object_id, term_taxonomy_id FROM $wpdb->term_relationships INNER JOIN $wpdb->posts ON object_id = ID WHERE term_taxonomy_id IN (" . implode(',', array_keys($term_ids)) . ") AND post_type IN ('" . implode("', '", $object_types) . "') AND post_status = 'publish'"); |
4021 foreach ( $results as $row ) { |
3394 foreach ( $results as $row ) { |
4022 $id = $term_ids[$row->term_taxonomy_id]; |
3395 $id = $term_ids[$row->term_taxonomy_id]; |
4023 $term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1; |
3396 $term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1; |
4024 } |
3397 } |
4025 |
3398 |
4026 // Touch every ancestor's lookup row for each post in each term |
3399 // Touch every ancestor's lookup row for each post in each term. |
4027 foreach ( $term_ids as $term_id ) { |
3400 foreach ( $term_ids as $term_id ) { |
4028 $child = $term_id; |
3401 $child = $term_id; |
4029 $ancestors = array(); |
3402 $ancestors = array(); |
4030 while ( !empty( $terms_by_id[$child] ) && $parent = $terms_by_id[$child]->parent ) { |
3403 while ( !empty( $terms_by_id[$child] ) && $parent = $terms_by_id[$child]->parent ) { |
4031 $ancestors[] = $child; |
3404 $ancestors[] = $child; |
4039 break; |
3412 break; |
4040 } |
3413 } |
4041 } |
3414 } |
4042 } |
3415 } |
4043 |
3416 |
4044 // Transfer the touched cells |
3417 // Transfer the touched cells. |
4045 foreach ( (array) $term_items as $id => $items ) |
3418 foreach ( (array) $term_items as $id => $items ) |
4046 if ( isset($terms_by_id[$id]) ) |
3419 if ( isset($terms_by_id[$id]) ) |
4047 $terms_by_id[$id]->count = count($items); |
3420 $terms_by_id[$id]->count = count($items); |
4048 } |
3421 } |
4049 |
3422 |
3423 /** |
|
3424 * Adds any terms from the given IDs to the cache that do not already exist in cache. |
|
3425 * |
|
3426 * @since 4.6.0 |
|
3427 * @access private |
|
3428 * |
|
3429 * @global wpdb $wpdb WordPress database abstraction object. |
|
3430 * |
|
3431 * @param array $term_ids Array of term IDs. |
|
3432 * @param bool $update_meta_cache Optional. Whether to update the meta cache. Default true. |
|
3433 */ |
|
3434 function _prime_term_caches( $term_ids, $update_meta_cache = true ) { |
|
3435 global $wpdb; |
|
3436 |
|
3437 $non_cached_ids = _get_non_cached_ids( $term_ids, 'terms' ); |
|
3438 if ( ! empty( $non_cached_ids ) ) { |
|
3439 $fresh_terms = $wpdb->get_results( sprintf( "SELECT t.*, tt.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE t.term_id IN (%s)", join( ",", array_map( 'intval', $non_cached_ids ) ) ) ); |
|
3440 |
|
3441 update_term_cache( $fresh_terms, $update_meta_cache ); |
|
3442 |
|
3443 if ( $update_meta_cache ) { |
|
3444 update_termmeta_cache( $non_cached_ids ); |
|
3445 } |
|
3446 } |
|
3447 } |
|
3448 |
|
4050 // |
3449 // |
4051 // Default callbacks |
3450 // Default callbacks |
4052 // |
3451 // |
4053 |
3452 |
4054 /** |
3453 /** |
4060 * @access private |
3459 * @access private |
4061 * @since 2.3.0 |
3460 * @since 2.3.0 |
4062 * |
3461 * |
4063 * @global wpdb $wpdb WordPress database abstraction object. |
3462 * @global wpdb $wpdb WordPress database abstraction object. |
4064 * |
3463 * |
4065 * @param array $terms List of Term taxonomy IDs |
3464 * @param array $terms List of Term taxonomy IDs. |
4066 * @param object $taxonomy Current taxonomy object of terms |
3465 * @param object $taxonomy Current taxonomy object of terms. |
4067 */ |
3466 */ |
4068 function _update_post_term_count( $terms, $taxonomy ) { |
3467 function _update_post_term_count( $terms, $taxonomy ) { |
4069 global $wpdb; |
3468 global $wpdb; |
4070 |
3469 |
4071 $object_types = (array) $taxonomy->object_type; |
3470 $object_types = (array) $taxonomy->object_type; |
4084 $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) ); |
3483 $object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) ); |
4085 |
3484 |
4086 foreach ( (array) $terms as $term ) { |
3485 foreach ( (array) $terms as $term ) { |
4087 $count = 0; |
3486 $count = 0; |
4088 |
3487 |
4089 // Attachments can be 'inherit' status, we need to base count off the parent's status if so |
3488 // Attachments can be 'inherit' status, we need to base count off the parent's status if so. |
4090 if ( $check_attachments ) |
3489 if ( $check_attachments ) |
4091 $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) ); |
3490 $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts p1 WHERE p1.ID = $wpdb->term_relationships.object_id AND ( post_status = 'publish' OR ( post_status = 'inherit' AND post_parent > 0 AND ( SELECT post_status FROM $wpdb->posts WHERE ID = p1.post_parent ) = 'publish' ) ) AND post_type = 'attachment' AND term_taxonomy_id = %d", $term ) ); |
4092 |
3491 |
4093 if ( $object_types ) |
3492 if ( $object_types ) |
4094 $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) ); |
3493 $count += (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d", $term ) ); |
4103 } |
3502 } |
4104 |
3503 |
4105 /** |
3504 /** |
4106 * Will update term count based on number of objects. |
3505 * Will update term count based on number of objects. |
4107 * |
3506 * |
4108 * Default callback for the link_category taxonomy. |
3507 * Default callback for the 'link_category' taxonomy. |
4109 * |
3508 * |
4110 * @since 3.3.0 |
3509 * @since 3.3.0 |
4111 * |
3510 * |
4112 * @global wpdb $wpdb WordPress database abstraction object. |
3511 * @global wpdb $wpdb WordPress database abstraction object. |
4113 * |
3512 * |
4114 * @param array $terms List of Term taxonomy IDs |
3513 * @param array $terms List of term taxonomy IDs. |
4115 * @param object $taxonomy Current taxonomy object of terms |
3514 * @param object $taxonomy Current taxonomy object of terms. |
4116 */ |
3515 */ |
4117 function _update_generic_term_count( $terms, $taxonomy ) { |
3516 function _update_generic_term_count( $terms, $taxonomy ) { |
4118 global $wpdb; |
3517 global $wpdb; |
4119 |
3518 |
4120 foreach ( (array) $terms as $term ) { |
3519 foreach ( (array) $terms as $term ) { |
4128 do_action( 'edited_term_taxonomy', $term, $taxonomy->name ); |
3527 do_action( 'edited_term_taxonomy', $term, $taxonomy->name ); |
4129 } |
3528 } |
4130 } |
3529 } |
4131 |
3530 |
4132 /** |
3531 /** |
4133 * Create a new term for a term_taxonomy item that currently shares its term with another term_taxonomy. |
3532 * Create a new term for a term_taxonomy item that currently shares its term |
3533 * with another term_taxonomy. |
|
4134 * |
3534 * |
4135 * @ignore |
3535 * @ignore |
4136 * @since 4.2.0 |
3536 * @since 4.2.0 |
4137 * |
3537 * @since 4.3.0 Introduced `$record` parameter. Also, `$term_id` and |
4138 * @param int $term_id ID of the shared term. |
3538 * `$term_taxonomy_id` can now accept objects. |
4139 * @param int $term_taxonomy_id ID of the term_taxonomy item to receive a new term. |
3539 * |
3540 * @global wpdb $wpdb WordPress database abstraction object. |
|
3541 * |
|
3542 * @param int|object $term_id ID of the shared term, or the shared term object. |
|
3543 * @param int|object $term_taxonomy_id ID of the term_taxonomy item to receive a new term, or the term_taxonomy object |
|
3544 * (corresponding to a row from the term_taxonomy table). |
|
3545 * @param bool $record Whether to record data about the split term in the options table. The recording |
|
3546 * process has the potential to be resource-intensive, so during batch operations |
|
3547 * it can be beneficial to skip inline recording and do it just once, after the |
|
3548 * batch is processed. Only set this to `false` if you know what you are doing. |
|
3549 * Default: true. |
|
4140 * @return int|WP_Error When the current term does not need to be split (or cannot be split on the current |
3550 * @return int|WP_Error When the current term does not need to be split (or cannot be split on the current |
4141 * database schema), `$term_id` is returned. When the term is successfully split, the |
3551 * database schema), `$term_id` is returned. When the term is successfully split, the |
4142 * new term_id is returned. A WP_Error is returned for miscellaneous errors. |
3552 * new term_id is returned. A WP_Error is returned for miscellaneous errors. |
4143 */ |
3553 */ |
4144 function _split_shared_term( $term_id, $term_taxonomy_id ) { |
3554 function _split_shared_term( $term_id, $term_taxonomy_id, $record = true ) { |
4145 global $wpdb; |
3555 global $wpdb; |
4146 |
3556 |
4147 // Don't try to split terms if database schema does not support shared slugs. |
3557 if ( is_object( $term_id ) ) { |
4148 $current_db_version = get_option( 'db_version' ); |
3558 $shared_term = $term_id; |
4149 if ( $current_db_version < 30133 ) { |
3559 $term_id = intval( $shared_term->term_id ); |
4150 return $term_id; |
3560 } |
3561 |
|
3562 if ( is_object( $term_taxonomy_id ) ) { |
|
3563 $term_taxonomy = $term_taxonomy_id; |
|
3564 $term_taxonomy_id = intval( $term_taxonomy->term_taxonomy_id ); |
|
4151 } |
3565 } |
4152 |
3566 |
4153 // If there are no shared term_taxonomy rows, there's nothing to do here. |
3567 // If there are no shared term_taxonomy rows, there's nothing to do here. |
4154 $shared_tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy tt WHERE tt.term_id = %d AND tt.term_taxonomy_id != %d", $term_id, $term_taxonomy_id ) ); |
3568 $shared_tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy tt WHERE tt.term_id = %d AND tt.term_taxonomy_id != %d", $term_id, $term_taxonomy_id ) ); |
3569 |
|
4155 if ( ! $shared_tt_count ) { |
3570 if ( ! $shared_tt_count ) { |
4156 return $term_id; |
3571 return $term_id; |
4157 } |
3572 } |
4158 |
3573 |
3574 /* |
|
3575 * Verify that the term_taxonomy_id passed to the function is actually associated with the term_id. |
|
3576 * If there's a mismatch, it may mean that the term is already split. Return the actual term_id from the db. |
|
3577 */ |
|
3578 $check_term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) ); |
|
3579 if ( $check_term_id != $term_id ) { |
|
3580 return $check_term_id; |
|
3581 } |
|
3582 |
|
4159 // Pull up data about the currently shared slug, which we'll use to populate the new one. |
3583 // Pull up data about the currently shared slug, which we'll use to populate the new one. |
4160 $shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) ); |
3584 if ( empty( $shared_term ) ) { |
3585 $shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) ); |
|
3586 } |
|
4161 |
3587 |
4162 $new_term_data = array( |
3588 $new_term_data = array( |
4163 'name' => $shared_term->name, |
3589 'name' => $shared_term->name, |
4164 'slug' => $shared_term->slug, |
3590 'slug' => $shared_term->slug, |
4165 'term_group' => $shared_term->term_group, |
3591 'term_group' => $shared_term->term_group, |
4176 array( 'term_id' => $new_term_id ), |
3602 array( 'term_id' => $new_term_id ), |
4177 array( 'term_taxonomy_id' => $term_taxonomy_id ) |
3603 array( 'term_taxonomy_id' => $term_taxonomy_id ) |
4178 ); |
3604 ); |
4179 |
3605 |
4180 // Reassign child terms to the new parent. |
3606 // Reassign child terms to the new parent. |
4181 $term_taxonomy = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) ); |
3607 if ( empty( $term_taxonomy ) ) { |
4182 $children_tt_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = %s AND parent = %d", $term_taxonomy->taxonomy, $term_id ) ); |
3608 $term_taxonomy = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) ); |
4183 |
3609 } |
3610 |
|
3611 $children_tt_ids = $wpdb->get_col( $wpdb->prepare( "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE parent = %d AND taxonomy = %s", $term_id, $term_taxonomy->taxonomy ) ); |
|
4184 if ( ! empty( $children_tt_ids ) ) { |
3612 if ( ! empty( $children_tt_ids ) ) { |
4185 foreach ( $children_tt_ids as $child_tt_id ) { |
3613 foreach ( $children_tt_ids as $child_tt_id ) { |
4186 $wpdb->update( $wpdb->term_taxonomy, |
3614 $wpdb->update( $wpdb->term_taxonomy, |
4187 array( 'parent' => $new_term_id ), |
3615 array( 'parent' => $new_term_id ), |
4188 array( 'term_taxonomy_id' => $child_tt_id ) |
3616 array( 'term_taxonomy_id' => $child_tt_id ) |
4189 ); |
3617 ); |
4190 clean_term_cache( $term_id, $term_taxonomy->taxonomy ); |
3618 clean_term_cache( (int) $child_tt_id, '', false ); |
4191 } |
3619 } |
4192 } else { |
3620 } else { |
4193 // If the term has no children, we must force its taxonomy cache to be rebuilt separately. |
3621 // If the term has no children, we must force its taxonomy cache to be rebuilt separately. |
4194 clean_term_cache( $new_term_id, $term_taxonomy->taxonomy ); |
3622 clean_term_cache( $new_term_id, $term_taxonomy->taxonomy, false ); |
4195 } |
3623 } |
3624 |
|
3625 clean_term_cache( $term_id, $term_taxonomy->taxonomy, false ); |
|
3626 |
|
3627 /* |
|
3628 * Taxonomy cache clearing is delayed to avoid race conditions that may occur when |
|
3629 * regenerating the taxonomy's hierarchy tree. |
|
3630 */ |
|
3631 $taxonomies_to_clean = array( $term_taxonomy->taxonomy ); |
|
4196 |
3632 |
4197 // Clean the cache for term taxonomies formerly shared with the current term. |
3633 // Clean the cache for term taxonomies formerly shared with the current term. |
4198 $shared_term_taxonomies = $wpdb->get_row( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) ); |
3634 $shared_term_taxonomies = $wpdb->get_col( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) ); |
4199 if ( $shared_term_taxonomies ) { |
3635 $taxonomies_to_clean = array_merge( $taxonomies_to_clean, $shared_term_taxonomies ); |
4200 foreach ( $shared_term_taxonomies as $shared_term_taxonomy ) { |
3636 |
4201 clean_term_cache( $term_id, $shared_term_taxonomy ); |
3637 foreach ( $taxonomies_to_clean as $taxonomy_to_clean ) { |
4202 } |
3638 clean_taxonomy_cache( $taxonomy_to_clean ); |
4203 } |
3639 } |
4204 |
3640 |
4205 // Keep a record of term_ids that have been split, keyed by old term_id. See {@see wp_get_split_term()}. |
3641 // Keep a record of term_ids that have been split, keyed by old term_id. See wp_get_split_term(). |
4206 $split_term_data = get_option( '_split_terms', array() ); |
3642 if ( $record ) { |
4207 if ( ! isset( $split_term_data[ $term_id ] ) ) { |
3643 $split_term_data = get_option( '_split_terms', array() ); |
4208 $split_term_data[ $term_id ] = array(); |
3644 if ( ! isset( $split_term_data[ $term_id ] ) ) { |
4209 } |
3645 $split_term_data[ $term_id ] = array(); |
4210 |
3646 } |
4211 $split_term_data[ $term_id ][ $term_taxonomy->taxonomy ] = $new_term_id; |
3647 |
4212 |
3648 $split_term_data[ $term_id ][ $term_taxonomy->taxonomy ] = $new_term_id; |
4213 update_option( '_split_terms', $split_term_data ); |
3649 update_option( '_split_terms', $split_term_data ); |
3650 } |
|
3651 |
|
3652 // If we've just split the final shared term, set the "finished" flag. |
|
3653 $shared_terms_exist = $wpdb->get_results( |
|
3654 "SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt |
|
3655 LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id |
|
3656 GROUP BY t.term_id |
|
3657 HAVING term_tt_count > 1 |
|
3658 LIMIT 1" |
|
3659 ); |
|
3660 if ( ! $shared_terms_exist ) { |
|
3661 update_option( 'finished_splitting_shared_terms', true ); |
|
3662 } |
|
4214 |
3663 |
4215 /** |
3664 /** |
4216 * Fires after a previously shared taxonomy term is split into two separate terms. |
3665 * Fires after a previously shared taxonomy term is split into two separate terms. |
4217 * |
3666 * |
4218 * @since 4.2.0 |
3667 * @since 4.2.0 |
4226 |
3675 |
4227 return $new_term_id; |
3676 return $new_term_id; |
4228 } |
3677 } |
4229 |
3678 |
4230 /** |
3679 /** |
3680 * Splits a batch of shared taxonomy terms. |
|
3681 * |
|
3682 * @since 4.3.0 |
|
3683 * |
|
3684 * @global wpdb $wpdb WordPress database abstraction object. |
|
3685 */ |
|
3686 function _wp_batch_split_terms() { |
|
3687 global $wpdb; |
|
3688 |
|
3689 $lock_name = 'term_split.lock'; |
|
3690 |
|
3691 // Try to lock. |
|
3692 $lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) ); |
|
3693 |
|
3694 if ( ! $lock_result ) { |
|
3695 $lock_result = get_option( $lock_name ); |
|
3696 |
|
3697 // Bail if we were unable to create a lock, or if the existing lock is still valid. |
|
3698 if ( ! $lock_result || ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) ) { |
|
3699 wp_schedule_single_event( time() + ( 5 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' ); |
|
3700 return; |
|
3701 } |
|
3702 } |
|
3703 |
|
3704 // Update the lock, as by this point we've definitely got a lock, just need to fire the actions. |
|
3705 update_option( $lock_name, time() ); |
|
3706 |
|
3707 // Get a list of shared terms (those with more than one associated row in term_taxonomy). |
|
3708 $shared_terms = $wpdb->get_results( |
|
3709 "SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt |
|
3710 LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id |
|
3711 GROUP BY t.term_id |
|
3712 HAVING term_tt_count > 1 |
|
3713 LIMIT 10" |
|
3714 ); |
|
3715 |
|
3716 // No more terms, we're done here. |
|
3717 if ( ! $shared_terms ) { |
|
3718 update_option( 'finished_splitting_shared_terms', true ); |
|
3719 delete_option( $lock_name ); |
|
3720 return; |
|
3721 } |
|
3722 |
|
3723 // Shared terms found? We'll need to run this script again. |
|
3724 wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' ); |
|
3725 |
|
3726 // Rekey shared term array for faster lookups. |
|
3727 $_shared_terms = array(); |
|
3728 foreach ( $shared_terms as $shared_term ) { |
|
3729 $term_id = intval( $shared_term->term_id ); |
|
3730 $_shared_terms[ $term_id ] = $shared_term; |
|
3731 } |
|
3732 $shared_terms = $_shared_terms; |
|
3733 |
|
3734 // Get term taxonomy data for all shared terms. |
|
3735 $shared_term_ids = implode( ',', array_keys( $shared_terms ) ); |
|
3736 $shared_tts = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" ); |
|
3737 |
|
3738 // Split term data recording is slow, so we do it just once, outside the loop. |
|
3739 $split_term_data = get_option( '_split_terms', array() ); |
|
3740 $skipped_first_term = $taxonomies = array(); |
|
3741 foreach ( $shared_tts as $shared_tt ) { |
|
3742 $term_id = intval( $shared_tt->term_id ); |
|
3743 |
|
3744 // Don't split the first tt belonging to a given term_id. |
|
3745 if ( ! isset( $skipped_first_term[ $term_id ] ) ) { |
|
3746 $skipped_first_term[ $term_id ] = 1; |
|
3747 continue; |
|
3748 } |
|
3749 |
|
3750 if ( ! isset( $split_term_data[ $term_id ] ) ) { |
|
3751 $split_term_data[ $term_id ] = array(); |
|
3752 } |
|
3753 |
|
3754 // Keep track of taxonomies whose hierarchies need flushing. |
|
3755 if ( ! isset( $taxonomies[ $shared_tt->taxonomy ] ) ) { |
|
3756 $taxonomies[ $shared_tt->taxonomy ] = 1; |
|
3757 } |
|
3758 |
|
3759 // Split the term. |
|
3760 $split_term_data[ $term_id ][ $shared_tt->taxonomy ] = _split_shared_term( $shared_terms[ $term_id ], $shared_tt, false ); |
|
3761 } |
|
3762 |
|
3763 // Rebuild the cached hierarchy for each affected taxonomy. |
|
3764 foreach ( array_keys( $taxonomies ) as $tax ) { |
|
3765 delete_option( "{$tax}_children" ); |
|
3766 _get_term_hierarchy( $tax ); |
|
3767 } |
|
3768 |
|
3769 update_option( '_split_terms', $split_term_data ); |
|
3770 |
|
3771 delete_option( $lock_name ); |
|
3772 } |
|
3773 |
|
3774 /** |
|
3775 * In order to avoid the _wp_batch_split_terms() job being accidentally removed, |
|
3776 * check that it's still scheduled while we haven't finished splitting terms. |
|
3777 * |
|
3778 * @ignore |
|
3779 * @since 4.3.0 |
|
3780 */ |
|
3781 function _wp_check_for_scheduled_split_terms() { |
|
3782 if ( ! get_option( 'finished_splitting_shared_terms' ) && ! wp_next_scheduled( 'wp_split_shared_term_batch' ) ) { |
|
3783 wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'wp_split_shared_term_batch' ); |
|
3784 } |
|
3785 } |
|
3786 |
|
3787 /** |
|
4231 * Check default categories when a term gets split to see if any of them need to be updated. |
3788 * Check default categories when a term gets split to see if any of them need to be updated. |
4232 * |
3789 * |
4233 * @ignore |
3790 * @ignore |
4234 * @since 4.2.0 |
3791 * @since 4.2.0 |
4235 * |
3792 * |
4253 /** |
3810 /** |
4254 * Check menu items when a term gets split to see if any of them need to be updated. |
3811 * Check menu items when a term gets split to see if any of them need to be updated. |
4255 * |
3812 * |
4256 * @ignore |
3813 * @ignore |
4257 * @since 4.2.0 |
3814 * @since 4.2.0 |
3815 * |
|
3816 * @global wpdb $wpdb WordPress database abstraction object. |
|
4258 * |
3817 * |
4259 * @param int $term_id ID of the formerly shared term. |
3818 * @param int $term_id ID of the formerly shared term. |
4260 * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. |
3819 * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. |
4261 * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. |
3820 * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. |
4262 * @param string $taxonomy Taxonomy for the split term. |
3821 * @param string $taxonomy Taxonomy for the split term. |
4267 "SELECT m1.post_id |
3826 "SELECT m1.post_id |
4268 FROM {$wpdb->postmeta} AS m1 |
3827 FROM {$wpdb->postmeta} AS m1 |
4269 INNER JOIN {$wpdb->postmeta} AS m2 ON ( m2.post_id = m1.post_id ) |
3828 INNER JOIN {$wpdb->postmeta} AS m2 ON ( m2.post_id = m1.post_id ) |
4270 INNER JOIN {$wpdb->postmeta} AS m3 ON ( m3.post_id = m1.post_id ) |
3829 INNER JOIN {$wpdb->postmeta} AS m3 ON ( m3.post_id = m1.post_id ) |
4271 WHERE ( m1.meta_key = '_menu_item_type' AND m1.meta_value = 'taxonomy' ) |
3830 WHERE ( m1.meta_key = '_menu_item_type' AND m1.meta_value = 'taxonomy' ) |
4272 AND ( m2.meta_key = '_menu_item_object' AND m2.meta_value = '%s' ) |
3831 AND ( m2.meta_key = '_menu_item_object' AND m2.meta_value = %s ) |
4273 AND ( m3.meta_key = '_menu_item_object_id' AND m3.meta_value = %d )", |
3832 AND ( m3.meta_key = '_menu_item_object_id' AND m3.meta_value = %d )", |
4274 $taxonomy, |
3833 $taxonomy, |
4275 $term_id |
3834 $term_id |
4276 ) ); |
3835 ) ); |
4277 |
3836 |
4281 } |
3840 } |
4282 } |
3841 } |
4283 } |
3842 } |
4284 |
3843 |
4285 /** |
3844 /** |
3845 * If the term being split is a nav_menu, change associations. |
|
3846 * |
|
3847 * @ignore |
|
3848 * @since 4.3.0 |
|
3849 * |
|
3850 * @param int $term_id ID of the formerly shared term. |
|
3851 * @param int $new_term_id ID of the new term created for the $term_taxonomy_id. |
|
3852 * @param int $term_taxonomy_id ID for the term_taxonomy row affected by the split. |
|
3853 * @param string $taxonomy Taxonomy for the split term. |
|
3854 */ |
|
3855 function _wp_check_split_nav_menu_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) { |
|
3856 if ( 'nav_menu' !== $taxonomy ) { |
|
3857 return; |
|
3858 } |
|
3859 |
|
3860 // Update menu locations. |
|
3861 $locations = get_nav_menu_locations(); |
|
3862 foreach ( $locations as $location => $menu_id ) { |
|
3863 if ( $term_id == $menu_id ) { |
|
3864 $locations[ $location ] = $new_term_id; |
|
3865 } |
|
3866 } |
|
3867 set_theme_mod( 'nav_menu_locations', $locations ); |
|
3868 } |
|
3869 |
|
3870 /** |
|
4286 * Get data about terms that previously shared a single term_id, but have since been split. |
3871 * Get data about terms that previously shared a single term_id, but have since been split. |
4287 * |
3872 * |
4288 * @since 4.2.0 |
3873 * @since 4.2.0 |
4289 * |
3874 * |
4290 * @param int $old_term_id Term ID. This is the old, pre-split term ID. |
3875 * @param int $old_term_id Term ID. This is the old, pre-split term ID. |
4306 * |
3891 * |
4307 * @since 4.2.0 |
3892 * @since 4.2.0 |
4308 * |
3893 * |
4309 * @param int $old_term_id Term ID. This is the old, pre-split term ID. |
3894 * @param int $old_term_id Term ID. This is the old, pre-split term ID. |
4310 * @param string $taxonomy Taxonomy that the term belongs to. |
3895 * @param string $taxonomy Taxonomy that the term belongs to. |
4311 * @return bool|int If a previously split term is found corresponding to the old term_id and taxonomy, |
3896 * @return int|false If a previously split term is found corresponding to the old term_id and taxonomy, |
4312 * the new term_id will be returned. If no previously split term is found matching |
3897 * the new term_id will be returned. If no previously split term is found matching |
4313 * the parameters, returns false. |
3898 * the parameters, returns false. |
4314 */ |
3899 */ |
4315 function wp_get_split_term( $old_term_id, $taxonomy ) { |
3900 function wp_get_split_term( $old_term_id, $taxonomy ) { |
4316 $split_terms = wp_get_split_terms( $old_term_id ); |
3901 $split_terms = wp_get_split_terms( $old_term_id ); |
4317 |
3902 |
4318 $term_id = false; |
3903 $term_id = false; |
4322 |
3907 |
4323 return $term_id; |
3908 return $term_id; |
4324 } |
3909 } |
4325 |
3910 |
4326 /** |
3911 /** |
3912 * Determine whether a term is shared between multiple taxonomies. |
|
3913 * |
|
3914 * Shared taxonomy terms began to be split in 4.3, but failed cron tasks or |
|
3915 * other delays in upgrade routines may cause shared terms to remain. |
|
3916 * |
|
3917 * @since 4.4.0 |
|
3918 * |
|
3919 * @param int $term_id Term ID. |
|
3920 * @return bool Returns false if a term is not shared between multiple taxonomies or |
|
3921 * if splittng shared taxonomy terms is finished. |
|
3922 */ |
|
3923 function wp_term_is_shared( $term_id ) { |
|
3924 global $wpdb; |
|
3925 |
|
3926 if ( get_option( 'finished_splitting_shared_terms' ) ) { |
|
3927 return false; |
|
3928 } |
|
3929 |
|
3930 $tt_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_taxonomy WHERE term_id = %d", $term_id ) ); |
|
3931 |
|
3932 return $tt_count > 1; |
|
3933 } |
|
3934 |
|
3935 /** |
|
4327 * Generate a permalink for a taxonomy term archive. |
3936 * Generate a permalink for a taxonomy term archive. |
4328 * |
3937 * |
4329 * @since 2.5.0 |
3938 * @since 2.5.0 |
3939 * |
|
3940 * @global WP_Rewrite $wp_rewrite |
|
4330 * |
3941 * |
4331 * @param object|int|string $term The term object, ID, or slug whose link will be retrieved. |
3942 * @param object|int|string $term The term object, ID, or slug whose link will be retrieved. |
4332 * @param string $taxonomy Optional. Taxonomy. Default empty. |
3943 * @param string $taxonomy Optional. Taxonomy. Default empty. |
4333 * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist. |
3944 * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist. |
4334 */ |
3945 */ |
4335 function get_term_link( $term, $taxonomy = '') { |
3946 function get_term_link( $term, $taxonomy = '' ) { |
4336 global $wp_rewrite; |
3947 global $wp_rewrite; |
4337 |
3948 |
4338 if ( !is_object($term) ) { |
3949 if ( !is_object($term) ) { |
4339 if ( is_int($term) ) { |
3950 if ( is_int( $term ) ) { |
4340 $term = get_term($term, $taxonomy); |
3951 $term = get_term( $term, $taxonomy ); |
4341 } else { |
3952 } else { |
4342 $term = get_term_by('slug', $term, $taxonomy); |
3953 $term = get_term_by( 'slug', $term, $taxonomy ); |
4343 } |
3954 } |
4344 } |
3955 } |
4345 |
3956 |
4346 if ( !is_object($term) ) |
3957 if ( !is_object($term) ) |
4347 $term = new WP_Error('invalid_term', __('Empty Term')); |
3958 $term = new WP_Error( 'invalid_term', __( 'Empty Term.' ) ); |
4348 |
3959 |
4349 if ( is_wp_error( $term ) ) |
3960 if ( is_wp_error( $term ) ) |
4350 return $term; |
3961 return $term; |
4351 |
3962 |
4352 $taxonomy = $term->taxonomy; |
3963 $taxonomy = $term->taxonomy; |
4353 |
3964 |
4354 $termlink = $wp_rewrite->get_extra_permastruct($taxonomy); |
3965 $termlink = $wp_rewrite->get_extra_permastruct($taxonomy); |
3966 |
|
3967 /** |
|
3968 * Filters the permalink structure for a terms before token replacement occurs. |
|
3969 * |
|
3970 * @since 4.9.0 |
|
3971 * |
|
3972 * @param string $termlink The permalink structure for the term's taxonomy. |
|
3973 * @param WP_Term $term The term object. |
|
3974 */ |
|
3975 $termlink = apply_filters( 'pre_term_link', $termlink, $term ); |
|
4355 |
3976 |
4356 $slug = $term->slug; |
3977 $slug = $term->slug; |
4357 $t = get_taxonomy($taxonomy); |
3978 $t = get_taxonomy($taxonomy); |
4358 |
3979 |
4359 if ( empty($termlink) ) { |
3980 if ( empty($termlink) ) { |
4382 } |
4003 } |
4383 // Back Compat filters. |
4004 // Back Compat filters. |
4384 if ( 'post_tag' == $taxonomy ) { |
4005 if ( 'post_tag' == $taxonomy ) { |
4385 |
4006 |
4386 /** |
4007 /** |
4387 * Filter the tag link. |
4008 * Filters the tag link. |
4388 * |
4009 * |
4389 * @since 2.3.0 |
4010 * @since 2.3.0 |
4390 * @deprecated 2.5.0 Use 'term_link' instead. |
4011 * @deprecated 2.5.0 Use 'term_link' instead. |
4391 * |
4012 * |
4392 * @param string $termlink Tag link URL. |
4013 * @param string $termlink Tag link URL. |
4394 */ |
4015 */ |
4395 $termlink = apply_filters( 'tag_link', $termlink, $term->term_id ); |
4016 $termlink = apply_filters( 'tag_link', $termlink, $term->term_id ); |
4396 } elseif ( 'category' == $taxonomy ) { |
4017 } elseif ( 'category' == $taxonomy ) { |
4397 |
4018 |
4398 /** |
4019 /** |
4399 * Filter the category link. |
4020 * Filters the category link. |
4400 * |
4021 * |
4401 * @since 1.5.0 |
4022 * @since 1.5.0 |
4402 * @deprecated 2.5.0 Use 'term_link' instead. |
4023 * @deprecated 2.5.0 Use 'term_link' instead. |
4403 * |
4024 * |
4404 * @param string $termlink Category link URL. |
4025 * @param string $termlink Category link URL. |
4406 */ |
4027 */ |
4407 $termlink = apply_filters( 'category_link', $termlink, $term->term_id ); |
4028 $termlink = apply_filters( 'category_link', $termlink, $term->term_id ); |
4408 } |
4029 } |
4409 |
4030 |
4410 /** |
4031 /** |
4411 * Filter the term link. |
4032 * Filters the term link. |
4412 * |
4033 * |
4413 * @since 2.5.0 |
4034 * @since 2.5.0 |
4414 * |
4035 * |
4415 * @param string $termlink Term link URL. |
4036 * @param string $termlink Term link URL. |
4416 * @param object $term Term object. |
4037 * @param object $term Term object. |
4427 * display the taxonomies for a specific post. |
4048 * display the taxonomies for a specific post. |
4428 * |
4049 * |
4429 * @since 2.5.0 |
4050 * @since 2.5.0 |
4430 * |
4051 * |
4431 * @param array $args { |
4052 * @param array $args { |
4432 * Arguments about which post to use and how to format the output. Shares all of the arguments supported by |
4053 * Arguments about which post to use and how to format the output. Shares all of the arguments |
4433 * {@link get_the_taxonomies()}, in addition to the following. |
4054 * supported by get_the_taxonomies(), in addition to the following. |
4434 * |
4055 * |
4435 * @type int|WP_Post $post Post ID or object to get taxonomies of. Default current post. |
4056 * @type int|WP_Post $post Post ID or object to get taxonomies of. Default current post. |
4436 * @type string $before Displays before the taxonomies. Default empty string. |
4057 * @type string $before Displays before the taxonomies. Default empty string. |
4437 * @type string $sep Separates each taxonomy. Default is a space. |
4058 * @type string $sep Separates each taxonomy. Default is a space. |
4438 * @type string $after Displays after the taxonomies. Default empty string. |
4059 * @type string $after Displays after the taxonomies. Default empty string. |
4439 * } |
4060 * } |
4440 * @param array $args See {@link get_the_taxonomies()} for a description of arguments and their defaults. |
|
4441 */ |
4061 */ |
4442 function the_taxonomies( $args = array() ) { |
4062 function the_taxonomies( $args = array() ) { |
4443 $defaults = array( |
4063 $defaults = array( |
4444 'post' => 0, |
4064 'post' => 0, |
4445 'before' => '', |
4065 'before' => '', |
4460 * |
4080 * |
4461 * @since 2.5.0 |
4081 * @since 2.5.0 |
4462 * |
4082 * |
4463 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. |
4083 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. |
4464 * @param array $args { |
4084 * @param array $args { |
4465 * Arguments about how to format the list of taxonomies. |
4085 * Optional. Arguments about how to format the list of taxonomies. Default empty array. |
4466 * |
4086 * |
4467 * @type string $template Template for displaying a taxonomy label and list of terms. |
4087 * @type string $template Template for displaying a taxonomy label and list of terms. |
4468 * Default is "Label: Terms." |
4088 * Default is "Label: Terms." |
4469 * @type string $term_template Template for displaying a single term in the list. Default is the term name |
4089 * @type string $term_template Template for displaying a single term in the list. Default is the term name |
4470 * linked to its archive. |
4090 * linked to its archive. |
4521 * Retrieve all taxonomies of a post with just the names. |
4141 * Retrieve all taxonomies of a post with just the names. |
4522 * |
4142 * |
4523 * @since 2.5.0 |
4143 * @since 2.5.0 |
4524 * |
4144 * |
4525 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. |
4145 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post. |
4526 * @return array |
4146 * @return array An array of all taxonomy names for the given post. |
4527 */ |
4147 */ |
4528 function get_post_taxonomies( $post = 0 ) { |
4148 function get_post_taxonomies( $post = 0 ) { |
4529 $post = get_post( $post ); |
4149 $post = get_post( $post ); |
4530 |
4150 |
4531 return get_object_taxonomies($post); |
4151 return get_object_taxonomies($post); |
4538 * Terms given as integers will only be checked against the object's terms' term_ids. |
4158 * Terms given as integers will only be checked against the object's terms' term_ids. |
4539 * If no terms are given, determines if object is associated with any terms in the given taxonomy. |
4159 * If no terms are given, determines if object is associated with any terms in the given taxonomy. |
4540 * |
4160 * |
4541 * @since 2.7.0 |
4161 * @since 2.7.0 |
4542 * |
4162 * |
4543 * @param int $object_id ID of the object (post ID, link ID, ...) |
4163 * @param int $object_id ID of the object (post ID, link ID, ...). |
4544 * @param string $taxonomy Single taxonomy name |
4164 * @param string $taxonomy Single taxonomy name. |
4545 * @param int|string|array $terms Optional. Term term_id, name, slug or array of said |
4165 * @param int|string|array $terms Optional. Term term_id, name, slug or array of said. Default null. |
4546 * @return bool|WP_Error WP_Error on input error. |
4166 * @return bool|WP_Error WP_Error on input error. |
4547 */ |
4167 */ |
4548 function is_object_in_term( $object_id, $taxonomy, $terms = null ) { |
4168 function is_object_in_term( $object_id, $taxonomy, $terms = null ) { |
4549 if ( !$object_id = (int) $object_id ) |
4169 if ( !$object_id = (int) $object_id ) |
4550 return new WP_Error( 'invalid_object', __( 'Invalid object ID' ) ); |
4170 return new WP_Error( 'invalid_object', __( 'Invalid object ID.' ) ); |
4551 |
4171 |
4552 $object_terms = get_object_term_cache( $object_id, $taxonomy ); |
4172 $object_terms = get_object_term_cache( $object_id, $taxonomy ); |
4553 if ( false === $object_terms ) |
4173 if ( false === $object_terms ) { |
4554 $object_terms = wp_get_object_terms( $object_id, $taxonomy ); |
4174 $object_terms = wp_get_object_terms( $object_id, $taxonomy, array( 'update_term_meta_cache' => false ) ); |
4175 if ( is_wp_error( $object_terms ) ) { |
|
4176 return $object_terms; |
|
4177 } |
|
4178 |
|
4179 wp_cache_set( $object_id, wp_list_pluck( $object_terms, 'term_id' ), "{$taxonomy}_relationships" ); |
|
4180 } |
|
4555 |
4181 |
4556 if ( is_wp_error( $object_terms ) ) |
4182 if ( is_wp_error( $object_terms ) ) |
4557 return $object_terms; |
4183 return $object_terms; |
4558 if ( empty( $object_terms ) ) |
4184 if ( empty( $object_terms ) ) |
4559 return false; |
4185 return false; |
4591 /** |
4217 /** |
4592 * Determine if the given object type is associated with the given taxonomy. |
4218 * Determine if the given object type is associated with the given taxonomy. |
4593 * |
4219 * |
4594 * @since 3.0.0 |
4220 * @since 3.0.0 |
4595 * |
4221 * |
4596 * @param string $object_type Object type string |
4222 * @param string $object_type Object type string. |
4597 * @param string $taxonomy Single taxonomy name |
4223 * @param string $taxonomy Single taxonomy name. |
4598 * @return bool True if object is associated with the taxonomy, otherwise false. |
4224 * @return bool True if object is associated with the taxonomy, otherwise false. |
4599 */ |
4225 */ |
4600 function is_object_in_taxonomy($object_type, $taxonomy) { |
4226 function is_object_in_taxonomy( $object_type, $taxonomy ) { |
4601 $taxonomies = get_object_taxonomies($object_type); |
4227 $taxonomies = get_object_taxonomies( $object_type ); |
4602 |
4228 if ( empty( $taxonomies ) ) { |
4603 if ( empty($taxonomies) ) |
|
4604 return false; |
4229 return false; |
4605 |
4230 } |
4606 if ( in_array($taxonomy, $taxonomies) ) |
4231 return in_array( $taxonomy, $taxonomies ); |
4607 return true; |
|
4608 |
|
4609 return false; |
|
4610 } |
4232 } |
4611 |
4233 |
4612 /** |
4234 /** |
4613 * Get an array of ancestor IDs for a given object. |
4235 * Get an array of ancestor IDs for a given object. |
4614 * |
4236 * |
4650 } elseif ( 'post_type' === $resource_type ) { |
4272 } elseif ( 'post_type' === $resource_type ) { |
4651 $ancestors = get_post_ancestors($object_id); |
4273 $ancestors = get_post_ancestors($object_id); |
4652 } |
4274 } |
4653 |
4275 |
4654 /** |
4276 /** |
4655 * Filter a given object's ancestors. |
4277 * Filters a given object's ancestors. |
4656 * |
4278 * |
4657 * @since 3.1.0 |
4279 * @since 3.1.0 |
4658 * @since 4.1.0 Introduced the `$resource_type` parameter. |
4280 * @since 4.1.1 Introduced the `$resource_type` parameter. |
4659 * |
4281 * |
4660 * @param array $ancestors An array of object ancestors. |
4282 * @param array $ancestors An array of object ancestors. |
4661 * @param int $object_id Object ID. |
4283 * @param int $object_id Object ID. |
4662 * @param string $object_type Type of object. |
4284 * @param string $object_type Type of object. |
4663 * @param string $resource_type Type of resource $object_type is. |
4285 * @param string $resource_type Type of resource $object_type is. |
4664 */ |
4286 */ |
4665 return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type ); |
4287 return apply_filters( 'get_ancestors', $ancestors, $object_id, $object_type, $resource_type ); |
4666 } |
4288 } |
4667 |
4289 |
4668 /** |
4290 /** |
4669 * Returns the term's parent's term_ID |
4291 * Returns the term's parent's term_ID. |
4670 * |
4292 * |
4671 * @since 3.1.0 |
4293 * @since 3.1.0 |
4672 * |
4294 * |
4673 * @param int $term_id |
4295 * @param int $term_id Term ID. |
4674 * @param string $taxonomy |
4296 * @param string $taxonomy Taxonomy name. |
4675 * |
4297 * @return int|false False on error. |
4676 * @return int|bool false on error |
|
4677 */ |
4298 */ |
4678 function wp_get_term_taxonomy_parent_id( $term_id, $taxonomy ) { |
4299 function wp_get_term_taxonomy_parent_id( $term_id, $taxonomy ) { |
4679 $term = get_term( $term_id, $taxonomy ); |
4300 $term = get_term( $term_id, $taxonomy ); |
4680 if ( !$term || is_wp_error( $term ) ) |
4301 if ( ! $term || is_wp_error( $term ) ) { |
4681 return false; |
4302 return false; |
4303 } |
|
4682 return (int) $term->parent; |
4304 return (int) $term->parent; |
4683 } |
4305 } |
4684 |
4306 |
4685 /** |
4307 /** |
4686 * Checks the given subset of the term hierarchy for hierarchy loops. |
4308 * Checks the given subset of the term hierarchy for hierarchy loops. |
4687 * Prevents loops from forming and breaks those that it finds. |
4309 * Prevents loops from forming and breaks those that it finds. |
4688 * |
4310 * |
4689 * Attached to the wp_update_term_parent filter. |
4311 * Attached to the {@see 'wp_update_term_parent'} filter. |
4690 * |
4312 * |
4691 * @since 3.1.0 |
4313 * @since 3.1.0 |
4692 * |
4314 * |
4693 * @param int $parent term_id of the parent for the term we're checking. |
4315 * @param int $parent `term_id` of the parent for the term we're checking. |
4694 * @param int $term_id The term we're checking. |
4316 * @param int $term_id The term we're checking. |
4695 * @param string $taxonomy The taxonomy of the term we're checking. |
4317 * @param string $taxonomy The taxonomy of the term we're checking. |
4696 * |
4318 * |
4697 * @return int The new parent for the term. |
4319 * @return int The new parent for the term. |
4698 */ |
4320 */ |
4699 function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) { |
4321 function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) { |
4700 // Nothing fancy here - bail |
4322 // Nothing fancy here - bail |
4701 if ( !$parent ) |
4323 if ( !$parent ) |
4702 return 0; |
4324 return 0; |
4703 |
4325 |
4704 // Can't be its own parent |
4326 // Can't be its own parent. |
4705 if ( $parent == $term_id ) |
4327 if ( $parent == $term_id ) |
4706 return 0; |
4328 return 0; |
4707 |
4329 |
4708 // Now look for larger loops |
4330 // Now look for larger loops. |
4709 |
|
4710 if ( !$loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) ) |
4331 if ( !$loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) ) |
4711 return $parent; // No loop |
4332 return $parent; // No loop |
4712 |
4333 |
4713 // Setting $parent to the given value causes a loop |
4334 // Setting $parent to the given value causes a loop. |
4714 if ( isset( $loop[$term_id] ) ) |
4335 if ( isset( $loop[$term_id] ) ) |
4715 return 0; |
4336 return 0; |
4716 |
4337 |
4717 // There's a loop, but it doesn't contain $term_id. Break the loop. |
4338 // There's a loop, but it doesn't contain $term_id. Break the loop. |
4718 foreach ( array_keys( $loop ) as $loop_member ) |
4339 foreach ( array_keys( $loop ) as $loop_member ) |