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.

Built from https://develop.svn.wordpress.org/branches/6.4@56979


git-svn-id: http://core.svn.wordpress.org/branches/6.4@56490 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Joe McGill 2023-10-20 19:36:01 +00:00
parent ddc3c030cb
commit 51111edbeb
16 changed files with 1106 additions and 5348 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -341,7 +341,7 @@ function _register_theme_block_patterns() {
$registry = WP_Block_Patterns_Registry::get_instance();
foreach ( $themes as $theme ) {
$patterns = _wp_get_block_patterns( $theme );
$patterns = $theme->get_block_patterns();
$dirpath = $theme->get_stylesheet_directory() . '/patterns/';
$text_domain = $theme->get( 'TextDomain' );
@ -387,170 +387,3 @@ function _register_theme_block_patterns() {
}
}
add_action( 'init', '_register_theme_block_patterns' );
/**
* Gets block pattern data for a specified theme.
* Each pattern is defined as a PHP file and defines
* its metadata using plugin-style headers. The minimum required definition is:
*
* /**
* * Title: My Pattern
* * Slug: my-theme/my-pattern
* *
*
* The output of the PHP source corresponds to the content of the pattern, e.g.:
*
* <main><p><?php echo "Hello"; ?></p></main>
*
* If applicable, this will collect from both parent and child theme.
*
* Other settable fields include:
*
* - Description
* - Viewport Width
* - Inserter (yes/no)
* - Categories (comma-separated values)
* - Keywords (comma-separated values)
* - Block Types (comma-separated values)
* - Post Types (comma-separated values)
* - Template Types (comma-separated values)
*
* @since 6.4.0
* @access private
*
* @param WP_Theme $theme Theme object.
* @return array Block pattern data.
*/
function _wp_get_block_patterns( WP_Theme $theme ) {
$can_use_cached = ! wp_is_development_mode( 'theme' );
$pattern_data = $theme->get_pattern_cache();
if ( is_array( $pattern_data ) ) {
if ( $can_use_cached ) {
return $pattern_data;
}
// If in development mode, clear pattern cache.
$theme->delete_pattern_cache();
}
$dirpath = $theme->get_stylesheet_directory() . '/patterns/';
$pattern_data = array();
if ( ! file_exists( $dirpath ) ) {
if ( $can_use_cached ) {
$theme->set_pattern_cache( $pattern_data );
}
return $pattern_data;
}
$files = glob( $dirpath . '*.php' );
if ( ! $files ) {
if ( $can_use_cached ) {
$theme->set_pattern_cache( $pattern_data );
}
return $pattern_data;
}
$default_headers = array(
'title' => 'Title',
'slug' => 'Slug',
'description' => 'Description',
'viewportWidth' => 'Viewport Width',
'inserter' => 'Inserter',
'categories' => 'Categories',
'keywords' => 'Keywords',
'blockTypes' => 'Block Types',
'postTypes' => 'Post Types',
'templateTypes' => 'Template Types',
);
$properties_to_parse = array(
'categories',
'keywords',
'blockTypes',
'postTypes',
'templateTypes',
);
foreach ( $files as $file ) {
$pattern = get_file_data( $file, $default_headers );
if ( empty( $pattern['slug'] ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: file name. */
__( 'Could not register file "%s" as a block pattern ("Slug" field missing)' ),
$file
),
'6.0.0'
);
continue;
}
if ( ! preg_match( '/^[A-z0-9\/_-]+$/', $pattern['slug'] ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: file name; 2: slug value found. */
__( 'Could not register file "%1$s" as a block pattern (invalid slug "%2$s")' ),
$file,
$pattern['slug']
),
'6.0.0'
);
}
// Title is a required property.
if ( ! $pattern['title'] ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: file name. */
__( 'Could not register file "%s" as a block pattern ("Title" field missing)' ),
$file
),
'6.0.0'
);
continue;
}
// For properties of type array, parse data as comma-separated.
foreach ( $properties_to_parse as $property ) {
if ( ! empty( $pattern[ $property ] ) ) {
$pattern[ $property ] = array_filter( wp_parse_list( (string) $pattern[ $property ] ) );
} else {
unset( $pattern[ $property ] );
}
}
// Parse properties of type int.
$property = 'viewportWidth';
if ( ! empty( $pattern[ $property ] ) ) {
$pattern[ $property ] = (int) $pattern[ $property ];
} else {
unset( $pattern[ $property ] );
}
// Parse properties of type bool.
$property = 'inserter';
if ( ! empty( $pattern[ $property ] ) ) {
$pattern[ $property ] = in_array(
strtolower( $pattern[ $property ] ),
array( 'yes', 'true' ),
true
);
} else {
unset( $pattern[ $property ] );
}
$key = str_replace( $dirpath, '', $file );
$pattern_data[ $key ] = $pattern;
}
if ( $can_use_cached ) {
$theme->set_pattern_cache( $pattern_data );
}
return $pattern_data;
}

