Make WordPress Core


Ignore:
Timestamp:
07/14/2015 07:08:40 AM (10 years ago)
Author:
westonruter
Message:

Customizer: Improve performance of menus by caching results of wp_setup_nav_menu_item() calls.

Also fixes property list in phpdoc for wp_setup_nav_menu_item().

Fixes #32769.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-customize-setting.php

    r33221 r33256  
    702702     * A negative value represents a placeholder ID for a new menu not yet saved.
    703703     *
    704      * @todo Should this be $db_id, and also use this for WP_Customize_Nav_Menu_Setting::$term_id
    705      *
    706704     * @since 4.3.0
    707705     * @access public
     
    709707     */
    710708    public $post_id;
     709
     710    /**
     711     * Storage of pre-setup menu item to prevent wasted calls to wp_setup_nav_menu_item().
     712     *
     713     * @since 4.3.0
     714     * @access protected
     715     * @var array
     716     */
     717    protected $value;
    711718
    712719    /**
     
    807814
    808815        $this->post_id = intval( $matches['id'] );
    809 
    810         $menu = $this->value();
    811         $this->original_nav_menu_term_id = $menu['nav_menu_term_id'];
     816        add_action( 'wp_update_nav_menu_item', array( $this, 'flush_cached_value' ), 10, 2 );
    812817
    813818        parent::__construct( $manager, $id, $args );
     819
     820        // Ensure that an initially-supplied value is valid.
     821        if ( isset( $this->value ) ) {
     822            $this->populate_value();
     823            foreach ( array_diff( array_keys( $this->default ), array_keys( $this->value ) ) as $missing ) {
     824                throw new Exception( "Supplied nav_menu_item value missing property: $missing" );
     825            }
     826        }
     827
     828    }
     829
     830    /**
     831     * Clear the cached value when this nav menu item is updated.
     832     *
     833     * @since 4.3.0
     834     * @access public
     835     *
     836     * @param int $menu_id       The term ID for the menu.
     837     * @param int $menu_item_id  The post ID for the menu item.
     838     */
     839    public function flush_cached_value( $menu_id, $menu_item_id ) {
     840        unset( $menu_id );
     841        if ( $menu_item_id === $this->post_id ) {
     842            $this->value = null;
     843        }
    814844    }
    815845
     
    822852     * @see wp_setup_nav_menu_item()
    823853     *
    824      * @return array Instance data.
     854     * @return array|false Instance data array, or false if the item is marked for deletion.
    825855     */
    826856    public function value() {
     
    834864                $value = $post_value;
    835865            }
     866        } else if ( isset( $this->value ) ) {
     867            $value = $this->value;
    836868        } else {
    837869            $value = false;
     
    841873                $post = get_post( $this->post_id );
    842874                if ( $post && self::POST_TYPE === $post->post_type ) {
    843                     $item  = wp_setup_nav_menu_item( $post );
    844                     $value = wp_array_slice_assoc(
    845                         (array) $item,
    846                         array_keys( $this->default )
    847                     );
    848                     $value['position']       = $item->menu_order;
    849                     $value['status']         = $item->post_status;
    850                     $value['original_title'] = '';
    851 
    852                     $menus = wp_get_post_terms( $post->ID, WP_Customize_Nav_Menu_Setting::TAXONOMY, array(
    853                         'fields' => 'ids',
    854                     ) );
    855 
    856                     if ( ! empty( $menus ) ) {
    857                         $value['nav_menu_term_id'] = array_shift( $menus );
    858                     } else {
    859                         $value['nav_menu_term_id'] = 0;
    860                     }
    861 
    862                     if ( 'post_type' === $value['type'] ) {
    863                         $original_title = get_the_title( $value['object_id'] );
    864                     } elseif ( 'taxonomy' === $value['type'] ) {
    865                         $original_title = get_term_field( 'name', $value['object_id'], $value['object'], 'raw' );
    866                         if ( is_wp_error( $original_title ) ) {
    867                             $original_title = '';
    868                         }
    869                     }
    870 
    871                     if ( ! empty( $original_title ) ) {
    872                         $value['original_title'] = html_entity_decode( $original_title, ENT_QUOTES, get_bloginfo( 'charset' ) );
    873                     }
     875                    $value = (array) wp_setup_nav_menu_item( $post );
    874876                }
    875877            }
     
    878880                $value = $this->default;
    879881            }
    880         }
    881 
    882         if ( is_array( $value ) ) {
    883             foreach ( array( 'object_id', 'menu_item_parent', 'nav_menu_term_id' ) as $key ) {
    884                 $value[ $key ] = intval( $value[ $key ] );
    885             }
     882
     883            // Cache the value for future calls to avoid having to re-call wp_setup_nav_menu_item().
     884            $this->value = $value;
     885            $this->populate_value();
     886            $value = $this->value;
    886887        }
    887888
    888889        return $value;
     890    }
     891
     892    /**
     893     * Ensure that the value is fully populated with the necessary properties.
     894     *
     895     * Translates some properties added by wp_setup_nav_menu_item() and removes others.
     896     *
     897     * @since 4.3.0
     898     * @access protected
     899     *
     900     * @see WP_Customize_Nav_Menu_Item_Setting::value()
     901     */
     902    protected function populate_value() {
     903        if ( ! is_array( $this->value ) ) {
     904            return;
     905        }
     906
     907        if ( isset( $this->value['menu_order'] ) ) {
     908            $this->value['position'] = $this->value['menu_order'];
     909            unset( $this->value['menu_order'] );
     910        }
     911        if ( isset( $this->value['post_status'] ) ) {
     912            $this->value['status'] = $this->value['post_status'];
     913            unset( $this->value['post_status'] );
     914        }
     915
     916        if ( ! isset( $this->value['original_title'] ) ) {
     917            $original_title = '';
     918            if ( 'post_type' === $this->value['type'] ) {
     919                $original_title = get_the_title( $this->value['object_id'] );
     920            } elseif ( 'taxonomy' === $this->value['type'] ) {
     921                $original_title = get_term_field( 'name', $this->value['object_id'], $this->value['object'], 'raw' );
     922                if ( is_wp_error( $original_title ) ) {
     923                    $original_title = '';
     924                }
     925            }
     926            $this->value['original_title'] = html_entity_decode( $original_title, ENT_QUOTES, get_bloginfo( 'charset' ) );
     927        }
     928
     929        if ( ! isset( $this->value['nav_menu_term_id'] ) && $this->post_id > 0 ) {
     930            $menus = wp_get_post_terms( $this->post_id, WP_Customize_Nav_Menu_Setting::TAXONOMY, array(
     931                'fields' => 'ids',
     932            ) );
     933            if ( ! empty( $menus ) ) {
     934                $this->value['nav_menu_term_id'] = array_shift( $menus );
     935            } else {
     936                $this->value['nav_menu_term_id'] = 0;
     937            }
     938        }
     939
     940        foreach ( array( 'object_id', 'menu_item_parent', 'nav_menu_term_id' ) as $key ) {
     941            if ( ! is_int( $this->value[ $key ] ) ) {
     942                $this->value[ $key ] = intval( $this->value[ $key ] );
     943            }
     944        }
     945
     946        // Remove remaining properties available on a setup nav_menu_item post object which aren't relevant to the setting value.
     947        $irrelevant_properties = array(
     948            'ID',
     949            'comment_count',
     950            'comment_status',
     951            'db_id',
     952            'filter',
     953            'guid',
     954            'ping_status',
     955            'pinged',
     956            'post_author',
     957            'post_content',
     958            'post_content_filtered',
     959            'post_date',
     960            'post_date_gmt',
     961            'post_excerpt',
     962            'post_mime_type',
     963            'post_modified',
     964            'post_modified_gmt',
     965            'post_name',
     966            'post_parent',
     967            'post_password',
     968            'post_title',
     969            'post_type',
     970            'to_ping',
     971            'type_label',
     972        );
     973        foreach ( $irrelevant_properties as $property ) {
     974            unset( $this->value[ $property ] );
     975        }
    889976    }
    890977
     
    10441131        unset( $item->position );
    10451132
    1046         $item->post_author = get_current_user_id();
    1047 
    10481133        if ( $item->title ) {
    10491134            $item->post_title = $item->title;
     
    10511136
    10521137        $item->ID = $this->post_id;
     1138        $item->db_id = $this->post_id;
    10531139        $post = new WP_Post( (object) $item );
    1054         $post = wp_setup_nav_menu_item( $post );
    1055 
     1140
     1141        if ( empty( $post->post_author ) ) {
     1142            $post->post_author = get_current_user_id();
     1143        }
     1144
     1145        if ( ! isset( $post->type_label ) ) {
     1146            $post->type_label = null;
     1147        }
    10561148        return $post;
    10571149    }
     
    11611253        $is_delete        = ( false === $value );
    11621254
     1255        // Update the cached value.
     1256        $this->value = $value;
     1257
    11631258        add_filter( 'customize_save_response', array( $this, 'amend_customize_save_response' ) );
    11641259
Note: See TracChangeset for help on using the changeset viewer.