mirror of
https://github.com/WordPress/WordPress.git
synced 2024-11-12 13:44:21 +01:00
Introduce metadata for taxonomy terms.
Adds a new table to the database schema (`wp_termmeta`), and a set of `*_term_meta()` API functions. `get_terms()` and `wp_get_object_terms()` now also support 'meta_query' parameters, with syntax identical to other uses of `WP_Meta_Query`. When fetching terms via `get_terms()` or `wp_get_object_terms()`, metadata for matched terms is preloaded into the cache by default. Disable this behavior by setting the new `$update_term_meta_cache` paramater to `false`. To maximize performance, within `WP_Query` loops, the termmeta cache is *not* primed by default. Instead, we use a lazy-loading technique: metadata for all terms belonging to posts in the loop is loaded into the cache the first time that `get_term_meta()` is called within the loop. Props boonebgorges, sirzooro. See #10142. Built from https://develop.svn.wordpress.org/trunk@34529 git-svn-id: http://core.svn.wordpress.org/trunk@34493 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
80974b0db6
commit
8b4a5d1ec0
@ -57,7 +57,16 @@ function wp_get_db_schema( $scope = 'all', $blog_id = null ) {
|
||||
$max_index_length = 191;
|
||||
|
||||
// Blog specific tables.
|
||||
$blog_tables = "CREATE TABLE $wpdb->terms (
|
||||
$blog_tables = "CREATE TABLE $wpdb->termmeta (
|
||||
meta_id bigint(20) unsigned NOT NULL auto_increment,
|
||||
term_id bigint(20) unsigned NOT NULL default '0',
|
||||
meta_key varchar(255) default NULL,
|
||||
meta_value longtext,
|
||||
PRIMARY KEY (meta_id),
|
||||
KEY term_id (term_id),
|
||||
KEY meta_key (meta_key($max_index_length))
|
||||
) $charset_collate;
|
||||
CREATE TABLE $wpdb->terms (
|
||||
term_id bigint(20) unsigned NOT NULL auto_increment,
|
||||
name varchar(200) NOT NULL default '',
|
||||
slug varchar(200) NOT NULL default '',
|
||||
|
@ -2628,6 +2628,14 @@ function pre_schema_upgrade() {
|
||||
$wpdb->query( "ALTER TABLE $wpdb->postmeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" );
|
||||
$wpdb->query( "ALTER TABLE $wpdb->posts DROP INDEX post_name, ADD INDEX post_name(post_name(191))" );
|
||||
}
|
||||
|
||||
// Upgrade versions prior to 4.4.
|
||||
if ( $wp_current_db_version < 34370 ) {
|
||||
// If compatible termmeta table is found, use it, but enforce a proper index.
|
||||
if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->termmeta}'" ) && $wpdb->get_results( "SHOW INDEX FROM {$wpdb->termmeta} WHERE Column_name = 'meta_key'" ) ) {
|
||||
$wpdb->query( "ALTER TABLE $wpdb->termmeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,6 +201,7 @@ add_filter( 'pingback_ping_source_uri', 'pingback_ping_source_uri' );
|
||||
add_filter( 'xmlrpc_pingback_error', 'xmlrpc_pingback_error' );
|
||||
add_filter( 'title_save_pre', 'trim' );
|
||||
add_filter( 'get_comment_metadata', 'wp_lazyload_comment_meta', 10, 2 );
|
||||
add_filter( 'get_term_metadata', 'wp_lazyload_term_meta', 10, 2 );
|
||||
|
||||
add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 );
|
||||
|
||||
|
@ -957,6 +957,7 @@ function get_term_to_edit( $id, $taxonomy ) {
|
||||
* @since 2.3.0
|
||||
* @since 4.2.0 Introduced 'name' and 'childless' parameters.
|
||||
* @since 4.4.0 Introduced the ability to pass 'term_id' as an alias of 'id' for the `orderby` parameter.
|
||||
* Introduced the 'meta_query' and 'update_term_meta_cache' parameters.
|
||||
*
|
||||
* @global wpdb $wpdb WordPress database abstraction object.
|
||||
* @global array $wp_filter
|
||||
@ -1013,6 +1014,9 @@ function get_term_to_edit( $id, $taxonomy ) {
|
||||
* no effect on non-hierarchical taxonomies. Default false.
|
||||
* @type string $cache_domain Unique cache key to be produced when this query is stored in an
|
||||
* object cache. Default is 'core'.
|
||||
* @type bool $update_term_meta_cache Whether to prime meta caches for matched terms. Default true.
|
||||
* @type array $meta_query Meta query clauses to limit retrieved terms by.
|
||||
* See `WP_Meta_Query`. Default empty.
|
||||
* }
|
||||
* @return array|int|WP_Error List of Term Objects and their children. Will return WP_Error, if any of $taxonomies
|
||||
* do not exist.
|
||||
@ -1036,7 +1040,8 @@ function get_terms( $taxonomies, $args = '' ) {
|
||||
'hide_empty' => true, 'exclude' => array(), 'exclude_tree' => array(), 'include' => array(),
|
||||
'number' => '', 'fields' => 'all', 'name' => '', 'slug' => '', 'parent' => '', 'childless' => false,
|
||||
'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'description__like' => '',
|
||||
'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core' );
|
||||
'pad_counts' => false, 'offset' => '', 'search' => '', 'cache_domain' => 'core',
|
||||
'update_term_meta_cache' => true, 'meta_query' => '' );
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
$args['number'] = absint( $args['number'] );
|
||||
$args['offset'] = absint( $args['offset'] );
|
||||
@ -1296,6 +1301,16 @@ function get_terms( $taxonomies, $args = '' ) {
|
||||
$where .= $wpdb->prepare( ' AND ((t.name LIKE %s) OR (t.slug LIKE %s))', $like, $like );
|
||||
}
|
||||
|
||||
// Meta query support.
|
||||
$join = '';
|
||||
if ( ! empty( $args['meta_query'] ) ) {
|
||||
$mquery = new WP_Meta_Query( $args['meta_query'] );
|
||||
$mq_sql = $mquery->get_sql( 'term', 't', 'term_id' );
|
||||
|
||||
$join .= $mq_sql['join'];
|
||||
$where .= $mq_sql['where'];
|
||||
}
|
||||
|
||||
$selects = array();
|
||||
switch ( $args['fields'] ) {
|
||||
case 'all':
|
||||
@ -1341,7 +1356,7 @@ function get_terms( $taxonomies, $args = '' ) {
|
||||
*/
|
||||
$fields = implode( ', ', apply_filters( 'get_terms_fields', $selects, $args, $taxonomies ) );
|
||||
|
||||
$join = "INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
|
||||
$join .= " INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id";
|
||||
|
||||
$pieces = array( 'fields', 'join', 'where', 'orderby', 'order', 'limits' );
|
||||
|
||||
@ -1374,6 +1389,12 @@ function get_terms( $taxonomies, $args = '' ) {
|
||||
update_term_cache( $terms );
|
||||
}
|
||||
|
||||
// Prime termmeta cache.
|
||||
if ( $args['update_term_meta_cache'] ) {
|
||||
$term_ids = wp_list_pluck( $terms, 'term_id' );
|
||||
update_termmeta_cache( $term_ids );
|
||||
}
|
||||
|
||||
if ( empty($terms) ) {
|
||||
wp_cache_add( $cache_key, array(), 'terms', DAY_IN_SECONDS );
|
||||
|
||||
@ -1454,6 +1475,142 @@ function get_terms( $taxonomies, $args = '' ) {
|
||||
return apply_filters( 'get_terms', $terms, $taxonomies, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds metadata to a term.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @param int $term_id Term ID.
|
||||
* @param string $meta_key Metadata name.
|
||||
* @param mixed $meta_value Metadata value.
|
||||
* @param bool $unique Optional. Whether to bail if an entry with the same key is found for the term.
|
||||
* Default false.
|
||||
* @return int|bool Meta ID on success, false on failure.
|
||||
*/
|
||||
function add_term_meta( $term_id, $meta_key, $meta_value, $unique = false ) {
|
||||
return add_metadata( 'term', $term_id, $meta_key, $meta_value, $unique );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes metadata matching criteria from a term.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @param int $term_id Term ID.
|
||||
* @param string $meta_key Metadata name.
|
||||
* @param mixed $meta_value Optional. Metadata value. If provided, rows will only be removed that match the value.
|
||||
* @return bool True on success, false on failure.
|
||||
*/
|
||||
function delete_term_meta( $term_id, $meta_key, $meta_value = '' ) {
|
||||
return delete_metadata( 'term', $term_id, $meta_key, $meta_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves metadata for a term.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @param int $term_id Term ID.
|
||||
* @param string $key Optional. The meta key to retrieve. If no key is provided, fetches all metadata for the term.
|
||||
* @param bool $single Whether to return a single value. If false, an array of all values matching the
|
||||
* `$term_id`/`$key` pair will be returned. Default: false.
|
||||
* @return mixed If `$single` is false, an array of metadata values. If `$single` is true, a single metadata value.
|
||||
*/
|
||||
function get_term_meta( $term_id, $key = '', $single = false ) {
|
||||
return get_metadata( 'term', $term_id, $key, $single );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates term metadata.
|
||||
*
|
||||
* Use the `$prev_value` parameter to differentiate between meta fields with the same key and term ID.
|
||||
*
|
||||
* If the meta field for the term does not exist, it will be added.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @param int $term_id Term ID.
|
||||
* @param string $meta_key Metadata key.
|
||||
* @param mixed $meta_value Metadata value.
|
||||
* @param mixed $prev_value Optional. Previous value to check before removing.
|
||||
* @return int|bool Meta ID if the key didn't previously exist. True on successful update. False on failure.
|
||||
*/
|
||||
function update_term_meta( $term_id, $meta_key, $meta_value, $prev_value = '' ) {
|
||||
return update_metadata( 'term', $term_id, $meta_key, $meta_value, $prev_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates metadata cache for list of term IDs.
|
||||
*
|
||||
* Performs SQL query to retrieve all metadata for the terms matching `$term_ids` and stores them in the cache.
|
||||
* Subsequent calls to `get_term_meta()` will not need to query the database.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @param array $term_ids List of term IDs.
|
||||
* @return array|false Returns false if there is nothing to update. Returns an array of metadata on success.
|
||||
*/
|
||||
function update_termmeta_cache( $term_ids ) {
|
||||
return update_meta_cache( 'term', $term_ids );
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazy-loads termmeta when inside of a `WP_Query` loop.
|
||||
*
|
||||
* As a rule, term queries (`get_terms()` and `wp_get_object_terms()`) prime the metadata cache for matched terms by
|
||||
* default. However, this can cause a slight performance penalty, especially when that metadata is not actually used.
|
||||
* In the context of a `WP_Query` loop, we're able to avoid this potential penalty. `update_object_term_cache()`,
|
||||
* called from `update_post_caches()`, does not 'update_term_meta_cache'. Instead, the first time `get_term_meta()` is
|
||||
* called from within a `WP_Query` loop, the current function detects the fact, and then primes the metadata cache for
|
||||
* all terms attached to all posts in the loop, with a single database query.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @param null $check The `$check` param passed from the 'pre_term_metadata' hook.
|
||||
* @param int $term_id ID of the term whose metadata is being cached.
|
||||
* @return null In order not to short-circuit `get_metadata()`.
|
||||
*/
|
||||
function wp_lazyload_term_meta( $check, $term_id ) {
|
||||
global $wp_query;
|
||||
|
||||
if ( $wp_query instanceof WP_Query && ! empty( $wp_query->posts ) && $wp_query->get( 'update_post_term_cache' ) ) {
|
||||
// We can only lazyload if the entire post object is present.
|
||||
$posts = array();
|
||||
foreach ( $wp_query->posts as $post ) {
|
||||
if ( $post instanceof WP_Post ) {
|
||||
$posts[] = $post;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $posts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch cached term_ids for each post. Keyed by term_id for faster lookup.
|
||||
$term_ids = array();
|
||||
foreach ( $posts as $post ) {
|
||||
$taxonomies = get_object_taxonomies( $post->post_type );
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
// No extra queries. Term cache should already be primed by 'update_post_term_cache'.
|
||||
$terms = get_object_term_cache( $post->ID, $taxonomy );
|
||||
if ( false !== $terms ) {
|
||||
foreach ( $terms as $term ) {
|
||||
if ( ! isset( $term_ids[ $term->term_id ] ) ) {
|
||||
$term_ids[ $term->term_id ] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $term_ids ) {
|
||||
update_termmeta_cache( array_keys( $term_ids ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $check;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Term exists.
|
||||
*
|
||||
@ -2011,6 +2168,7 @@ function wp_delete_category( $cat_ID ) {
|
||||
* @since 2.3.0
|
||||
* @since 4.2.0 Added support for 'taxonomy', 'parent', and 'term_taxonomy_id' values of `$orderby`.
|
||||
* Introduced `$parent` argument.
|
||||
* @since 4.4.0 Introduced `$meta_query` and `$update_term_meta_cache` arguments.
|
||||
*
|
||||
* @global wpdb $wpdb WordPress database abstraction object.
|
||||
*
|
||||
@ -2026,6 +2184,10 @@ function wp_delete_category( $cat_ID ) {
|
||||
* term objects being returned, 'ids' will return an array of integers, and 'names' an array
|
||||
* of strings.
|
||||
* @type int $parent Optional. Limit results to the direct children of a given term ID.
|
||||
* @type bool $update_term_meta_cache Whether to prime termmeta cache for matched terms. Only applies when
|
||||
* `$fields` is 'all', 'all_with_object_id', or 'term_id'. Default true.
|
||||
* @type array $meta_query Meta query clauses to limit retrieved terms by. See `WP_Meta_Query`.
|
||||
* Default empty.
|
||||
* }
|
||||
* @return array|WP_Error The requested term data or empty array if no terms found.
|
||||
* WP_Error if any of the $taxonomies don't exist.
|
||||
@ -2053,6 +2215,8 @@ function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
|
||||
'order' => 'ASC',
|
||||
'fields' => 'all',
|
||||
'parent' => '',
|
||||
'update_term_meta_cache' => true,
|
||||
'meta_query' => '',
|
||||
);
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
@ -2126,9 +2290,21 @@ function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
|
||||
$where[] = $wpdb->prepare( 'tt.parent = %d', $args['parent'] );
|
||||
}
|
||||
|
||||
// Meta query support.
|
||||
$meta_query_join = '';
|
||||
if ( ! empty( $args['meta_query'] ) ) {
|
||||
$mquery = new WP_Meta_Query( $args['meta_query'] );
|
||||
$mq_sql = $mquery->get_sql( 'term', 't', 'term_id' );
|
||||
|
||||
$meta_query_join .= $mq_sql['join'];
|
||||
|
||||
// Strip leading AND.
|
||||
$where[] = preg_replace( '/^\s*AND/', '', $mq_sql['where'] );
|
||||
}
|
||||
|
||||
$where = implode( ' AND ', $where );
|
||||
|
||||
$query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE $where $orderby $order";
|
||||
$query = "SELECT $select_this FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id $meta_query_join WHERE $where $orderby $order";
|
||||
|
||||
$objects = false;
|
||||
if ( 'all' == $fields || 'all_with_object_id' == $fields ) {
|
||||
@ -2153,6 +2329,17 @@ function wp_get_object_terms($object_ids, $taxonomies, $args = array()) {
|
||||
}
|
||||
}
|
||||
|
||||
// Update termmeta cache, if necessary.
|
||||
if ( $args['update_term_meta_cache'] && ( 'all' === $fields || 'all_with_object_ids' === $fields || 'term_id' === $fields ) ) {
|
||||
if ( 'term_id' === $fields ) {
|
||||
$term_ids = $fields;
|
||||
} else {
|
||||
$term_ids = wp_list_pluck( $terms, 'term_id' );
|
||||
}
|
||||
|
||||
update_termmeta_cache( $term_ids );
|
||||
}
|
||||
|
||||
if ( ! $terms ) {
|
||||
$terms = array();
|
||||
} elseif ( $objects && 'all_with_object_id' !== $fields ) {
|
||||
@ -3288,6 +3475,7 @@ function update_object_term_cache($object_ids, $object_type) {
|
||||
$terms = wp_get_object_terms( $ids, $taxonomies, array(
|
||||
'fields' => 'all_with_object_id',
|
||||
'orderby' => 'none',
|
||||
'update_term_meta_cache' => false,
|
||||
) );
|
||||
|
||||
$object_terms = array();
|
||||
|
@ -4,14 +4,14 @@
|
||||
*
|
||||
* @global string $wp_version
|
||||
*/
|
||||
$wp_version = '4.4-alpha-34528';
|
||||
$wp_version = '4.4-alpha-34529';
|
||||
|
||||
/**
|
||||
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.
|
||||
*
|
||||
* @global int $wp_db_version
|
||||
*/
|
||||
$wp_db_version = 34030;
|
||||
$wp_db_version = 34528;
|
||||
|
||||
/**
|
||||
* Holds the TinyMCE version
|
||||
|
@ -266,7 +266,7 @@ class wpdb {
|
||||
* @var array
|
||||
*/
|
||||
var $tables = array( 'posts', 'comments', 'links', 'options', 'postmeta',
|
||||
'terms', 'term_taxonomy', 'term_relationships', 'commentmeta' );
|
||||
'terms', 'term_taxonomy', 'term_relationships', 'termmeta', 'commentmeta' );
|
||||
|
||||
/**
|
||||
* List of deprecated WordPress tables
|
||||
@ -382,6 +382,15 @@ class wpdb {
|
||||
*/
|
||||
public $term_taxonomy;
|
||||
|
||||
/**
|
||||
* WordPress Term Meta table.
|
||||
*
|
||||
* @since 4.4.0
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
public $termmeta;
|
||||
|
||||
/*
|
||||
* Global and Multisite tables
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user