View File

@ -844,48 +844,6 @@ final class WP_Theme implements ArrayAccess {
$this->delete_pattern_cache();
}
/**
* Gets block pattern cache.
*
* @since 6.4.0
*
* @return array|false Returns an array of patterns if cache is found, otherwise false.
*/
public function get_pattern_cache() {
if ( ! $this->exists() ) {
return false;
}
$pattern_data = get_transient( 'wp_theme_patterns_' . $this->stylesheet );
if ( is_array( $pattern_data ) && $pattern_data['version'] === $this->get( 'Version' ) ) {
return $pattern_data['patterns'];
}
return false;
}
/**
* Sets block pattern cache.
*
* @since 6.4.0
*
* @param array $patterns Block patterns data to set in cache.
*/
public function set_pattern_cache( array $patterns ) {
$pattern_data = array(
'version' => $this->get( 'Version' ),
'patterns' => $patterns,
);
set_transient( 'wp_theme_patterns_' . $this->stylesheet, $pattern_data );
}
/**
* Clears block pattern cache.
*
* @since 6.4.0
*/
public function delete_pattern_cache() {
delete_transient( 'wp_theme_patterns_' . $this->stylesheet );
}
/**
* Gets a raw, unformatted theme header.
*
@ -1840,6 +1798,213 @@ final class WP_Theme implements ArrayAccess {
return $this->block_template_folders;
}
/**
* Gets block pattern data for a specified theme.
* Each pattern is defined as a PHP file and defines
* its metadata using plugin-style headers. The minimum required definition is:
*
* /**
* * Title: My Pattern
* * Slug: my-theme/my-pattern
* *
*
* The output of the PHP source corresponds to the content of the pattern, e.g.:
*
* <main><p><?php echo "Hello"; ?></p></main>
*
* If applicable, this will collect from both parent and child theme.
*
* Other settable fields include:
*
* - Description
* - Viewport Width
* - Inserter (yes/no)
* - Categories (comma-separated values)
* - Keywords (comma-separated values)
* - Block Types (comma-separated values)
* - Post Types (comma-separated values)
* - Template Types (comma-separated values)
*
* @since 6.4.0
*
* @return array Block pattern data.
*/
public function get_block_patterns() {
$can_use_cached = ! wp_is_development_mode( 'theme' );
$pattern_data = $this->get_pattern_cache();
if ( is_array( $pattern_data ) ) {
if ( $can_use_cached ) {
return $pattern_data;
}
// If in development mode, clear pattern cache.
$this->delete_pattern_cache();
}
$dirpath = $this->get_stylesheet_directory() . '/patterns/';
$pattern_data = array();
if ( ! file_exists( $dirpath ) ) {
if ( $can_use_cached ) {
$this->set_pattern_cache( $pattern_data );
}
return $pattern_data;
}
$files = glob( $dirpath . '*.php' );
if ( ! $files ) {
if ( $can_use_cached ) {
$this->set_pattern_cache( $pattern_data );
}
return $pattern_data;
}
$default_headers = array(
'title' => 'Title',
'slug' => 'Slug',
'description' => 'Description',
'viewportWidth' => 'Viewport Width',
'inserter' => 'Inserter',
'categories' => 'Categories',
'keywords' => 'Keywords',
'blockTypes' => 'Block Types',
'postTypes' => 'Post Types',
'templateTypes' => 'Template Types',
);
$properties_to_parse = array(
'categories',
'keywords',
'blockTypes',
'postTypes',
'templateTypes',
);
foreach ( $files as $file ) {
$pattern = get_file_data( $file, $default_headers );
if ( empty( $pattern['slug'] ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: file name. */
__( 'Could not register file "%s" as a block pattern ("Slug" field missing)' ),
$file
),
'6.0.0'
);
continue;
}
if ( ! preg_match( '/^[A-z0-9\/_-]+$/', $pattern['slug'] ) ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: file name; 2: slug value found. */
__( 'Could not register file "%1$s" as a block pattern (invalid slug "%2$s")' ),
$file,
$pattern['slug']
),
'6.0.0'
);
}
// Title is a required property.
if ( ! $pattern['title'] ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: file name. */
__( 'Could not register file "%s" as a block pattern ("Title" field missing)' ),
$file
),
'6.0.0'
);
continue;
}
// For properties of type array, parse data as comma-separated.
foreach ( $properties_to_parse as $property ) {
if ( ! empty( $pattern[ $property ] ) ) {
$pattern[ $property ] = array_filter( wp_parse_list( (string) $pattern[ $property ] ) );
} else {
unset( $pattern[ $property ] );
}
}
// Parse properties of type int.
$property = 'viewportWidth';
if ( ! empty( $pattern[ $property ] ) ) {
$pattern[ $property ] = (int) $pattern[ $property ];
} else {
unset( $pattern[ $property ] );
}
// Parse properties of type bool.
$property = 'inserter';
if ( ! empty( $pattern[ $property ] ) ) {
$pattern[ $property ] = in_array(
strtolower( $pattern[ $property ] ),
array( 'yes', 'true' ),
true
);
} else {
unset( $pattern[ $property ] );
}
$key = str_replace( $dirpath, '', $file );
$pattern_data[ $key ] = $pattern;
}
if ( $can_use_cached ) {
$this->set_pattern_cache( $pattern_data );
}
return $pattern_data;
}
/**
* Gets block pattern cache.
*
* @since 6.4.0
*
* @return array|false Returns an array of patterns if cache is found, otherwise false.
*/
private function get_pattern_cache() {
if ( ! $this->exists() ) {
return false;
}
$pattern_data = wp_cache_get( 'wp_theme_patterns_' . $this->stylesheet );
if ( is_array( $pattern_data ) && $pattern_data['version'] === $this->get( 'Version' ) ) {
return $pattern_data['patterns'];
}
return false;
}
/**
* Sets block pattern cache.
*
* @since 6.4.0
*
* @param array $patterns Block patterns data to set in cache.
*/
private function set_pattern_cache( array $patterns ) {
$pattern_data = array(
'version' => $this->get( 'Version' ),
'patterns' => $patterns,
);
wp_cache_set( 'wp_theme_patterns_' . $this->stylesheet, $pattern_data );
}
/**
* Clears block pattern cache.
*
* @since 6.4.0
*/
public function delete_pattern_cache() {
wp_cache_delete( 'wp_theme_patterns_' . $this->stylesheet );
}
/**
* Enables a theme for all sites on the current network.
*

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -12508,19 +12508,22 @@ function convertLegacyBlockNameAndAttributes(name, attributes) {
* Given object and string of dot-delimited path segments, returns value at
* path or undefined if path cannot be resolved.
*
* @param object Lookup object
* @param path Path to resolve
* @return Resolved value
* @param {Object} object Lookup object
* @param {string} path Path to resolve
* @return {?*} Resolved value
*/
function getPath(object, path) {
var segments = path.split('.');
var segment;
while (segment = segments.shift()) {
if (!(segment in object)) {
return;
}
object = object[segment];
}
return object;
}
;// CONCATENATED MODULE: ./node_modules/hpq/es/index.js
@ -12532,162 +12535,133 @@ function getPath(object, path) {
* Function returning a DOM document created by `createHTMLDocument`. The same
* document is returned between invocations.
*
* @return DOM document.
* @return {Document} DOM document.
*/
var getDocument = function () {
var doc;
return function () {
if (!doc) {
doc = document.implementation.createHTMLDocument('');
}
return doc;
};
}();
/**
* Given a markup string or DOM element, creates an object aligning with the
* shape of the matchers object, or the value returned by the matcher.
*
* @param source Source content
* @param matchers Matcher function or object of matchers
* @param {(string|Element)} source Source content
* @param {(Object|Function)} matchers Matcher function or object of matchers
* @return {(Object|*)} Matched value(s), shaped by object
*/
/**
* Given a markup string or DOM element, creates an object aligning with the
* shape of the matchers object, or the value returned by the matcher.
*
* @param source Source content
* @param matchers Matcher function or object of matchers
*/
function parse(source, matchers) {
if (!matchers) {
return;
}
} // Coerce to element
// Coerce to element
if ('string' === typeof source) {
var doc = getDocument();
doc.body.innerHTML = source;
source = doc.body;
}
} // Return singular value
// Return singular value
if (typeof matchers === 'function') {
if ('function' === typeof matchers) {
return matchers(source);
}
} // Bail if we can't handle matchers
// Bail if we can't handle matchers
if (Object !== matchers.constructor) {
return;
}
} // Shape result by matcher object
// Shape result by matcher object
return Object.keys(matchers).reduce(function (memo, key) {
var inner = matchers[key];
memo[key] = parse(source, inner);
memo[key] = parse(source, matchers[key]);
return memo;
}, {});
}
/**
* Generates a function which matches node of type selector, returning an
* attribute by property if the attribute exists. If no selector is passed,
* returns property of the query element.
*
* @param name Property name
* @return Property value
* @param {?string} selector Optional selector
* @param {string} name Property name
* @return {*} Property value
*/
/**
* Generates a function which matches node of type selector, returning an
* attribute by property if the attribute exists. If no selector is passed,
* returns property of the query element.
*
* @param selector Optional selector
* @param name Property name
* @return Property value
*/
function prop(arg1, arg2) {
var name;
var selector;
function prop(selector, name) {
if (1 === arguments.length) {
name = arg1;
name = selector;
selector = undefined;
} else {
name = arg2;
selector = arg1;
}
return function (node) {
var match = node;
if (selector) {
match = node.querySelector(selector);
}
if (match) {
return getPath(match, name);
}
};
}
/**
* Generates a function which matches node of type selector, returning an
* attribute by name if the attribute exists. If no selector is passed,
* returns attribute of the query element.
*
* @param name Attribute name
* @return Attribute value
* @param {?string} selector Optional selector
* @param {string} name Attribute name
* @return {?string} Attribute value
*/
/**
* Generates a function which matches node of type selector, returning an
* attribute by name if the attribute exists. If no selector is passed,
* returns attribute of the query element.
*
* @param selector Optional selector
* @param name Attribute name
* @return Attribute value
*/
function attr(arg1, arg2) {
var name;
var selector;
function attr(selector, name) {
if (1 === arguments.length) {
name = arg1;
name = selector;
selector = undefined;
} else {
name = arg2;
selector = arg1;
}
return function (node) {
var attributes = prop(selector, 'attributes')(node);
if (attributes && Object.prototype.hasOwnProperty.call(attributes, name)) {
if (attributes && attributes.hasOwnProperty(name)) {
return attributes[name].value;
}
};
}
/**
* Convenience for `prop( selector, 'innerHTML' )`.
*
* @see prop()
*
* @param selector Optional selector
* @return Inner HTML
* @param {?string} selector Optional selector
* @return {string} Inner HTML
*/
function html(selector) {
return prop(selector, 'innerHTML');
}
/**
* Convenience for `prop( selector, 'textContent' )`.
*
* @see prop()
*
* @param selector Optional selector
* @return Text content
* @param {?string} selector Optional selector
* @return {string} Text content
*/
function es_text(selector) {
return prop(selector, 'textContent');
}
/**
* Creates a new matching context by first finding elements matching selector
* using querySelectorAll before then running another `parse` on `matchers`
@ -12695,10 +12669,11 @@ function es_text(selector) {
*
* @see parse()
*
* @param selector Selector to match
* @param matchers Matcher function or object of matchers
* @return Matcher function which returns an array of matched value(s)
* @param {string} selector Selector to match
* @param {(Object|Function)} matchers Matcher function or object of matchers
* @return {Array.<*,Object>} Array of matched value(s)
*/
function query(selector, matchers) {
return function (node) {
var matches = node.querySelectorAll(selector);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -8329,16 +8329,6 @@ function usePostVisibilityLabel() {
return visibilityOptions[visibility]?.label;
}
;// CONCATENATED MODULE: ./node_modules/date-fns/node_modules/@babel/runtime/helpers/esm/typeof.js
function _typeof(obj) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
return typeof obj;
} : function (obj) {
return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
}, _typeof(obj);
}
;// CONCATENATED MODULE: ./node_modules/date-fns/esm/_lib/requiredArgs/index.js
function requiredArgs(required, args) {
if (args.length < required) {
@ -8346,6 +8336,7 @@ function requiredArgs(required, args) {
}
}
;// CONCATENATED MODULE: ./node_modules/date-fns/esm/toDate/index.js
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
/**
@ -8378,11 +8369,11 @@ function requiredArgs(required, args) {
* const result = toDate(1392098430000)
* //=> Tue Feb 11 2014 11:30:30
*/
function toDate(argument) {
requiredArgs(1, arguments);
var argStr = Object.prototype.toString.call(argument);
var argStr = Object.prototype.toString.call(argument); // Clone the date
// Clone the date
if (argument instanceof Date || _typeof(argument) === 'object' && argStr === '[object Date]') {
// Prevent the date to lose the milliseconds when passed to new Date() in IE10
return new Date(argument.getTime());
@ -8391,10 +8382,11 @@ function toDate(argument) {
} else {
if ((typeof argument === 'string' || argStr === '[object String]') && typeof console !== 'undefined') {
// eslint-disable-next-line no-console
console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as date arguments. Please use `parseISO` to parse strings. See: https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#string-arguments");
// eslint-disable-next-line no-console
console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as date arguments. Please use `parseISO` to parse strings. See: https://github.com/date-fns/date-fns/blob/master/docs/upgradeGuide.md#string-arguments"); // eslint-disable-next-line no-console
console.warn(new Error().stack);
}
return new Date(NaN);
}
}
@ -8419,6 +8411,7 @@ function toDate(argument) {
* const result = startOfMonth(new Date(2014, 8, 2, 11, 55, 0))
* //=> Mon Sep 01 2014 00:00:00
*/
function startOfMonth(dirtyDate) {
requiredArgs(1, arguments);
var date = toDate(dirtyDate);
@ -8447,6 +8440,7 @@ function startOfMonth(dirtyDate) {
* const result = endOfMonth(new Date(2014, 8, 2, 11, 55, 0))
* //=> Tue Sep 30 2014 23:59:59.999
*/
function endOfMonth(dirtyDate) {
requiredArgs(1, arguments);
var date = toDate(dirtyDate);
@ -8465,7 +8459,6 @@ function endOfMonth(dirtyDate) {
* @default
*/
var daysInWeek = 7;
/**
* Days in 1 year
* One years equals 365.2425 days according to the formula:
@ -8478,8 +8471,8 @@ var daysInWeek = 7;
* @type {number}
* @default
*/
var daysInYear = 365.2425;
var daysInYear = 365.2425;
/**
* Maximum allowed time.
*
@ -8488,8 +8481,8 @@ var daysInYear = 365.2425;
* @type {number}
* @default
*/
var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1000;
var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1000;
/**
* Milliseconds in 1 minute
*
@ -8498,8 +8491,8 @@ var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1000;
* @type {number}
* @default
*/
var millisecondsInMinute = 60000;
var millisecondsInMinute = 60000;
/**
* Milliseconds in 1 hour
*
@ -8508,8 +8501,8 @@ var millisecondsInMinute = 60000;
* @type {number}
* @default
*/
var millisecondsInHour = 3600000;
var millisecondsInHour = 3600000;
/**
* Milliseconds in 1 second
*
@ -8518,8 +8511,8 @@ var millisecondsInHour = 3600000;
* @type {number}
* @default
*/
var millisecondsInSecond = 1000;
var millisecondsInSecond = 1000;
/**
* Minimum allowed time.
*
@ -8528,8 +8521,8 @@ var millisecondsInSecond = 1000;
* @type {number}
* @default
*/
var minTime = -maxTime;
var minTime = -maxTime;
/**
* Minutes in 1 hour
*
@ -8538,8 +8531,8 @@ var minTime = -maxTime;
* @type {number}
* @default
*/
var minutesInHour = 60;
var minutesInHour = 60;
/**
* Months in 1 quarter
*
@ -8548,8 +8541,8 @@ var minutesInHour = 60;
* @type {number}
* @default
*/
var monthsInQuarter = 3;
var monthsInQuarter = 3;
/**
* Months in 1 year
*
@ -8558,8 +8551,8 @@ var monthsInQuarter = 3;
* @type {number}
* @default
*/
var monthsInYear = 12;
var monthsInYear = 12;
/**
* Quarters in 1 year
*
@ -8568,8 +8561,8 @@ var monthsInYear = 12;
* @type {number}
* @default
*/
var quartersInYear = 4;
var quartersInYear = 4;
/**
* Seconds in 1 hour
*
@ -8578,8 +8571,8 @@ var quartersInYear = 4;
* @type {number}
* @default
*/
var secondsInHour = 3600;
var secondsInHour = 3600;
/**
* Seconds in 1 minute
*
@ -8588,8 +8581,8 @@ var secondsInHour = 3600;
* @type {number}
* @default
*/
var secondsInMinute = 60;
var secondsInMinute = 60;
/**
* Seconds in 1 day
*
@ -8598,8 +8591,8 @@ var secondsInMinute = 60;
* @type {number}
* @default
*/
var secondsInDay = secondsInHour * 24;
var secondsInDay = secondsInHour * 24;
/**
* Seconds in 1 week
*
@ -8608,8 +8601,8 @@ var secondsInDay = secondsInHour * 24;
* @type {number}
* @default
*/
var secondsInWeek = secondsInDay * 7;
var secondsInWeek = secondsInDay * 7;
/**
* Seconds in 1 year
*
@ -8618,8 +8611,8 @@ var secondsInWeek = secondsInDay * 7;
* @type {number}
* @default
*/
var secondsInYear = secondsInDay * daysInYear;
var secondsInYear = secondsInDay * daysInYear;
/**
* Seconds in 1 month
*
@ -8628,8 +8621,8 @@ var secondsInYear = secondsInDay * daysInYear;
* @type {number}
* @default
*/
var secondsInMonth = secondsInYear / 12;
var secondsInMonth = secondsInYear / 12;
/**
* Seconds in 1 quarter
*
@ -8638,16 +8631,20 @@ var secondsInMonth = secondsInYear / 12;
* @type {number}
* @default
*/
var secondsInQuarter = secondsInMonth * 3;
;// CONCATENATED MODULE: ./node_modules/date-fns/esm/_lib/toInteger/index.js
function toInteger(dirtyNumber) {
if (dirtyNumber === null || dirtyNumber === true || dirtyNumber === false) {
return NaN;
}
var number = Number(dirtyNumber);
if (isNaN(number)) {
return number;
}
return number < 0 ? Math.ceil(number) : Math.floor(number);
}
;// CONCATENATED MODULE: ./node_modules/date-fns/esm/parseISO/index.js
@ -8686,51 +8683,64 @@ function toInteger(dirtyNumber) {
* const result = parseISO('+02014101', { additionalDigits: 1 })
* //=> Fri Apr 11 2014 00:00:00
*/
function parseISO(argument, options) {
var _options$additionalDi;
requiredArgs(1, arguments);
var additionalDigits = toInteger((_options$additionalDi = options === null || options === void 0 ? void 0 : options.additionalDigits) !== null && _options$additionalDi !== void 0 ? _options$additionalDi : 2);
if (additionalDigits !== 2 && additionalDigits !== 1 && additionalDigits !== 0) {
throw new RangeError('additionalDigits must be 0, 1 or 2');
}
if (!(typeof argument === 'string' || Object.prototype.toString.call(argument) === '[object String]')) {
return new Date(NaN);
}
var dateStrings = splitDateString(argument);
var date;
if (dateStrings.date) {
var parseYearResult = parseYear(dateStrings.date, additionalDigits);
date = parseDate(parseYearResult.restDateString, parseYearResult.year);
}
if (!date || isNaN(date.getTime())) {
return new Date(NaN);
}
var timestamp = date.getTime();
var time = 0;
var offset;
if (dateStrings.time) {
time = parseTime(dateStrings.time);
if (isNaN(time)) {
return new Date(NaN);
}
}
if (dateStrings.timezone) {
offset = parseTimezone(dateStrings.timezone);
if (isNaN(offset)) {
return new Date(NaN);
}
} else {
var dirtyDate = new Date(timestamp + time);
// js parsed string assuming it's in UTC timezone
var dirtyDate = new Date(timestamp + time); // js parsed string assuming it's in UTC timezone
// but we need it to be parsed in our timezone
// so we use utc values to build date in our timezone.
// Year values from 0 to 99 map to the years 1900 to 1999
// so set year explicitly with setFullYear.
var result = new Date(0);
result.setFullYear(dirtyDate.getUTCFullYear(), dirtyDate.getUTCMonth(), dirtyDate.getUTCDate());
result.setHours(dirtyDate.getUTCHours(), dirtyDate.getUTCMinutes(), dirtyDate.getUTCSeconds(), dirtyDate.getUTCMilliseconds());
return result;
}
return new Date(timestamp + time + offset);
}
var patterns = {
@ -8741,28 +8751,32 @@ var patterns = {
var dateRegex = /^-?(?:(\d{3})|(\d{2})(?:-?(\d{2}))?|W(\d{2})(?:-?(\d{1}))?|)$/;
var timeRegex = /^(\d{2}(?:[.,]\d*)?)(?::?(\d{2}(?:[.,]\d*)?))?(?::?(\d{2}(?:[.,]\d*)?))?$/;
var timezoneRegex = /^([+-])(\d{2})(?::?(\d{2}))?$/;
function splitDateString(dateString) {
var dateStrings = {};
var array = dateString.split(patterns.dateTimeDelimiter);
var timeString;
// The regex match should only return at maximum two array elements.
var timeString; // The regex match should only return at maximum two array elements.
// [date], [time], or [date, time].
if (array.length > 2) {
return dateStrings;
}
if (/:/.test(array[0])) {
timeString = array[0];
} else {
dateStrings.date = array[0];
timeString = array[1];
if (patterns.timeZoneDelimiter.test(dateStrings.date)) {
dateStrings.date = dateString.split(patterns.timeZoneDelimiter)[0];
timeString = dateString.substr(dateStrings.date.length, dateString.length);
}
}
if (timeString) {
var token = patterns.timezone.exec(timeString);
if (token) {
dateStrings.time = timeString.replace(token[1], '');
dateStrings.timezone = token[1];
@ -8770,30 +8784,32 @@ function splitDateString(dateString) {
dateStrings.time = timeString;
}
}
return dateStrings;
}
function parseYear(dateString, additionalDigits) {
var regex = new RegExp('^(?:(\\d{4}|[+-]\\d{' + (4 + additionalDigits) + '})|(\\d{2}|[+-]\\d{' + (2 + additionalDigits) + '})$)');
var captures = dateString.match(regex);
// Invalid ISO-formatted year
var captures = dateString.match(regex); // Invalid ISO-formatted year
if (!captures) return {
year: NaN,
restDateString: ''
};
var year = captures[1] ? parseInt(captures[1]) : null;
var century = captures[2] ? parseInt(captures[2]) : null;
var century = captures[2] ? parseInt(captures[2]) : null; // either year or century is null, not both
// either year or century is null, not both
return {
year: century === null ? year : century * 100,
restDateString: dateString.slice((captures[1] || captures[2]).length)
};
}
function parseDate(dateString, year) {
// Invalid ISO-formatted year
if (year === null) return new Date(NaN);
var captures = dateString.match(dateRegex);
// Invalid ISO-formatted string
var captures = dateString.match(dateRegex); // Invalid ISO-formatted string
if (!captures) return new Date(NaN);
var isWeekDate = !!captures[4];
var dayOfYear = parseDateUnit(captures[1]);
@ -8801,23 +8817,29 @@ function parseDate(dateString, year) {
var day = parseDateUnit(captures[3]);
var week = parseDateUnit(captures[4]);
var dayOfWeek = parseDateUnit(captures[5]) - 1;
if (isWeekDate) {
if (!validateWeekDate(year, week, dayOfWeek)) {
return new Date(NaN);
}
return dayOfISOWeekYear(year, week, dayOfWeek);
} else {
var date = new Date(0);
if (!validateDate(year, month, day) || !validateDayOfYearDate(year, dayOfYear)) {
return new Date(NaN);
}
date.setUTCFullYear(year, month, Math.max(dayOfYear, day));
return date;
}
}
function parseDateUnit(value) {
return value ? parseInt(value) : 1;
}
function parseTime(timeString) {
var captures = timeString.match(timeRegex);
if (!captures) return NaN; // Invalid ISO-formatted time
@ -8825,14 +8847,18 @@ function parseTime(timeString) {
var hours = parseTimeUnit(captures[1]);
var minutes = parseTimeUnit(captures[2]);
var seconds = parseTimeUnit(captures[3]);
if (!validateTime(hours, minutes, seconds)) {
return NaN;
}
return hours * millisecondsInHour + minutes * millisecondsInMinute + seconds * 1000;
}
function parseTimeUnit(value) {
return value && parseFloat(value.replace(',', '.')) || 0;
}
function parseTimezone(timezoneString) {
if (timezoneString === 'Z') return 0;
var captures = timezoneString.match(timezoneRegex);
@ -8840,11 +8866,14 @@ function parseTimezone(timezoneString) {
var sign = captures[1] === '+' ? -1 : 1;
var hours = parseInt(captures[2]);
var minutes = captures[3] && parseInt(captures[3]) || 0;
if (!validateTimezone(hours, minutes)) {
return NaN;
}
return sign * (hours * millisecondsInHour + minutes * millisecondsInMinute);
}
function dayOfISOWeekYear(isoWeekYear, week, day) {
var date = new Date(0);
date.setUTCFullYear(isoWeekYear, 0, 4);
@ -8852,30 +8881,36 @@ function dayOfISOWeekYear(isoWeekYear, week, day) {
var diff = (week - 1) * 7 + day + 1 - fourthOfJanuaryDay;
date.setUTCDate(date.getUTCDate() + diff);
return date;
}
// Validation functions
} // Validation functions
// February is null to handle the leap year (using ||)
var daysInMonths = [31, null, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
function isLeapYearIndex(year) {
return year % 400 === 0 || year % 4 === 0 && year % 100 !== 0;
}
function validateDate(year, month, date) {
return month >= 0 && month <= 11 && date >= 1 && date <= (daysInMonths[month] || (isLeapYearIndex(year) ? 29 : 28));
}
function validateDayOfYearDate(year, dayOfYear) {
return dayOfYear >= 1 && dayOfYear <= (isLeapYearIndex(year) ? 366 : 365);
}
function validateWeekDate(_year, week, day) {
return week >= 1 && week <= 53 && day >= 0 && day <= 6;
}
function validateTime(hours, minutes, seconds) {
if (hours === 24) {
return minutes === 0 && seconds === 0;
}
return seconds >= 0 && seconds < 60 && minutes >= 0 && minutes < 60 && hours >= 0 && hours < 25;
}
function validateTimezone(_hours, minutes) {
return minutes >= 0 && minutes <= 59;
}

File diff suppressed because one or more lines are too long

View File

@ -16,7 +16,7 @@
*
* @global string $wp_version
*/
$wp_version = '6.4-RC1-56964';
$wp_version = '6.4-RC1-56979';
/**
* Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.