~canonical-sysadmins/wordpress/4.8.3

« back to all changes in this revision

Viewing changes to wp-includes/taxonomy.php

  • Committer: Ryan Finnie
  • Date: 2015-08-31 16:09:47 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: ryan.finnie@canonical.com-20150831160947-1h6rfxby9z1ec62u
Merge WP4.3 from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
/**
3
3
 * Taxonomy API
4
4
 *
 
5
 * @since 2.3.0
 
6
 *
5
7
 * @package WordPress
6
8
 * @subpackage Taxonomy
7
 
 * @since 2.3.0
8
9
 */
9
10
 
10
11
//
15
16
 * Creates the initial taxonomies.
16
17
 *
17
18
 * 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
19
 
 * registering rewrite rules before the 'init' action.
 
19
 * backwards compatibility reasons), and again on the {@see 'init'} action. We must
 
20
 * avoid registering rewrite rules before the {@see 'init'} action.
 
21
 *
 
22
 * @since 2.8.0
 
23
 *
 
24
 * @global WP_Rewrite $wp_rewrite The WordPress rewrite class.
20
25
 */
21
26
function create_initial_taxonomies() {
22
27
        global $wp_rewrite;
129
134
}
130
135
 
131
136
/**
132
 
 * Get a list of registered taxonomy objects.
 
137
 * Retrieves a list of registered taxonomy names or objects.
133
138
 *
134
139
 * @since 3.0.0
135
 
 * @uses $wp_taxonomies
136
 
 *
137
 
 * @param array $args An array of key => value arguments to match against the taxonomy objects.
138
 
 * @param string $output The type of output to return, either taxonomy 'names' or 'objects'. 'names' is the default.
139
 
 * @param string $operator The logical operation to perform. 'or' means only one element
140
 
 *  from the array needs to match; 'and' means all elements must match. The default is 'and'.
141
 
 * @return array A list of taxonomy names or objects
 
140
 *
 
141
 * @global array $wp_taxonomies The registered taxonomies.
 
142
 *
 
143
 * @param array  $args     Optional. An array of `key => value` arguments to match against the taxonomy objects.
 
144
 *                         Default empty array.
 
145
 * @param string $output   Optional. The type of output to return in the array. Accepts either taxonomy 'names'
 
146
 *                         or 'objects'. Default 'names'.
 
147
 * @param string $operator Optional. The logical operation to perform. Accepts 'and' or 'or'. 'or' means only
 
148
 *                         one element from the array needs to match; 'and' means all elements must match.
 
149
 *                         Default 'and'.
 
150
 * @return array A list of taxonomy names or objects.
142
151
 */
