Make WordPress Core

Changeset 56979


Ignore:
Timestamp:
10/20/2023 07:33:59 PM (8 months ago)
Author:
joemcgill
Message:

Themes: Make caches for block patterns clearable.

In [56765], theme block pattern files were cached to a transient as a performance enhancement. However, transients are not easily clearable when caches are flushed on environments not using a persistent cache, which can lead to errors if the theme files are renamed, edited, or moved.

This changes the caching mechanism to use wp_cache_set() instead, and caches these values to the global group so they are still persistent on environments using an object cache, and will be cleared by a cache flush.

In addition, the helper _wp_get_block_patterns has been moved WP_Theme::get_block_patterns for consistency with other block related theme methods and cache helpers for these values, WP_Theme::get_pattern_cache and WP_Theme::set_pattern_cache, have been made private.

Relevant unit tests updated.

Props afercia, flixos90, mukesh27, joemcgill.
Merges [56978] to the 6.4 branch.
Fixes #59633. See #59591, #59490.

Location:
branches/6.4
Files:
1 deleted
4 edited
1 copied

Legend:

Unmodified
Added
Removed
  • branches/6.4

    • Property svn:mergeinfo changed
      /trunk (added)merged: 56978
  • branches/6.4/src/wp-includes/block-patterns.php

    r56931 r56979  
    342342
    343343    foreach ( $themes as $theme ) {
    344         $patterns    = _wp_get_block_patterns( $theme );
     344        $patterns    = $theme->get_block_patterns();
    345345        $dirpath     = $theme->get_stylesheet_directory() . '/patterns/';
    346346        $text_domain = $theme->get( 'TextDomain' );
     
    388388}
    389389add_action( 'init', '_register_theme_block_patterns' );
    390 
    391 /**
    392  * Gets block pattern data for a specified theme.
    393  * Each pattern is defined as a PHP file and defines
    394  *  its metadata using plugin-style headers. The minimum required definition is:
    395  *
    396  *      /**
    397  *       * Title: My Pattern
    398  *       * Slug: my-theme/my-pattern
    399  *       *
    400  *
    401  *  The output of the PHP source corresponds to the content of the pattern, e.g.:
    402  *
    403  *      <main><p><?php echo "Hello"; ?></p></main>
    404  *
    405  *  If applicable, this will collect from both parent and child theme.
    406  *
    407  *  Other settable fields include:
    408  *
    409  *    - Description
    410  *    - Viewport Width
    411  *    - Inserter         (yes/no)
    412  *    - Categories       (comma-separated values)
    413  *    - Keywords         (comma-separated values)
    414  *    - Block Types      (comma-separated values)
    415  *    - Post Types       (comma-separated values)
    416  *    - Template Types   (comma-separated values)
    417  *
    418  * @since 6.4.0
    419  * @access private
    420  *
    421  * @param WP_Theme $theme Theme object.
    422  * @return array Block pattern data.
    423  */
    424 function _wp_get_block_patterns( WP_Theme $theme ) {
    425     $can_use_cached = ! wp_is_development_mode( 'theme' );
    426 
    427     $pattern_data = $theme->get_pattern_cache();
    428     if ( is_array( $pattern_data ) ) {
    429         if ( $can_use_cached ) {
    430             return $pattern_data;
    431         }
    432         // If in development mode, clear pattern cache.
    433         $theme->delete_pattern_cache();
    434     }
    435 
    436     $dirpath      = $theme->get_stylesheet_directory() . '/patterns/';
    437     $pattern_data = array();
    438 
    439     if ( ! file_exists( $dirpath ) ) {
    440         if ( $can_use_cached ) {
    441             $theme->set_pattern_cache( $pattern_data );
    442         }
    443         return $pattern_data;
    444     }
    445     $files = glob( $dirpath . '*.php' );
    446     if ( ! $files ) {
    447         if ( $can_use_cached ) {
    448             $theme->set_pattern_cache( $pattern_data );
    449         }
    450         return $pattern_data;
    451     }
    452 
    453     $default_headers = array(
    454         'title'         => 'Title',
    455         'slug'          => 'Slug',
    456         'description'   => 'Description',
    457         'viewportWidth' => 'Viewport Width',
    458         'inserter'      => 'Inserter',
    459         'categories'    => 'Categories',
    460         'keywords'      => 'Keywords',
    461         'blockTypes'    => 'Block Types',
    462         'postTypes'     => 'Post Types',
    463         'templateTypes' => 'Template Types',
    464     );
    465 
    466     $properties_to_parse = array(
    467         'categories',
    468         'keywords',
    469         'blockTypes',
    470         'postTypes',
    471         'templateTypes',
    472     );
    473 
    474     foreach ( $files as $file ) {
    475         $pattern = get_file_data( $file, $default_headers );
    476 
    477         if ( empty( $pattern['slug'] ) ) {
    478             _doing_it_wrong(
    479                 __FUNCTION__,
    480                 sprintf(
    481                     /* translators: 1: file name. */
    482                     __( 'Could not register file "%s" as a block pattern ("Slug" field missing)' ),
    483                     $file
    484                 ),
    485                 '6.0.0'
    486             );
    487             continue;
    488         }
    489 
    490         if ( ! preg_match( '/^[A-z0-9\/_-]+$/', $pattern['slug'] ) ) {
    491             _doing_it_wrong(
    492                 __FUNCTION__,
    493                 sprintf(
    494                     /* translators: 1: file name; 2: slug value found. */
    495                     __( 'Could not register file "%1$s" as a block pattern (invalid slug "%2$s")' ),
    496                     $file,
    497                     $pattern['slug']
    498                 ),
    499                 '6.0.0'
    500             );
    501         }
    502 
    503         // Title is a required property.
    504         if ( ! $pattern['title'] ) {
    505             _doing_it_wrong(
    506                 __FUNCTION__,
    507                 sprintf(
    508                     /* translators: 1: file name. */
    509                     __( 'Could not register file "%s" as a block pattern ("Title" field missing)' ),
    510                     $file
    511                 ),
    512                 '6.0.0'
    513             );
    514             continue;
    515         }
    516 
    517         // For properties of type array, parse data as comma-separated.
    518         foreach ( $properties_to_parse as $property ) {
    519             if ( ! empty( $pattern[ $property ] ) ) {
    520                 $pattern[ $property ] = array_filter( wp_parse_list( (string) $pattern[ $property ] ) );
    521             } else {
    522                 unset( $pattern[ $property ] );
    523             }
    524         }
    525 
    526         // Parse properties of type int.
    527         $property = 'viewportWidth';
    528         if ( ! empty( $pattern[ $property ] ) ) {
    529             $pattern[ $property ] = (int) $pattern[ $property ];
    530         } else {
    531             unset( $pattern[ $property ] );
    532         }
    533 
    534         // Parse properties of type bool.
    535         $property = 'inserter';
    536         if ( ! empty( $pattern[ $property ] ) ) {
    537             $pattern[ $property ] = in_array(
    538                 strtolower( $pattern[ $property ] ),
    539                 array( 'yes', 'true' ),
    540                 true
    541             );
    542         } else {
    543             unset( $pattern[ $property ] );
    544         }
    545 
    546         $key = str_replace( $dirpath, '', $file );
    547 
    548         $pattern_data[ $key ] = $pattern;
    549     }
    550 
    551     if ( $can_use_cached ) {
    552         $theme->set_pattern_cache( $pattern_data );
    553     }
    554 
    555     return $pattern_data;
    556 }
  • branches/6.4/src/wp-includes/class-wp-theme.php

    r56943 r56979  
    846846
    847847    /**
    848      * Gets block pattern cache.
    849      *
    850      * @since 6.4.0
    851      *
    852      * @return array|false Returns an array of patterns if cache is found, otherwise false.
    853      */
    854     public function get_pattern_cache() {
    855         if ( ! $this->exists() ) {
    856             return false;
    857         }
    858         $pattern_data = get_transient( 'wp_theme_patterns_' . $this->stylesheet );
    859         if ( is_array( $pattern_data ) && $pattern_data['version'] === $this->get( 'Version' ) ) {
    860             return $pattern_data['patterns'];
    861         }
    862         return false;
    863     }
    864 
    865     /**
    866      * Sets block pattern cache.
    867      *
    868      * @since 6.4.0
    869      *
    870      * @param array $patterns Block patterns data to set in cache.
    871      */
    872     public function set_pattern_cache( array $patterns ) {
    873         $pattern_data = array(
    874             'version'  => $this->get( 'Version' ),
    875             'patterns' => $patterns,
    876         );
    877         set_transient( 'wp_theme_patterns_' . $this->stylesheet, $pattern_data );
    878     }
    879 
    880     /**
    881      * Clears block pattern cache.
    882      *
    883      * @since 6.4.0
    884      */
    885     public function delete_pattern_cache() {
    886         delete_transient( 'wp_theme_patterns_' . $this->stylesheet );
    887     }
    888 
    889     /**
    890848     * Gets a raw, unformatted theme header.
    891849     *
     
    18421800
    18431801    /**
     1802     * Gets block pattern data for a specified theme.
     1803     * Each pattern is defined as a PHP file and defines
     1804     * its metadata using plugin-style headers. The minimum required definition is:
     1805     *
     1806     *     /**
     1807     *      * Title: My Pattern
     1808     *      * Slug: my-theme/my-pattern
     1809     *      *
     1810     *
     1811     * The output of the PHP source corresponds to the content of the pattern, e.g.:
     1812     *
     1813     *     <main><p><?php echo "Hello"; ?></p></main>
     1814     *
     1815     * If applicable, this will collect from both parent and child theme.
     1816     *
     1817     * Other settable fields include:
     1818     *
     1819     *     - Description
     1820     *     - Viewport Width
     1821     *     - Inserter         (yes/no)
     1822     *     - Categories       (comma-separated values)
     1823     *     - Keywords         (comma-separated values)
     1824     *     - Block Types      (comma-separated values)
     1825     *     - Post Types       (comma-separated values)
     1826     *     - Template Types   (comma-separated values)
     1827     *
     1828     * @since 6.4.0
     1829     *
     1830     * @return array Block pattern data.
     1831     */
     1832    public function get_block_patterns() {
     1833        $can_use_cached = ! wp_is_development_mode( 'theme' );
     1834
     1835        $pattern_data = $this->get_pattern_cache();
     1836        if ( is_array( $pattern_data ) ) {
     1837            if ( $can_use_cached ) {
     1838                return $pattern_data;
     1839            }
     1840            // If in development mode, clear pattern cache.
     1841            $this->delete_pattern_cache();
     1842        }
     1843
     1844        $dirpath      = $this->get_stylesheet_directory() . '/patterns/';
     1845        $pattern_data = array();
     1846
     1847        if ( ! file_exists( $dirpath ) ) {
     1848            if ( $can_use_cached ) {
     1849                $this->set_pattern_cache( $pattern_data );
     1850            }
     1851            return $pattern_data;
     1852        }
     1853        $files = glob( $dirpath . '*.php' );
     1854        if ( ! $files ) {
     1855            if ( $can_use_cached ) {
     1856                $this->set_pattern_cache( $pattern_data );
     1857            }
     1858            return $pattern_data;
     1859        }
     1860
     1861        $default_headers = array(
     1862            'title'         => 'Title',
     1863            'slug'          => 'Slug',
     1864            'description'   => 'Description',
     1865            'viewportWidth' => 'Viewport Width',
     1866            'inserter'      => 'Inserter',
     1867            'categories'    => 'Categories',
     1868            'keywords'      => 'Keywords',
     1869            'blockTypes'    => 'Block Types',
     1870            'postTypes'     => 'Post Types',
     1871            'templateTypes' => 'Template Types',
     1872        );
     1873
     1874        $properties_to_parse = array(
     1875            'categories',
     1876            'keywords',
     1877            'blockTypes',
     1878            'postTypes',
     1879            'templateTypes',
     1880        );
     1881
     1882        foreach ( $files as $file ) {
     1883            $pattern = get_file_data( $file, $default_headers );
     1884
     1885            if ( empty( $pattern['slug'] ) ) {
     1886                _doing_it_wrong(
     1887                    __FUNCTION__,
     1888                    sprintf(
     1889                        /* translators: 1: file name. */
     1890                        __( 'Could not register file "%s" as a block pattern ("Slug" field missing)' ),
     1891                        $file
     1892                    ),
     1893                    '6.0.0'
     1894                );
     1895                continue;
     1896            }
     1897
     1898            if ( ! preg_match( '/^[A-z0-9\/_-]+$/', $pattern['slug'] ) ) {
     1899                _doing_it_wrong(
     1900                    __FUNCTION__,
     1901                    sprintf(
     1902                        /* translators: 1: file name; 2: slug value found. */
     1903                        __( 'Could not register file "%1$s" as a block pattern (invalid slug "%2$s")' ),
     1904                        $file,
     1905                        $pattern['slug']
     1906                    ),
     1907                    '6.0.0'
     1908                );
     1909            }
     1910
     1911            // Title is a required property.
     1912            if ( ! $pattern['title'] ) {
     1913                _doing_it_wrong(
     1914                    __FUNCTION__,
     1915                    sprintf(
     1916                        /* translators: 1: file name. */
     1917                        __( 'Could not register file "%s" as a block pattern ("Title" field missing)' ),
     1918                        $file
     1919                    ),
     1920                    '6.0.0'
     1921                );
     1922                continue;
     1923            }
     1924
     1925            // For properties of type array, parse data as comma-separated.
     1926            foreach ( $properties_to_parse as $property ) {
     1927                if ( ! empty( $pattern[ $property ] ) ) {
     1928                    $pattern[ $property ] = array_filter( wp_parse_list( (string) $pattern[ $property ] ) );
     1929                } else {
     1930                    unset( $pattern[ $property ] );
     1931                }
     1932            }
     1933
     1934            // Parse properties of type int.
     1935            $property = 'viewportWidth';
     1936            if ( ! empty( $pattern[ $property ] ) ) {
     1937                $pattern[ $property ] = (int) $pattern[ $property ];
     1938            } else {
     1939                unset( $pattern[ $property ] );
     1940            }
     1941
     1942            // Parse properties of type bool.
     1943            $property = 'inserter';
     1944            if ( ! empty( $pattern[ $property ] ) ) {
     1945                $pattern[ $property ] = in_array(
     1946                    strtolower( $pattern[ $property ] ),
     1947                    array( 'yes', 'true' ),
     1948                    true
     1949                );
     1950            } else {
     1951                unset( $pattern[ $property ] );
     1952            }
     1953
     1954            $key = str_replace( $dirpath, '', $file );
     1955
     1956            $pattern_data[ $key ] = $pattern;
     1957        }
     1958
     1959        if ( $can_use_cached ) {
     1960            $this->set_pattern_cache( $pattern_data );
     1961        }
     1962
     1963        return $pattern_data;
     1964    }
     1965
     1966    /**
     1967     * Gets block pattern cache.
     1968     *
     1969     * @since 6.4.0
     1970     *
     1971     * @return array|false Returns an array of patterns if cache is found, otherwise false.
     1972     */
     1973    private function get_pattern_cache() {
     1974        if ( ! $this->exists() ) {
     1975            return false;
     1976        }
     1977        $pattern_data = wp_cache_get( 'wp_theme_patterns_' . $this->stylesheet );
     1978        if ( is_array( $pattern_data ) && $pattern_data['version'] === $this->get( 'Version' ) ) {
     1979            return $pattern_data['patterns'];
     1980        }
     1981        return false;
     1982    }
     1983
     1984    /**
     1985     * Sets block pattern cache.
     1986     *
     1987     * @since 6.4.0
     1988     *
     1989     * @param array $patterns Block patterns data to set in cache.
     1990     */
     1991    private function set_pattern_cache( array $patterns ) {
     1992        $pattern_data = array(
     1993            'version'  => $this->get( 'Version' ),
     1994            'patterns' => $patterns,
     1995        );
     1996        wp_cache_set( 'wp_theme_patterns_' . $this->stylesheet, $pattern_data );
     1997    }
     1998
     1999    /**
     2000     * Clears block pattern cache.
     2001     *
     2002     * @since 6.4.0
     2003     */
     2004    public function delete_pattern_cache() {
     2005        wp_cache_delete( 'wp_theme_patterns_' . $this->stylesheet );
     2006    }
     2007
     2008    /**
    18442009     * Enables a theme for all sites on the current network.
    18452010     *
  • branches/6.4/tests/phpunit/tests/theme/wpGetGlobalStylesheet.php

    r56042 r56979  
    2727
    2828    public function tear_down() {
     29        // Reset development mode after each test.
     30        unset( $GLOBALS['_wp_tests_development_mode'] );
     31
    2932        // Reset the theme support.
    3033        if ( $this->remove_theme_support_at_teardown ) {
Note: See TracChangeset for help on using the changeset viewer.