Changeset 34704
- Timestamp:
- 09/29/2015 09:59:44 PM (10 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/default-filters.php
r34685 r34704 202 202 add_filter( 'title_save_pre', 'trim' ); 203 203 add_filter( 'get_comment_metadata', 'wp_lazyload_comment_meta', 10, 2 ); 204 add_filter( 'get_term_metadata', 'wp_lazyload_term_meta', 10, 2 );205 204 206 205 add_filter( 'http_request_host_is_external', 'allowed_http_request_hosts', 10, 2 ); -
trunk/src/wp-includes/query.php
r34697 r34704 1302 1302 */ 1303 1303 public $thumbnails_cached = false; 1304 1305 /** 1306 * Whether the term meta cache for matched posts has been primed. 1307 * 1308 * @since 4.4.0 1309 * @access protected 1310 * @var bool 1311 */ 1312 public $updated_term_meta_cache = false; 1304 1313 1305 1314 /** … … 3542 3551 $this->posts = array_map( 'get_post', $this->posts ); 3543 3552 3553 3554 if ( $q['update_post_term_cache'] ) { 3555 add_action( 'get_term_metadata', array( $this, 'lazyload_term_meta' ), 10, 2 ); 3556 } 3557 3544 3558 if ( ! $q['suppress_filters'] ) { 3545 3559 /** … … 4723 4737 } 4724 4738 } 4739 4740 /** 4741 * Lazy-loads termmeta for located posts. 4742 * 4743 * As a rule, term queries (`get_terms()` and `wp_get_object_terms()`) prime the metadata cache for matched 4744 * terms by default. However, this can cause a slight performance penalty, especially when that metadata is 4745 * not actually used. In the context of a `WP_Query` instance, we're able to avoid this potential penalty. 4746 * `update_object_term_cache()`, called from `update_post_caches()`, does not 'update_term_meta_cache'. 4747 * Instead, the first time `get_term_meta()` is called from within a `WP_Query` loop, the current method 4748 * detects the fact, and then primes the metadata cache for all terms attached to all posts in the loop, 4749 * with a single database query. 4750 * 4751 * This method is public so that it can be used as a filter callback. As a rule, there is no need to invoke it 4752 * directly, from either inside or outside the `WP_Query` object. 4753 * 4754 * @since 4.4.0 4755 * @access public 4756 * 4757 * @param null $check The `$check` param passed from the 'pre_term_metadata' hook. 4758 * @param int $term_id ID of the term whose metadata is being cached. 4759 * @return mixed In order not to short-circuit `get_metadata()`. Generally, this is `null`, but it could be 4760 * another value if filtered by a plugin. 4761 */ 4762 public function lazyload_term_meta( $check, $term_id ) { 4763 /* 4764 * We only do this once per `WP_Query` instance. 4765 * Can't use `remove_action()` because of non-unique object hashes. 4766 */ 4767 if ( $this->updated_term_meta_cache ) { 4768 return $check; 4769 } 4770 4771 // We can only lazyload if the entire post object is present. 4772 $posts = array(); 4773 foreach ( $this->posts as $post ) { 4774 if ( $post instanceof WP_Post ) { 4775 $posts[] = $post; 4776 } 4777 } 4778 $_p = array(); 4779 foreach ( $posts as $post ) { 4780 $_p[] = $post->ID; 4781 } 4782 4783 if ( ! empty( $posts ) ) { 4784 // Fetch cached term_ids for each post. Keyed by term_id for faster lookup. 4785 $term_ids = array(); 4786 foreach ( $posts as $post ) { 4787 $taxonomies = get_object_taxonomies( $post->post_type ); 4788 foreach ( $taxonomies as $taxonomy ) { 4789 // Term cache should already be primed by 'update_post_term_cache'. 4790 $terms = get_object_term_cache( $post->ID, $taxonomy ); 4791 if ( false !== $terms ) { 4792 foreach ( $terms as $term ) { 4793 if ( ! isset( $term_ids[ $term->term_id ] ) ) { 4794 $term_ids[ $term->term_id ] = 1; 4795 } 4796 } 4797 } 4798 } 4799 } 4800 4801 /* 4802 * Only update the metadata cache for terms belonging to these posts if the term_id passed 4803 * to `get_term_meta()` matches one of those terms. This prevents a single call to 4804 * `get_term_meta()` from priming metadata for all `WP_Query` objects. 4805 */ 4806 if ( isset( $term_ids[ $term_id ] ) ) { 4807 update_termmeta_cache( array_keys( $term_ids ) ); 4808 $this->updated_term_meta_cache = true; 4809 } 4810 } 4811 4812 // If no terms were found, there's no need to run this again. 4813 if ( empty( $term_ids ) ) { 4814 $this->updated_term_meta_cache = true; 4815 } 4816 4817 return $check; 4818 } 4725 4819 } 4726 4820 -
trunk/src/wp-includes/taxonomy-functions.php
r34679 r34704 1590 1590 1591 1591 /** 1592 * Lazy-loads termmeta when inside of a `WP_Query` loop.1593 *1594 * As a rule, term queries (`get_terms()` and `wp_get_object_terms()`) prime the metadata cache for matched terms by1595 * default. However, this can cause a slight performance penalty, especially when that metadata is not actually used.1596 * In the context of a `WP_Query` loop, we're able to avoid this potential penalty. `update_object_term_cache()`,1597 * called from `update_post_caches()`, does not 'update_term_meta_cache'. Instead, the first time `get_term_meta()` is1598 * called from within a `WP_Query` loop, the current function detects the fact, and then primes the metadata cache for1599 * all terms attached to all posts in the loop, with a single database query.1600 *1601 * @since 4.4.01602 *1603 * @param null $check The `$check` param passed from the 'pre_term_metadata' hook.1604 * @param int $term_id ID of the term whose metadata is being cached.1605 * @return null In order not to short-circuit `get_metadata()`.1606 */1607 function wp_lazyload_term_meta( $check, $term_id ) {1608 global $wp_query;1609 1610 if ( $wp_query instanceof WP_Query && ! empty( $wp_query->posts ) && $wp_query->get( 'update_post_term_cache' ) ) {1611 // We can only lazyload if the entire post object is present.1612 $posts = array();1613 foreach ( $wp_query->posts as $post ) {1614 if ( $post instanceof WP_Post ) {1615 $posts[] = $post;1616 }1617 }1618 1619 if ( empty( $posts ) ) {1620 return;1621 }1622 1623 // Fetch cached term_ids for each post. Keyed by term_id for faster lookup.1624 $term_ids = array();1625 foreach ( $posts as $post ) {1626 $taxonomies = get_object_taxonomies( $post->post_type );1627 foreach ( $taxonomies as $taxonomy ) {1628 // No extra queries. Term cache should already be primed by 'update_post_term_cache'.1629 $terms = get_object_term_cache( $post->ID, $taxonomy );1630 if ( false !== $terms ) {1631 foreach ( $terms as $term ) {1632 if ( ! isset( $term_ids[ $term->term_id ] ) ) {1633 $term_ids[ $term->term_id ] = 1;1634 }1635 }1636 }1637 }1638 }1639 1640 if ( $term_ids ) {1641 update_termmeta_cache( array_keys( $term_ids ) );1642 }1643 }1644 1645 return $check;1646 }1647 1648 /**1649 1592 * Check if Term exists. 1650 1593 * -
trunk/tests/phpunit/tests/term/meta.php
r34538 r34704 146 146 } 147 147 148 /** 149 * @ticket 34073 150 */ 151 public function test_term_meta_should_be_lazy_loaded_only_for_the_queries_in_which_the_term_has_posts() { 152 global $wpdb; 153 154 $posts = $this->factory->post->create_many( 3, array( 'post_status' => 'publish' ) ); 155 register_taxonomy( 'wptests_tax', 'post' ); 156 $terms = $this->factory->term->create_many( 6, array( 'taxonomy' => 'wptests_tax' ) ); 157 158 wp_set_object_terms( $posts[0], array( $terms[0], $terms[1] ), 'wptests_tax' ); 159 wp_set_object_terms( $posts[1], array( $terms[2], $terms[3] ), 'wptests_tax' ); 160 wp_set_object_terms( $posts[2], array( $terms[0], $terms[4], $terms[5] ), 'wptests_tax' ); 161 162 foreach ( $terms as $t ) { 163 add_term_meta( $t, 'foo', 'bar' ); 164 } 165 166 $q0 = new WP_Query( array( 'p' => $posts[0] ) ); 167 $q1 = new WP_Query( array( 'p' => $posts[1] ) ); 168 $q2 = new WP_Query( array( 'p' => $posts[2] ) ); 169 170 /* 171 * $terms[0] belongs to both $posts[0] and $posts[2], so `get_term_meta( $terms[0] )` should prime 172 * the cache for term matched by $q0 and $q2. 173 */ 174 175 // First request will hit the database. 176 $num_queries = $wpdb->num_queries; 177 178 // Prime caches. 179 $this->assertSame( 'bar', get_term_meta( $terms[0], 'foo', true ) ); 180 181 // Two queries: one for $q0 and one for $q2. 182 $num_queries += 2; 183 $this->assertSame( $num_queries, $wpdb->num_queries ); 184 185 // Next requests should be in cache. 186 $this->assertSame( 'bar', get_term_meta( $terms[1], 'foo', true ) ); 187 $this->assertSame( 'bar', get_term_meta( $terms[4], 'foo', true ) ); 188 $this->assertSame( 'bar', get_term_meta( $terms[5], 'foo', true ) ); 189 $this->assertSame( $num_queries, $wpdb->num_queries ); 190 191 // Querying for $terms[2] will prime $terms[3] as well. 192 $this->assertSame( 'bar', get_term_meta( $terms[2], 'foo', true ) ); 193 $num_queries++; 194 $this->assertSame( $num_queries, $wpdb->num_queries ); 195 196 $this->assertSame( 'bar', get_term_meta( $terms[3], 'foo', true ) ); 197 $this->assertSame( $num_queries, $wpdb->num_queries ); 198 } 199 148 200 public function test_adding_term_meta_should_bust_get_terms_cache() { 149 201 $terms = $this->factory->term->create_many( 2, array( 'taxonomy' => 'wptests_tax' ) );
Note: See TracChangeset
for help on using the changeset viewer.