Make WordPress Core


Ignore:
Timestamp:
11/08/2021 07:18:39 PM (2 years ago)
Author:
jorgefilipecosta
Message:

Update theme.json classes for WordPress 5.9.

This commit ports to core the changes to the classes that deal with theme.json code.

See #54336.
Props oandregal, spacedmonkey, noisysocks, hellofromtonya, youknowriad.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-theme-json-resolver.php

    r51693 r52049  
    1212 * for site-level config and offers an API to work with them.
    1313 *
     14 * This class is for internal core usage and is not supposed to be used by extenders (plugins and/or themes).
     15 * This is a low-level API that may need to do breaking changes. Please,
     16 * use get_global_settings, get_global_styles, and get_global_stylesheet instead.
     17 *
    1418 * @access private
    1519 */
     
    4145
    4246    /**
     47     * Container for data coming from the user.
     48     *
     49     * @since 5.9.0
     50     * @var WP_Theme_JSON
     51     */
     52    private static $user = null;
     53
     54    /**
     55     * Stores the ID of the custom post type
     56     * that holds the user data.
     57     *
     58     * @since 5.9.0
     59     * @var integer
     60     */
     61    private static $user_custom_post_type_id = null;
     62
     63    /**
    4364     * Container to keep loaded i18n schema for `theme.json`.
    4465     *
    45      * @since 5.9.0
     66     * @since 5.8.0
     67     * @since 5.9.0 Renamed from $theme_json_i18n
    4668     * @var array
    4769     */
     
    123145     * Returns the theme's data.
    124146     *
    125      * Data from theme.json can be augmented via the $theme_support_data variable.
    126      * This is useful, for example, to backfill the gaps in theme.json that a theme
    127      * has declared via add_theme_supports.
    128      *
    129      * Note that if the same data is present in theme.json and in $theme_support_data,
    130      * the theme.json's is not overwritten.
    131      *
    132      * @since 5.8.0
    133      *
    134      * @param array $theme_support_data Optional. Theme support data in theme.json format.
    135      *                                  Default empty array.
     147     * Data from theme.json will be backfilled from existing
     148     * theme supports, if any. Note that if the same data
     149     * is present in theme.json and in theme supports,
     150     * the theme.json takes precendence.
     151     *
     152     * @since 5.8.0
     153     * @since 5.9.0 Theme supports have been inlined and the argument removed.
     154     *
    136155     * @return WP_Theme_JSON Entity that holds theme data.
    137156     */
    138     public static function get_theme_data( $theme_support_data = array() ) {
     157    public static function get_theme_data( $deprecated = array() ) {
     158        if ( ! empty( $deprecated ) ) {
     159            _deprecated_argument( __METHOD__, '5.9' );
     160        }
    139161        if ( null === self::$theme ) {
    140162            $theme_json_data = self::read_json_file( self::get_file_path_from_theme( 'theme.json' ) );
    141163            $theme_json_data = self::translate( $theme_json_data, wp_get_theme()->get( 'TextDomain' ) );
    142164            self::$theme     = new WP_Theme_JSON( $theme_json_data );
    143         }
    144 
    145         if ( empty( $theme_support_data ) ) {
    146             return self::$theme;
     165
     166            if ( wp_get_theme()->parent() ) {
     167                // Get parent theme.json.
     168                $parent_theme_json_data = self::read_json_file( self::get_file_path_from_theme( 'theme.json', true ) );
     169                $parent_theme_json_data = self::translate( $parent_theme_json_data, wp_get_theme()->parent()->get( 'TextDomain' ) );
     170                $parent_theme           = new WP_Theme_JSON( $parent_theme_json_data );
     171
     172                // Merge the child theme.json into the parent theme.json.
     173                // The child theme takes precedence over the parent.
     174                $parent_theme->merge( self::$theme );
     175                self::$theme = $parent_theme;
     176            }
    147177        }
    148178
    149179        /*
    150          * We want the presets and settings declared in theme.json
    151          * to override the ones declared via add_theme_support.
    152          */
     180        * We want the presets and settings declared in theme.json
     181        * to override the ones declared via theme supports.
     182        * So we take theme supports, transform it to theme.json shape
     183        * and merge the self::$theme upon that.
     184        */
     185        $theme_support_data  = WP_Theme_JSON::get_from_editor_settings( get_default_block_editor_settings() );
    153186        $with_theme_supports = new WP_Theme_JSON( $theme_support_data );
    154187        $with_theme_supports->merge( self::$theme );
     
    158191
    159192    /**
    160      * There are different sources of data for a site: core and theme.
    161      *
    162      * While the getters {@link get_core_data}, {@link get_theme_data} return the raw data
    163      * from the respective origins, this method merges them all together.
    164      *
    165      * If the same piece of data is declared in different origins (core and theme),
    166      * the last origin overrides the previous. For example, if core disables custom colors
    167      * but a theme enables them, the theme config wins.
    168      *
    169      * @since 5.8.0
    170      *
    171      * @param array $settings Optional. Existing block editor settings. Default empty array.
     193     * Returns the CPT that contains the user's origin config
     194     * for the current theme or a void array if none found.
     195     *
     196     * It can also create and return a new draft CPT.
     197     *
     198     * @since 5.9.0
     199     *
     200     * @param bool  $should_create_cpt  Optional. Whether a new CPT should be created if no one was found.
     201     *                                  False by default.
     202     * @param array $post_status_filter Filter Optional. CPT by post status.
     203     *                                   ['publish'] by default, so it only fetches published posts.
     204     *
     205     * @return array Custom Post Type for the user's origin config.
     206     */
     207    private static function get_user_data_from_custom_post_type( $should_create_cpt = false, $post_status_filter = array( 'publish' ) ) {
     208        $user_cpt         = array();
     209        $post_type_filter = 'wp_global_styles';
     210        $query            = new WP_Query(
     211            array(
     212                'posts_per_page' => 1,
     213                'orderby'        => 'date',
     214                'order'          => 'desc',
     215                'post_type'      => $post_type_filter,
     216                'post_status'    => $post_status_filter,
     217                'tax_query'      => array(
     218                    array(
     219                        'taxonomy' => 'wp_theme',
     220                        'field'    => 'name',
     221                        'terms'    => wp_get_theme()->get_stylesheet(),
     222                    ),
     223                ),
     224            )
     225        );
     226
     227        if ( is_array( $query->posts ) && ( 1 === $query->post_count ) ) {
     228            $user_cpt = $query->posts[0]->to_array();
     229        } elseif ( $should_create_cpt ) {
     230            $cpt_post_id = wp_insert_post(
     231                array(
     232                    'post_content' => '{"version": ' . WP_Theme_JSON::LATEST_SCHEMA . ', "isGlobalStylesUserThemeJSON": true }',
     233                    'post_status'  => 'publish',
     234                    'post_title'   => __( 'Custom Styles', 'default' ),
     235                    'post_type'    => $post_type_filter,
     236                    'post_name'    => 'wp-global-styles-' . urlencode( wp_get_theme()->get_stylesheet() ),
     237                    'tax_input'    => array(
     238                        'wp_theme' => array( wp_get_theme()->get_stylesheet() ),
     239                    ),
     240                ),
     241                true
     242            );
     243
     244            if ( is_wp_error( $cpt_post_id ) ) {
     245                $user_cpt = array();
     246            } else {
     247                $user_cpt = get_post( $cpt_post_id, ARRAY_A );
     248            }
     249        }
     250
     251        return $user_cpt;
     252    }
     253
     254    /**
     255     * Returns the user's origin config.
     256     *
     257     * @since 5.9.0
     258     *
     259     * @return WP_Theme_JSON Entity that holds user data.
     260     */
     261    public static function get_user_data() {
     262        if ( null !== self::$user ) {
     263            return self::$user;
     264        }
     265
     266        $config   = array();
     267        $user_cpt = self::get_user_data_from_custom_post_type();
     268
     269        if ( array_key_exists( 'post_content', $user_cpt ) ) {
     270            $decoded_data = json_decode( $user_cpt['post_content'], true );
     271
     272            $json_decoding_error = json_last_error();
     273            if ( JSON_ERROR_NONE !== $json_decoding_error ) {
     274                trigger_error( 'Error when decoding a theme.json schema for user data. ' . json_last_error_msg() );
     275                return new WP_Theme_JSON( $config, 'user' );
     276            }
     277
     278            // Very important to verify if the flag isGlobalStylesUserThemeJSON is true.
     279            // If is not true the content was not escaped and is not safe.
     280            if (
     281                is_array( $decoded_data ) &&
     282                isset( $decoded_data['isGlobalStylesUserThemeJSON'] ) &&
     283                $decoded_data['isGlobalStylesUserThemeJSON']
     284            ) {
     285                unset( $decoded_data['isGlobalStylesUserThemeJSON'] );
     286                $config = $decoded_data;
     287            }
     288        }
     289        self::$user = new WP_Theme_JSON( $config, 'user' );
     290
     291        return self::$user;
     292    }
     293
     294    /**
     295     * There are three sources of data (origins) for a site:
     296     * core, theme, and user. The user's has higher priority
     297     * than the theme's, and the theme's higher than core's.
     298     *
     299     * Unlike the getters {@link get_core_data},
     300     * {@link get_theme_data}, and {@link get_user_data},
     301     * this method returns data after it has been merged
     302     * with the previous origins. This means that if the same piece of data
     303     * is declared in different origins (user, theme, and core),
     304     * the last origin overrides the previous.
     305     *
     306     * For example, if the user has set a background color
     307     * for the paragraph block, and the theme has done it as well,
     308     * the user preference wins.
     309     *
     310     * @since 5.8.0
     311     * @since 5.9.0 Add user data and change the arguments.
     312     *
     313     * @param string $origin Optional. To what level should we merge data.
     314     *                       Valid values are 'theme' or 'user'.
     315     *                       Default is 'user'.
    172316     * @return WP_Theme_JSON
    173317     */
    174     public static function get_merged_data( $settings = array() ) {
    175         $theme_support_data = WP_Theme_JSON::get_from_editor_settings( $settings );
     318    public static function get_merged_data( $origin = 'user' ) {
     319        if ( is_array( $origin ) ) {
     320            _deprecated_argument( __FUNCTION__, '5.9' );
     321        }
    176322
    177323        $result = new WP_Theme_JSON();
    178324        $result->merge( self::get_core_data() );
    179         $result->merge( self::get_theme_data( $theme_support_data ) );
     325        $result->merge( self::get_theme_data() );
     326
     327        if ( 'user' === $origin ) {
     328            $result->merge( self::get_user_data() );
     329        }
    180330
    181331        return $result;
     
    183333
    184334    /**
     335     * Returns the ID of the custom post type
     336     * that stores user data.
     337     *
     338     * @since 5.9.0
     339     *
     340     * @return integer|null
     341     */
     342    public static function get_user_custom_post_type_id() {
     343        if ( null !== self::$user_custom_post_type_id ) {
     344            return self::$user_custom_post_type_id;
     345        }
     346
     347        $user_cpt = self::get_user_data_from_custom_post_type( true );
     348
     349        if ( array_key_exists( 'ID', $user_cpt ) ) {
     350            self::$user_custom_post_type_id = $user_cpt['ID'];
     351        }
     352
     353        return self::$user_custom_post_type_id;
     354    }
     355
     356    /**
    185357     * Whether the current theme has a theme.json file.
    186358     *
    187359     * @since 5.8.0
     360     * @since 5.9.0 Also check in the parent theme.
    188361     *
    189362     * @return bool
     
    191364    public static function theme_has_support() {
    192365        if ( ! isset( self::$theme_has_support ) ) {
    193             self::$theme_has_support = (bool) self::get_file_path_from_theme( 'theme.json' );
     366            self::$theme_has_support = is_readable( get_theme_file_path( 'theme.json' ) );
    194367        }
    195368
     
    203376     *
    204377     * @since 5.8.0
     378     * @since 5.9.0 Adapt to work with child themes.
    205379     *
    206380     * @param string $file_name Name of the file.
     381     * @param bool   $template  Optional. Use template theme directory. Default false.
    207382     * @return string The whole file path or empty if the file doesn't exist.
    208383     */
    209     private static function get_file_path_from_theme( $file_name ) {
    210         /*
    211          * This used to be a locate_template call. However, that method proved problematic
    212          * due to its use of constants (STYLESHEETPATH) that threw errors in some scenarios.
    213          *
    214          * When the theme.json merge algorithm properly supports child themes,
    215          * this should also fall back to the template path, as locate_template did.
    216          */
    217         $located   = '';
    218         $candidate = get_stylesheet_directory() . '/' . $file_name;
    219         if ( is_readable( $candidate ) ) {
    220             $located = $candidate;
    221         }
    222         return $located;
     384    private static function get_file_path_from_theme( $file_name, $template = false ) {
     385        $path      = $template ? get_template_directory() : get_stylesheet_directory();
     386        $candidate = $path . '/' . $file_name;
     387
     388        return is_readable( $candidate ) ? $candidate : '';
    223389    }
    224390
     
    227393     *
    228394     * @since 5.8.0
     395     * @since 5.9.0 Added new variables to reset.
    229396     */
    230397    public static function clean_cached_data() {
    231         self::$core              = null;
    232         self::$theme             = null;
    233         self::$theme_has_support = null;
     398        self::$core                     = null;
     399        self::$theme                    = null;
     400        self::$user                     = null;
     401        self::$user_custom_post_type_id = null;
     402        self::$theme_has_support        = null;
     403        self::$i18n_schema              = null;
    234404    }
    235405
Note: See TracChangeset for help on using the changeset viewer.