From ef8f9168b6ce85d7c2c4994d771464db30bd9be0 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Fri, 7 Oct 2016 17:12:29 +0000 Subject: [PATCH] Taxonomy: Introduce `WP_Taxonomy` and use it in `register_taxonomy()` and `unregister_taxonomy()`. This changes the global `$wp_taxonomies` to an array of `WP_Taxonomy ` objects. `WP_Taxonomy ` includes methods to handle rewrite rules and hooks. Each taxonomy argument becomes a property of `WP_Taxonomy`. Introducing such a class makes further improvements in the future much more feasible. Props boonebgorges for review. Fixes #36224. See #36217. Built from https://develop.svn.wordpress.org/trunk@38747 git-svn-id: http://core.svn.wordpress.org/trunk@38690 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/includes/ajax-actions.php | 6 +- wp-includes/class-wp-taxonomy.php | 416 +++++++++++++++++++++++++ wp-includes/class-wp-xmlrpc-server.php | 6 +- wp-includes/taxonomy.php | 145 +-------- wp-includes/version.php | 2 +- wp-settings.php | 1 + 6 files changed, 436 insertions(+), 140 deletions(-) create mode 100644 wp-includes/class-wp-taxonomy.php diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php index f3799b4ec3..35edf541b6 100644 --- a/wp-admin/includes/ajax-actions.php +++ b/wp-admin/includes/ajax-actions.php @@ -134,9 +134,9 @@ function wp_ajax_ajax_tag_search() { * * @since 4.0.0 * - * @param int $characters The minimum number of characters required. Default 2. - * @param object $tax The taxonomy object. - * @param string $s The search term. + * @param int $characters The minimum number of characters required. Default 2. + * @param WP_Taxonomy $tax The taxonomy object. + * @param string $s The search term. */ $term_search_min_chars = (int) apply_filters( 'term_search_min_chars', 2, $tax, $s ); diff --git a/wp-includes/class-wp-taxonomy.php b/wp-includes/class-wp-taxonomy.php new file mode 100644 index 0000000000..4611ce9744 --- /dev/null +++ b/wp-includes/class-wp-taxonomy.php @@ -0,0 +1,416 @@ +name = $taxonomy; + + $this->set_props( $object_type, $args ); + } + + /** + * Sets taxonomy properties. + * + * @since 4.7.0 + * @access public + * + * @param array|string $object_type Name of the object type for the taxonomy object. + * @param array|string $args Array or query string of arguments for registering a taxonomy. + */ + public function set_props( $object_type, $args ) { + $args = wp_parse_args( $args ); + + /** + * Filters the arguments for registering a taxonomy. + * + * @since 4.4.0 + * + * @param array $args Array of arguments for registering a taxonomy. + * @param string $taxonomy Taxonomy key. + * @param array $object_type Array of names of object types for the taxonomy. + */ + $args = apply_filters( 'register_taxonomy_args', $args, $this->name, (array) $object_type ); + + $defaults = array( + 'labels' => array(), + 'description' => '', + 'public' => true, + 'publicly_queryable' => null, + 'hierarchical' => false, + 'show_ui' => null, + 'show_in_menu' => null, + 'show_in_nav_menus' => null, + 'show_tagcloud' => null, + 'show_in_quick_edit' => null, + 'show_admin_column' => false, + 'meta_box_cb' => null, + 'capabilities' => array(), + 'rewrite' => true, + 'query_var' => $this->name, + 'update_count_callback' => '', + '_builtin' => false, + ); + + $args = array_merge( $defaults, $args ); + + // If not set, default to the setting for public. + if ( null === $args['publicly_queryable'] ) { + $args['publicly_queryable'] = $args['public']; + } + + if ( false !== $args['query_var'] && ( is_admin() || false !== $args['publicly_queryable'] ) ) { + if ( true === $args['query_var'] ) { + $args['query_var'] = $this->name; + } else { + $args['query_var'] = sanitize_title_with_dashes( $args['query_var'] ); + } + } else { + // Force query_var to false for non-public taxonomies. + $args['query_var'] = false; + } + + if ( false !== $args['rewrite'] && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) { + $args['rewrite'] = wp_parse_args( $args['rewrite'], array( + 'with_front' => true, + 'hierarchical' => false, + 'ep_mask' => EP_NONE, + ) ); + + if ( empty( $args['rewrite']['slug'] ) ) { + $args['rewrite']['slug'] = sanitize_title_with_dashes( $this->name ); + } + } + + // If not set, default to the setting for public. + if ( null === $args['show_ui'] ) { + $args['show_ui'] = $args['public']; + } + + // If not set, default to the setting for show_ui. + if ( null === $args['show_in_menu'] || ! $args['show_ui'] ) { + $args['show_in_menu'] = $args['show_ui']; + } + + // If not set, default to the setting for public. + if ( null === $args['show_in_nav_menus'] ) { + $args['show_in_nav_menus'] = $args['public']; + } + + // If not set, default to the setting for show_ui. + if ( null === $args['show_tagcloud'] ) { + $args['show_tagcloud'] = $args['show_ui']; + } + + // If not set, default to the setting for show_ui. + if ( null === $args['show_in_quick_edit'] ) { + $args['show_in_quick_edit'] = $args['show_ui']; + } + + $default_caps = array( + 'manage_terms' => 'manage_categories', + 'edit_terms' => 'manage_categories', + 'delete_terms' => 'manage_categories', + 'assign_terms' => 'edit_posts', + ); + + $args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] ); + unset( $args['capabilities'] ); + + $args['object_type'] = array_unique( (array) $object_type ); + + // If not set, use the default meta box + if ( null === $args['meta_box_cb'] ) { + if ( $args['hierarchical'] ) { + $args['meta_box_cb'] = 'post_categories_meta_box'; + } else { + $args['meta_box_cb'] = 'post_tags_meta_box'; + } + } + + foreach ( $args as $property_name => $property_value ) { + $this->$property_name = $property_value; + } + + $this->labels = get_taxonomy_labels( $this ); + $this->label = $this->labels->name; + } + + /** + * Adds the necessary rewrite rules for the taxonomy. + * + * @since 4.7.0 + * @access public + * + * @global WP $wp Current WordPress environment instance. + */ + public function add_rewrite_rules() { + /* @var WP $wp */ + global $wp; + + // Non-publicly queryable taxonomies should not register query vars, except in the admin. + if ( false !== $this->query_var && $wp ) { + $wp->add_query_var( $this->query_var ); + } + + if ( false !== $this->rewrite && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) { + if ( $this->hierarchical && $this->rewrite['hierarchical'] ) { + $tag = '(.+?)'; + } else { + $tag = '([^/]+)'; + } + + add_rewrite_tag( "%$this->name%", $tag, $this->query_var ? "{$this->query_var}=" : "taxonomy=$this->name&term=" ); + add_permastruct( $this->name, "{$this->rewrite['slug']}/%$this->name%", $this->rewrite ); + } + } + + /** + * Removes any rewrite rules, permastructs, and rules for the taxonomy. + * + * @since 4.7.0 + * @access public + * + * @global WP $wp Current WordPress environment instance. + */ + public function remove_rewrite_rules() { + /* @var WP $wp */ + global $wp; + + // Remove query var. + if ( false !== $this->query_var ) { + $wp->remove_query_var( $this->query_var ); + } + + // Remove rewrite tags and permastructs. + if ( false !== $this->rewrite ) { + remove_rewrite_tag( "%$this->name%" ); + remove_permastruct( $this->name ); + } + } + + /** + * Registers the ajax callback for the meta box. + * + * @since 4.7.0 + * @access public + */ + public function add_hooks() { + add_filter( 'wp_ajax_add-' . $this->name, '_wp_ajax_add_hierarchical_term' ); + } + + /** + * Removes the ajax callback for the meta box. + * + * @since 4.7.0 + * @access public + */ + public function remove_hooks() { + remove_filter( 'wp_ajax_add-' . $this->name, '_wp_ajax_add_hierarchical_term' ); + } +} diff --git a/wp-includes/class-wp-xmlrpc-server.php b/wp-includes/class-wp-xmlrpc-server.php index 528c74bf46..861a0e8b68 100644 --- a/wp-includes/class-wp-xmlrpc-server.php +++ b/wp-includes/class-wp-xmlrpc-server.php @@ -717,9 +717,9 @@ class wp_xmlrpc_server extends IXR_Server { * * @since 3.4.0 * - * @param array $_taxonomy An array of taxonomy data. - * @param object $taxonomy Taxonomy object. - * @param array $fields The subset of taxonomy fields to return. + * @param array $_taxonomy An array of taxonomy data. + * @param WP_Taxonomy $taxonomy Taxonomy object. + * @param array $fields The subset of taxonomy fields to return. */ return apply_filters( 'xmlrpc_prepare_taxonomy', $_taxonomy, $taxonomy, $fields ); } diff --git a/wp-includes/taxonomy.php b/wp-includes/taxonomy.php index 73b769cbc9..12efa5a995 100644 --- a/wp-includes/taxonomy.php +++ b/wp-includes/taxonomy.php @@ -223,7 +223,7 @@ function get_object_taxonomies( $object, $output = 'names' ) { * @global array $wp_taxonomies The registered taxonomies. * * @param string $taxonomy Name of taxonomy object to return. - * @return object|false The Taxonomy Object or false if $taxonomy doesn't exist. + * @return WP_Taxonomy|false The Taxonomy Object or false if $taxonomy doesn't exist. */ function get_taxonomy( $taxonomy ) { global $wp_taxonomies; @@ -290,7 +290,6 @@ function is_taxonomy_hierarchical($taxonomy) { * @since 4.5.0 Introduced `publicly_queryable` argument. * * @global array $wp_taxonomies Registered taxonomies. - * @global WP $wp WP instance. * * @param string $taxonomy Taxonomy key, must not exceed 32 characters. * @param array|string $object_type Object type or array of object types with which the taxonomy should be associated. @@ -359,134 +358,25 @@ function is_taxonomy_hierarchical($taxonomy) { * @return WP_Error|void WP_Error, if errors. */ function register_taxonomy( $taxonomy, $object_type, $args = array() ) { - global $wp_taxonomies, $wp; + global $wp_taxonomies; if ( ! is_array( $wp_taxonomies ) ) $wp_taxonomies = array(); $args = wp_parse_args( $args ); - /** - * Filters the arguments for registering a taxonomy. - * - * @since 4.4.0 - * - * @param array $args Array of arguments for registering a taxonomy. - * @param string $taxonomy Taxonomy key. - * @param array $object_type Array of names of object types for the taxonomy. - */ - $args = apply_filters( 'register_taxonomy_args', $args, $taxonomy, (array) $object_type ); - - $defaults = array( - 'labels' => array(), - 'description' => '', - 'public' => true, - 'publicly_queryable' => null, - 'hierarchical' => false, - 'show_ui' => null, - 'show_in_menu' => null, - 'show_in_nav_menus' => null, - 'show_tagcloud' => null, - 'show_in_quick_edit' => null, - 'show_admin_column' => false, - 'meta_box_cb' => null, - 'capabilities' => array(), - 'rewrite' => true, - 'query_var' => $taxonomy, - 'update_count_callback' => '', - '_builtin' => false, - ); - $args = array_merge( $defaults, $args ); - if ( empty( $taxonomy ) || strlen( $taxonomy ) > 32 ) { _doing_it_wrong( __FUNCTION__, __( 'Taxonomy names must be between 1 and 32 characters in length.' ), '4.2.0' ); return new WP_Error( 'taxonomy_length_invalid', __( 'Taxonomy names must be between 1 and 32 characters in length.' ) ); } - // If not set, default to the setting for public. - if ( null === $args['publicly_queryable'] ) { - $args['publicly_queryable'] = $args['public']; - } + $taxonomy_object = new WP_Taxonomy( $taxonomy, $object_type, $args ); + $taxonomy_object->add_rewrite_rules(); - // Non-publicly queryable taxonomies should not register query vars, except in the admin. - if ( false !== $args['query_var'] && ( is_admin() || false !== $args['publicly_queryable'] ) && ! empty( $wp ) ) { - if ( true === $args['query_var'] ) - $args['query_var'] = $taxonomy; - else - $args['query_var'] = sanitize_title_with_dashes( $args['query_var'] ); - $wp->add_query_var( $args['query_var'] ); - } else { - // Force query_var to false for non-public taxonomies. - $args['query_var'] = false; - } + $wp_taxonomies[ $taxonomy ] = $taxonomy_object; - if ( false !== $args['rewrite'] && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) { - $args['rewrite'] = wp_parse_args( $args['rewrite'], array( - 'with_front' => true, - 'hierarchical' => false, - 'ep_mask' => EP_NONE, - ) ); + $taxonomy_object->add_hooks(); - if ( empty( $args['rewrite']['slug'] ) ) - $args['rewrite']['slug'] = sanitize_title_with_dashes( $taxonomy ); - - if ( $args['hierarchical'] && $args['rewrite']['hierarchical'] ) - $tag = '(.+?)'; - else - $tag = '([^/]+)'; - - add_rewrite_tag( "%$taxonomy%", $tag, $args['query_var'] ? "{$args['query_var']}=" : "taxonomy=$taxonomy&term=" ); - add_permastruct( $taxonomy, "{$args['rewrite']['slug']}/%$taxonomy%", $args['rewrite'] ); - } - - // If not set, default to the setting for public. - if ( null === $args['show_ui'] ) - $args['show_ui'] = $args['public']; - - // If not set, default to the setting for show_ui. - if ( null === $args['show_in_menu' ] || ! $args['show_ui'] ) - $args['show_in_menu' ] = $args['show_ui']; - - // If not set, default to the setting for public. - if ( null === $args['show_in_nav_menus'] ) - $args['show_in_nav_menus'] = $args['public']; - - // If not set, default to the setting for show_ui. - if ( null === $args['show_tagcloud'] ) - $args['show_tagcloud'] = $args['show_ui']; - - // If not set, default to the setting for show_ui. - if ( null === $args['show_in_quick_edit'] ) { - $args['show_in_quick_edit'] = $args['show_ui']; - } - - $default_caps = array( - 'manage_terms' => 'manage_categories', - 'edit_terms' => 'manage_categories', - 'delete_terms' => 'manage_categories', - 'assign_terms' => 'edit_posts', - ); - $args['cap'] = (object) array_merge( $default_caps, $args['capabilities'] ); - unset( $args['capabilities'] ); - - $args['name'] = $taxonomy; - $args['object_type'] = array_unique( (array) $object_type ); - - $args['labels'] = get_taxonomy_labels( (object) $args ); - $args['label'] = $args['labels']->name; - - // If not set, use the default meta box - if ( null === $args['meta_box_cb'] ) { - if ( $args['hierarchical'] ) - $args['meta_box_cb'] = 'post_categories_meta_box'; - else - $args['meta_box_cb'] = 'post_tags_meta_box'; - } - - $wp_taxonomies[ $taxonomy ] = (object) $args; - - // Register callback handling for meta box. - add_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' ); /** * Fires after a taxonomy is registered. @@ -518,28 +408,17 @@ function unregister_taxonomy( $taxonomy ) { return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) ); } - $taxonomy_args = get_taxonomy( $taxonomy ); + $taxonomy_object = get_taxonomy( $taxonomy ); // Do not allow unregistering internal taxonomies. - if ( $taxonomy_args->_builtin ) { + if ( $taxonomy_object->_builtin ) { return new WP_Error( 'invalid_taxonomy', __( 'Unregistering a built-in taxonomy is not allowed' ) ); } - global $wp, $wp_taxonomies; + global $wp_taxonomies; - // Remove query var. - if ( false !== $taxonomy_args->query_var ) { - $wp->remove_query_var( $taxonomy_args->query_var ); - } - - // Remove rewrite tags and permastructs. - if ( false !== $taxonomy_args->rewrite ) { - remove_rewrite_tag( "%$taxonomy%" ); - remove_permastruct( $taxonomy ); - } - - // Unregister callback handling for meta box. - remove_filter( 'wp_ajax_add-' . $taxonomy, '_wp_ajax_add_hierarchical_term' ); + $taxonomy_object->remove_rewrite_rules(); + $taxonomy_object->remove_hooks(); // Remove the taxonomy. unset( $wp_taxonomies[ $taxonomy ] ); @@ -589,7 +468,7 @@ function unregister_taxonomy( $taxonomy ) { * @since 4.3.0 Added the `no_terms` label. * @since 4.4.0 Added the `items_list_navigation` and `items_list` labels. * - * @param object $tax Taxonomy object. + * @param WP_Taxonomy $tax Taxonomy object. * @return object object with all the labels as member variables. */ function get_taxonomy_labels( $tax ) { diff --git a/wp-includes/version.php b/wp-includes/version.php index 510c10d914..26abcec457 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -4,7 +4,7 @@ * * @global string $wp_version */ -$wp_version = '4.7-alpha-38746'; +$wp_version = '4.7-alpha-38747'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. diff --git a/wp-settings.php b/wp-settings.php index 80f556c334..6ff4ab4ccc 100644 --- a/wp-settings.php +++ b/wp-settings.php @@ -187,6 +187,7 @@ require( ABSPATH . WPINC . '/cron.php' ); require( ABSPATH . WPINC . '/deprecated.php' ); require( ABSPATH . WPINC . '/script-loader.php' ); require( ABSPATH . WPINC . '/taxonomy.php' ); +require( ABSPATH . WPINC . '/class-wp-taxonomy.php' ); require( ABSPATH . WPINC . '/class-wp-term.php' ); require( ABSPATH . WPINC . '/class-wp-term-query.php' ); require( ABSPATH . WPINC . '/class-wp-tax-query.php' );