143
152
function get_taxonomies( $args = array(), $output = 'names', $operator = 'and' ) {
144
153
        global $wp_taxonomies;
159
168
 *
160
169
 * @since 2.3.0
161
170
 *
162
 
 * @uses $wp_taxonomies
 
171
 * @global array $wp_taxonomies The registered taxonomies.
163
172
 *
164
 
 * @param array|string|object $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.
 
173
 * @param array|string|WP_Post $object Name of the type of taxonomy object, or an object (row from posts)
 
174
 * @param string               $output Optional. The type of output to return in the array. Accepts either
 
175
 *                                     taxonomy 'names' or 'objects'. Default 'names'.
166
176
 * @return array The names of all taxonomy of $object_type.
167
177
 */
168
 
function get_object_taxonomies($object, $output = 'names') {
 
178
function get_object_taxonomies( $object, $output = 'names' ) {
169
179
        global $wp_taxonomies;
170
180
 
171
181
        if ( is_object($object) ) {
197
207
 *
198
208
 * @since 2.3.0
199
209
 *
200
 
 * @uses $wp_taxonomies
 
210
 * @global array $wp_taxonomies The registered taxonomies.
201
211
 *
202
 
 * @param string $taxonomy Name of taxonomy object to return
203
 
 * @return object|bool The Taxonomy Object or false if $taxonomy doesn't exist
 
212
 * @param string $taxonomy Name of taxonomy object to return.
 
213
 * @return object|false The Taxonomy Object or false if $taxonomy doesn't exist.
204
214
 */
205
215
function get_taxonomy( $taxonomy ) {
206
216
        global $wp_taxonomies;
218
228
 *
219
229
 * @since 3.0.0
220
230
 *
221
 
 * @uses $wp_taxonomies
 
231
 * @global array $wp_taxonomies The registered taxonomies.
222
232
 *
223
 
 * @param string $taxonomy Name of taxonomy object
 
233
 * @param string $taxonomy Name of taxonomy object.
224
234
 * @return bool Whether the taxonomy exists.
225
235
 */
226
236
function taxonomy_exists( $taxonomy ) {
239
249
 *
240
250
 * @since 2.3.0
241
251
 *
242
 
 * @param string $taxonomy Name of taxonomy object
243
 
 * @return bool Whether the taxonomy is hierarchical
 
252
 * @param string $taxonomy Name of taxonomy object.
 
253
 * @return bool Whether the taxonomy is hierarchical.
244
254
 */
245
255
function is_taxonomy_hierarchical($taxonomy) {
246
256
        if ( ! taxonomy_exists($taxonomy) )
309
319
 *     * Defaults to _update_generic_term_count() for taxonomies attached to other object types, such as links.
310
320
 * - _builtin - true if this taxonomy is a native or "built-in" taxonomy. THIS IS FOR INTERNAL USE ONLY!
311
321
 *
 
322
 * @todo Document $args as a hash notation.
 
323
 *
312
324
 * @since 2.3.0
313
325
 * @since 4.2.0 Introduced `show_in_quick_edit` argument.
314
326
 *
315
327
 * @global array $wp_taxonomies Registered taxonomies.
316
328
 * @global WP    $wp            WP instance.
317
329
 *
318
 
 * @param string $taxonomy Taxonomy key, must not exceed 32 characters.
 
330
 * @param string       $taxonomy    Taxonomy key, must not exceed 32 characters.
319
331
 * @param array|string $object_type Name of the object type for the taxonomy object.
320
 
 * @param array|string $args See optional args description above.
321
 
 * @return null|WP_Error WP_Error if errors, otherwise null.
 
332
 * @param array|string $args        See optional args description above.
 
333
 * @return WP_Error|void WP_Error, if errors.
322
334
 */
323
335
function register_taxonomy( $taxonomy, $object_type, $args = array() ) {
324
336
        global $wp_taxonomies, $wp;
460
472
 * - 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.
461
473
 * - 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.
462
474
 * - not_found - Default is "No tags found"/"No categories found", used in the meta box and taxonomy list table.
 
475
 * - no_terms - Default is "No tags"/"No categories", used in the posts and media list tables.
463
476
 *
464
477
 * Above, the first default value is for non-hierarchical taxonomies (like tags) and the second one is for hierarchical taxonomies (like categories).
465
478
 *
 
479
 * @todo Better documentation for the labels array.
 
480
 *
466
481
 * @since 3.0.0
467
 
 * @param object $tax Taxonomy object
468
 
 * @return object object with all the labels as member variables
 
482
 * @since 4.3.0 Added the `no_terms` label.
 
483
 *
 
484
 * @param object $tax Taxonomy object.
 
485
 * @return object object with all the labels as member variables.
469
486
 */
470
 
 
471
487
function get_taxonomy_labels( $tax ) {
472
488
        $tax->labels = (array) $tax->labels;
473
489
 
494
510
                'add_or_remove_items' => array( __( 'Add or remove tags' ), null ),
495
511
                'choose_from_most_used' => array( __( 'Choose from the most used tags' ), null ),
496
512
                'not_found' => array( __( 'No tags found.' ), __( 'No categories found.' ) ),
 
513
                'no_terms' => array( __( 'No tags' ), __( 'No categories' ) ),
497
514
        );
498
515
        $nohier_vs_hier_defaults['menu_name'] = $nohier_vs_hier_defaults['name'];
499
516
 
504
521
 * Add an already registered taxonomy to an object type.
505
522
 *
506
523
 * @since 3.0.0
507
 
 * @uses $wp_taxonomies Modifies taxonomy object
508
 
 *
509
 
 * @param string $taxonomy Name of taxonomy object
510
 
 * @param string $object_type Name of the object type
511
 
 * @return bool True if successful, false if not
 
524
 *
 
525
 * @global array $wp_taxonomies The registered taxonomies.
 
526
 *
 
527
 * @param string $taxonomy    Name of taxonomy object.
 
528
 * @param string $object_type Name of the object type.
 
529
 * @return bool True if successful, false if not.
512
530
 */
513
531
function register_taxonomy_for_object_type( $taxonomy, $object_type) {
514
532
        global $wp_taxonomies;
522
540
        if ( ! in_array( $object_type, $wp_taxonomies[$taxonomy]->object_type ) )
523
541
                $wp_taxonomies[$taxonomy]->object_type[] = $object_type;
524
542
 
 
543
        // Filter out empties.
 
544
        $wp_taxonomies[ $taxonomy ]->object_type = array_filter( $wp_taxonomies[ $taxonomy ]->object_type );
 
545
 
525
546
        return true;
526
547
}
527
548
 
530
551
 *
531
552
 * @since 3.7.0
532
553
 *
 
554
 * @global array $wp_taxonomies The registered taxonomies.
 
555
 *
533
556
 * @param string $taxonomy    Name of taxonomy object.
534
557
 * @param string $object_type Name of the object type.
535
558
 * @return bool True if successful, false if not.
574
597
 *
575
598
 * @global wpdb $wpdb WordPress database abstraction object.
576
599
 *
577
 
 * @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
579
 
 * @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
 
600
 * @param int|array    $term_ids   Term id or array of term ids of terms that will be used.
 
601
 * @param string|array $taxonomies String of taxonomy name or Array of string values of taxonomy names.
 
602
 * @param array|string $args       Change the order of the object_ids, either ASC or DESC.
 
603
 * @return WP_Error|array If the taxonomy does not exist, then WP_Error will be returned. On success.
581
604
 *      the array can be empty meaning that there are no $object_ids found or it will return the $object_ids found.
582
605
 */
583
606
function get_objects_in_term( $term_ids, $taxonomies, $args = array() ) {
620
643
 *
621
644
 * @see WP_Tax_Query
622
645
 *
623
 
 * @param array $tax_query A compact tax query
 
646
 * @param array  $tax_query         A compact tax query
624
647
 * @param string $primary_table
625
648
 * @param string $primary_id_column
626
649
 * @return array
633
656
/**
634
657
 * Class for generating SQL clauses that filter a primary query according to object taxonomy terms.
635
658
 *
636
 
 * `WP_Tax_Query` is a helper that allows primary query classes, such as {@see WP_Query}, to filter
 
659
 * `WP_Tax_Query` is a helper that allows primary query classes, such as WP_Query, to filter
637
660
 * their results by object metadata, by generating `JOIN` and `WHERE` subclauses to be attached
638
661
 * to the primary SQL query string.
639
662
 *
665
688
         * Standard response when the query should not return any rows.
666
689
         *
667
690
         * @since 3.2.0
 
691
         *
 
692
         * @static
668
693
         * @access private
669
694
         * @var string
670
695
         */
683
708
         * Terms and taxonomies fetched by this query.
684
709
         *
685
710
         * We store this data in a flat array because they are referenced in a
686
 
         * number of places by {@see WP_Query}.
 
711
         * number of places by WP_Query.
687
712
         *
688
713
         * @since 4.1.0
689
714
         * @access public
848
873
         * determined, by process of elimination, to be a higher-order query.
849
874
         *
850
875
         * @since 4.1.0
 
876
         *
 
877
         * @static
851
878
         * @access protected
852
879
         *
853
880
         * @param array $query Tax query arguments.
861
888
         * Generates SQL clauses to be appended to a main query.
862
889
         *
863
890
         * @since 3.1.0
 
891
         *
 
892
         * @static
864
893
         * @access public
865
894
         *
866
895
         * @param string $primary_table     Database table where the object being filtered is stored (eg wp_users).
882
911
        /**
883
912
         * Generate SQL clauses to be appended to a main query.
884
913
         *
885
 
         * Called by the public {@see WP_Tax_Query::get_sql()}, this method
 
914
         * Called by the public WP_Tax_Query::get_sql(), this method
886
915
         * is abstracted out to maintain parity with the other Query classes.
887
916
         *
888
917
         * @since 4.1.0
1001
1030
         * @since 4.1.0
1002
1031
         * @access public
1003
1032
         *
1004
 
         * @param array $clause       Query clause, passed by reference
 
1033
         * @global wpdb $wpdb The WordPress database abstraction object.
 
1034
         *
 
1035
         * @param array $clause       Query clause, passed by reference.
1005
1036
         * @param array $parent_query Parent query array.
1006
1037
         * @return array {
1007
1038
         *     Array containing JOIN and WHERE SQL clauses to append to a first-order query.
1018
1049
                        'join'  => array(),
1019
1050
                );
1020
1051
 
1021
 
                $join = '';
 
1052
                $join = $where = '';
1022
1053
 
1023
1054
                $this->clean_query( $clause );
1024
1055
 
1119
1150
         * An existing alias is compatible if (a) it is a sibling of `$clause`
1120
1151
         * (ie, it's under the scope of the same relation), and (b) the combination
1121
1152
         * 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'
 
1153
         * join. In the case of WP_Tax_Query, this only applies to 'IN'
1123
1154
         * clauses that are connected by the relation 'OR'.
1124
1155
         *
1125
1156
         * @since 4.1.0
1127
1158
         *
1128
1159
         * @param array       $clause       Query clause.
1129
1160
         * @param array       $parent_query Parent query of $clause.
1130
 
         * @return string|bool Table alias if found, otherwise false.
 
1161
         * @return string|false Table alias if found, otherwise false.
1131
1162
         */
1132
1163
        protected function find_compatible_table_alias( $clause, $parent_query ) {
1133
1164
                $alias = false;
1209
1240
         *
1210
1241
         * @since 3.2.0
1211
1242
         *
 
1243
         * @global wpdb $wpdb The WordPress database abstraction object.
 
1244
         *
1212
1245
         * @param array  &$query          The single query.
1213
1246
         * @param string $resulting_field The resulting field. Accepts 'slug', 'name', 'term_taxonomy_id',
1214
 
         *                                or 'term_id'. Default: 'term_id'.
 
1247
         *                                or 'term_id'. Default 'term_id'.
1215
1248
         */
1216
1249
        public function transform_query( &$query, $resulting_field ) {
1217
1250
                global $wpdb;
1290
1323
 * term object, and the taxonomy name as parameters. Both hooks are expected to
1291
1324
 * return a Term object.
1292
1325
 *
1293
 
 * 'get_term' hook - Takes two parameters the term Object and the taxonomy name.
 
1326
 * {@see 'get_term'} hook - Takes two parameters the term Object and the taxonomy name.
1294
1327
 * Must return term object. Used in get_term() as a catch-all filter for every
1295
1328
 * $term.
1296
1329
 *
1297
 
 * 'get_$taxonomy' hook - Takes two parameters the term Object and the taxonomy
 
1330
 * {@see 'get_$taxonomy'} hook - Takes two parameters the term Object and the taxonomy
1298
1331
 * name. Must return term object. $taxonomy will be the taxonomy name, so for
1299
1332
 * example, if 'category', it would be 'get_category' as the filter name. Useful
1300
1333
 * for custom taxonomies or plugging into default taxonomies.
1301
1334
 *
 
1335
 * @todo Better formatting for DocBlock
 
1336
 *
1302
1337
 * @since 2.3.0
1303
1338
 *
1304
1339
 * @global wpdb $wpdb WordPress database abstraction object.
1305
1340
 * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
1306
1341
 *
1307
 
 * @param int|object $term If integer, will get from database. If object will apply filters and return $term.
1308
 
 * @param string $taxonomy Taxonomy name that $term is part of.
1309
 
 * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
1310
 
 * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
1311
 
 * @return mixed|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
 
1342
 * @param int|object $term     If integer, will get from database. If object will apply filters and return $term.
 
1343
 * @param string     $taxonomy Taxonomy name that $term is part of.
 
1344
 * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
 
1345
 * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
 
1346
 * @return object|array|null|WP_Error Term Row from database. Will return null if $term is empty. If taxonomy does not
1312
1347
 * exist then WP_Error will be returned.
1313
1348
 */
1314
1349
function get_term($term, $taxonomy, $output = OBJECT, $filter = 'raw') {
1315
1350
        global $wpdb;
1316
1351
 
1317
 
        if ( empty($term) ) {
1318
 
                $error = new WP_Error('invalid_term', __('Empty Term'));
1319
 
                return $error;
 
1352
        if ( empty( $term ) ) {
 
1353
                return new WP_Error( 'invalid_term', __( 'Empty Term' ) );
1320
1354
        }
1321
1355
 
1322
 
        if ( ! taxonomy_exists($taxonomy) ) {
1323
 
                $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
1324
 
                return $error;
 
1356
        if ( ! taxonomy_exists( $taxonomy ) ) {
 
1357
                return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
1325
1358
        }
1326
1359
 
1327
1360
        if ( is_object($term) && empty($term->filter) ) {
1389
1422
 * If $value does not exist, the return value will be false. If $taxonomy exists
1390
1423
 * and $field and $value combinations exist, the Term will be returned.
1391
1424
 *
 
1425
 * @todo Better formatting for DocBlock.
 
1426
 *
1392
1427
 * @since 2.3.0
1393
1428
 *
1394
1429
 * @global wpdb $wpdb WordPress database abstraction object.
1395
1430
 * @see sanitize_term_field() The $context param lists the available values for get_term_by() $filter param.
1396
1431
 *
1397
 
 * @param string $field Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
1398
 
 * @param string|int $value Search for this term value
1399
 
 * @param string $taxonomy Taxonomy Name
1400
 
 * @param string $output Constant OBJECT, ARRAY_A, or ARRAY_N
1401
 
 * @param string $filter Optional, default is raw or no WordPress defined filter will applied.
1402
 
 * @return mixed Term Row from database. Will return false if $taxonomy does not exist or $term was not found.
 
1432
 * @param string     $field    Either 'slug', 'name', 'id' (term_id), or 'term_taxonomy_id'
 
1433
 * @param string|int $value    Search for this term value
 
1434
 * @param string     $taxonomy Taxonomy Name
 
1435
 * @param string     $output   Constant OBJECT, ARRAY_A, or ARRAY_N
 
1436
 * @param string     $filter   Optional, default is raw or no WordPress defined filter will applied.
 
1437
 * @return object|array|null|WP_Error|false Term Row from database.
 
1438
 *                                          Will return false if $taxonomy does not exist or $term was not found.
1403
1439
 */
1404
1440
function get_term_by($field, $value, $taxonomy, $output = OBJECT, $filter = 'raw') {
1405
1441
        global $wpdb;
1461
1497
 *
1462
1498
 * @since 2.3.0
1463
1499
 *
1464
 
 * @global wpdb $wpdb WordPress database abstraction object.
1465
 
 *
1466
 
 * @param string $term_id ID of Term to get children
1467
 
 * @param string $taxonomy Taxonomy Name
1468
 
 * @return array|WP_Error List of Term IDs. WP_Error returned if $taxonomy does not exist
 
1500
 * @param string $term_id  ID of Term to get children.
 
1501
 * @param string $taxonomy Taxonomy Name.
 
1502
 * @return array|WP_Error List of Term IDs. WP_Error returned if `$taxonomy` does not exist.
1469
1503
 */
1470
1504
function get_term_children( $term_id, $taxonomy ) {
1471
1505
        if ( ! taxonomy_exists($taxonomy) )
1501
1535
 *
1502
1536
 * @since 2.3.0
1503
1537
 *
1504
 
 * @param string $field Term field to fetch
1505
 
 * @param int $term Term ID
1506
 
 * @param string $taxonomy Taxonomy Name
1507
 
 * @param string $context Optional, default is display. Look at sanitize_term_field() for available options.
1508
 
 * @return mixed Will return an empty string if $term is not an object or if $field is not set in $term.
 
1538
 * @param string $field    Term field to fetch.
 
1539
 * @param int    $term     Term ID.
 
1540
 * @param string $taxonomy Taxonomy Name.
 
1541
 * @param string $context  Optional, default is display. Look at sanitize_term_field() for available options.
 
1542
 * @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.
1509
1543
 */
1510
1544
function get_term_field( $field, $term, $taxonomy, $context = 'display' ) {
1511
1545
        $term = (int) $term;
1530
1564
 *
1531
1565
 * @since 2.3.0
1532
1566
 *
1533
 
 * @param int|object $id Term ID or Object
1534
 
 * @param string $taxonomy Taxonomy Name
1535
 
 * @return mixed|null|WP_Error Will return empty string if $term is not an object.
 
1567
 * @param int|object $id       Term ID or object.
 
1568
 * @param string     $taxonomy Taxonomy name.
 
1569
 * @return string|int|null|WP_Error Will return empty string if $term is not an object.
1536
1570
 */
1537
1571
function get_term_to_edit( $id, $taxonomy ) {
1538
1572
        $term = get_term( $id, $taxonomy );
1552
1586
 * You can fully inject any customizations to the query before it is sent, as
1553
1587
 * well as control the output with a filter.
1554
1588
 *
1555
 
 * The 'get_terms' filter will be called when the cache has the term and will
 
1589
 * The {@see 'get_terms'} filter will be called when the cache has the term and will
1556
1590
 * pass the found term along with the array of $taxonomies and array of $args.
1557
1591
 * This filter is also called before the array of terms is passed and will pass
1558
1592
 * the array of terms, along with the $taxonomies and $args.
1559
1593
 *
1560
 
 * The 'list_terms_exclusions' filter passes the compiled exclusions along with
 
1594
 * The {@see 'list_terms_exclusions'} filter passes the compiled exclusions along with
1561
1595
 * the $args.
1562
1596
 *
1563
 
 * The 'get_terms_orderby' filter passes the ORDER BY clause for the query
 
1597
 * The {@see 'get_terms_orderby'} filter passes the `ORDER BY` clause for the query
1564
1598
 * along with the $args array.
1565
1599
 *
1566
1600
 * @since 2.3.0
1567
1601
 * @since 4.2.0 Introduced 'name' and 'childless' parameters.
1568
1602
 *
1569
 
 * @global wpdb $wpdb WordPress database abstraction object.
 
1603
 * @global wpdb  $wpdb WordPress database abstraction object.
 
1604
 * @global array $wp_filter
1570
1605
 *
1571
1606
 * @param string|array $taxonomies Taxonomy name or list of Taxonomy names.
1572
1607
 * @param array|string $args {
1617
1652
 *     @type string       $cache_domain      Unique cache key to be produced when this query is stored in an
1618
1653
 *                                           object cache. Default is 'core'.
1619
1654
 * }
1620
 
 * @return array|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies
 
1655
 * @return array|int|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies
1621
1656
 *                        do not exist.
1622
1657
 */
1623
1658
function get_terms( $taxonomies, $args = '' ) {
1631
1666
 
1632
1667
        foreach ( $taxonomies as $taxonomy ) {
1633
1668
                if ( ! taxonomy_exists($taxonomy) ) {
1634
 
                        $error = new WP_Error('invalid_taxonomy', __('Invalid taxonomy'));
1635
 
                        return $error;
 
1669
                        return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
1636
1670
                }
1637
1671
        }
1638
1672
 
1676
1710
         *
1677
1711
         * @since 3.1.0
1678
1712
         *
1679
 
         * @param array $args       An array of arguments.
 
1713
         * @param array $args       An array of get_term() arguments.
1680
1714
         * @param array $taxonomies An array of taxonomies.
1681
1715
         */
1682
1716
        $args = apply_filters( 'get_terms_args', $args, $taxonomies );
1708
1742
                }
1709
1743
        }
1710
1744
 
1711
 
        // $args can be whatever, only use the args defined in defaults to compute the key
 
1745
        // $args can be whatever, only use the args defined in defaults to compute the key.
1712
1746
        $filter_key = ( has_filter('list_terms_exclusions') ) ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
1713
1747
        $key = md5( serialize( wp_array_slice_assoc( $args, array_keys( $defaults ) ) ) . serialize( $taxonomies ) . $filter_key );
1714
1748
        $last_changed = wp_cache_get( 'last_changed', 'terms' );
1727
1761
                 *
1728
1762
                 * @param array $cache      Cached array of terms for the given taxonomy.
1729
1763
                 * @param array $taxonomies An array of taxonomies.
1730
 
                 * @param array $args       An array of arguments to get terms.
 
1764
                 * @param array $args       An array of get_terms() arguments.
1731
1765
                 */
1732
 
                $cache = apply_filters( 'get_terms', $cache, $taxonomies, $args );
1733
 
                return $cache;
 
1766
                return apply_filters( 'get_terms', $cache, $taxonomies, $args );
1734
1767
        }
1735
1768
 
1736
1769
        $_orderby = strtolower( $args['orderby'] );
1754
1787
        } else {
1755
1788
                $orderby = 't.name';
1756
1789
        }
 
1790
 
1757
1791
        /**
1758
1792
         * Filter the ORDERBY clause of the terms query.
1759
1793
         *
1760
1794
         * @since 2.8.0
1761
1795
         *
1762
 
         * @param string $orderby    ORDERBY clause of the terms query.
 
1796
         * @param string $orderby    `ORDERBY` clause of the terms query.
1763
1797
         * @param array  $args       An array of terms query arguments.
1764
1798
         * @param array  $taxonomies An array of taxonomies.
1765
1799
         */
1831
1865
         *
1832
1866
         * @since 2.3.0
1833
1867
         *
1834
 
         * @param string $exclusions NOT IN clause of the terms query.
 
1868
         * @param string $exclusions `NOT IN` clause of the terms query.
1835
1869
         * @param array  $args       An array of terms query arguments.
1836
1870
         * @param array  $taxonomies An array of taxonomies.
1837
1871
         */
1842
1876
        }
1843
1877
 
1844
1878
        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 );
 
1879
                $names = (array) $args['name'];
 
1880
                foreach ( $names as &$_name ) {
 
1881
                        $_name = sanitize_term_field( 'name', $_name, 0, reset( $taxonomies ), 'db' );
1851
1882
                }
 
1883
 
 
1884
                $where .= " AND t.name IN ('" . implode( "', '", array_map( 'esc_sql', $names ) ) . "')";
1852
1885
        }
1853
1886
 
1854
1887
        if ( ! empty( $args['slug'] ) ) {
1885
1918
        $number = $args['number'];
1886
1919
        $offset = $args['offset'];
1887
1920
 
1888
 
        // don't limit the query results when we have to descend the family tree
 
1921
        // Don't limit the query results when we have to descend the family tree.
1889
1922
        if ( $number && ! $hierarchical && ! $child_of && '' === $parent ) {
1890
1923
                if ( $offset ) {
1891
1924
                        $limits = 'LIMIT ' . $offset . ',' . $number;
1960
1993
         * @param array $args       An array of terms query arguments.
1961
1994
         */
1962
1995
        $clauses = apply_filters( 'terms_clauses', compact( $pieces ), $taxonomies, $args );
 
1996
 
1963
1997
        $fields = isset( $clauses[ 'fields' ] ) ? $clauses[ 'fields' ] : '';
1964
1998
        $join = isset( $clauses[ 'join' ] ) ? $clauses[ 'join' ] : '';
1965
1999
        $where = isset( $clauses[ 'where' ] ) ? $clauses[ 'where' ] : '';
1970
2004
        $query = "SELECT $fields FROM $wpdb->terms AS t $join WHERE $where $orderby $order $limits";
1971
2005
 
1972
2006
        if ( 'count' == $_fields ) {
1973
 
                $term_count = $wpdb->get_var($query);
1974
 
                return $term_count;
 
2007
                return $wpdb->get_var( $query );
1975
2008
        }
1976
2009
 
1977
2010
        $terms = $wpdb->get_results($query);
1983
2016
                wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS );
1984
2017
 
1985
2018
                /** This filter is documented in wp-includes/taxonomy.php */
1986
 
                $terms = apply_filters( 'get_terms', array(), $taxonomies, $args );
1987
 
                return $terms;
 
2019
                return apply_filters( 'get_terms', array(), $taxonomies, $args );
1988
2020
        }
1989
2021
 
1990
2022
        if ( $child_of ) {
2017
2049
                                        }
2018
2050
                                }
2019
2051
 
2020
 
                                // It really is empty
 
2052
                                // It really is empty.
2021
2053
                                unset($terms[$k]);
2022
2054
                        }
2023
2055
                }
2057
2089
        wp_cache_add( $cache_key, $terms, 'terms', DAY_IN_SECONDS );
2058
2090
 
2059
2091
        /** This filter is documented in wp-includes/taxonomy */
2060
 
        $terms = apply_filters( 'get_terms', $terms, $taxonomies, $args );
2061
 
        return $terms;
 
2092
        return apply_filters( 'get_terms', $terms, $taxonomies, $args );
2062
2093
}
2063
2094
 
2064
2095
/**
2070
2101
 *
2071
2102
 * @global wpdb $wpdb WordPress database abstraction object.
2072
2103
 *
2073
 
 * @param int|string $term The term to check
2074
 
 * @param string $taxonomy The taxonomy name to use
2075
 
 * @param int $parent Optional. ID of parent term under which to confine the exists search.
 
2104
 * @param int|string $term     The term to check
 
2105
 * @param string     $taxonomy The taxonomy name to use
 
2106
 * @param int        $parent   Optional. ID of parent term under which to confine the exists search.
2076
2107
 * @return mixed Returns null if the term does not exist. Returns the term ID
2077
2108
 *               if no taxonomy is specified and the term ID exists. Returns
2078
2109
 *               an array of the term ID and the term taxonomy ID the taxonomy
2134
2165
 *
2135
2166
 * @since 3.4.0
2136
2167
 *
2137
 
 * @param int|object $term1 ID or object to check if this is the parent term.
2138
 
 * @param int|object $term2 The child term.
2139
 
 * @param string $taxonomy Taxonomy name that $term1 and $term2 belong to.
2140
 
 * @return bool Whether $term2 is child of $term1
 
2168
 * @param int|object $term1    ID or object to check if this is the parent term.
 
2169
 * @param int|object $term2    The child term.
 
2170
 * @param string     $taxonomy Taxonomy name that $term1 and `$term2` belong to.
 
2171
 * @return bool Whether `$term2` is a child of `$term1`.
2141
2172
 */
2142
2173
function term_is_ancestor_of( $term1, $term2, $taxonomy ) {
2143
2174
        if ( ! isset( $term1->term_id ) )
2164
2195
 *
2165
2196
 * @since 2.3.0
2166
2197
 *
2167
 
 * @param array|object $term The term to check
2168
 
 * @param string $taxonomy The taxonomy name to use
2169
 
 * @param string $context Default is 'display'.
2170
 
 * @return array|object Term with all fields sanitized
 
2198
 * @param array|object $term     The term to check.
 
2199
 * @param string       $taxonomy The taxonomy name to use.
 
2200
 * @param string       $context  Optional. Context in which to sanitize the term. Accepts 'edit', 'db',
 
2201
 *                               'display', 'attribute', or 'js'. Default 'display'.
 
2202
 * @return array|object Term with all fields sanitized.
2171
2203
 */
2172
2204
function sanitize_term($term, $taxonomy, $context = 'display') {
2173
 
 
2174
2205
        $fields = array( 'term_id', 'name', 'description', 'slug', 'count', 'parent', 'term_group', 'term_taxonomy_id', 'object_id' );
2175
2206
 
2176
2207
        $do_object = is_object( $term );
2210
2241
 *
2211
2242
 * @since 2.3.0
2212
2243
 *
2213
 
 * @global wpdb $wpdb WordPress database abstraction object.
2214
 
 *
2215
 
 * @param string $field Term field to sanitize
2216
 
 * @param string $value Search for this term value
2217
 
 * @param int $term_id Term ID
2218
 
 * @param string $taxonomy Taxonomy Name
2219
 
 * @param string $context Either edit, db, display, attribute, or js.
2220
 
 * @return mixed sanitized field
 
2244
 * @param string $field    Term field to sanitize.
 
2245
 * @param string $value    Search for this term value.
 
2246
 * @param int    $term_id  Term ID.
 
2247
 * @param string $taxonomy Taxonomy Name.
 
2248
 * @param string $context  Context in which to sanitize the term field. Accepts 'edit', 'db', 'display',
 
2249
 *                         'attribute', or 'js'.
 
2250
 * @return mixed Sanitized field.
2221
2251
 */
2222
2252
function sanitize_term_field($field, $value, $term_id, $taxonomy, $context) {
2223
2253
        $int_fields = array( 'parent', 'term_id', 'count', 'term_group', 'term_taxonomy_id', 'object_id' );
2257
2287
                 * @param int   $term_id Term ID.
2258
2288
                 */
2259
2289
                $value = apply_filters( "edit_{$taxonomy}_{$field}", $value, $term_id );
 
2290
 
2260
2291
                if ( 'description' == $field )
2261
2292
                        $value = esc_html($value); // textarea_escaped
2262
2293
                else
2286
2317
                 * @param mixed $value Value of the taxonomy field.
2287
2318
                 */
2288
2319
                $value = apply_filters( "pre_{$taxonomy}_{$field}", $value );
 
2320
 
2289
2321
                // Back compat filters
2290
2322
                if ( 'slug' == $field ) {
2291
2323
                        /**
2317
2349
                /**
2318
2350
                 * Filter the taxonomy field for use in RSS.
2319
2351
                 *
2320
 
                 * The dynamic portions of the hook name, `$taxonomy`, and $field, refer
 
2352
                 * The dynamic portions of the hook name, `$taxonomy`, and `$field`, refer
2321
2353
                 * to the taxonomy slug and field name, respectively.
2322
2354
                 *
2323
2355
                 * @since 2.3.0
2345
2377
                /**
2346
2378
                 * Filter the taxonomy field sanitized for display.
2347
2379
                 *
2348
 
                 * The dynamic portions of the filter name, `$taxonomy`, and $field, refer
 
2380
                 * The dynamic portions of the filter name, `$taxonomy`, and `$field`, refer
2349
2381
                 * to the taxonomy slug and taxonomy field, respectively.
2350
2382
                 *
2351
2383
                 * @since 2.3.0
2370
2402
 *
2371
2403
 * Default $args is 'hide_empty' which can be 'hide_empty=true' or array('hide_empty' => true).
2372
2404
 *
 
2405
 * @todo Document $args as a hash notation.
 
2406
 *
2373
2407
 * @since 2.3.0
2374
2408
 *
2375
 
 * @param string $taxonomy Taxonomy name
2376
 
 * @param array|string $args Overwrite defaults. See get_terms()
2377
 
 * @return int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist.
 
2409
 * @param string       $taxonomy Taxonomy name
 
2410
 * @param array|string $args     Overwrite defaults. See get_terms()
 
2411
 * @return array|int|WP_Error How many terms are in $taxonomy. WP_Error if $taxonomy does not exist.
2378
2412
 */
2379
2413
function wp_count_terms( $taxonomy, $args = array() ) {
2380
2414
        $defaults = array('hide_empty' => false);
2400
2434
 *
2401
2435
 * @since 2.3.0
2402
2436
 *
2403
 
 * @param int $object_id The term Object Id that refers to the term
 
2437
 * @param int          $object_id  The term Object Id that refers to the term.
2404
2438
 * @param string|array $taxonomies List of Taxonomy Names or single Taxonomy name.
2405
2439
 */
2406
2440
function wp_delete_object_term_relationships( $object_id, $taxonomies ) {
2422
2456
 * If the term is a parent of other terms, then the children will be updated to
2423
2457
 * that term's parent.
2424
2458
 *
2425
 
 * The $args 'default' will only override the terms found, if there is only one
 
2459
 * The `$args` 'default' will only override the terms found, if there is only one
2426
2460
 * term found. Any other and the found terms are used.
2427
2461
 *
2428
2462
 * The $args 'force_default' will force the term supplied as default to be
2429
2463
 * assigned even if the object was not going to be termless
2430
2464
 *
 
2465
 * @todo Document $args as a hash notation.
 
2466
 *
2431
2467
 * @since 2.3.0
2432
2468
 *
2433
2469
 * @global wpdb $wpdb WordPress database abstraction object.
2434
2470
 *
2435
 
 * @param int $term Term ID
2436
 
 * @param string $taxonomy Taxonomy Name
2437
 
 * @param array|string $args Optional. Change 'default' term id and override found term ids.
2438
 
 * @return bool|WP_Error Returns false if not term; true if completes delete action.
 
2471
 * @param int          $term     Term ID.
 
2472
 * @param string       $taxonomy Taxonomy Name.
 
2473
 * @param array|string $args     Optional. Change 'default' term id and override found term ids.
 
2474
 * @return bool|int|WP_Error Returns false if not term; true if completes delete action.
2439
2475
 */
2440
2476
function wp_delete_term( $term, $taxonomy, $args = array() ) {
2441
2477
        global $wpdb;
2498
2534
                 * @param array $edit_tt_ids An array of term taxonomy IDs for the given term.
2499
2535
                 */
2500
2536
                do_action( 'edit_term_taxonomies', $edit_tt_ids );
 
2537
 
2501
2538
                $wpdb->update( $wpdb->term_taxonomy, compact( 'parent' ), array( 'parent' => $term_obj->term_id) + compact( 'taxonomy' ) );
2502
2539
 
2503
2540
                // Clean the cache for all child terms.
2529
2566
                wp_set_object_terms($object, $terms, $taxonomy);
2530
2567
        }
2531
2568
 
2532
 
        // Clean the relationship caches for all object types using this term
 
2569
        // Clean the relationship caches for all object types using this term.
2533
2570
        $tax_object = get_taxonomy( $taxonomy );
2534
2571
        foreach ( $tax_object->object_type as $object_type )
2535
2572
                clean_object_term_cache( $objects, $object_type );
2586
2623
         * @param int     $term         Term ID.
2587
2624
         * @param int     $tt_id        Term taxonomy ID.
2588
2625
         * @param mixed   $deleted_term Copy of the already-deleted term, in the form specified
2589
 
         *                              by the parent function. {@see WP_Error} otherwise.
 
2626
         *                              by the parent function. WP_Error otherwise.
2590
2627
         */
2591
2628
        do_action( "delete_$taxonomy", $term, $tt_id, $deleted_term );
2592
2629
 
2599
2636
 * @since 2.0.0
2600
2637
 *
2601
2638
 * @param int $cat_ID
2602
 
 * @return mixed Returns true if completes delete action; false if term doesn't exist;
 
2639
 * @return bool|int|WP_Error Returns true if completes delete action; false if term doesn't exist;
2603
2640
 *      Zero on attempted deletion of default Category; WP_Error object is also a possibility.
2604
2641
 */
2605
2642
function wp_delete_category( $cat_ID ) {
2678
2715
 
2679
2716
        if ( in_array( $orderby, array( 'term_id', 'name', 'slug', 'term_group' ) ) ) {
2680
2717
                $orderby = "t.$orderby";
2681
 
        } else if ( in_array( $orderby, array( 'count', 'parent', 'taxonomy', 'term_taxonomy_id' ) ) ) {
 
2718
        } elseif ( in_array( $orderby, array( 'count', 'parent', 'taxonomy', 'term_taxonomy_id' ) ) ) {
2682
2719
                $orderby = "tt.$orderby";
2683
 
        } else if ( 'term_order' === $orderby ) {
 
2720
        } elseif ( 'term_order' === $orderby ) {
2684
2721
                $orderby = 'tr.term_order';
2685
 
        } else if ( 'none' === $orderby ) {
 
2722
        } elseif ( 'none' === $orderby ) {
2686
2723
                $orderby = '';
2687
2724
                $order = '';
2688
2725
        } else {
2928
2965
                                }
2929
2966
 
2930
2967
                                if ( $existing_term ) {
2931
 
                                        return new WP_Error( 'term_exists', __( 'A term with the name already exists with this parent.' ), $existing_term->term_id );
 
2968
                                        return new WP_Error( 'term_exists', __( 'A term with the name provided already exists with this parent.' ), $existing_term->term_id );
2932
2969
                                }
2933
2970
                        } else {
2934
 
                                return new WP_Error( 'term_exists', __( 'A term with the name already exists in this taxonomy.' ), $name_match->term_id );
 
2971
                                return new WP_Error( 'term_exists', __( 'A term with the name provided already exists in this taxonomy.' ), $name_match->term_id );
2935
2972
                        }
2936
2973
                }
2937
2974
        }
3022
3059
         * Fires after a new term is created, and after the term cache has been cleaned.
3023
3060
         *
3024
3061
         * @since 2.3.0
 
3062
         *
 
3063
         * @param int    $term_id  Term ID.
 
3064
         * @param int    $tt_id    Term taxonomy ID.
 
3065
         * @param string $taxonomy Taxonomy slug.
3025
3066
         */
3026
 
        do_action( "created_term", $term_id, $tt_id, $taxonomy );
 
3067
        do_action( 'created_term', $term_id, $tt_id, $taxonomy );
3027
3068
 
3028
3069
        /**
3029
3070
         * Fires after a new term in a specific taxonomy is created, and after the term
3030
3071
         * cache has been cleaned.
3031
3072
         *
 
3073
         * The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
 
3074
         *
3032
3075
         * @since 2.3.0
3033
3076
         *
3034
3077
         * @param int $term_id Term ID.
3052
3095
 *
3053
3096
 * @since 2.3.0
3054
3097
 *
 
3098
 * @global wpdb $wpdb The WordPress database abstraction object.
 
3099
 *
3055
3100
 * @param int              $object_id The object to relate to.
3056
3101
 * @param array|int|string $terms     A single term slug, single term id, or array of either term slugs or ids.
3057
3102
 *                                    Will replace all existing related terms in this taxonomy.
3175
3220
 *
3176
3221
 * @since 3.6.0
3177
3222
 *
3178
 
 * @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.
3180
 
 * @param array|string $taxonomy Taxonomy name.
 
3223
 * @param int              $object_id The ID of the object to which the terms will be added.
 
3224
 * @param array|int|string $terms     The slug(s) or ID(s) of the term(s) to add.
 
3225
 * @param array|string     $taxonomy  Taxonomy name.
3181
3226
 * @return array|WP_Error Affected Term IDs
3182
3227
 */
3183
3228
function wp_add_object_terms( $object_id, $terms, $taxonomy ) {
3191
3236
 *
3192
3237
 * @global wpdb $wpdb WordPress database abstraction object.
3193
3238
 *
3194
 
 * @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.
3196
 
 * @param array|string $taxonomy Taxonomy name.
 
3239
 * @param int              $object_id The ID of the object from which the terms will be removed.
 
3240
 * @param array|int|string $terms     The slug(s) or ID(s) of the term(s) to remove.
 
3241
 * @param array|string     $taxonomy  Taxonomy name.
3197
3242
 * @return bool|WP_Error True on success, false or WP_Error on failure.
3198
3243
 */
3199
3244
function wp_remove_object_terms( $object_id, $terms, $taxonomy ) {
3253
3298
                 * @param array $tt_ids    An array of term taxonomy IDs.
3254
3299
                 */
3255
3300
                do_action( 'deleted_term_relationships', $object_id, $tt_ids );
 
3301
 
3256
3302
                wp_update_term_count( $tt_ids, $taxonomy );
3257
3303
 
3258
3304
                return (bool) $deleted;
3264
3310
/**
3265
3311
 * Will make slug unique, if it isn't already.
3266
3312
 *
3267
 
 * The $slug has to be unique global to every taxonomy, meaning that one
 
3313
 * The `$slug` has to be unique global to every taxonomy, meaning that one
3268
3314
 * taxonomy term can't have a matching slug with another taxonomy term. Each
3269
3315
 * slug has to be globally unique for every taxonomy.
3270
3316
 *
3274
3320
 * If that still doesn't return an unique slug, then it try to append a number
3275
3321
 * until it finds a number that is truly unique.
3276
3322
 *
3277
 
 * The only purpose for $term is for appending a parent, if one exists.
 
3323
 * The only purpose for `$term` is for appending a parent, if one exists.
3278
3324
 *
3279
3325
 * @since 2.3.0
3280
3326
 *
3281
3327
 * @global wpdb $wpdb WordPress database abstraction object.
3282
3328
 *
3283
 
 * @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
 
3329
 * @param string $slug The string that will be tried for a unique slug.
 
3330
 * @param object $term The term object that the `$slug` will belong to.
3285
3331
 * @return string Will return a true unique slug.
3286
3332
 */
3287
 
function wp_unique_term_slug($slug, $term) {
 
3333
function wp_unique_term_slug( $slug, $term ) {
3288
3334
        global $wpdb;
3289
3335
 
3290
 
        if ( ! term_exists( $slug ) )
3291
 
                return $slug;
 
3336
        $needs_suffix = true;
 
3337
        $original_slug = $slug;
3292
3338
 
3293
3339
        // 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 ) ) {
3295
 
                return $slug;
 
3340
        if ( ! term_exists( $slug ) || get_option( 'db_version' ) >= 30133 && ! get_term_by( 'slug', $slug, $term->taxonomy ) ) {
 
3341
                $needs_suffix = false;
3296
3342
        }
3297
3343
 
3298
 
        // If the taxonomy supports hierarchy and the term has a parent, make the slug unique
3299
 
        // by incorporating parent slugs.
3300
 
        if ( is_taxonomy_hierarchical($term->taxonomy) && !empty($term->parent) ) {
 
3344
        /*
 
3345
         * If the taxonomy supports hierarchy and the term has a parent, make the slug unique
 
3346
         * by incorporating parent slugs.
 
3347
         */
 
3348
        $parent_suffix = '';
 
3349
        if ( $needs_suffix && is_taxonomy_hierarchical( $term->taxonomy ) && ! empty( $term->parent ) ) {
3301
3350
                $the_parent = $term->parent;
3302
3351
                while ( ! empty($the_parent) ) {
3303
3352
                        $parent_term = get_term($the_parent, $term->taxonomy);
3304
3353
                        if ( is_wp_error($parent_term) || empty($parent_term) )
3305
3354
                                break;
3306
 
                        $slug .= '-' . $parent_term->slug;
3307
 
                        if ( ! term_exists( $slug ) )
3308
 
                                return $slug;
 
3355
                        $parent_suffix .= '-' . $parent_term->slug;
 
3356
                        if ( ! term_exists( $slug . $parent_suffix ) ) {
 
3357
                                break;
 
3358
                        }
3309
3359
 
3310
3360
                        if ( empty($parent_term->parent) )
3311
3361
                                break;
3314
3364
        }
3315
3365
 
3316
3366
        // If we didn't get a unique slug, try appending a number to make it unique.
3317
 
        if ( ! empty( $term->term_id ) )
3318
 
                $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id );
3319
 
        else
3320
 
                $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
3321
 
 
3322
 
        if ( $wpdb->get_var( $query ) ) {
3323
 
                $num = 2;
3324
 
                do {
3325
 
                        $alt_slug = $slug . "-$num";
3326
 
                        $num++;
3327
 
                        $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) );
3328
 
                } while ( $slug_check );
3329
 
                $slug = $alt_slug;
 
3367
 
 
3368
        /**
 
3369
         * Filter whether the proposed unique term slug is bad.
 
3370
         *
 
3371
         * @since 4.3.0
 
3372
         *
 
3373
         * @param bool   $needs_suffix Whether the slug needs to be made unique with a suffix.
 
3374
         * @param string $slug         The slug.
 
3375
         * @param object $term         Term object.
 
3376
         */
 
3377
        if ( apply_filters( 'wp_unique_term_slug_is_bad_slug', $needs_suffix, $slug, $term ) ) {
 
3378
                if ( $parent_suffix ) {
 
3379
                        $slug .= $parent_suffix;
 
3380
                } else {
 
3381
                        if ( ! empty( $term->term_id ) )
 
3382
                                $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s AND term_id != %d", $slug, $term->term_id );
 
3383
                        else
 
3384
                                $query = $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $slug );
 
3385
 
 
3386
                        if ( $wpdb->get_var( $query ) ) {
 
3387
                                $num = 2;
 
3388
                                do {
 
3389
                                        $alt_slug = $slug . "-$num";
 
3390
                                        $num++;
 
3391
                                        $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) );
 
3392
                                } while ( $slug_check );
 
3393
                                $slug = $alt_slug;
 
3394
                        }
 
3395
                }
3330
3396
        }
3331
3397
 
3332
 
        return $slug;
 
3398
        /**
 
3399
         * Filter the unique term slug.
 
3400
         *
 
3401
         * @since 4.3.0
 
3402
         *
 
3403
         * @param string $slug          Unique term slug.
 
3404
         * @param object $term          Term object.
 
3405
         * @param string $original_slug Slug originally passed to the function for testing.
 
3406
         */
 
3407
        return apply_filters( 'wp_unique_term_slug', $slug, $term, $original_slug );
3333
3408
}
3334
3409
 
3335
3410
/**
3350
3425
 * a WP_Error will be passed back. If you don't pass any slug, then a unique one
3351
3426
 * will be created for you.
3352
3427
 *
3353
 
 * For what can be overrode in $args, check the term scheme can contain and stay
 
3428
 * For what can be overrode in `$args`, check the term scheme can contain and stay
3354
3429
 * away from the term keys.
3355
3430
 *
3356
3431
 * @since 2.3.0
3357
3432
 *
3358
3433
 * @global wpdb $wpdb WordPress database abstraction object.
3359
3434
 *
3360
 
 * @param int $term_id The ID of the term
3361
 
 * @param string $taxonomy The context in which to relate the term to the object.
3362
 
 * @param array|string $args Overwrite term field values
 
3435
 * @param int          $term_id  The ID of the term
 
3436
 * @param string       $taxonomy The context in which to relate the term to the object.
 
3437
 * @param array|string $args     Optional. Array of get_terms() arguments. Default empty array.
3363
3438
 * @return array|WP_Error Returns Term ID and Taxonomy Term ID
3364
3439
 */
3365
3440
function wp_update_term( $term_id, $taxonomy, $args = array() ) {
3506
3581
         * @param string $taxonomy Taxonomy slug.
3507
3582
         */
3508
3583
        do_action( 'edit_term_taxonomy', $tt_id, $taxonomy );
 
3584
 
3509
3585
        $wpdb->update( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent' ), array( 'term_taxonomy_id' => $tt_id ) );
3510
3586
 
3511
3587
        /**
3518
3594
         */
3519
3595
        do_action( 'edited_term_taxonomy', $tt_id, $taxonomy );
3520
3596
 
3521
 
        // Clean the relationship caches for all object types using this term
 
3597
        // Clean the relationship caches for all object types using this term.
3522
3598
        $objects = $wpdb->get_col( $wpdb->prepare( "SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $tt_id ) );
3523
3599
        $tax_object = get_taxonomy( $taxonomy );
3524
3600
        foreach ( $tax_object->object_type as $object_type ) {
3586
3662
 *
3587
3663
 * @since 2.5.0
3588
3664
 *
 
3665
 * @staticvar bool $_defer
 
3666
 *
3589
3667
 * @param bool $defer Optional. Enable if true, disable if false.
3590
3668
 * @return bool Whether term counting is enabled or disabled.
3591
3669
 */
3613
3691
 *
3614
3692
 * @since 2.3.0
3615
3693
 *
3616
 
 * @global wpdb $wpdb WordPress database abstraction object.
 
3694
 * @staticvar array $_deferred
3617
3695
 *
3618
 
 * @param int|array $terms The term_taxonomy_id of the terms
3619
 
 * @param string $taxonomy The context of the term.
 
3696
 * @param int|array $terms    The term_taxonomy_id of the terms.
 
3697
 * @param string    $taxonomy The context of the term.
3620
3698
 * @return bool If no terms will return false, and if successful will return true.
3621
3699
 */
3622
3700
function wp_update_term_count( $terms, $taxonomy, $do_deferred=false ) {
3650
3728
 *
3651
3729
 * @since 2.5.0
3652
3730
 *
3653
 
 * @param array $terms The term_taxonomy_id of terms to update.
 
3731
 * @param array  $terms    The term_taxonomy_id of terms to update.
3654
3732
 * @param string $taxonomy The context of the term.
3655
 
 * @return bool Always true when complete.
 
3733
 * @return true Always true when complete.
3656
3734
 */
3657
3735
function wp_update_term_count_now( $terms, $taxonomy ) {
3658
3736
        $terms = array_map('intval', $terms);
3688
3766
/**
3689
3767
 * Removes the taxonomy relationship to terms from the cache.
3690
3768
 *
3691
 
 * 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
 
3769
 * Will remove the entire taxonomy relationship containing term `$object_id`. The
 
3770
 * term IDs have to exist within the taxonomy `$object_type` for the deletion to
3693
3771
 * take place.
3694
3772
 *
3695
3773
 * @since 2.3.0
3696
3774
 *
3697
 
 * @see get_object_taxonomies() for more on $object_type
 
3775
 * @see get_object_taxonomies() for more on $object_type.
3698
3776
 *
3699
 
 * @param int|array $object_ids Single or list of term object ID(s)
3700
 
 * @param array|string $object_type The taxonomy object type
 
3777
 * @param int|array    $object_ids  Single or list of term object ID(s).
 
3778
 * @param array|string $object_type The taxonomy object type.
3701
3779
 */
3702
3780
function clean_object_term_cache($object_ids, $object_type) {
3703
3781
        if ( !is_array($object_ids) )
3728
3806
 * @since 2.3.0
3729
3807
 *
3730
3808
 * @global wpdb $wpdb WordPress database abstraction object.
 
3809
 * @global bool $_wp_suspend_cache_invalidation
3731
3810
 *
3732
 
 * @param int|array $ids Single or list of Term IDs
3733
 
 * @param string $taxonomy Can be empty and will assume tt_ids, else will use for context.
3734
 
 * @param bool $clean_taxonomy Whether to clean taxonomy wide caches (true), or just individual term object caches (false). Default is true.
 
3811
 * @param int|array $ids            Single or list of Term IDs.
 
3812
 * @param string    $taxonomy       Optional. Can be empty and will assume `tt_ids`, else will use for context.
 
3813
 *                                  Default empty.
 
3814
 * @param bool      $clean_taxonomy Optional. Whether to clean taxonomy wide caches (true), or just individual
 
3815
 *                                  term object caches (false). Default true.
3735
3816
 */
3736
3817
function clean_term_cache($ids, $taxonomy = '', $clean_taxonomy = true) {
3737
 
        global $wpdb;
 
3818
        global $wpdb, $_wp_suspend_cache_invalidation;
 
3819
 
 
3820
        if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
 
3821
                return;
 
3822
        }
3738
3823
 
3739
3824
        if ( !is_array($ids) )
3740
3825
                $ids = array($ids);
3789
3874
 *
3790
3875
 * @since 2.3.0
3791
3876
 *
3792
 
 * @param int    $id       Term object ID
3793
 
 * @param string $taxonomy Taxonomy Name
3794
 
 * @return bool|array Empty array if $terms found, but not $taxonomy. False if nothing is in cache for $taxonomy and $id.
 
3877
 * @param int    $id       Term object ID.
 
3878
 * @param string $taxonomy Taxonomy name.
 
3879
 * @return bool|mixed Empty array if $terms found, but not `$taxonomy`. False if nothing is in cache
 
3880
 *                    for `$taxonomy` and `$id`.
3795
3881
 */
3796
 
function get_object_term_cache($id, $taxonomy) {
3797
 
        $cache = wp_cache_get($id, "{$taxonomy}_relationships");
3798
 
        return $cache;
 
3882
function get_object_term_cache( $id, $taxonomy ) {
 
3883
        return wp_cache_get( $id, "{$taxonomy}_relationships" );
3799
3884
}
3800
3885
 
3801
3886
/**
3810
3895
 *
3811
3896
 * @since 2.3.0
3812
3897
 *
3813
 
 * @param string|array $object_ids  Comma-separated list or array of term object IDs..
 
3898
 * @param string|array $object_ids  Comma-separated list or array of term object IDs.
3814
3899
 * @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
3816
 
 *                    `$object_ids` are already cached.
 
3900
 * @return void|false False if all of the terms in `$object_ids` are already cached.
3817
3901
 */
3818
3902
function update_object_term_cache($object_ids, $object_type) {
3819
3903
        if ( empty($object_ids) )
3867
3951
 *
3868
3952
 * @since 2.3.0
3869
3953
 *
3870
 
 * @param array $terms List of Term objects to change
3871
 
 * @param string $taxonomy Optional. Update Term to this taxonomy in cache
 
3954
 * @param array  $terms    List of term objects to change.
 
3955
 * @param string $taxonomy Optional. Update Term to this taxonomy in cache. Default empty.
3872
3956
 */
3873
 
function update_term_cache($terms, $taxonomy = '') {
 
3957
function update_term_cache( $terms, $taxonomy = '' ) {
3874
3958
        foreach ( (array) $terms as $term ) {
3875
3959
                $term_taxonomy = $taxonomy;
3876
3960
                if ( empty($term_taxonomy) )
3887
3971
/**
3888
3972
 * Retrieves children of taxonomy as Term IDs.
3889
3973
 *
3890
 
 * @access private
 
3974
 * @ignore
3891
3975
 * @since 2.3.0
3892
3976
 *
3893
 
 * @param string $taxonomy Taxonomy Name
 
3977
 * @param string $taxonomy Taxonomy name.
3894
3978
 * @return array Empty if $taxonomy isn't hierarchical or returns children as Term IDs.
3895
3979
 */
3896
 
function _get_term_hierarchy($taxonomy) {
 
3980
function _get_term_hierarchy( $taxonomy ) {
3897
3981
        if ( !is_taxonomy_hierarchical($taxonomy) )
3898
3982
                return array();
3899
3983
        $children = get_option("{$taxonomy}_children");
3914
3998
/**
3915
3999
 * Get the subset of $terms that are descendants of $term_id.
3916
4000
 *
3917
 
 * 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.
 
4001
 * If `$terms` is an array of objects, then _get_term_children() returns an array of objects.
 
4002
 * If `$terms` is an array of IDs, then _get_term_children() returns an array of IDs.
3919
4003
 *
3920
4004
 * @access private
3921
4005
 * @since 2.3.0
3922
4006
 *
3923
 
 * @param int $term_id The ancestor term: all returned terms should be descendants of $term_id.
 
4007
 * @param int    $term_id   The ancestor term: all returned terms should be descendants of `$term_id`.
3924
4008
 * @param array  $terms     The set of terms - either an array of term objects or term IDs - from which those that
3925
4009
 *                          are descendants of $term_id will be chosen.
3926
4010
 * @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
3928
 
 *                          found terms when recursing the hierarchy. The array of located ancestors is used to prevent
3929
 
 *                          infinite recursion loops. For performance, term_ids are used as array keys, with 1 as value.
3930
 
 * @return array The subset of $terms that are descendants of $term_id.
 
4011
 * @param array  $ancestors Optional. Term ancestors that have already been identified. Passed by reference, to keep
 
4012
 *                          track of found terms when recursing the hierarchy. The array of located ancestors is used
 
4013
 *                          to prevent infinite recursion loops. For performance, `term_ids` are used as array keys,
 
4014
 *                          with 1 as value. Default empty array.
 
4015
 * @return array|WP_Error The subset of $terms that are descendants of $term_id.
3931
4016
 */
3932
4017
function _get_term_children( $term_id, $terms, $taxonomy, &$ancestors = array() ) {
3933
4018
        $empty_array = array();
3989
4074
 *
3990
4075
 * @global wpdb $wpdb WordPress database abstraction object.
3991
4076
 *
3992
 
 * @param array $terms List of Term IDs
3993
 
 * @param string $taxonomy Term Context
3994
 
 * @return null Will break from function if conditions are not met.
 
4077
 * @param array  $terms    List of term IDs, passed by reference.
 
4078
 * @param string $taxonomy Term context.
3995
4079
 */
3996
 
function _pad_term_counts(&$terms, $taxonomy) {
 
4080
function _pad_term_counts( &$terms, $taxonomy ) {
3997
4081
        global $wpdb;
3998
4082
 
3999
4083
        // This function only works for hierarchical taxonomies like post categories.
4014
4098
                $term_ids[$term->term_taxonomy_id] = $term->term_id;
4015
4099
        }
4016
4100
 
4017
 
        // Get the object and term ids and stick them in a lookup table
 
4101
        // Get the object and term ids and stick them in a lookup table.
4018
4102
        $tax_obj = get_taxonomy($taxonomy);
4019
4103
        $object_types = esc_sql($tax_obj->object_type);
4020
4104
        $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'");
4023
4107
                $term_items[$id][$row->object_id] = isset($term_items[$id][$row->object_id]) ? ++$term_items[$id][$row->object_id] : 1;
4024
4108
        }
4025
4109
 
4026
 
        // Touch every ancestor's lookup row for each post in each term
 
4110
        // Touch every ancestor's lookup row for each post in each term.
4027
4111
        foreach ( $term_ids as $term_id ) {
4028
4112
                $child = $term_id;
4029
4113
                $ancestors = array();
4041
4125
                }
4042
4126
        }
4043
4127
 
4044
 
        // Transfer the touched cells
 
4128
        // Transfer the touched cells.
4045
4129
        foreach ( (array) $term_items as $id => $items )
4046
4130
                if ( isset($terms_by_id[$id]) )
4047
4131
                        $terms_by_id[$id]->count = count($items);
4062
4146
 *
4063
4147
 * @global wpdb $wpdb WordPress database abstraction object.
4064
4148
 *
4065
 
 * @param array $terms List of Term taxonomy IDs
4066
 
 * @param object $taxonomy Current taxonomy object of terms
 
4149
 * @param array  $terms    List of Term taxonomy IDs.
 
4150
 * @param object $taxonomy Current taxonomy object of terms.
4067
4151
 */
4068
4152
function _update_post_term_count( $terms, $taxonomy ) {
4069
4153
        global $wpdb;
4086
4170
        foreach ( (array) $terms as $term ) {
4087
4171
                $count = 0;
4088
4172
 
4089
 
                // Attachments can be 'inherit' status, we need to base count off the parent's status if so
 
4173
                // Attachments can be 'inherit' status, we need to base count off the parent's status if so.
4090
4174
                if ( $check_attachments )
4091
4175
                        $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
4176
 
4105
4189
/**
4106
4190
 * Will update term count based on number of objects.
4107
4191
 *
4108
 
 * Default callback for the link_category taxonomy.
 
4192
 * Default callback for the 'link_category' taxonomy.
4109
4193
 *
4110
4194
 * @since 3.3.0
4111
4195
 *
4112
4196
 * @global wpdb $wpdb WordPress database abstraction object.
4113
4197
 *
4114
 
 * @param array $terms List of Term taxonomy IDs
4115
 
 * @param object $taxonomy Current taxonomy object of terms
 
4198
 * @param array  $terms    List of term taxonomy IDs.
 
4199
 * @param object $taxonomy Current taxonomy object of terms.
4116
4200
 */
4117
4201
function _update_generic_term_count( $terms, $taxonomy ) {
4118
4202
        global $wpdb;
4130
4214
}
4131
4215
 
4132
4216
/**
4133
 
 * Create a new term for a term_taxonomy item that currently shares its term with another term_taxonomy.
 
4217
 * Create a new term for a term_taxonomy item that currently shares its term
 
4218
 * with another term_taxonomy.
4134
4219
 *
4135
4220
 * @ignore
4136
4221
 * @since 4.2.0
4137
 
 *
4138
 
 * @param int  $term_id          ID of the shared term.
4139
 
 * @param int  $term_taxonomy_id ID of the term_taxonomy item to receive a new term.
 
4222
 * @since 4.3.0 Introduced `$record` parameter. Also, `$term_id` and
 
4223
 *              `$term_taxonomy_id` can now accept objects.
 
4224
 *
 
4225
 * @global wpdb $wpdb
 
4226
 *
 
4227
 * @param int|object $term_id          ID of the shared term, or the shared term object.
 
4228
 * @param int|object $term_taxonomy_id ID of the term_taxonomy item to receive a new term, or the term_taxonomy object
 
4229
 *                                     (corresponding to a row from the term_taxonomy table).
 
4230
 * @param bool       $record           Whether to record data about the split term in the options table. The recording
 
4231
 *                                     process has the potential to be resource-intensive, so during batch operations
 
4232
 *                                     it can be beneficial to skip inline recording and do it just once, after the
 
4233
 *                                     batch is processed. Only set this to `false` if you know what you are doing.
 
4234
 *                                     Default: true.
4140
4235
 * @return int|WP_Error When the current term does not need to be split (or cannot be split on the current
4141
4236
 *                      database schema), `$term_id` is returned. When the term is successfully split, the
4142
4237
 *                      new term_id is returned. A WP_Error is returned for miscellaneous errors.
4143
4238
 */
4144
 
function _split_shared_term( $term_id, $term_taxonomy_id ) {
 
4239
function _split_shared_term( $term_id, $term_taxonomy_id, $record = true ) {
4145
4240
        global $wpdb;
4146
4241
 
4147
 
        // Don't try to split terms if database schema does not support shared slugs.
4148
 
        $current_db_version = get_option( 'db_version' );
4149
 
        if ( $current_db_version < 30133 ) {
4150
 
                return $term_id;
 
4242
        if ( is_object( $term_id ) ) {
 
4243
                $shared_term = $term_id;
 
4244
                $term_id = intval( $shared_term->term_id );
 
4245
        }
 
4246
 
 
4247
        if ( is_object( $term_taxonomy_id ) ) {
 
4248
                $term_taxonomy = $term_taxonomy_id;
 
4249
                $term_taxonomy_id = intval( $term_taxonomy->term_taxonomy_id );
4151
4250
        }
4152
4251
 
4153
4252
        // If there are no shared term_taxonomy rows, there's nothing to do here.
4154
4253
        $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 ) );
 
4254
 
4155
4255
        if ( ! $shared_tt_count ) {
4156
4256
                return $term_id;
4157
4257
        }
4158
4258
 
 
4259
        /*
 
4260
         * Verify that the term_taxonomy_id passed to the function is actually associated with the term_id.
 
4261
         * If there's a mismatch, it may mean that the term is already split. Return the actual term_id from the db.
 
4262
         */
 
4263
        $check_term_id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
 
4264
        if ( $check_term_id != $term_id ) {
 
4265
                return $check_term_id;
 
4266
        }
 
4267
 
4159
4268
        // 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 ) );
 
4269
        if ( empty( $shared_term ) ) {
 
4270
                $shared_term = $wpdb->get_row( $wpdb->prepare( "SELECT t.* FROM $wpdb->terms t WHERE t.term_id = %d", $term_id ) );
 
4271
        }
4161
4272
 
4162
4273
        $new_term_data = array(
4163
4274
                'name' => $shared_term->name,
4178
4289
        );
4179
4290
 
4180
4291
        // 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 ) );
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 ) );
 
4292
        if ( empty( $term_taxonomy ) ) {
 
4293
                $term_taxonomy = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->term_taxonomy WHERE term_taxonomy_id = %d", $term_taxonomy_id ) );
 
4294
        }
4183
4295
 
 
4296
        $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
4297
        if ( ! empty( $children_tt_ids ) ) {
4185
4298
                foreach ( $children_tt_ids as $child_tt_id ) {
4186
4299
                        $wpdb->update( $wpdb->term_taxonomy,
4203
4316
        }
4204
4317
 
4205
4318
        // Keep a record of term_ids that have been split, keyed by old term_id. See {@see wp_get_split_term()}.
4206
 
        $split_term_data = get_option( '_split_terms', array() );
4207
 
        if ( ! isset( $split_term_data[ $term_id ] ) ) {
4208
 
                $split_term_data[ $term_id ] = array();
 
4319
        if ( $record ) {
 
4320
                $split_term_data = get_option( '_split_terms', array() );
 
4321
                if ( ! isset( $split_term_data[ $term_id ] ) ) {
 
4322
                        $split_term_data[ $term_id ] = array();
 
4323
                }
 
4324
 
 
4325
                $split_term_data[ $term_id ][ $term_taxonomy->taxonomy ] = $new_term_id;
 
4326
                update_option( '_split_terms', $split_term_data );
4209
4327
        }
4210
4328
 
4211
 
        $split_term_data[ $term_id ][ $term_taxonomy->taxonomy ] = $new_term_id;
4212
 
 
4213
 
        update_option( '_split_terms', $split_term_data );
4214
 
 
4215
4329
        /**
4216
4330
         * Fires after a previously shared taxonomy term is split into two separate terms.
4217
4331
         *
4228
4342
}
4229
4343
 
4230
4344
/**
 
4345
 * Splits a batch of shared taxonomy terms.
 
4346
 *
 
4347
 * @since 4.3.0
 
4348
 *
 
4349
 * @global wpdb $wpdb WordPress database abstraction object.
 
4350
 */
 
4351
function _wp_batch_split_terms() {
 
4352
        global $wpdb;
 
4353
 
 
4354
        $lock_name = 'term_split.lock';
 
4355
 
 
4356
        // Try to lock.
 
4357
        $lock_result = $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO `$wpdb->options` ( `option_name`, `option_value`, `autoload` ) VALUES (%s, %s, 'no') /* LOCK */", $lock_name, time() ) );
 
4358
 
 
4359
        if ( ! $lock_result ) {
 
4360
                $lock_result = get_option( $lock_name );
 
4361
 
 
4362
                // Bail if we were unable to create a lock, or if the existing lock is still valid.
 
4363
                if ( ! $lock_result || ( $lock_result > ( time() - HOUR_IN_SECONDS ) ) ) {
 
4364
                        wp_schedule_single_event( time() + ( 5 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
 
4365
                        return;
 
4366
                }
 
4367
        }
 
4368
 
 
4369
        // Update the lock, as by this point we've definitely got a lock, just need to fire the actions.
 
4370
        update_option( $lock_name, time() );
 
4371
 
 
4372
        // Get a list of shared terms (those with more than one associated row in term_taxonomy).
 
4373
        $shared_terms = $wpdb->get_results(
 
4374
                "SELECT tt.term_id, t.*, count(*) as term_tt_count FROM {$wpdb->term_taxonomy} tt
 
4375
                 LEFT JOIN {$wpdb->terms} t ON t.term_id = tt.term_id
 
4376
                 GROUP BY t.term_id
 
4377
                 HAVING term_tt_count > 1
 
4378
                 LIMIT 10"
 
4379
        );
 
4380
 
 
4381
        // No more terms, we're done here.
 
4382
        if ( ! $shared_terms ) {
 
4383
                update_option( 'finished_splitting_shared_terms', true );
 
4384
                delete_option( $lock_name );
 
4385
                return;
 
4386
        }
 
4387
 
 
4388
        // Shared terms found? We'll need to run this script again.
 
4389
        wp_schedule_single_event( time() + ( 2 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' );
 
4390
 
 
4391
        // Rekey shared term array for faster lookups.
 
4392
        $_shared_terms = array();
 
4393
        foreach ( $shared_terms as $shared_term ) {
 
4394
                $term_id = intval( $shared_term->term_id );
 
4395
                $_shared_terms[ $term_id ] = $shared_term;
 
4396
        }
 
4397
        $shared_terms = $_shared_terms;
 
4398
 
 
4399
        // Get term taxonomy data for all shared terms.
 
4400
        $shared_term_ids = implode( ',', array_keys( $shared_terms ) );
 
4401
        $shared_tts = $wpdb->get_results( "SELECT * FROM {$wpdb->term_taxonomy} WHERE `term_id` IN ({$shared_term_ids})" );
 
4402
 
 
4403
        // Split term data recording is slow, so we do it just once, outside the loop.
 
4404
        $split_term_data = get_option( '_split_terms', array() );
 
4405
        $skipped_first_term = $taxonomies = array();
 
4406
        foreach ( $shared_tts as $shared_tt ) {
 
4407
                $term_id = intval( $shared_tt->term_id );
 
4408
 
 
4409
                // Don't split the first tt belonging to a given term_id.
 
4410
                if ( ! isset( $skipped_first_term[ $term_id ] ) ) {
 
4411
                        $skipped_first_term[ $term_id ] = 1;
 
4412
                        continue;
 
4413
                }
 
4414
 
 
4415
                if ( ! isset( $split_term_data[ $term_id ] ) ) {
 
4416
                        $split_term_data[ $term_id ] = array();
 
4417
                }
 
4418
 
 
4419
                // Keep track of taxonomies whose hierarchies need flushing.
 
4420
                if ( ! isset( $taxonomies[ $shared_tt->taxonomy ] ) ) {
 
4421
                        $taxonomies[ $shared_tt->taxonomy ] = 1;
 
4422
                }
 
4423
 
 
4424
                // Split the term.
 
4425
                $split_term_data[ $term_id ][ $shared_tt->taxonomy ] = _split_shared_term( $shared_terms[ $term_id ], $shared_tt, false );
 
4426
        }
 
4427
 
 
4428
        // Rebuild the cached hierarchy for each affected taxonomy.
 
4429
        foreach ( array_keys( $taxonomies ) as $tax ) {
 
4430
                delete_option( "{$tax}_children" );
 
4431
                _get_term_hierarchy( $tax );
 
4432
        }
 
4433
 
 
4434
        update_option( '_split_terms', $split_term_data );
 
4435
 
 
4436
        delete_option( $lock_name );
 
4437
}
 
4438
 
 
4439
/**
 
4440
 * In order to avoid the wp_batch_split_terms() job being accidentally removed,
 
4441
 * check that it's still scheduled while we haven't finished splitting terms.
 
4442
 *
 
4443
 * @ignore
 
4444
 * @since 4.3.0
 
4445
 */
 
4446
function _wp_check_for_scheduled_split_terms() {
 
4447
        if ( ! get_option( 'finished_splitting_shared_terms' ) && ! wp_next_scheduled( 'wp_batch_split_terms' ) ) {
 
4448
                wp_schedule_single_event( 'wp_batch_split_terms', time() + MINUTE_IN_SECONDS );
 
4449
        }
 
4450
}
 
4451
 
 
4452
/**
4231
4453
 * Check default categories when a term gets split to see if any of them need to be updated.
4232
4454
 *
4233
4455
 * @ignore
4256
4478
 * @ignore
4257
4479
 * @since 4.2.0
4258
4480
 *
 
4481
 * @global wpdb $wpdb
 
4482
 *
4259
4483
 * @param int    $term_id          ID of the formerly shared term.
4260
4484
 * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
4261
4485
 * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
4283
4507
}
4284
4508
 
4285
4509
/**
 
4510
 * If the term being split is a nav_menu, change associations.
 
4511
 *
 
4512
 * @ignore
 
4513
 * @since 4.3.0
 
4514
 *
 
4515
 * @global wpdb $wpdb
 
4516
 *
 
4517
 * @param int    $term_id          ID of the formerly shared term.
 
4518
 * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
 
4519
 * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
 
4520
 * @param string $taxonomy         Taxonomy for the split term.
 
4521
 */
 
4522
function _wp_check_split_nav_menu_terms( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
 
4523
        if ( 'nav_menu' !== $taxonomy ) {
 
4524
                return;
 
4525
        }
 
4526
 
 
4527
        // Update menu locations.
 
4528
        $locations = get_nav_menu_locations();
 
4529
        foreach ( $locations as $location => $menu_id ) {
 
4530
                if ( $term_id == $menu_id ) {
 
4531
                        $locations[ $location ] = $new_term_id;
 
4532
                }
 
4533
        }
 
4534
        set_theme_mod( 'nav_menu_locations', $locations );
 
4535
}
 
4536
 
 
4537
/**
4286
4538
 * Get data about terms that previously shared a single term_id, but have since been split.
4287
4539
 *
4288
4540
 * @since 4.2.0
4308
4560
 *
4309
4561
 * @param int    $old_term_id Term ID. This is the old, pre-split term ID.
4310
4562
 * @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,
4312
 
 *                  the new term_id will be returned. If no previously split term is found matching
4313
 
 *                  the parameters, returns false.
 
4563
 * @return int|false If a previously split term is found corresponding to the old term_id and taxonomy,
 
4564
 *                   the new term_id will be returned. If no previously split term is found matching
 
4565
 *                   the parameters, returns false.
4314
4566
 */
4315
4567
function wp_get_split_term( $old_term_id, $taxonomy ) {
4316
4568
        $split_terms = wp_get_split_terms( $old_term_id );
4328
4580
 *
4329
4581
 * @since 2.5.0
4330
4582
 *
 
4583
 * @global WP_Rewrite $wp_rewrite
 
4584
 *
4331
4585
 * @param object|int|string $term     The term object, ID, or slug whose link will be retrieved.
4332
4586
 * @param string            $taxonomy Optional. Taxonomy. Default empty.
4333
4587
 * @return string|WP_Error HTML link to taxonomy term archive on success, WP_Error if term does not exist.
4334
4588
 */
4335
 
function get_term_link( $term, $taxonomy = '') {
 
4589
function get_term_link( $term, $taxonomy = '' ) {
4336
4590
        global $wp_rewrite;
4337
4591
 
4338
4592
        if ( !is_object($term) ) {
4339
 
                if ( is_int($term) ) {
4340
 
                        $term = get_term($term, $taxonomy);
 
4593
                if ( is_int( $term ) ) {
 
4594
                        $term = get_term( $term, $taxonomy );
4341
4595
                } else {
4342
 
                        $term = get_term_by('slug', $term, $taxonomy);
 
4596
                        $term = get_term_by( 'slug', $term, $taxonomy );
4343
4597
                }
4344
4598
        }
4345
4599
 
4429
4683
 * @since 2.5.0
4430
4684
 *
4431
4685
 * @param array $args {
4432
 
 *     Arguments about which post to use and how to format the output. Shares all of the arguments supported by
4433
 
 *     {@link get_the_taxonomies()}, in addition to the following.
 
4686
 *     Arguments about which post to use and how to format the output. Shares all of the arguments
 
4687
 *     supported by get_the_taxonomies(), in addition to the following.
4434
4688
 *
4435
4689
 *     @type  int|WP_Post $post   Post ID or object to get taxonomies of. Default current post.
4436
4690
 *     @type  string      $before Displays before the taxonomies. Default empty string.
4462
4716
 *
4463
4717
 * @param int|WP_Post $post Optional. Post ID or WP_Post object. Default is global $post.
4464
4718
 * @param array $args {
4465
 
 *     Arguments about how to format the list of taxonomies.
 
4719
 *     Optional. Arguments about how to format the list of taxonomies. Default empty array.
4466
4720
 *
4467
4721
 *     @type string $template      Template for displaying a taxonomy label and list of terms.
4468
4722
 *                                 Default is "Label: Terms."
4540
4794
 *
4541
4795
 * @since 2.7.0
4542
4796
 *
4543
 
 * @param int $object_id ID of the object (post ID, link ID, ...)
4544
 
 * @param string $taxonomy Single taxonomy name
4545
 
 * @param int|string|array $terms Optional. Term term_id, name, slug or array of said
 
4797
 * @param int              $object_id ID of the object (post ID, link ID, ...).
 
4798
 * @param string           $taxonomy  Single taxonomy name.
 
4799
 * @param int|string|array $terms     Optional. Term term_id, name, slug or array of said. Default null.
4546
4800
 * @return bool|WP_Error WP_Error on input error.
4547
4801
 */
4548
4802
function is_object_in_term( $object_id, $taxonomy, $terms = null ) {
4593
4847
 *
4594
4848
 * @since 3.0.0
4595
4849
 *
4596
 
 * @param string $object_type Object type string
4597
 
 * @param string $taxonomy Single taxonomy name
 
4850
 * @param string $object_type Object type string.
 
4851
 * @param string $taxonomy    Single taxonomy name.
4598
4852
 * @return bool True if object is associated with the taxonomy, otherwise false.
4599
4853
 */
4600
 
function is_object_in_taxonomy($object_type, $taxonomy) {
4601
 
        $taxonomies = get_object_taxonomies($object_type);
4602
 
 
4603
 
        if ( empty($taxonomies) )
 
4854
function is_object_in_taxonomy( $object_type, $taxonomy ) {
 
4855
        $taxonomies = get_object_taxonomies( $object_type );
 
4856
        if ( empty( $taxonomies ) ) {
4604
4857
                return false;
4605
 
 
4606
 
        if ( in_array($taxonomy, $taxonomies) )
4607
 
                return true;
4608
 
 
4609
 
        return false;
 
4858
        }
 
4859
        return in_array( $taxonomy, $taxonomies );
4610
4860
}
4611
4861
 
4612
4862
/**
4655
4905
         * Filter a given object's ancestors.
4656
4906
         *
4657
4907
         * @since 3.1.0
4658
 
         * @since 4.1.0 Introduced the `$resource_type` parameter.
 
4908
         * @since 4.1.1 Introduced the `$resource_type` parameter.
4659
4909
         *
4660
4910
         * @param array  $ancestors     An array of object ancestors.
4661
4911
         * @param int    $object_id     Object ID.
4666
4916
}
4667
4917
 
4668
4918
/**
4669
 
 * Returns the term's parent's term_ID
 
4919
 * Returns the term's parent's term_ID.
4670
4920
 *
4671
4921
 * @since 3.1.0
4672
4922
 *
4673
 
 * @param int $term_id
4674
 
 * @param string $taxonomy
4675
 
 *
4676
 
 * @return int|bool false on error
 
4923
 * @param int    $term_id  Term ID.
 
4924
 * @param string $taxonomy Taxonomy name.
 
4925
 * @return int|false False on error.
4677
4926
 */
4678
4927
function wp_get_term_taxonomy_parent_id( $term_id, $taxonomy ) {
4679
4928
        $term = get_term( $term_id, $taxonomy );
4680
 
        if ( !$term || is_wp_error( $term ) )
 
4929
        if ( ! $term || is_wp_error( $term ) ) {
4681
4930
                return false;
 
4931
        }
4682
4932
        return (int) $term->parent;
4683
4933
}
4684
4934
 
4686
4936
 * Checks the given subset of the term hierarchy for hierarchy loops.
4687
4937
 * Prevents loops from forming and breaks those that it finds.
4688
4938
 *
4689
 
 * Attached to the wp_update_term_parent filter.
 
4939
 * Attached to the {@see 'wp_update_term_parent'} filter.
4690
4940
 *
4691
4941
 * @since 3.1.0
4692
4942
 *
4693
 
 * @param int $parent term_id of the parent for the term we're checking.
4694
 
 * @param int $term_id The term we're checking.
 
4943
 * @param int    $parent   `term_id` of the parent for the term we're checking.
 
4944
 * @param int    $term_id  The term we're checking.
4695
4945
 * @param string $taxonomy The taxonomy of the term we're checking.
4696
4946
 *
4697
4947
 * @return int The new parent for the term.
4701
4951
        if ( !$parent )
4702
4952
                return 0;
4703
4953
 
4704
 
        // Can't be its own parent
 
4954
        // Can't be its own parent.
4705
4955
        if ( $parent == $term_id )
4706
4956
                return 0;
4707
4957
 
4708
 
        // Now look for larger loops
4709
 
 
 
4958
        // Now look for larger loops.
4710
4959
        if ( !$loop = wp_find_hierarchy_loop( 'wp_get_term_taxonomy_parent_id', $term_id, $parent, array( $taxonomy ) ) )
4711
4960
                return $parent; // No loop
4712
4961
 
4713
 
        // Setting $parent to the given value causes a loop
 
4962
        // Setting $parent to the given value causes a loop.
4714
4963
        if ( isset( $loop[$term_id] ) )
4715
4964
                return 0;
4716
4965