diff --git a/.github/workflows/callable-test-core-build-process.yml b/.github/workflows/callable-test-core-build-process.yml
index bf566e7782241..136a4a048ae1b 100644
--- a/.github/workflows/callable-test-core-build-process.yml
+++ b/.github/workflows/callable-test-core-build-process.yml
@@ -46,7 +46,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up Node.js
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
check-latest: true
@@ -79,7 +79,7 @@ jobs:
run: git diff --exit-code
- name: Upload ZIP as a GitHub Actions artifact
- uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
+ uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
if: ${{ inputs.directory == 'build' && 'ubuntu-latest' == inputs.os }}
with:
name: wordpress-build-${{ github.event_name == 'pull_request' && github.event.number || github.sha }}
diff --git a/.github/workflows/callable-test-gutenberg-build-process.yml b/.github/workflows/callable-test-gutenberg-build-process.yml
index ed45a4f2ac032..95236b78ed1d5 100644
--- a/.github/workflows/callable-test-gutenberg-build-process.yml
+++ b/.github/workflows/callable-test-gutenberg-build-process.yml
@@ -55,7 +55,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up Node.js
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
check-latest: true
diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml
index 393c7d1d7b013..a2c7ed894e7dc 100644
--- a/.github/workflows/coding-standards.yml
+++ b/.github/workflows/coding-standards.yml
@@ -75,7 +75,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up PHP
- uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # v2.28.0
+ uses: shivammathur/setup-php@6d7209f44a25a59e904b1ee9f3b0c33ab2cd888d # v2.29.0
with:
php-version: 'latest'
coverage: none
@@ -88,7 +88,7 @@ jobs:
run: echo "date=$(/bin/date -u --date='last Mon' "+%F")" >> $GITHUB_OUTPUT
- name: Cache PHPCS scan cache
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
+ uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
with:
path: |
.cache/phpcs-src.json
@@ -152,7 +152,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up Node.js
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
cache: npm
diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/end-to-end-tests.yml
index 344201d2572d5..924708771d931 100644
--- a/.github/workflows/end-to-end-tests.yml
+++ b/.github/workflows/end-to-end-tests.yml
@@ -76,7 +76,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up Node.js
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
cache: npm
@@ -127,7 +127,7 @@ jobs:
run: npm run test:e2e
- name: Archive debug artifacts (screenshots, HTML snapshots)
- uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
+ uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
if: always()
with:
name: failures-artifacts${{ matrix.LOCAL_SCRIPT_DEBUG && '-SCRIPT_DEBUG' || '' }}-${{ github.run_id }}
diff --git a/.github/workflows/install-testing.yml b/.github/workflows/install-testing.yml
index 60e531a43ce30..ae841a75d8e67 100644
--- a/.github/workflows/install-testing.yml
+++ b/.github/workflows/install-testing.yml
@@ -141,7 +141,7 @@ jobs:
steps:
- name: Set up PHP ${{ matrix.php }}
- uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # v2.28.0
+ uses: shivammathur/setup-php@6d7209f44a25a59e904b1ee9f3b0c33ab2cd888d # v2.29.0
with:
php-version: '${{ matrix.php }}'
coverage: none
diff --git a/.github/workflows/javascript-tests.yml b/.github/workflows/javascript-tests.yml
index 1826b03041b9d..669ec6e1c123a 100644
--- a/.github/workflows/javascript-tests.yml
+++ b/.github/workflows/javascript-tests.yml
@@ -67,7 +67,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up Node.js
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
cache: npm
diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml
index 900b77417b400..8e156a932aac5 100644
--- a/.github/workflows/performance.yml
+++ b/.github/workflows/performance.yml
@@ -110,7 +110,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up Node.js
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
cache: npm
@@ -192,7 +192,7 @@ jobs:
git reset --hard $TARGET_SHA
- name: Set up Node.js
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
cache: npm
@@ -220,7 +220,7 @@ jobs:
run: git reset --hard $GITHUB_SHA
- name: Set up Node.js
- uses: actions/setup-node@5e21ff4d9bc1a8cf6de233a3057d20ec6b3fb69d # v3.8.1
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
cache: npm
diff --git a/.github/workflows/php-compatibility.yml b/.github/workflows/php-compatibility.yml
index 06463a72b7073..1606277d35495 100644
--- a/.github/workflows/php-compatibility.yml
+++ b/.github/workflows/php-compatibility.yml
@@ -70,7 +70,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up PHP
- uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # v2.28.0
+ uses: shivammathur/setup-php@6d7209f44a25a59e904b1ee9f3b0c33ab2cd888d # v2.29.0
with:
php-version: '7.4'
coverage: none
@@ -87,7 +87,7 @@ jobs:
run: echo "date=$(/bin/date -u --date='last Mon' "+%F")" >> $GITHUB_OUTPUT
- name: Cache PHP compatibility scan cache
- uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2
+ uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
with:
path: .cache/phpcompat.json
key: ${{ runner.os }}-date-${{ steps.get-date.outputs.date }}-phpcompat-cache-${{ hashFiles('**/composer.json', 'phpcompat.xml.dist') }}
diff --git a/.github/workflows/phpunit-tests-run.yml b/.github/workflows/phpunit-tests-run.yml
index bebd1e3a29d23..cdedb4527379e 100644
--- a/.github/workflows/phpunit-tests-run.yml
+++ b/.github/workflows/phpunit-tests-run.yml
@@ -90,7 +90,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up Node.js
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
cache: npm
@@ -103,7 +103,7 @@ jobs:
# dependency versions are installed and cached.
##
- name: Set up PHP
- uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # v2.28.0
+ uses: shivammathur/setup-php@6d7209f44a25a59e904b1ee9f3b0c33ab2cd888d # v2.29.0
with:
php-version: '${{ inputs.php }}'
coverage: none
diff --git a/.github/workflows/phpunit-tests.yml b/.github/workflows/phpunit-tests.yml
index 15cb91df50422..250e5594dca95 100644
--- a/.github/workflows/phpunit-tests.yml
+++ b/.github/workflows/phpunit-tests.yml
@@ -47,7 +47,7 @@ jobs:
os: [ ubuntu-latest ]
php: [ '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3' ]
db-type: [ 'mysql' ]
- db-version: [ '5.7', '8.0', '8.1', '8.2' ]
+ db-version: [ '5.7', '8.0', '8.1', '8.2', '8.3' ]
multisite: [ false, true ]
memcached: [ false ]
diff --git a/.github/workflows/props-bot.yml b/.github/workflows/props-bot.yml
new file mode 100644
index 0000000000000..f9d5668742372
--- /dev/null
+++ b/.github/workflows/props-bot.yml
@@ -0,0 +1,90 @@
+name: Props Bot
+
+on:
+ # This event runs anytime a PR is (re)opened, updated, marked ready for review, or labeled.
+ # GitHub does not allow filtering the `labeled` event by a specific label.
+ # However, the logic below will short-circuit the workflow when the `props-bot` label is not the one being added.
+ # Note: The pull_request_target event is used instead of pull_request because this workflow needs permission to comment
+ # on the pull request. Because this event grants extra permissions to `GITHUB_TOKEN`, any code changes within the PR
+ # should be considered untrusted. See https://securitylab.github.com/research/github-actions-preventing-pwn-requests/.
+ pull_request_target:
+ types:
+ - opened
+ - synchronize
+ - reopened
+ - labeled
+ - ready_for_review
+ # This event runs anytime a comment is added or deleted.
+ # You cannot filter this event for PR comments only.
+ # However, the logic below does short-circuit the workflow for issues.
+ issue_comment:
+ type:
+ - created
+ # This event will run everytime a new PR review is initially submitted.
+ pull_request_review:
+ types:
+ - submitted
+ # This event runs anytime a PR review comment is created or deleted.
+ pull_request_review_comment:
+ types:
+ - created
+
+# Cancels all previous workflow runs for pull requests that have not completed.
+concurrency:
+ # The concurrency group contains the workflow name and the branch name for pull requests
+ # or the commit hash for any other events.
+ group: ${{ github.workflow }}-${{ contains( fromJSON( '["pull_request_target", "pull_request_review", "pull_request_review_comment"]' ), github.event_name ) && github.head_ref || github.sha }}
+ cancel-in-progress: true
+
+# Disable permissions for all available scopes by default.
+# Any needed permissions should be configured at the job level.
+permissions: {}
+
+jobs:
+ # Compiles a list of props for a pull request.
+ #
+ # Performs the following steps:
+ # - Collects a list of contributor props and leaves a comment.
+ # - Removes the props-bot label, if necessary.
+ props-bot:
+ name: Generate a list of props
+ runs-on: ubuntu-latest
+ permissions:
+ # The action needs permission `write` permission for PRs in order to add a comment.
+ pull-requests: write
+ contents: read
+ timeout-minutes: 20
+ # The job will run when pull requests are open, ready for review and:
+ #
+ # - A comment is added to the pull request.
+ # - A review is created or commented on.
+ # - The pull request is opened, synchronized, marked ready for review, or reopened.
+ # - The `props-bot` label is added to the pull request.
+ if: |
+ (
+ github.event_name == 'issue_comment' && github.event.issue.pull_request ||
+ contains( fromJSON( '["pull_request_review", "pull_request_review_comment"]' ), github.event_name ) ||
+ github.event_name == 'pull_request_target' && github.event.action != 'labeled' ||
+ 'props-bot' == github.event.label.name
+ ) &&
+ ( ! github.event.pull_request.draft && github.event.pull_request.state == 'open' || ! github.event.issue.draft && github.event.issue.state == 'open' )
+
+ steps:
+ - name: Gather a list of contributors
+ uses: WordPress/props-bot-action@trunk
+ with:
+ format: 'svn'
+
+ - name: Remove the props-bot label
+ uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
+ if: ${{ github.event.action == 'labeled' && 'props-bot' == github.event.label.name }}
+ with:
+ retries: 2
+ retry-exempt-status-codes: 418
+ script: |
+ github.rest.issues.removeLabel({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: '${{ github.event.number }}',
+ name: 'props-bot'
+ });
diff --git a/.github/workflows/slack-notifications.yml b/.github/workflows/slack-notifications.yml
index 566979a5698f8..aab3a85147bc0 100644
--- a/.github/workflows/slack-notifications.yml
+++ b/.github/workflows/slack-notifications.yml
@@ -167,7 +167,7 @@ jobs:
steps:
- name: Post failure notifications to Slack
- uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0
+ uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
with:
payload: ${{ needs.prepare.outputs.payload }}
env:
@@ -183,7 +183,7 @@ jobs:
steps:
- name: Post failure notifications to Slack
- uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0
+ uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
with:
payload: ${{ needs.prepare.outputs.payload }}
env:
@@ -199,7 +199,7 @@ jobs:
steps:
- name: Post success notifications to Slack
- uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0
+ uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
with:
payload: ${{ needs.prepare.outputs.payload }}
env:
@@ -215,7 +215,7 @@ jobs:
steps:
- name: Post cancelled notifications to Slack
- uses: slackapi/slack-github-action@e28cf165c92ffef168d23c5c9000cffc8a25e117 # v1.24.0
+ uses: slackapi/slack-github-action@6c661ce58804a1a20f6dc5fbee7f0381b469e001 # v1.25.0
with:
payload: ${{ needs.prepare.outputs.payload }}
env:
diff --git a/.github/workflows/test-and-zip-default-themes.yml b/.github/workflows/test-and-zip-default-themes.yml
index 771c4e21c9063..cea98ab2292b3 100644
--- a/.github/workflows/test-and-zip-default-themes.yml
+++ b/.github/workflows/test-and-zip-default-themes.yml
@@ -131,7 +131,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up Node.js
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
cache: npm
@@ -187,7 +187,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Upload theme ZIP as an artifact
- uses: actions/upload-artifact@c7d193f32edcb7bfad88892161225aeda64e9392 # v4.0.0
+ uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
with:
if-no-files-found: error
name: ${{ matrix.theme }}
diff --git a/.github/workflows/test-build-processes.yml b/.github/workflows/test-build-processes.yml
index 660cfdee81543..a9276a6c58307 100644
--- a/.github/workflows/test-build-processes.yml
+++ b/.github/workflows/test-build-processes.yml
@@ -124,7 +124,7 @@ jobs:
echo ${{ github.event.number }} > ./pr-number/NR
- name: Upload PR number as artifact
- uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
+ uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
with:
name: pr-number
path: pr-number/
diff --git a/.github/workflows/test-coverage.yml b/.github/workflows/test-coverage.yml
index 5d1e6b2f2af85..b99a4625bd905 100644
--- a/.github/workflows/test-coverage.yml
+++ b/.github/workflows/test-coverage.yml
@@ -81,7 +81,7 @@ jobs:
show-progress: ${{ runner.debug == '1' && 'true' || 'false' }}
- name: Set up Node.js
- uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
+ uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
with:
node-version-file: '.nvmrc'
cache: npm
@@ -94,7 +94,7 @@ jobs:
# dependency versions are installed and cached.
##
- name: Set up PHP
- uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # v2.28.0
+ uses: shivammathur/setup-php@6d7209f44a25a59e904b1ee9f3b0c33ab2cd888d # v2.29.0
with:
php-version: '7.4'
coverage: none
@@ -152,8 +152,9 @@ jobs:
- name: Upload single site report to Codecov
if: ${{ ! matrix.multisite && github.event_name != 'pull_request' }}
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
+ uses: codecov/codecov-action@e0b68c6749509c5f83f984dd99a76a1c1a231044 # v4.0.1
with:
+ token: ${{ secrets.CODECOV_TOKEN }}
file: wp-code-coverage-single-clover-${{ github.sha }}.xml
flags: single,php
fail_ci_if_error: true
@@ -167,8 +168,9 @@ jobs:
- name: Upload multisite report to Codecov
if: ${{ matrix.multisite && github.event_name != 'pull_request' }}
- uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d # v3.1.4
+ uses: codecov/codecov-action@e0b68c6749509c5f83f984dd99a76a1c1a231044 # v4.0.1
with:
+ token: ${{ secrets.CODECOV_TOKEN }}
file: wp-code-coverage-multisite-clover-${{ github.sha }}.xml
flags: multisite,php
fail_ci_if_error: true
diff --git a/.github/workflows/upgrade-testing-run.yml b/.github/workflows/upgrade-testing-run.yml
index ce7452a047656..67e29983caa60 100644
--- a/.github/workflows/upgrade-testing-run.yml
+++ b/.github/workflows/upgrade-testing-run.yml
@@ -62,7 +62,7 @@ jobs:
steps:
- name: Set up PHP ${{ inputs.php }}
- uses: shivammathur/setup-php@e6f75134d35752277f093989e72e140eaa222f35 # v2.28.0
+ uses: shivammathur/setup-php@6d7209f44a25a59e904b1ee9f3b0c33ab2cd888d # v2.29.0
with:
php-version: '${{ inputs.php }}'
coverage: none
diff --git a/.prettierrc.js b/.prettierrc.js
new file mode 100644
index 0000000000000..51b8aeb41505a
--- /dev/null
+++ b/.prettierrc.js
@@ -0,0 +1,3 @@
+// Import the default config file and expose it in the project root.
+// Useful for editor integrations.
+module.exports = require( '@wordpress/prettier-config' );
diff --git a/.version-support-mysql.json b/.version-support-mysql.json
index e316908bc9aac..79858143a1ebd 100644
--- a/.version-support-mysql.json
+++ b/.version-support-mysql.json
@@ -1,6 +1,8 @@
{
"6-5": [
+ "8.3",
"8.2",
+ "8.1",
"8.0",
"5.7",
"5.6",
diff --git a/Gruntfile.js b/Gruntfile.js
index 92feec563818a..38904c6dac170 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -1033,6 +1033,7 @@ module.exports = function(grunt) {
cwd: SOURCE_DIR,
src: [
'wp-{admin,includes}/images/**/*.{png,jpg,gif,jpeg}',
+ 'wp-content/themes/**/*.{png,jpg,gif,jpeg}',
'wp-includes/js/tinymce/skins/wordpress/images/*.{png,jpg,gif,jpeg}'
],
dest: SOURCE_DIR
@@ -1558,14 +1559,18 @@ module.exports = function(grunt) {
} );
/**
- * Build assertions for the lack of source maps in JavaScript files.
+ * Compiled JavaScript files may link to sourcemaps. In some cases,
+ * the source map may not be available, which can cause 404 errors when
+ * browsers try to download the sourcemap from the referenced URLs.
+ * Ensure that sourcemap links are not included in JavaScript files.
*
* @ticket 24994
* @ticket 46218
+ * @ticket 60348
*/
grunt.registerTask( 'verify:source-maps', function() {
const ignoredFiles = [
- 'build/wp-includes/js/dist/components.js'
+ 'build/wp-includes/js/dist/components.js',
];
const files = buildFiles.reduce( ( acc, path ) => {
// Skip excluded paths and any path that isn't a file.
@@ -1588,10 +1593,10 @@ module.exports = function(grunt) {
encoding: 'utf8',
} );
// `data:` URLs are allowed:
- const match = contents.match( /sourceMappingURL=((?!data:).)/ );
+ const doesNotHaveSourceMap = ! /^\/\/# sourceMappingURL=((?!data:).)/m.test(contents);
assert(
- match === null,
+ doesNotHaveSourceMap,
`The ${ file } file must not contain a sourceMappingURL.`
);
} );
diff --git a/composer.json b/composer.json
index 750952457ff17..632ebd9f63136 100644
--- a/composer.json
+++ b/composer.json
@@ -10,13 +10,14 @@
"issues": "https://core.trac.wordpress.org/"
},
"require": {
+ "ext-json": "*",
"php": ">=7.0"
},
"suggest": {
"ext-dom": "*"
},
"require-dev": {
- "squizlabs/php_codesniffer": "3.7.2",
+ "squizlabs/php_codesniffer": "3.8.1",
"wp-coding-standards/wpcs": "~3.0.1",
"phpcompatibility/phpcompatibility-wp": "~2.1.3",
"yoast/phpunit-polyfills": "^1.1.0"
diff --git a/package-lock.json b/package-lock.json
index 620787e67eea9..8be5038019fdb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,74 +11,77 @@
"dependencies": {
"@emotion/is-prop-valid": "0.8.8",
"@emotion/memoize": "0.7.4",
- "@wordpress/a11y": "3.42.13",
- "@wordpress/annotations": "2.42.13",
- "@wordpress/api-fetch": "6.39.13",
- "@wordpress/autop": "3.42.13",
- "@wordpress/blob": "3.42.13",
- "@wordpress/block-directory": "4.19.16",
- "@wordpress/block-editor": "12.10.14",
- "@wordpress/block-library": "8.19.16",
- "@wordpress/block-serialization-default-parser": "4.42.13",
- "@wordpress/blocks": "12.19.13",
- "@wordpress/commands": "0.13.14",
- "@wordpress/components": "25.8.14",
- "@wordpress/compose": "6.19.13",
- "@wordpress/core-commands": "0.11.14",
- "@wordpress/core-data": "6.19.14",
- "@wordpress/customize-widgets": "4.19.16",
- "@wordpress/data": "9.12.13",
- "@wordpress/data-controls": "3.11.13",
- "@wordpress/date": "4.42.13",
- "@wordpress/deprecated": "3.42.13",
- "@wordpress/dom": "3.42.13",
- "@wordpress/dom-ready": "3.42.13",
- "@wordpress/edit-post": "7.19.16",
- "@wordpress/edit-site": "5.19.16",
- "@wordpress/edit-widgets": "5.19.16",
- "@wordpress/editor": "13.19.14",
- "@wordpress/element": "5.19.13",
- "@wordpress/escape-html": "2.42.13",
- "@wordpress/format-library": "4.19.14",
- "@wordpress/hooks": "3.42.13",
- "@wordpress/html-entities": "3.42.13",
- "@wordpress/i18n": "4.42.13",
- "@wordpress/icons": "9.33.13",
- "@wordpress/interactivity": "2.3.13",
- "@wordpress/interface": "5.19.14",
- "@wordpress/is-shallow-equal": "4.42.13",
- "@wordpress/keyboard-shortcuts": "4.19.13",
- "@wordpress/keycodes": "3.42.13",
- "@wordpress/list-reusable-blocks": "4.19.14",
- "@wordpress/media-utils": "4.33.13",
- "@wordpress/notices": "4.10.13",
- "@wordpress/nux": "8.4.14",
- "@wordpress/patterns": "1.3.14",
- "@wordpress/plugins": "6.10.14",
- "@wordpress/preferences": "3.19.14",
- "@wordpress/preferences-persistence": "1.34.13",
- "@wordpress/primitives": "3.40.13",
- "@wordpress/priority-queue": "2.42.13",
- "@wordpress/private-apis": "0.24.13",
- "@wordpress/redux-routine": "4.42.13",
- "@wordpress/reusable-blocks": "4.19.14",
- "@wordpress/rich-text": "6.19.13",
- "@wordpress/router": "0.11.13",
- "@wordpress/server-side-render": "4.19.14",
- "@wordpress/shortcode": "3.42.13",
- "@wordpress/style-engine": "1.25.13",
- "@wordpress/sync": "0.4.13",
- "@wordpress/token-list": "2.42.13",
- "@wordpress/undo-manager": "0.2.13",
- "@wordpress/url": "3.43.13",
- "@wordpress/viewport": "5.19.13",
- "@wordpress/warning": "2.42.13",
- "@wordpress/widgets": "3.19.14",
- "@wordpress/wordcount": "3.42.13",
+ "@wordpress/a11y": "3.50.0",
+ "@wordpress/annotations": "2.50.0",
+ "@wordpress/api-fetch": "6.47.0",
+ "@wordpress/autop": "3.50.0",
+ "@wordpress/blob": "3.50.0",
+ "@wordpress/block-directory": "4.27.2",
+ "@wordpress/block-editor": "12.18.2",
+ "@wordpress/block-library": "8.27.2",
+ "@wordpress/block-serialization-default-parser": "4.50.0",
+ "@wordpress/blocks": "12.27.1",
+ "@wordpress/commands": "0.21.0",
+ "@wordpress/components": "25.16.0",
+ "@wordpress/compose": "6.27.0",
+ "@wordpress/core-commands": "0.19.2",
+ "@wordpress/core-data": "6.27.2",
+ "@wordpress/customize-widgets": "4.27.2",
+ "@wordpress/data": "9.20.0",
+ "@wordpress/data-controls": "3.19.0",
+ "@wordpress/dataviews": "0.4.1",
+ "@wordpress/date": "4.50.0",
+ "@wordpress/deprecated": "3.50.0",
+ "@wordpress/dom": "3.50.0",
+ "@wordpress/dom-ready": "3.50.0",
+ "@wordpress/edit-post": "7.27.2",
+ "@wordpress/edit-site": "5.27.2",
+ "@wordpress/edit-widgets": "5.27.2",
+ "@wordpress/editor": "13.27.2",
+ "@wordpress/element": "5.27.0",
+ "@wordpress/escape-html": "2.50.0",
+ "@wordpress/format-library": "4.27.2",
+ "@wordpress/hooks": "3.50.0",
+ "@wordpress/html-entities": "3.50.0",
+ "@wordpress/i18n": "4.50.0",
+ "@wordpress/icons": "9.41.0",
+ "@wordpress/interactivity": "4.0.1",
+ "@wordpress/interactivity-router": "1.0.1",
+ "@wordpress/interface": "5.27.0",
+ "@wordpress/is-shallow-equal": "4.50.0",
+ "@wordpress/keyboard-shortcuts": "4.27.0",
+ "@wordpress/keycodes": "3.50.0",
+ "@wordpress/list-reusable-blocks": "4.27.0",
+ "@wordpress/media-utils": "4.41.0",
+ "@wordpress/notices": "4.18.0",
+ "@wordpress/nux": "8.12.0",
+ "@wordpress/patterns": "1.11.2",
+ "@wordpress/plugins": "6.18.0",
+ "@wordpress/preferences": "3.27.0",
+ "@wordpress/preferences-persistence": "1.42.0",
+ "@wordpress/primitives": "3.48.0",
+ "@wordpress/priority-queue": "2.50.0",
+ "@wordpress/private-apis": "0.32.0",
+ "@wordpress/redux-routine": "4.50.0",
+ "@wordpress/reusable-blocks": "4.27.2",
+ "@wordpress/rich-text": "6.27.0",
+ "@wordpress/router": "0.19.0",
+ "@wordpress/server-side-render": "4.27.1",
+ "@wordpress/shortcode": "3.50.0",
+ "@wordpress/style-engine": "1.33.1",
+ "@wordpress/sync": "0.12.0",
+ "@wordpress/token-list": "2.50.0",
+ "@wordpress/undo-manager": "0.10.0",
+ "@wordpress/url": "3.51.0",
+ "@wordpress/viewport": "5.27.0",
+ "@wordpress/warning": "2.50.0",
+ "@wordpress/widgets": "3.27.2",
+ "@wordpress/wordcount": "3.50.0",
"backbone": "1.5.0",
"clipboard": "2.0.11",
"core-js-url-browser": "3.6.4",
"element-closest": "^3.0.2",
+ "es-module-shims": "1.8.2",
"formdata-polyfill": "4.0.10",
"framer-motion": "10.16.4",
"hoverintent": "2.2.1",
@@ -98,6 +101,7 @@
"polyfill-library": "4.8.0",
"react": "18.2.0",
"react-dom": "18.2.0",
+ "react-is": "18.2.0",
"regenerator-runtime": "0.14.0",
"tslib": "2.6.2",
"underscore": "1.13.6",
@@ -108,11 +112,12 @@
"@lodder/grunt-postcss": "^3.1.1",
"@playwright/test": "1.32.0",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.5",
- "@wordpress/babel-preset-default": "7.26.13",
- "@wordpress/dependency-extraction-webpack-plugin": "4.25.13",
- "@wordpress/e2e-test-utils": "10.13.13",
- "@wordpress/e2e-test-utils-playwright": "0.10.13",
- "@wordpress/scripts": "26.13.13",
+ "@wordpress/babel-preset-default": "7.34.0",
+ "@wordpress/dependency-extraction-webpack-plugin": "5.1.0",
+ "@wordpress/e2e-test-utils": "10.21.0",
+ "@wordpress/e2e-test-utils-playwright": "0.18.0",
+ "@wordpress/prettier-config": "3.7.0",
+ "@wordpress/scripts": "27.1.0",
"autoprefixer": "10.4.16",
"chalk": "5.3.0",
"check-node-version": "4.2.1",
@@ -185,16 +190,16 @@
}
},
"node_modules/@ariakit/core": {
- "version": "0.2.7",
- "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.2.7.tgz",
- "integrity": "sha512-Hs0N1EMYq88WW4v9xnSIHNR38TvbQuoUX6FYFmeLCZSTIXQBiET7lr1DQXwOOmdEtRtlxQ5HsxbTkxeOkPv+eg=="
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.3.11.tgz",
+ "integrity": "sha512-+MnOeqnA4FLI/7vqsZLbZQHHN4ofd9kvkNjz44fNi0gqmD+ZbMWiDkFAvZII75dYnxYw5ZPpWjA4waK22VBWig=="
},
"node_modules/@ariakit/react": {
- "version": "0.2.12",
- "resolved": "https://registry.npmjs.org/@ariakit/react/-/react-0.2.12.tgz",
- "integrity": "sha512-4rAgMyUURHW78EKgRCanhyRUtsiYCOxO65BBHF4mg3tZsDeOvu9kBG5IAXX8mUgakTcyr0EKXuOtGThaj7gobA==",
+ "version": "0.3.14",
+ "resolved": "https://registry.npmjs.org/@ariakit/react/-/react-0.3.14.tgz",
+ "integrity": "sha512-h71BPMZ2eW+E2ESbdYxSAEMR1DozYzd5eHE5IOzGd9Egi5u7EZxqmuW4CXVXZ1Y6vbaDMV3SudgPh7iHS/ArFw==",
"dependencies": {
- "@ariakit/react-core": "0.2.12"
+ "@ariakit/react-core": "0.3.14"
},
"funding": {
"type": "opencollective",
@@ -206,11 +211,11 @@
}
},
"node_modules/@ariakit/react-core": {
- "version": "0.2.12",
- "resolved": "https://registry.npmjs.org/@ariakit/react-core/-/react-core-0.2.12.tgz",
- "integrity": "sha512-3KSKlX10nnhCvjsbPW0CAnqG+6grryfwnMkeJJ/h34FSV7hEfUMexmIjKBVZyfBG08Xj8NjSK8kkx9c3ChkXeA==",
+ "version": "0.3.14",
+ "resolved": "https://registry.npmjs.org/@ariakit/react-core/-/react-core-0.3.14.tgz",
+ "integrity": "sha512-16Qj6kDPglpdWtU5roY9q+G66naOjauTY5HvUIaL2aLY0187ATaRrABIKoMMzTtJyhvsud4jFlzivz+/zCQ8yw==",
"dependencies": {
- "@ariakit/core": "0.2.7",
+ "@ariakit/core": "0.3.11",
"@floating-ui/dom": "^1.0.0",
"use-sync-external-store": "^1.2.0"
},
@@ -3645,19 +3650,11 @@
"node": ">= 8"
}
},
- "node_modules/@pkgr/utils": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz",
- "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==",
+ "node_modules/@pkgr/core": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
+ "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
"dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "fast-glob": "^3.3.0",
- "is-glob": "^4.0.3",
- "open": "^9.1.0",
- "picocolors": "^1.0.0",
- "tslib": "^2.6.0"
- },
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
@@ -3665,80 +3662,6 @@
"url": "https://opencollective.com/unts"
}
},
- "node_modules/@pkgr/utils/node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/@pkgr/utils/node_modules/define-lazy-prop": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
- "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@pkgr/utils/node_modules/open": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz",
- "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==",
- "dev": true,
- "dependencies": {
- "default-browser": "^4.0.0",
- "define-lazy-prop": "^3.0.0",
- "is-inside-container": "^1.0.0",
- "is-wsl": "^2.2.0"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/@pkgr/utils/node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@pkgr/utils/node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@pkgr/utils/node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/@playwright/test": {
"version": "1.32.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.0.tgz",
@@ -3888,9 +3811,9 @@
}
},
"node_modules/@polka/url": {
- "version": "1.0.0-next.21",
- "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
- "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
+ "version": "1.0.0-next.24",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz",
+ "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==",
"dev": true
},
"node_modules/@popperjs/core": {
@@ -3903,9 +3826,9 @@
}
},
"node_modules/@preact/signals": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@preact/signals/-/signals-1.2.1.tgz",
- "integrity": "sha512-hRPvp1C2ooDzOHqfnhdpHgoIFDbYFAXLhoid3+jSItuPPD/J0r/UsiWKv/8ZO/oEhjRaP0M5niuRYsWqmY2GEA==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@preact/signals/-/signals-1.2.2.tgz",
+ "integrity": "sha512-ColCqdo4cRP18bAuIR4Oik5rDpiyFtPIJIygaYPMEAwTnl4buWkBOflGBSzhYyPyJfKpkwlekrvK+1pzQ2ldWw==",
"dependencies": {
"@preact/signals-core": "^1.4.0"
},
@@ -3918,9 +3841,9 @@
}
},
"node_modules/@preact/signals-core": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.5.0.tgz",
- "integrity": "sha512-U2diO1Z4i1n2IoFgMYmRdHWGObNrcuTRxyNEn7deSq2cru0vj0583HYQZHsAqcs7FE+hQyX3mjIV7LAfHCvy8w==",
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.5.1.tgz",
+ "integrity": "sha512-dE6f+WCX5ZUDwXzUIWNMhhglmuLpqJhuy3X3xHrhZYI0Hm2LyQwOu0l9mdPiWrVNsE+Q7txOnJPgtIqHCYoBVA==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
@@ -4114,35 +4037,6 @@
"@babel/runtime": "^7.13.10"
}
},
- "node_modules/@radix-ui/react-arrow": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.2.tgz",
- "integrity": "sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-primitive": "1.0.2"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
- "node_modules/@radix-ui/react-collection": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.2.tgz",
- "integrity": "sha512-s8WdQQ6wNXpaxdZ308KSr8fEWGrg4un8i4r/w7fhiS4ElRNjk5rRcl0/C6TANG2LvLOGIxtzo/jAg6Qf73TEBw==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-slot": "1.0.1"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
"node_modules/@radix-ui/react-compose-refs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
@@ -4297,53 +4191,6 @@
}
}
},
- "node_modules/@radix-ui/react-direction": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.0.tgz",
- "integrity": "sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==",
- "dependencies": {
- "@babel/runtime": "^7.13.10"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0"
- }
- },
- "node_modules/@radix-ui/react-dismissable-layer": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.3.tgz",
- "integrity": "sha512-nXZOvFjOuHS1ovumntGV7NNoLaEp9JEvTht3MBjP44NSW5hUKj/8OnfN3+8WmB+CEhN44XaGhpHoSsUIEl5P7Q==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/primitive": "1.0.0",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-callback-ref": "1.0.0",
- "@radix-ui/react-use-escape-keydown": "1.0.2"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
- "node_modules/@radix-ui/react-dropdown-menu": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.4.tgz",
- "integrity": "sha512-y6AT9+MydyXcByivdK1+QpjWoKaC7MLjkS/cH1Q3keEyMvDkiY85m8o2Bi6+Z1PPUlCsMULopxagQOSfN0wahg==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/primitive": "1.0.0",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-id": "1.0.0",
- "@radix-ui/react-menu": "2.0.4",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-controllable-state": "1.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
"node_modules/@radix-ui/react-focus-guards": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz",
@@ -4355,21 +4202,6 @@
"react": "^16.8 || ^17.0 || ^18.0"
}
},
- "node_modules/@radix-ui/react-focus-scope": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.2.tgz",
- "integrity": "sha512-spwXlNTfeIprt+kaEWE/qYuYT3ZAqJiAGjN/JgdvgVDTu8yc+HuX+WOWXrKliKnLnwck0F6JDkqIERncnih+4A==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-callback-ref": "1.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
"node_modules/@radix-ui/react-id": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",
@@ -4382,97 +4214,6 @@
"react": "^16.8 || ^17.0 || ^18.0"
}
},
- "node_modules/@radix-ui/react-menu": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.4.tgz",
- "integrity": "sha512-mzKR47tZ1t193trEqlQoJvzY4u9vYfVH16ryBrVrCAGZzkgyWnMQYEZdUkM7y8ak9mrkKtJiqB47TlEnubeOFQ==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/primitive": "1.0.0",
- "@radix-ui/react-collection": "1.0.2",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-direction": "1.0.0",
- "@radix-ui/react-dismissable-layer": "1.0.3",
- "@radix-ui/react-focus-guards": "1.0.0",
- "@radix-ui/react-focus-scope": "1.0.2",
- "@radix-ui/react-id": "1.0.0",
- "@radix-ui/react-popper": "1.1.1",
- "@radix-ui/react-portal": "1.0.2",
- "@radix-ui/react-presence": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-roving-focus": "1.0.3",
- "@radix-ui/react-slot": "1.0.1",
- "@radix-ui/react-use-callback-ref": "1.0.0",
- "aria-hidden": "^1.1.1",
- "react-remove-scroll": "2.5.5"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
- "node_modules/@radix-ui/react-popper": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.1.tgz",
- "integrity": "sha512-keYDcdMPNMjSC8zTsZ8wezUMiWM9Yj14wtF3s0PTIs9srnEPC9Kt2Gny1T3T81mmSeyDjZxsD9N5WCwNNb712w==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@floating-ui/react-dom": "0.7.2",
- "@radix-ui/react-arrow": "1.0.2",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-callback-ref": "1.0.0",
- "@radix-ui/react-use-layout-effect": "1.0.0",
- "@radix-ui/react-use-rect": "1.0.0",
- "@radix-ui/react-use-size": "1.0.0",
- "@radix-ui/rect": "1.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
- "node_modules/@radix-ui/react-popper/node_modules/@floating-ui/core": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
- "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
- },
- "node_modules/@radix-ui/react-popper/node_modules/@floating-ui/dom": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
- "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
- "dependencies": {
- "@floating-ui/core": "^0.7.3"
- }
- },
- "node_modules/@radix-ui/react-popper/node_modules/@floating-ui/react-dom": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.2.tgz",
- "integrity": "sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==",
- "dependencies": {
- "@floating-ui/dom": "^0.5.3",
- "use-isomorphic-layout-effect": "^1.1.1"
- },
- "peerDependencies": {
- "react": ">=16.8.0",
- "react-dom": ">=16.8.0"
- }
- },
- "node_modules/@radix-ui/react-portal": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.2.tgz",
- "integrity": "sha512-swu32idoCW7KA2VEiUZGBSu9nB6qwGdV6k6HYhUoOo3M1FFpD+VgLzUqtt3mwL1ssz7r2x8MggpLSQach2Xy/Q==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-primitive": "1.0.2"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
"node_modules/@radix-ui/react-presence": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz",
@@ -4487,52 +4228,6 @@
"react-dom": "^16.8 || ^17.0 || ^18.0"
}
},
- "node_modules/@radix-ui/react-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz",
- "integrity": "sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-slot": "1.0.1"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
- "node_modules/@radix-ui/react-roving-focus": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.3.tgz",
- "integrity": "sha512-stjCkIoMe6h+1fWtXlA6cRfikdBzCLp3SnVk7c48cv/uy3DTGoXhN76YaOYUJuy3aEDvDIKwKR5KSmvrtPvQPQ==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/primitive": "1.0.0",
- "@radix-ui/react-collection": "1.0.2",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-direction": "1.0.0",
- "@radix-ui/react-id": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-callback-ref": "1.0.0",
- "@radix-ui/react-use-controllable-state": "1.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0",
- "react-dom": "^16.8 || ^17.0 || ^18.0"
- }
- },
- "node_modules/@radix-ui/react-slot": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz",
- "integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-compose-refs": "1.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0"
- }
- },
"node_modules/@radix-ui/react-use-callback-ref": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz",
@@ -4556,18 +4251,6 @@
"react": "^16.8 || ^17.0 || ^18.0"
}
},
- "node_modules/@radix-ui/react-use-escape-keydown": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz",
- "integrity": "sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-use-callback-ref": "1.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0"
- }
- },
"node_modules/@radix-ui/react-use-layout-effect": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz",
@@ -4579,38 +4262,6 @@
"react": "^16.8 || ^17.0 || ^18.0"
}
},
- "node_modules/@radix-ui/react-use-rect": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.0.tgz",
- "integrity": "sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/rect": "1.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0"
- }
- },
- "node_modules/@radix-ui/react-use-size": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.0.tgz",
- "integrity": "sha512-imZ3aYcoYCKhhgNpkNDh/aTiU05qw9hX+HHI1QDBTyIlcFjgeFlKKySNGMwTp7nYFLQg/j0VA2FmCY4WPDDHMg==",
- "dependencies": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-use-layout-effect": "1.0.0"
- },
- "peerDependencies": {
- "react": "^16.8 || ^17.0 || ^18.0"
- }
- },
- "node_modules/@radix-ui/rect": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.0.tgz",
- "integrity": "sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg==",
- "dependencies": {
- "@babel/runtime": "^7.13.10"
- }
- },
"node_modules/@react-spring/animated": {
"version": "9.7.1",
"resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.1.tgz",
@@ -5522,9 +5173,9 @@
}
},
"node_modules/@types/body-parser": {
- "version": "1.19.2",
- "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
- "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
+ "version": "1.19.5",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
+ "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
"dev": true,
"dependencies": {
"@types/connect": "*",
@@ -5532,27 +5183,27 @@
}
},
"node_modules/@types/bonjour": {
- "version": "3.5.10",
- "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz",
- "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==",
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz",
+ "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/connect": {
- "version": "3.4.35",
- "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
- "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
"dev": true,
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@types/connect-history-api-fallback": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz",
- "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==",
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz",
+ "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==",
"dev": true,
"dependencies": {
"@types/express-serve-static-core": "*",
@@ -5586,9 +5237,9 @@
"dev": true
},
"node_modules/@types/express": {
- "version": "4.17.17",
- "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
- "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
+ "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
"dev": true,
"dependencies": {
"@types/body-parser": "*",
@@ -5598,14 +5249,15 @@
}
},
"node_modules/@types/express-serve-static-core": {
- "version": "4.17.33",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz",
- "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==",
+ "version": "4.17.41",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz",
+ "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==",
"dev": true,
"dependencies": {
"@types/node": "*",
"@types/qs": "*",
- "@types/range-parser": "*"
+ "@types/range-parser": "*",
+ "@types/send": "*"
}
},
"node_modules/@types/glob": {
@@ -5627,10 +5279,26 @@
"@types/node": "*"
}
},
+ "node_modules/@types/gradient-parser": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@types/gradient-parser/-/gradient-parser-0.1.3.tgz",
+ "integrity": "sha512-XDbrTSBlQV9nxE1GiDL3FaOPy4G/KaJkhDutBX48Kg8CYZMBARyyDFGCWfWJn4pobmInmwud1xxH7VJMAr0CKQ=="
+ },
+ "node_modules/@types/highlight-words-core": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/highlight-words-core/-/highlight-words-core-1.2.1.tgz",
+ "integrity": "sha512-9VZUA5omXBfn+hDxFjUDu1FOJTBM3LmvqfDey+Z6Aa8B8/JmF5SMj6FBrjfgJ/Q3YXOZd3qyTDfJyMZSs/wCUA=="
+ },
+ "node_modules/@types/http-errors": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
+ "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
+ "dev": true
+ },
"node_modules/@types/http-proxy": {
- "version": "1.17.9",
- "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz",
- "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==",
+ "version": "1.17.14",
+ "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz",
+ "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==",
"dev": true,
"dependencies": {
"@types/node": "*"
@@ -5706,9 +5374,9 @@
"dev": true
},
"node_modules/@types/mime": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
- "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==",
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
"dev": true
},
"node_modules/@types/minimatch": {
@@ -5731,8 +5399,16 @@
"node_modules/@types/node": {
"version": "14.14.20",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz",
- "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==",
- "dev": true
+ "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A=="
+ },
+ "node_modules/@types/node-forge": {
+ "version": "1.3.11",
+ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz",
+ "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/node": "*"
+ }
},
"node_modules/@types/normalize-package-data": {
"version": "2.4.1",
@@ -5758,15 +5434,15 @@
"optional": true
},
"node_modules/@types/qs": {
- "version": "6.9.7",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
- "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
+ "version": "6.9.11",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz",
+ "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==",
"dev": true
},
"node_modules/@types/range-parser": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
- "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
"dev": true
},
"node_modules/@types/react": {
@@ -5799,34 +5475,53 @@
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
},
"node_modules/@types/semver": {
- "version": "7.5.5",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz",
- "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==",
+ "version": "7.5.6",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
+ "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==",
"dev": true
},
+ "node_modules/@types/send": {
+ "version": "0.17.4",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
+ "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
+ "dev": true,
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/serve-index": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz",
- "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==",
+ "version": "1.9.4",
+ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz",
+ "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==",
"dev": true,
"dependencies": {
"@types/express": "*"
}
},
"node_modules/@types/serve-static": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz",
- "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==",
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
+ "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
"dev": true,
"dependencies": {
+ "@types/http-errors": "*",
"@types/mime": "*",
"@types/node": "*"
}
},
+ "node_modules/@types/simple-peer": {
+ "version": "9.11.8",
+ "resolved": "https://registry.npmjs.org/@types/simple-peer/-/simple-peer-9.11.8.tgz",
+ "integrity": "sha512-rvqefdp2rvIA6wiomMgKWd2UZNPe6LM2EV5AuY3CPQJF+8TbdrL5TjYdMf0VAjGczzlkH4l1NjDkihwbj3Xodw==",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
"node_modules/@types/sockjs": {
- "version": "0.3.33",
- "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz",
- "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==",
+ "version": "0.3.36",
+ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz",
+ "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==",
"dev": true,
"dependencies": {
"@types/node": "*"
@@ -5918,9 +5613,9 @@
}
},
"node_modules/@types/ws": {
- "version": "8.5.4",
- "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
- "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
+ "version": "8.5.10",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
+ "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==",
"dev": true,
"dependencies": {
"@types/node": "*"
@@ -5952,16 +5647,16 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.11.0.tgz",
- "integrity": "sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz",
+ "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==",
"dev": true,
"dependencies": {
"@eslint-community/regexpp": "^4.5.1",
- "@typescript-eslint/scope-manager": "6.11.0",
- "@typescript-eslint/type-utils": "6.11.0",
- "@typescript-eslint/utils": "6.11.0",
- "@typescript-eslint/visitor-keys": "6.11.0",
+ "@typescript-eslint/scope-manager": "6.19.1",
+ "@typescript-eslint/type-utils": "6.19.1",
+ "@typescript-eslint/utils": "6.19.1",
+ "@typescript-eslint/visitor-keys": "6.19.1",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
"ignore": "^5.2.4",
@@ -5987,15 +5682,15 @@
}
},
"node_modules/@typescript-eslint/parser": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.11.0.tgz",
- "integrity": "sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz",
+ "integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==",
"dev": true,
"dependencies": {
- "@typescript-eslint/scope-manager": "6.11.0",
- "@typescript-eslint/types": "6.11.0",
- "@typescript-eslint/typescript-estree": "6.11.0",
- "@typescript-eslint/visitor-keys": "6.11.0",
+ "@typescript-eslint/scope-manager": "6.19.1",
+ "@typescript-eslint/types": "6.19.1",
+ "@typescript-eslint/typescript-estree": "6.19.1",
+ "@typescript-eslint/visitor-keys": "6.19.1",
"debug": "^4.3.4"
},
"engines": {
@@ -6015,13 +5710,13 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.11.0.tgz",
- "integrity": "sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz",
+ "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "6.11.0",
- "@typescript-eslint/visitor-keys": "6.11.0"
+ "@typescript-eslint/types": "6.19.1",
+ "@typescript-eslint/visitor-keys": "6.19.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
@@ -6032,13 +5727,13 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.11.0.tgz",
- "integrity": "sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz",
+ "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==",
"dev": true,
"dependencies": {
- "@typescript-eslint/typescript-estree": "6.11.0",
- "@typescript-eslint/utils": "6.11.0",
+ "@typescript-eslint/typescript-estree": "6.19.1",
+ "@typescript-eslint/utils": "6.19.1",
"debug": "^4.3.4",
"ts-api-utils": "^1.0.1"
},
@@ -6059,9 +5754,9 @@
}
},
"node_modules/@typescript-eslint/types": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.11.0.tgz",
- "integrity": "sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz",
+ "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==",
"dev": true,
"engines": {
"node": "^16.0.0 || >=18.0.0"
@@ -6072,16 +5767,17 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.11.0.tgz",
- "integrity": "sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz",
+ "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "6.11.0",
- "@typescript-eslint/visitor-keys": "6.11.0",
+ "@typescript-eslint/types": "6.19.1",
+ "@typescript-eslint/visitor-keys": "6.19.1",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
+ "minimatch": "9.0.3",
"semver": "^7.5.4",
"ts-api-utils": "^1.0.1"
},
@@ -6098,18 +5794,42 @@
}
}
},
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+ "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/@typescript-eslint/utils": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.11.0.tgz",
- "integrity": "sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz",
+ "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12",
"@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "6.11.0",
- "@typescript-eslint/types": "6.11.0",
- "@typescript-eslint/typescript-estree": "6.11.0",
+ "@typescript-eslint/scope-manager": "6.19.1",
+ "@typescript-eslint/types": "6.19.1",
+ "@typescript-eslint/typescript-estree": "6.19.1",
"semver": "^7.5.4"
},
"engines": {
@@ -6124,12 +5844,12 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.11.0.tgz",
- "integrity": "sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz",
+ "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==",
"dev": true,
"dependencies": {
- "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/types": "6.19.1",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
@@ -6315,34 +6035,42 @@
}
},
"node_modules/@webpack-cli/configtest": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
- "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz",
+ "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==",
"dev": true,
+ "engines": {
+ "node": ">=14.15.0"
+ },
"peerDependencies": {
- "webpack": "4.x.x || 5.x.x",
- "webpack-cli": "4.x.x"
+ "webpack": "5.x.x",
+ "webpack-cli": "5.x.x"
}
},
"node_modules/@webpack-cli/info": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
- "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz",
+ "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==",
"dev": true,
- "dependencies": {
- "envinfo": "^7.7.3"
+ "engines": {
+ "node": ">=14.15.0"
},
"peerDependencies": {
- "webpack-cli": "4.x.x"
+ "webpack": "5.x.x",
+ "webpack-cli": "5.x.x"
}
},
"node_modules/@webpack-cli/serve": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
- "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz",
+ "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==",
"dev": true,
+ "engines": {
+ "node": ">=14.15.0"
+ },
"peerDependencies": {
- "webpack-cli": "4.x.x"
+ "webpack": "5.x.x",
+ "webpack-cli": "5.x.x"
},
"peerDependenciesMeta": {
"webpack-dev-server": {
@@ -6351,28 +6079,28 @@
}
},
"node_modules/@wordpress/a11y": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-3.42.13.tgz",
- "integrity": "sha512-57KH89dbt8ipimoBGezKQHLvwSsJHW/W4HpvzZFqnPHvnlNNYoVC9UuqiBavxdB2WkzMPmNYFKsM7kOInEdyTA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-3.50.0.tgz",
+ "integrity": "sha512-eQiPGnxqiL1LgnHztFG0RGSFZ5phwR8B8Fr4lbJsFalsc9R/tOcjewvf2KN0yi2UlRA5ssAeiTP+tYmeAqtOHQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/dom-ready": "^3.42.13",
- "@wordpress/i18n": "^4.42.13"
+ "@wordpress/dom-ready": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/annotations": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/annotations/-/annotations-2.42.13.tgz",
- "integrity": "sha512-S/bCU8AOYzVMKBSMMtmoB9Dw1kiOS3KNfFzdCLpiyzNhfqXPWp7ciM5WJTHJRdzobeTOh1CIJ6x5WHhBqO/t8w==",
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/annotations/-/annotations-2.50.0.tgz",
+ "integrity": "sha512-E9cu8xuGvIRw3LVtuS+XSzAXVBF41sgvxpVJAz/5FEibzxUHPy8flu5tTKf+mi4WGZxC4AJGNP1bhZRj7cynZQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/data": "^9.12.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/rich-text": "^6.19.13",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/rich-text": "^6.27.0",
"rememo": "^4.0.2",
"uuid": "^9.0.1"
},
@@ -6384,22 +6112,22 @@
}
},
"node_modules/@wordpress/api-fetch": {
- "version": "6.39.13",
- "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.39.13.tgz",
- "integrity": "sha512-DFaiNq5bEOVqYDpcqXqdxjyBDboeElma6e7FNSX2APVZZt/8xxeb4eI9X0877i6B15G5blyHsjSit5rq88iqtg==",
+ "version": "6.47.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.47.0.tgz",
+ "integrity": "sha512-NA/jWDXoVtJmiVBYhlxts2UrgKJpJM+zTGzLCfRQCZUzpJYm3LonB8x+uCQ78nEyxCY397Esod3jnbquYjOr0Q==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/url": "^3.51.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/autop": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-3.42.13.tgz",
- "integrity": "sha512-vQjEvJaYZ5OyMJ6IdbVL/RUqOy/VTe6E1BCkdRW8amJTm8koTkbBbOFWSsVoXh6jFoq2mDAqC7Tt2vL0yMA4rQ==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-3.50.0.tgz",
+ "integrity": "sha512-4E0vq2MvSOVDKXs4OulIbTdKU6S5O9QjT4qc63rAd0uiKGBYV12ViPzmwbJ6k38zOO0PKdcwlVCj55Gq4aoPDw==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -6408,9 +6136,9 @@
}
},
"node_modules/@wordpress/babel-plugin-import-jsx-pragma": {
- "version": "4.26.0",
- "resolved": "https://registry.npmjs.org/@wordpress/babel-plugin-import-jsx-pragma/-/babel-plugin-import-jsx-pragma-4.26.0.tgz",
- "integrity": "sha512-XZCTBqEmOlM87/6wkgtHhnHaj8cJPOY5avyjKtMDwoBbcXAmHUknbphZG7KEWIiVIilyxKyHnsTxjTplkqTtCQ==",
+ "version": "4.33.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/babel-plugin-import-jsx-pragma/-/babel-plugin-import-jsx-pragma-4.33.0.tgz",
+ "integrity": "sha512-CjzruFKWgzU/mO/nnQJ2l9UlzZQpqS60UC6l2vNdJ9oD2nKHR5Oou6kNic3QhWDVJrBf2JUiJJ0TC280bykXmA==",
"dev": true,
"engines": {
"node": ">=14"
@@ -6420,9 +6148,9 @@
}
},
"node_modules/@wordpress/babel-preset-default": {
- "version": "7.26.13",
- "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-7.26.13.tgz",
- "integrity": "sha512-kW9sg3lwbrhYzVR24n7cUEC2Sx1Pj4UNnITbXqVmxnVok0CK7IkvstMlbtLDbULh9o2f92OPNMwdAStErEjT7g==",
+ "version": "7.34.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-7.34.0.tgz",
+ "integrity": "sha512-yjFOllyTktFHtcIEgU3ghXBn8lItzr5mPLf0xdSpe0cHceFYL1hT1oprhgRL+olZweaO96Yfm0qUCCKQfJBWsA==",
"dev": true,
"dependencies": {
"@babel/core": "^7.16.0",
@@ -6431,27 +6159,27 @@
"@babel/preset-env": "^7.16.0",
"@babel/preset-typescript": "^7.16.0",
"@babel/runtime": "^7.16.0",
- "@wordpress/babel-plugin-import-jsx-pragma": "^4.25.13",
- "@wordpress/browserslist-config": "^5.25.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/warning": "^2.42.13",
- "browserslist": "^4.21.9",
- "core-js": "^3.31.0"
+ "@wordpress/babel-plugin-import-jsx-pragma": "^4.33.0",
+ "@wordpress/browserslist-config": "^5.33.0",
+ "@wordpress/warning": "^2.50.0",
+ "browserslist": "^4.21.10",
+ "core-js": "^3.31.0",
+ "react": "^18.2.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/@wordpress/base-styles": {
- "version": "4.34.0",
- "resolved": "https://registry.npmjs.org/@wordpress/base-styles/-/base-styles-4.34.0.tgz",
- "integrity": "sha512-LYiNFWl+6yJDVQ7hSNJu2kVuM1p3C3aTB769lXnMSxi3gubzxqjZqz9i9XQ3UjO9EFiDSvgbOXa8YhvTUfNnkQ==",
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/base-styles/-/base-styles-4.41.0.tgz",
+ "integrity": "sha512-MjPAZeAqvyskDXDp2wGZ0DjtYOQLOydI1WqVIZS4wnIdhsQWQD//VMeXgLrcmCzNyQg+iKTx3o+BzmXVTOD0+w==",
"dev": true
},
"node_modules/@wordpress/blob": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-3.42.13.tgz",
- "integrity": "sha512-W5TaJK9Vl8LInjdxRRq5hE08r34JKybVjm7UuSIPOppNErLu9g6edcGHsv3b/7f5so3TcSnPsLfDkPgwSFTjXA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-3.50.0.tgz",
+ "integrity": "sha512-QvBhsW9WPdsOJhJ0BxzZ83i+cH/gAdjJ1iHY4Rkb02qbZEz4jhdvucGQf2oVnWwvAsFiFPKWk7CwAM5XjoahCA==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -6460,29 +6188,30 @@
}
},
"node_modules/@wordpress/block-directory": {
- "version": "4.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-4.19.16.tgz",
- "integrity": "sha512-7YOqeZt8ExyMidbblzht7x5jnfpZVD6N69VuDrvdlB/8eB7gl62tKZdNXHwWoZccSWJb+xUTZL01k2HpJulcPQ==",
+ "version": "4.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-4.27.2.tgz",
+ "integrity": "sha512-EblzP8BbkqAeFomH3/L9wdmbz1iw0n2siBMdZNZKHifwWv0iLFQfZlMZo4ImgWwC4YE3is7zSGpkWJ1kHMbj7w==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/edit-post": "^7.19.16",
- "@wordpress/editor": "^13.19.14",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/edit-post": "^7.27.2",
+ "@wordpress/editor": "^13.27.2",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0",
"change-case": "^4.1.2"
},
"engines": {
@@ -6494,44 +6223,43 @@
}
},
"node_modules/@wordpress/block-editor": {
- "version": "12.10.14",
- "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-12.10.14.tgz",
- "integrity": "sha512-x56FPZZfJPk/Vd1aKIdpBIllrUuAVgwom+mYH0OohCmUzCBp1Eg8Urg5nshZpiLXpHt2dXycQCLu2Mpb+YpOJw==",
+ "version": "12.18.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-12.18.2.tgz",
+ "integrity": "sha512-LDZIcp5Bl2FCyfkf07XgfM0kzY+AYhyTS4kt2U4GRSeUey79AM+GIYXb8TM2Y68B09HP/rpntBW4e/cBqjHfjw==",
"dependencies": {
"@babel/runtime": "^7.16.0",
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@react-spring/web": "^9.4.5",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/commands": "^0.13.14",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/shortcode": "^3.42.13",
- "@wordpress/style-engine": "^1.25.13",
- "@wordpress/token-list": "^2.42.13",
- "@wordpress/url": "^3.43.13",
- "@wordpress/warning": "^2.42.13",
- "@wordpress/wordcount": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/style-engine": "^1.33.1",
+ "@wordpress/token-list": "^2.50.0",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/warning": "^2.50.0",
+ "@wordpress/wordcount": "^3.50.0",
"change-case": "^4.1.2",
"classnames": "^2.3.1",
"colord": "^2.7.0",
@@ -6539,12 +6267,14 @@
"diff": "^4.0.2",
"dom-scroll-into-view": "^1.2.1",
"fast-deep-equal": "^3.1.3",
- "inherits": "^2.0.3",
+ "memize": "^2.1.0",
+ "postcss": "^8.4.21",
+ "postcss-prefixwrap": "^1.41.0",
+ "postcss-urlrebase": "^1.0.0",
"react-autosize-textarea": "^7.1.0",
"react-easy-crop": "^4.5.1",
"rememo": "^4.0.2",
- "remove-accents": "^0.5.0",
- "traverse": "^0.6.6"
+ "remove-accents": "^0.5.0"
},
"engines": {
"node": ">=12"
@@ -6555,41 +6285,43 @@
}
},
"node_modules/@wordpress/block-library": {
- "version": "8.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-8.19.16.tgz",
- "integrity": "sha512-6NqTHjEYk3X+jzw6JS3pOgVYl2HPlr0iAI3Ch9sdOxozAm1+VrE5DKeM//rf9QpR7wWJ6je4F/eNjZ2WJIYTfw==",
+ "version": "8.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-8.27.2.tgz",
+ "integrity": "sha512-Wabc1nmCMuTr/BgS63iHaQYtvfVO9Z30SwLaMVLHwGe7Hrvtb19pSOwKb/PIuoiWrlqJ/sZEZPXFENAJB5FVYA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/autop": "^3.42.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interactivity": "^2.3.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/primitives": "^3.40.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/reusable-blocks": "^4.19.14",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/server-side-render": "^4.19.14",
- "@wordpress/url": "^3.43.13",
- "@wordpress/viewport": "^5.19.13",
- "@wordpress/wordcount": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/autop": "^3.50.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interactivity": "^4.0.1",
+ "@wordpress/interactivity-router": "^1.0.1",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/patterns": "^1.11.2",
+ "@wordpress/primitives": "^3.48.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/reusable-blocks": "^4.27.2",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/server-side-render": "^4.27.1",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/viewport": "^5.27.0",
+ "@wordpress/wordcount": "^3.50.0",
"change-case": "^4.1.2",
"classnames": "^2.3.1",
"colord": "^2.7.0",
@@ -6609,9 +6341,9 @@
}
},
"node_modules/@wordpress/block-serialization-default-parser": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-4.42.13.tgz",
- "integrity": "sha512-+ggjHxrjbpIwknsfKy18HXOVGWHeFykxlElE9dYVspJvr734mMMTQuIeL5WM+vZUy5NWv0oHF0VykX0MHyy60w==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-4.50.0.tgz",
+ "integrity": "sha512-ihf2vr+w2zHBOvYTPQZXDiR2IMvso8yJJtzKIHA2ZEgVQ+VVLb4X86n34hfWXtPA3i2KDW+t1WCtq56aNq3Zag==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -6620,32 +6352,33 @@
}
},
"node_modules/@wordpress/blocks": {
- "version": "12.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-12.19.13.tgz",
- "integrity": "sha512-KdNcYb5Cr4sgzOkJM+KpPZeLLFr8e06CkRDp0EQk7VGSsoScXpqIcMEtMcKNQp1XPuJ6npMr/BacC5qNjyHA1A==",
+ "version": "12.27.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-12.27.1.tgz",
+ "integrity": "sha512-9uZtuTG6+fiFV2bLn8b1gzv4BgMpBu4SDQGnvzc5f9U5GL5oYns3PP8vXDOwM2cK1DEmqPsohQWhRnz8QYZDtw==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/autop": "^3.42.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/block-serialization-default-parser": "^4.42.13",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/shortcode": "^3.42.13",
+ "@wordpress/autop": "^3.50.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/block-serialization-default-parser": "^4.50.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/shortcode": "^3.50.0",
"change-case": "^4.1.2",
"colord": "^2.7.0",
- "deepmerge": "^4.3.0",
"fast-deep-equal": "^3.1.3",
"hpq": "^1.3.0",
"is-plain-object": "^5.0.0",
"memize": "^2.1.0",
+ "react-is": "^18.2.0",
"rememo": "^4.0.2",
"remove-accents": "^0.5.0",
"showdown": "^1.9.1",
@@ -6660,27 +6393,27 @@
}
},
"node_modules/@wordpress/browserslist-config": {
- "version": "5.26.0",
- "resolved": "https://registry.npmjs.org/@wordpress/browserslist-config/-/browserslist-config-5.26.0.tgz",
- "integrity": "sha512-rpkxAnPOc4HuxKZBwZ1iV1oC0Rd21azzBDyS8OoVUW6V8DAv4eYfHNFGkyds7Z+nI6dI15Rl7xJYJhHJKVaJvg==",
+ "version": "5.33.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/browserslist-config/-/browserslist-config-5.33.0.tgz",
+ "integrity": "sha512-dv1ZlpqGk8gaSBJPP/Z/1uOuxjtP0EBsHVKInLRu6FWLTJkK8rnCeC3xJT3/2TtJ0rasLC79RoytfhXTOODVwg==",
"dev": true,
"engines": {
"node": ">=14"
}
},
"node_modules/@wordpress/commands": {
- "version": "0.13.14",
- "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-0.13.14.tgz",
- "integrity": "sha512-aSOuRbsr+YYFvRbkXaubHdlAtf/xpG1mUWXEw9VMWCag77hiK6vk04Xb3N8ad8eo8am0N/iRgn8V8IS4LyBTyA==",
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-0.21.0.tgz",
+ "integrity": "sha512-MzMUGCT9cQXto1jrA5lHAtnieTyAhcuNIxfyxlcE+316KNQfbyD8bc7KOzSV2sxXD/rfHuCxvHjfomFyyP+4kA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/components": "^25.8.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/private-apis": "^0.24.13",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/private-apis": "^0.32.0",
"classnames": "^2.3.1",
"cmdk": "^0.2.0",
"rememo": "^4.0.2"
@@ -6694,11 +6427,11 @@
}
},
"node_modules/@wordpress/components": {
- "version": "25.8.14",
- "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-25.8.14.tgz",
- "integrity": "sha512-wRQSRlLXsL4bEd1JhCQPSdIb0bO4WDAloQufeyIbXUIK9CDgN/jmkv+vrgKrpP3Nqu1sBAFzW1qd9WEXfSBgXw==",
+ "version": "25.16.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-25.16.0.tgz",
+ "integrity": "sha512-voQuMsO5JbH+JW33TnWurwwvpSb8IQ4XU5wyVMubX4TUwadt+/2ToNJbZIDXoaJPei7vbM81Ft+pH+zGlN8CyA==",
"dependencies": {
- "@ariakit/react": "^0.2.12",
+ "@ariakit/react": "^0.3.12",
"@babel/runtime": "^7.16.0",
"@emotion/cache": "^11.7.1",
"@emotion/css": "^11.7.1",
@@ -6707,25 +6440,26 @@
"@emotion/styled": "^11.6.0",
"@emotion/utils": "^1.0.0",
"@floating-ui/react-dom": "^2.0.1",
- "@radix-ui/react-dropdown-menu": "2.0.4",
+ "@types/gradient-parser": "0.1.3",
+ "@types/highlight-words-core": "1.2.1",
"@use-gesture/react": "^10.2.24",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/primitives": "^3.40.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/warning": "^2.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/primitives": "^3.48.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/warning": "^2.50.0",
"change-case": "^4.1.2",
"classnames": "^2.3.1",
"colord": "^2.7.0",
@@ -6757,21 +6491,21 @@
}
},
"node_modules/@wordpress/compose": {
- "version": "6.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-6.19.13.tgz",
- "integrity": "sha512-3HDdccND+EoEr7tHQ75eCDh07e5TdFh0KFIdWGweq9gU5Z/tssRW8QEyU9J+xEz+DTL/hvFilQ681f58eUZi1g==",
+ "version": "6.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-6.27.0.tgz",
+ "integrity": "sha512-jbEQQ2znRyJTwUNR4m5BKaDyIsuK9TMZx0SKqP+FTfGqT3y7scOnQrHpK0kZdPji++/1cBbn3gSPBLCEmtmHRw==",
"dependencies": {
"@babel/runtime": "^7.16.0",
"@types/mousetrap": "^1.6.8",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/priority-queue": "^2.42.13",
- "@wordpress/undo-manager": "^0.2.13",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/priority-queue": "^2.50.0",
+ "@wordpress/undo-manager": "^0.10.0",
"change-case": "^4.1.2",
- "clipboard": "^2.0.8",
+ "clipboard": "^2.0.11",
"mousetrap": "^1.6.5",
"use-memo-one": "^1.1.1"
},
@@ -6783,21 +6517,21 @@
}
},
"node_modules/@wordpress/core-commands": {
- "version": "0.11.14",
- "resolved": "https://registry.npmjs.org/@wordpress/core-commands/-/core-commands-0.11.14.tgz",
- "integrity": "sha512-f2DA9lUji96OC5UD85Gbv2vz14R0TR+FSXzXAa68F/EBPFkiaxs2huhruhRvZKbasxugk/vjTBbQuwZ8rinROA==",
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/core-commands/-/core-commands-0.19.2.tgz",
+ "integrity": "sha512-9ewP1fxB8MB5u15zMZBfShgGN2qJl+fBXCWR9MXB3gi8gA/Kd600W5I/jh2nLJuCRou09SsRzI6s+ihnir/V4A==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/commands": "^0.13.14",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/router": "^0.11.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/router": "^0.19.0",
+ "@wordpress/url": "^3.51.0"
},
"engines": {
"node": ">=12"
@@ -6808,25 +6542,26 @@
}
},
"node_modules/@wordpress/core-data": {
- "version": "6.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-6.19.14.tgz",
- "integrity": "sha512-wdstu/qMBKwXnFRX4wMeTkxvHsOgbXm7ZJ0Lgtj+jE86O086Ook7suxacOdMcCaAKNCfMqoGBHtjsNQk3SWE1Q==",
+ "version": "6.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-6.27.2.tgz",
+ "integrity": "sha512-Jsy+vW/izrd/T36D/4b266ScobCezNYX2Me/clCmHGB4eRW3drXZPbMnWZLNEDagYr87sQcM1Namasb69dnDhA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/sync": "^0.4.13",
- "@wordpress/undo-manager": "^0.2.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/sync": "^0.12.0",
+ "@wordpress/undo-manager": "^0.10.0",
+ "@wordpress/url": "^3.51.0",
"change-case": "^4.1.2",
"equivalent-key-map": "^0.2.2",
"fast-deep-equal": "^3.1.3",
@@ -6843,31 +6578,31 @@
}
},
"node_modules/@wordpress/customize-widgets": {
- "version": "4.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/customize-widgets/-/customize-widgets-4.19.16.tgz",
- "integrity": "sha512-UK4RrEBFwdn8WcY7qXXbRcncuWXLMpB9gjiBVhwPmM5m1//A0wsOQu2kAkZeACuhYoEJ/N6g4yZh2ZnldJVR3w==",
+ "version": "4.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/customize-widgets/-/customize-widgets-4.27.2.tgz",
+ "integrity": "sha512-zq/PacEqW8eMX6LKeMHn39JNU2ZJ3GiCH3+oOeI3eewN8/aGrtJJh1btSL0liLTDXo6dqnQ8AXHjGu9/J/XDSg==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/block-library": "^8.19.16",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interface": "^5.19.14",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/widgets": "^3.19.14",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/block-library": "^8.27.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interface": "^5.27.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/widgets": "^3.27.2",
"classnames": "^2.3.1",
"fast-deep-equal": "^3.1.3"
},
@@ -6880,25 +6615,24 @@
}
},
"node_modules/@wordpress/data": {
- "version": "9.12.13",
- "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-9.12.13.tgz",
- "integrity": "sha512-8SIsPFrnQ1LIZRWseOF+9uQ9thy8oB7NSOq+bkRCo+qldagooBTZUFp8Y++evFbPOotmTy6XGSPYf7HV9qBHVw==",
+ "version": "9.20.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-9.20.0.tgz",
+ "integrity": "sha512-3cm2te6NUj/X1zzmRO+WhueCanjocniX6sJFVzkg5mGXme6wFI8iSOnGPKlMkGcZGd0fVei1ydBKaIUMjrPBTQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/priority-queue": "^2.42.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/redux-routine": "^4.42.13",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/priority-queue": "^2.50.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/redux-routine": "^4.50.0",
"deepmerge": "^4.3.0",
"equivalent-key-map": "^0.2.2",
"is-plain-object": "^5.0.0",
"is-promise": "^4.0.0",
"redux": "^4.1.2",
"rememo": "^4.0.2",
- "turbo-combine-reducers": "^1.0.2",
"use-memo-one": "^1.1.1"
},
"engines": {
@@ -6909,14 +6643,39 @@
}
},
"node_modules/@wordpress/data-controls": {
- "version": "3.11.13",
- "resolved": "https://registry.npmjs.org/@wordpress/data-controls/-/data-controls-3.11.13.tgz",
- "integrity": "sha512-BW7yBPePnS5SVMVTTWeHG1U4RwV4X46NVOvX4/Vvq8CBjLmvqbiXZZxLMYI4xBi1y6+XRDjORHXP3WMJzwTdEg==",
+ "version": "3.19.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/data-controls/-/data-controls-3.19.0.tgz",
+ "integrity": "sha512-ceUK8kB8r8s8XFYlYWGVLuaoDJx5IAXND6q7B6MX1gKndqnSNi1766Q9iAEwOT9eVMai0lDLNq7mdK2ktVh4bw==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13"
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "peerDependencies": {
+ "react": "^18.0.0"
+ }
+ },
+ "node_modules/@wordpress/dataviews": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/dataviews/-/dataviews-0.4.1.tgz",
+ "integrity": "sha512-9ZTP5l9lyLMK95uEuAbOkILPIa2XvYxm2qa5Yo6SEUJbKnOVGCGH1fcNX1GuzHHrJwclYA3TeGgMaYoXpudjjw==",
+ "dependencies": {
+ "@babel/runtime": "^7.16.0",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/primitives": "^3.48.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "classnames": "^2.3.1",
+ "remove-accents": "^0.5.0"
},
"engines": {
"node": ">=12"
@@ -6926,12 +6685,12 @@
}
},
"node_modules/@wordpress/date": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-4.42.13.tgz",
- "integrity": "sha512-SrJL7WbnQwSmogyNiFA+ZKNuECPvneCZOVzC/76DIV7seVDbpdJky/3UAkQLMgvYzym5PK3A8vkENPgAykrh3g==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-4.50.0.tgz",
+ "integrity": "sha512-FhfaG6YRXWmni66RjwhCB7rQNlLJ05+qTa/jXrj2UNWDNv/sfZ6Ky+b/rKrrUnLaIs9pGiW1195cSxsAS4EY3w==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/deprecated": "^3.42.13",
+ "@wordpress/deprecated": "^3.50.0",
"moment": "^2.29.4",
"moment-timezone": "^0.5.40"
},
@@ -6940,49 +6699,48 @@
}
},
"node_modules/@wordpress/dependency-extraction-webpack-plugin": {
- "version": "4.25.13",
- "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-4.25.13.tgz",
- "integrity": "sha512-ke3CkU9wWgMpAsf5E1zG7aN/pr9P3qdDaIOgU2kXbjSLxrbhgBeK4mCgT/uxCJu0uqaieYkZWRcNmxXKMbF9hw==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-5.1.0.tgz",
+ "integrity": "sha512-W2W+9JNAaGirAtGDSf83pjEKb63DLhgpJGgvMOpEPoRPtucgO6CCm3uMoNkJTpKoxJQ2tSZEymAhF/YdLm+ScQ==",
"dev": true,
"dependencies": {
- "json2php": "^0.0.7",
- "webpack-sources": "^3.2.2"
+ "json2php": "^0.0.7"
},
"engines": {
- "node": ">=14"
+ "node": ">=18"
},
"peerDependencies": {
- "webpack": "^4.8.3 || ^5.0.0"
+ "webpack": "^5.0.0"
}
},
"node_modules/@wordpress/deprecated": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-3.42.13.tgz",
- "integrity": "sha512-Jxivx5eTKhjVNW1/rqShM1dzDKm/9wKp9jPlF58uAXpQSIaH8Q09D6Pgzi72DsDyefL8SV/QllLQbo0bVenydg==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-3.50.0.tgz",
+ "integrity": "sha512-DL01l0Wlo3df9OcSGHP11Ot/nq0HytbdmD+iPkiCCRI6Xctepbs/DzRR2CO3qLrJkWn6RReFwZWZZjzI7lZUqg==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/hooks": "^3.42.13"
+ "@wordpress/hooks": "^3.50.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/dom": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-3.42.13.tgz",
- "integrity": "sha512-E7TnWuSOrxY5sn57+6Bf5v7JAL9PmNrOljf8Jj7FDsRdH6tCXf8BDqyIBz53cmzv/bsWOklQKIOeU/BQoEItHw==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-3.50.0.tgz",
+ "integrity": "sha512-rMnV1ysGOHbKnmjLQYwGkT1co1iEkC3YsKrEObP8mklw1R7rbCy7fc2brIz7kqcHU1DRyg/+7wOCMkg8a/EV/Q==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/deprecated": "^3.42.13"
+ "@wordpress/deprecated": "^3.50.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/dom-ready": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.42.13.tgz",
- "integrity": "sha512-mtqstqT1YFfIGl8rQipG9d8UwvGIZUP4Y8E1Tq3V9CAMV6ChJEYCZIGs/asHjqJSebNnXEWUEzQKAbPnIhnW3Q==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.50.0.tgz",
+ "integrity": "sha512-97tJpat1emXnwfGlJMiG6p37CpHJXDLmM/SIbsGJ0Oj8P4/TXbTuE9DNT1H8B1wKe5zD7kICjp48y91ugmgSrQ==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -6991,15 +6749,15 @@
}
},
"node_modules/@wordpress/e2e-test-utils": {
- "version": "10.13.13",
- "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-10.13.13.tgz",
- "integrity": "sha512-QibCpLfRW6Stm5BDd1zxc0eqX3uOE1yINPs8K7esUIHL8AqnCPEJUPa86NnOIaA2t8E52f+bhlTxzM7ZsaffoQ==",
+ "version": "10.21.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-10.21.0.tgz",
+ "integrity": "sha512-Oh62GkqAKBIyD0IO3/Oa0l42yL/jbpTRDyh8H+t6gZbHWYTDvEGEr/LOqI9bk5Lwk7Jt5jpN6136FDwyMzHSXw==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/url": "^3.51.0",
"change-case": "^4.1.2",
"form-data": "^4.0.0",
"node-fetch": "^2.6.0"
@@ -7013,19 +6771,20 @@
}
},
"node_modules/@wordpress/e2e-test-utils-playwright": {
- "version": "0.10.13",
- "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.10.13.tgz",
- "integrity": "sha512-5zqIsG6Nn6N0DBlK9GyvYKxUrK7dEBHFInRnIqqfimWAQmz07iBCJU34njs9lQi+/GzKfXS+2XgBI7dDQnbfwQ==",
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.18.0.tgz",
+ "integrity": "sha512-Z8uH1dUzy/STQjOU6eb9nquVK4RC1rUx0gXY/GN1IVNDJvGN/yJxT/gNKmfiL7KpmHvNp2Q5M4bnUT9uiNcM+Q==",
"dev": true,
"dependencies": {
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/url": "^3.51.0",
"change-case": "^4.1.2",
"form-data": "^4.0.0",
"get-port": "^5.1.1",
"lighthouse": "^10.4.0",
- "mime": "^3.0.0"
+ "mime": "^3.0.0",
+ "web-vitals": "^3.5.0"
},
"engines": {
"node": ">=12"
@@ -7034,79 +6793,6 @@
"@playwright/test": ">=1"
}
},
- "node_modules/@wordpress/e2e-test-utils-playwright/node_modules/@wordpress/api-fetch": {
- "version": "6.40.0",
- "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.40.0.tgz",
- "integrity": "sha512-sNk6vZW02ldci1EpNIjmm61323x/0n2Ra/cDHuehZf8avOH/OV0zF0dXxttT8M9Fncz+XZDSIHopm76dU3Phug==",
- "dev": true,
- "dependencies": {
- "@babel/runtime": "^7.16.0",
- "@wordpress/i18n": "^4.43.0",
- "@wordpress/url": "^3.44.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@wordpress/e2e-test-utils-playwright/node_modules/@wordpress/hooks": {
- "version": "3.43.0",
- "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.43.0.tgz",
- "integrity": "sha512-SHSiyFUEsggihl0pDvY1l72q+fHMDyFHtIR3GCt0uV2ifctvoa/PIYdVwrxpGQaGdNEV25XCZ4kNldqJmfTddw==",
- "dev": true,
- "dependencies": {
- "@babel/runtime": "^7.16.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@wordpress/e2e-test-utils-playwright/node_modules/@wordpress/i18n": {
- "version": "4.43.0",
- "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.43.0.tgz",
- "integrity": "sha512-XHU/vGgI+pgjJU9WzWDHke1u948z8i3OPpKUNdxc/gMcTkKaKM4D8DW1+VMSQHyU6pneP8+ph7EF+1RIehP3lQ==",
- "dev": true,
- "dependencies": {
- "@babel/runtime": "^7.16.0",
- "@wordpress/hooks": "^3.43.0",
- "gettext-parser": "^1.3.1",
- "memize": "^2.1.0",
- "sprintf-js": "^1.1.1",
- "tannin": "^1.2.0"
- },
- "bin": {
- "pot-to-php": "tools/pot-to-php.js"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@wordpress/e2e-test-utils-playwright/node_modules/@wordpress/keycodes": {
- "version": "3.43.0",
- "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.43.0.tgz",
- "integrity": "sha512-B6rYPiKFdQTlnJfm93R+usQnjEODUX/K4+hMvY5ZZOinvxe7KyU/xyFGz7gRrS8WmIEYcJowqSmAlGgVs4XwKQ==",
- "dev": true,
- "dependencies": {
- "@babel/runtime": "^7.16.0",
- "@wordpress/i18n": "^4.43.0",
- "change-case": "^4.1.2"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@wordpress/e2e-test-utils-playwright/node_modules/@wordpress/url": {
- "version": "3.44.0",
- "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.44.0.tgz",
- "integrity": "sha512-QNtTPFg/cGHTJLOvOtQCvCgn5quFQgJml8A88I05o4dyUH/tc92rb8LNXi0qcVz/z4JPrx2g3+Ki8heYellP4A==",
- "dev": true,
- "dependencies": {
- "@babel/runtime": "^7.16.0",
- "remove-accents": "^0.5.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
"node_modules/@wordpress/e2e-test-utils-playwright/node_modules/form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
@@ -7148,41 +6834,41 @@
}
},
"node_modules/@wordpress/edit-post": {
- "version": "7.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-7.19.16.tgz",
- "integrity": "sha512-PK0XVHLrn6Bg47O8sq7UIBykJOJGF2xsbkOjhRVniD+6EYdYifpGYHTC9nHogEfw691xcz+vAqS87D01x3SfEQ==",
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-7.27.2.tgz",
+ "integrity": "sha512-GEWPr2TkzOH2OZx+WVtn+DGrkE+H5GOq1w+vAtoCEq1lLIdkGJe+YAieJKkSz/rqah25YzmRcyBgfYSL2iaULg==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/block-library": "^8.19.16",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/commands": "^0.13.14",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-commands": "^0.11.14",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/editor": "^13.19.14",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interface": "^5.19.14",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/url": "^3.43.13",
- "@wordpress/viewport": "^5.19.13",
- "@wordpress/warning": "^2.42.13",
- "@wordpress/widgets": "^3.19.14",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/block-library": "^8.27.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-commands": "^0.19.2",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/editor": "^13.27.2",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interface": "^5.27.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/viewport": "^5.27.0",
+ "@wordpress/warning": "^2.50.0",
+ "@wordpress/widgets": "^3.27.2",
"classnames": "^2.3.1",
"memize": "^2.1.0",
"rememo": "^4.0.2"
@@ -7196,54 +6882,55 @@
}
},
"node_modules/@wordpress/edit-site": {
- "version": "5.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/edit-site/-/edit-site-5.19.16.tgz",
- "integrity": "sha512-shraoCd4LCNngtBn9E7U6Na/l+zrU0nTXztgZSuVsqSGktAgHBi7pXMUTsCGqO/vp9fnmW9LU3tQ9XgLEogjkg==",
+ "version": "5.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/edit-site/-/edit-site-5.27.2.tgz",
+ "integrity": "sha512-/lZhqadnX/A7owFre4ZxcKjlj7pisdxVAQJgtB9OYSdpreG2x8sGNKvLhv686BTKzSffS1TzvmKbNl7e+pQZDA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/block-library": "^8.19.16",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/commands": "^0.13.14",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-commands": "^0.11.14",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/editor": "^13.19.14",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interface": "^5.19.14",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/patterns": "^1.3.14",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/primitives": "^3.40.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/reusable-blocks": "^4.19.14",
- "@wordpress/router": "^0.11.13",
- "@wordpress/style-engine": "^1.25.13",
- "@wordpress/url": "^3.43.13",
- "@wordpress/viewport": "^5.19.13",
- "@wordpress/widgets": "^3.19.14",
- "@wordpress/wordcount": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/block-library": "^8.27.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-commands": "^0.19.2",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/dataviews": "^0.4.1",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/editor": "^13.27.2",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interface": "^5.27.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/patterns": "^1.11.2",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/primitives": "^3.48.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/reusable-blocks": "^4.27.2",
+ "@wordpress/router": "^0.19.0",
+ "@wordpress/style-engine": "^1.33.1",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/viewport": "^5.27.0",
+ "@wordpress/widgets": "^3.27.2",
+ "@wordpress/wordcount": "^3.50.0",
"change-case": "^4.1.2",
"classnames": "^2.3.1",
"colord": "^2.9.2",
"deepmerge": "^4.3.0",
- "downloadjs": "^1.4.7",
"fast-deep-equal": "^3.1.3",
"is-plain-object": "^5.0.0",
"memize": "^2.1.0",
@@ -7260,38 +6947,39 @@
}
},
"node_modules/@wordpress/edit-widgets": {
- "version": "5.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/edit-widgets/-/edit-widgets-5.19.16.tgz",
- "integrity": "sha512-1yTkLHQjf/LEmxlw2y0bqgkZcqO2Gs0H8QK1JHEJdHrAK+R5nBd55Jq4Wb2IU+QsUAaGvQzuF+FfHAA4YkLUwQ==",
+ "version": "5.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/edit-widgets/-/edit-widgets-5.27.2.tgz",
+ "integrity": "sha512-AE5qgDCd5u16C3/EZQAP3STcxfpTZg2Ed6iHmN+PBg1RCEP11rv31aMaXy2+7Z+80bGsXwicmZAlqHxzm2vc2g==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/block-library": "^8.19.16",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interface": "^5.19.14",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/patterns": "^1.3.14",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/reusable-blocks": "^4.19.14",
- "@wordpress/url": "^3.43.13",
- "@wordpress/widgets": "^3.19.14",
- "classnames": "^2.3.1"
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/block-library": "^8.27.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interface": "^5.27.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/patterns": "^1.11.2",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/reusable-blocks": "^4.27.2",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/widgets": "^3.27.2",
+ "classnames": "^2.3.1",
+ "rememo": "^4.0.2"
},
"engines": {
"node": ">=12"
@@ -7302,40 +6990,41 @@
}
},
"node_modules/@wordpress/editor": {
- "version": "13.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-13.19.14.tgz",
- "integrity": "sha512-t1RFJl0Bf+qJpBHtiUl0qoxJjpNNGcpSZLejnhR97+i32l/4ewg8+z69zwFtW4ChNQjLnAFnpQZ5pT/CqkkKpQ==",
+ "version": "13.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-13.27.2.tgz",
+ "integrity": "sha512-Wk1dwG5bkmDD74zip36yC1NO3EleXe/t35Z9GHfLaiZkUYlhZV2gv66QrrGN7Y59Zl68j+b4lRGLkUxEMWkleA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/patterns": "^1.3.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/reusable-blocks": "^4.19.14",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/server-side-render": "^4.19.14",
- "@wordpress/url": "^3.43.13",
- "@wordpress/wordcount": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/patterns": "^1.11.2",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/reusable-blocks": "^4.27.2",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/server-side-render": "^4.27.1",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/wordcount": "^3.50.0",
"classnames": "^2.3.1",
"date-fns": "^2.28.0",
"memize": "^2.1.0",
@@ -7352,14 +7041,14 @@
}
},
"node_modules/@wordpress/element": {
- "version": "5.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.19.13.tgz",
- "integrity": "sha512-8VSGNrJkSf0coC2xciFBFodVa6eQOLPKMThVAz1eIDtQwbAcFo9001tjkMXgyhcn/FMoxdhaGGOxg4VeUvgJSw==",
+ "version": "5.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.27.0.tgz",
+ "integrity": "sha512-IA5LTAfx5bDNXULPmctcNb/04i4JcnIReG0RAuPgrZ8lbMZWUxGFymh10PEQjs7ZJ++qGsI6E+6JISpjkRaDQQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
- "@wordpress/escape-html": "^2.42.13",
+ "@wordpress/escape-html": "^2.50.0",
"change-case": "^4.1.2",
"is-plain-object": "^5.0.0",
"react": "^18.2.0",
@@ -7370,9 +7059,9 @@
}
},
"node_modules/@wordpress/escape-html": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.42.13.tgz",
- "integrity": "sha512-0I7loSc8M1vjqg6vXb6lCumaGzbbAeoI26NEpATcEq24MLgd8+UiidyHII4UNgdloRoq1Jj3e83AjDhFpAVfAg==",
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.50.0.tgz",
+ "integrity": "sha512-hBvoMCEZocziZDGCmBanSO+uupnd054mxd7FQ6toQ4UnsZ4JwXSmEC72W2Ed+cRGB1DeJDD0dY9iC0b4xkumsQ==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -7381,16 +7070,16 @@
}
},
"node_modules/@wordpress/eslint-plugin": {
- "version": "16.0.13",
- "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-16.0.13.tgz",
- "integrity": "sha512-Qk5Y7ifT0lfOOx5RQrEGa/DSw01CP+D2bCKr20SXLt3KDstViBlqjBiI1Yxv7EeS+AvaNbQO5M8Mm4B5mUB3kQ==",
+ "version": "17.7.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-17.7.0.tgz",
+ "integrity": "sha512-JSFaCogE0WlZpl0SV4q8DK8G6jwDjEzXRzOsgesWilea4OuVp1KxCamkddTorRNM3QAbjrGuPJ4NYaGrNG9QsA==",
"dev": true,
"dependencies": {
"@babel/eslint-parser": "^7.16.0",
"@typescript-eslint/eslint-plugin": "^6.4.1",
"@typescript-eslint/parser": "^6.4.1",
- "@wordpress/babel-preset-default": "^7.26.13",
- "@wordpress/prettier-config": "^2.25.13",
+ "@wordpress/babel-preset-default": "^7.34.0",
+ "@wordpress/prettier-config": "^3.7.0",
"cosmiconfig": "^7.0.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.25.2",
@@ -7411,7 +7100,7 @@
"peerDependencies": {
"@babel/core": ">=7",
"eslint": ">=8",
- "prettier": ">=2",
+ "prettier": ">=3",
"typescript": ">=4"
},
"peerDependenciesMeta": {
@@ -7424,9 +7113,9 @@
}
},
"node_modules/@wordpress/eslint-plugin/node_modules/globals": {
- "version": "13.23.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
- "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
"dev": true,
"dependencies": {
"type-fest": "^0.20.2"
@@ -7439,22 +7128,23 @@
}
},
"node_modules/@wordpress/format-library": {
- "version": "4.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/format-library/-/format-library-4.19.14.tgz",
- "integrity": "sha512-NyJ1nmb6PODE5hXM9oOEBlYA48k6c2DlGcUTXkSzDcdLPRVinTeWDfPL4kpze30JcQPv9m6Y5/EfWp48bDnByA==",
+ "version": "4.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/format-library/-/format-library-4.27.2.tgz",
+ "integrity": "sha512-pgLWc+8QuRyWc3GtEL1X18u4FNmWI3Y821TbKW1MjnfMDYNhN7Vpypqk4AFuxq2PY0NxzmM0PGdcoqUXRGdldQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/url": "^3.51.0"
},
"engines": {
"node": ">=12"
@@ -7465,9 +7155,9 @@
}
},
"node_modules/@wordpress/hooks": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.42.13.tgz",
- "integrity": "sha512-KITkyj2DhbbBevqLzGx4GCtq8XX/GjkMWe0NP7SkcX9d4rkEdON96eKwwoMUD6keL03Tijg87kIYZAU5Xsr8bA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.50.0.tgz",
+ "integrity": "sha512-YIhwT1y0ss7Byfz46NBx08EUmXzWMu+g5DCY7FMuDNhwxSEoZMB8edKMiwNmFk4mFKBCnXM1d5FeONUPIUkJwg==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -7476,9 +7166,9 @@
}
},
"node_modules/@wordpress/html-entities": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.42.13.tgz",
- "integrity": "sha512-015rUF0FOSGXbUBq+sc++vo3UTGZZkl23z7tGxrTTXZG10AjcTVd3oMnpvffJeiBjrtEAJz/gq3QKpFXihvmww==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.50.0.tgz",
+ "integrity": "sha512-DBRgShv6FLtDpapoTgmEx//6uHeq+mk5zKhAWAAqu6+/6LqOm/TCoUTxb0E2xtHh4oRBgU5nYC92pObRaczFdQ==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -7487,12 +7177,12 @@
}
},
"node_modules/@wordpress/i18n": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.42.13.tgz",
- "integrity": "sha512-4zYz5BbueJ3c19DYhO7cXf9GF2K5Fysd+c2r0rcE0lr2RqMqmyDdL49930L7XJw+mT4ql8g/8p+i3FOzPCsg9A==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.50.0.tgz",
+ "integrity": "sha512-FkA2se6HMQm4eFC+/kTWvWQqs51VxpZuvY2MlWUp/L1r1d/dMBHXu049x86+/+6yk3ZNqiK5h6j6Z76dvPHZ4w==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/hooks": "^3.42.13",
+ "@wordpress/hooks": "^3.50.0",
"gettext-parser": "^1.3.1",
"memize": "^2.1.0",
"sprintf-js": "^1.1.1",
@@ -7506,48 +7196,60 @@
}
},
"node_modules/@wordpress/icons": {
- "version": "9.33.13",
- "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.33.13.tgz",
- "integrity": "sha512-4M34sMRIlyL7a3CDRI7rAfysZQm2VW1ptB4aGDf5tVMXd//hCRkj/OGE++AYkTYQNckli9uqhTkv2xoOOw1F6Q==",
+ "version": "9.41.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.41.0.tgz",
+ "integrity": "sha512-L4fp9ZdxGBpMk3o2YqABgiPHNoHyu9Enid7JNkCdWP8iUgk7dEiDvo/XoiWPTAeNbF6W8Nqu54635mq01es0NQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/element": "^5.19.13",
- "@wordpress/primitives": "^3.40.13"
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/primitives": "^3.48.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/interactivity": {
- "version": "2.3.13",
- "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-2.3.13.tgz",
- "integrity": "sha512-WNmw/r+G1XllTZwKwpRDFJoGPm8cRztbU+MJhAogKzUOcrCu4Bp8xArroPSzlKr3aUuEquT/3WsWsFmHsSHYjg==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-4.0.1.tgz",
+ "integrity": "sha512-sw9Cqoj+MNF9FAU5nJC3nAqoH7kgUvh6HwaEMaLdSlK0qEcp05ba5x7geDSNi5cUWY4QSk1r9DH2jKUg9zfpNg==",
+ "dependencies": {
+ "@preact/signals": "^1.2.2",
+ "deepsignal": "^1.4.0",
+ "preact": "^10.19.3"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@wordpress/interactivity-router": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/interactivity-router/-/interactivity-router-1.0.1.tgz",
+ "integrity": "sha512-XShZV0+Sqs+1C26nVyns6nT8kjAGRBJNArVPceZlkkpsX7DIRZcEZ2larWxOuQFWk67lzIRiXd5V51L71b8XrQ==",
"dependencies": {
- "@preact/signals": "^1.1.3",
- "deepsignal": "^1.3.6",
- "preact": "^10.13.2"
+ "@wordpress/interactivity": "^4.0.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/interface": {
- "version": "5.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-5.19.14.tgz",
- "integrity": "sha512-WsIsSKJuhAcXD3YbmUoncL1JZ6hKAJXs7Lb/bjrOJxCts/YOy5yMF3/I05r8f1Tfw/pS8wlHMRjIXH/gvnvWVA==",
+ "version": "5.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-5.27.0.tgz",
+ "integrity": "sha512-ZybF4tuuuFOgGsB0n9u5ajrWKf/PYaS8d2yu2T+6ukliLnXI6AMMCXvM534H0VZa7DMLjMYKRXtfs7QqR/p95Q==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/viewport": "^5.19.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/viewport": "^5.27.0",
"classnames": "^2.3.1"
},
"engines": {
@@ -7559,9 +7261,9 @@
}
},
"node_modules/@wordpress/is-shallow-equal": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-4.42.13.tgz",
- "integrity": "sha512-C3Pdan4alanyaQJ4Ucg7GZvkgDv7mXQZXe0xIYmKUNCnohS3wcFXmaLE6VGvf3I2OhRz8WLh5uxno/suJ8cyRw==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-4.50.0.tgz",
+ "integrity": "sha512-lX0fMa1f/TwWYYF+Oj0MG2Eze4Bb+vsnhXX6X1l+Ri3PG34wWGonjq729qHbJRDwm8o1y9GeswCgESIpuAm9wg==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -7570,9 +7272,9 @@
}
},
"node_modules/@wordpress/jest-console": {
- "version": "7.14.0",
- "resolved": "https://registry.npmjs.org/@wordpress/jest-console/-/jest-console-7.14.0.tgz",
- "integrity": "sha512-o7EZZ+StfLg/qgTRn47O0WY2V1I+xNJCiN13a/fHZtXdRgPJ9qajf7tkDYz+MKPf8MhdMfHhgIr9sQrWhLCzDA==",
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/jest-console/-/jest-console-7.21.0.tgz",
+ "integrity": "sha512-o2vZRlwwJ6WoxRwnFFT5iZzfdc2d9MZvrtwB093RWPNcyK5qVtApji4VN/ieHijB4bjEHGalm0UKfKpt0EDlUQ==",
"dev": true,
"dependencies": {
"@babel/runtime": "^7.16.0",
@@ -7586,12 +7288,12 @@
}
},
"node_modules/@wordpress/jest-preset-default": {
- "version": "11.14.0",
- "resolved": "https://registry.npmjs.org/@wordpress/jest-preset-default/-/jest-preset-default-11.14.0.tgz",
- "integrity": "sha512-eGenm5xUpPcsgWMSFXYWg+RQlcAZa6zo7sT9bBK8HVIGqORTr3TTtWeHVGFL48UooL5PibUc+GxQdlW97YOwlQ==",
+ "version": "11.21.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/jest-preset-default/-/jest-preset-default-11.21.0.tgz",
+ "integrity": "sha512-XAztKOROu02iBsz+Qosv/RYuPWB1XwwlU+FiA5Y68tRztrqFy4b/il+DFg4Jue/zXF7UECWUvosd5ow/GmKa6Q==",
"dev": true,
"dependencies": {
- "@wordpress/jest-console": "^7.14.0",
+ "@wordpress/jest-console": "^7.21.0",
"babel-jest": "^29.6.2"
},
"engines": {
@@ -7603,14 +7305,14 @@
}
},
"node_modules/@wordpress/keyboard-shortcuts": {
- "version": "4.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-4.19.13.tgz",
- "integrity": "sha512-5u/pMERHn1b17d3HqDWWulJp08MLlNG1idsuJiLzbQBrYW3wLPd23fPG1QObUSH/texVDvi/W4/9N4hsbZlXEg==",
+ "version": "4.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-4.27.0.tgz",
+ "integrity": "sha512-mpYhaSAMHXbRMp9hP08LejX/u1nLQaZONhwGSytqIhN1DQwpBbNbmV8ZNm1dnevUsYqEfPVVov6HFyPxYQ6m4w==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/keycodes": "^3.42.13",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/keycodes": "^3.50.0",
"rememo": "^4.0.2"
},
"engines": {
@@ -7621,29 +7323,29 @@
}
},
"node_modules/@wordpress/keycodes": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.42.13.tgz",
- "integrity": "sha512-3lGlnYj+ky5OOnFjTW6NSxFFeNk/ESUF2Gbhz888HV+QF55SPvRfb+G7kjAzxRomIpdwACYsn80PdqabxLVqgw==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.50.0.tgz",
+ "integrity": "sha512-ykWpyCbgwcaT8i5kSfotYtd2oOHyMDpWEYR73InYrzEhl7pnS3wD7hi/KfeKLvMfYhbysUXlCVr6q/oH+qK/DQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/i18n": "^4.42.13",
- "change-case": "^4.1.2"
+ "@wordpress/i18n": "^4.50.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/list-reusable-blocks": {
- "version": "4.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/list-reusable-blocks/-/list-reusable-blocks-4.19.14.tgz",
- "integrity": "sha512-GuorU374D0Ft7RtIZWWc7ltIkV3ThjU/u+LwbNzh5y7iaVs4l64qvqopqoj/IoRVdahpnLEO3MNxj9InlUiNeg==",
+ "version": "4.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/list-reusable-blocks/-/list-reusable-blocks-4.27.0.tgz",
+ "integrity": "sha512-szDQnIdU34yIvNel+Kk1oBOugiqwXNm4jF77T90kaWB/SIQFW80CFYoIjIYQc63r9v3wi0D483KpXoci1AUSeQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
"change-case": "^4.1.2"
},
"engines": {
@@ -7655,28 +7357,28 @@
}
},
"node_modules/@wordpress/media-utils": {
- "version": "4.33.13",
- "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-4.33.13.tgz",
- "integrity": "sha512-+QJvDbBEtjMC6V2kJ04dEZkmElDneueW6HxGcx9lD786N0pcHwHZCnY9mLN+Tg/2f6Y8/9u0emvbFFuX0FLE8w==",
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-4.41.0.tgz",
+ "integrity": "sha512-wCxk8DAhmZ/3/a+oPRrieGurMOKDrYoDnnA0jhTm2D45kvn9y+NfnNBvLo2q1Is1ZiVTtNq54IRUXcdOjZgR9A==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13"
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/notices": {
- "version": "4.10.13",
- "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-4.10.13.tgz",
- "integrity": "sha512-6U0im51yJFXLLMzL6zZ+eyeJIeY2cyiUCDdziJSI1ZrsfV2ml9o4nB3EYYOxZBaVvJg66vY3wIQ/osMFwTW6xg==",
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-4.18.0.tgz",
+ "integrity": "sha512-Y2XpY6niJ7NuqPBtGYvDYSPCfw/y4yxv60ahu1kYd8r5BamKSchTYwKSnV0yrx/IUfNO04VAsNq9NCUQG12pRA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/data": "^9.12.13"
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/data": "^9.20.0"
},
"engines": {
"node": ">=12"
@@ -7686,9 +7388,9 @@
}
},
"node_modules/@wordpress/npm-package-json-lint-config": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@wordpress/npm-package-json-lint-config/-/npm-package-json-lint-config-4.28.0.tgz",
- "integrity": "sha512-lxrs1F4scwDuF8AJLK+SHtLWuhRVjzvl8EW/++ZQWRt7op99m41QQUqUwwCQC09cDcYlGddXeAczRijx5eLREg==",
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/npm-package-json-lint-config/-/npm-package-json-lint-config-4.35.0.tgz",
+ "integrity": "sha512-QmkhYM4/s+2r3RuolVRRmoUa5o3lFgcHA6I3A9akaSVGZr//4p2p+iXOGmNub9njgGlj7j8SAPN8GUsCO/VqZQ==",
"dev": true,
"engines": {
"node": ">=14"
@@ -7698,18 +7400,18 @@
}
},
"node_modules/@wordpress/nux": {
- "version": "8.4.14",
- "resolved": "https://registry.npmjs.org/@wordpress/nux/-/nux-8.4.14.tgz",
- "integrity": "sha512-JcxUtWOzl7lTuv39BWRwzwPDvVEhFECGzK819i3kExbTjmsVHCHtsdB7khPrdAYZOm2GXzR1le+/UFfkGuHS2Q==",
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/nux/-/nux-8.12.0.tgz",
+ "integrity": "sha512-fMnm9f+lmaCV5YoRHjqQNVU0P+FxthY8Lt84ZW1owlPjpJqdYZX/bKtp+bfWFgR3/Th26/uO4WxZqQzj8V1Pjg==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
"rememo": "^4.0.2"
},
"engines": {
@@ -7721,25 +7423,26 @@
}
},
"node_modules/@wordpress/patterns": {
- "version": "1.3.14",
- "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-1.3.14.tgz",
- "integrity": "sha512-eaZWZlaF/MlxqDY7KYzL8cApY4b4f89wuqHVSmjv52UfvaqxW0vd09ddX+jwkcXysDHFzwM63takIIVZwYn9Lg==",
+ "version": "1.11.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-1.11.2.tgz",
+ "integrity": "sha512-cN7xjw5pfKq73mVF0q0ebZh4DmAab5SlQ9CvM7PtB03JOl3GMwVIDV5Tnbbhfi1KIsFwep2/CGft3xwuJlS3FQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0",
+ "nanoid": "^3.3.4"
},
"engines": {
"node": ">=16.0.0"
@@ -7750,17 +7453,17 @@
}
},
"node_modules/@wordpress/plugins": {
- "version": "6.10.14",
- "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-6.10.14.tgz",
- "integrity": "sha512-Duxh0OxpSuUFTMHa500iitrD21/JeTklc8/Hf3ApCpn4SdDzFR4IrwUdoJk0jGDY79cTwBVeWts5GhObbJByng==",
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-6.18.0.tgz",
+ "integrity": "sha512-m2BRJ5BApIMwT2Ck5E5yD8pS3RiIoOvWhzsYWrRqRfwjRhc6K46BreCbkiHgduBaFgzDIWpujlUHkYtdl27RoQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
"memize": "^2.0.1"
},
"engines": {
@@ -7772,12 +7475,12 @@
}
},
"node_modules/@wordpress/postcss-plugins-preset": {
- "version": "4.27.0",
- "resolved": "https://registry.npmjs.org/@wordpress/postcss-plugins-preset/-/postcss-plugins-preset-4.27.0.tgz",
- "integrity": "sha512-4hk8UWfJvv21u/Et0NypfR1r22LVWGXMit3QM0MD7d6XQ4dNNbzqW2c9TfM36SdcR9KY5PZ8d5V1IrkheNUb/w==",
+ "version": "4.34.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/postcss-plugins-preset/-/postcss-plugins-preset-4.34.0.tgz",
+ "integrity": "sha512-OLQBSLE2q11Ik+WdcO2QfGr/O4X/zJYOGXNsychx/EaMamLzJInFcRL6kGbPX41zPINhadq5x2vFIZI2EC+Uyg==",
"dev": true,
"dependencies": {
- "@wordpress/base-styles": "^4.34.0",
+ "@wordpress/base-styles": "^4.41.0",
"autoprefixer": "^10.2.5"
},
"engines": {
@@ -7788,17 +7491,20 @@
}
},
"node_modules/@wordpress/preferences": {
- "version": "3.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-3.19.14.tgz",
- "integrity": "sha512-xLu+G22Vlm4KajE/Eimq8qLzBoxMZ7BJLp8WobFC3yyzdU9R785dug9t9et4r45NxWJr8aVWkFzhEBzAadHjnA==",
+ "version": "3.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-3.27.0.tgz",
+ "integrity": "sha512-LMhOHX5FI4CJHv2YhtpiEtHfLqL/pjKAMja/v7skkHPlrh64Sgzi/gep016/My5SjcR64JUD1Na2U2j/BnrBNQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/private-apis": "^0.32.0",
"classnames": "^2.3.1"
},
"engines": {
@@ -7810,36 +7516,36 @@
}
},
"node_modules/@wordpress/preferences-persistence": {
- "version": "1.34.13",
- "resolved": "https://registry.npmjs.org/@wordpress/preferences-persistence/-/preferences-persistence-1.34.13.tgz",
- "integrity": "sha512-23bUN1WdJ9mtfU51uoPBrSwbYHaW2zG+HDlH+leZURdPe48jbWSA8LRPwni5z3Kc9zh8D0vXkvt0hg1/RcNgUQ==",
+ "version": "1.42.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/preferences-persistence/-/preferences-persistence-1.42.0.tgz",
+ "integrity": "sha512-n/VBhZHUEXWoBGsvHUf5uq6b872Lzn+cenfB2ex/etcWLXiVUkEl3rlzocyS50g2YoNQg/zQOn1hoSh+AgCm8Q==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13"
+ "@wordpress/api-fetch": "^6.47.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/prettier-config": {
- "version": "2.25.13",
- "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-2.25.13.tgz",
- "integrity": "sha512-iz58o0X91E24j0VFtzwn5qG84w+s4VlRCuZWa/lPL6pfGtOSw30c60wCrYKCA1IWIIAWdpRAYfEh7errPyKiPQ==",
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-3.7.0.tgz",
+ "integrity": "sha512-JRTc5p7UxtcPkqdSDXSFJoJnVuS510uiRVz8anXEl5nuOx5p+SJAzi9QPrxTgOE8bN3wRABH4eIhfOcta4CFdg==",
"dev": true,
"engines": {
"node": ">=14"
},
"peerDependencies": {
- "prettier": ">=2"
+ "prettier": ">=3"
}
},
"node_modules/@wordpress/primitives": {
- "version": "3.40.13",
- "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.40.13.tgz",
- "integrity": "sha512-dYYrPceV8w78AHJfPe5wkxnT7P0tG/4yDcr9/HvznFHkzQFnW8kG8Nci20RV/+ENxfNiuWqfWyICI2y7myIoGw==",
+ "version": "3.48.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.48.0.tgz",
+ "integrity": "sha512-uBoMxpl+FiZF6aRXH/+Hwol4EAL6QqlNSaGF1IzEwklFzdRF1m5wTM4vh21w8Bq7lgxiuAqyueY7X5u32v+zPw==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/element": "^5.19.13",
+ "@wordpress/element": "^5.27.0",
"classnames": "^2.3.1"
},
"engines": {
@@ -7847,9 +7553,9 @@
}
},
"node_modules/@wordpress/priority-queue": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-2.42.13.tgz",
- "integrity": "sha512-vrkjBcJnuzhpfWLFF4LfdNVrM3s73KW3KOZBTuN6oizJVYKyQaaPSLmDdORuXFc017MMasO5N/fYk/qJyll5bg==",
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-2.50.0.tgz",
+ "integrity": "sha512-21E842EVFYUd1ZrNTLAW57IyloDCUZr6h1Te6BgqKoeKOEteoTQwA9BemMzZJUiThUSZymW94ot0Omb+C8VX2g==",
"dependencies": {
"@babel/runtime": "^7.16.0",
"requestidlecallback": "^0.3.0"
@@ -7859,9 +7565,9 @@
}
},
"node_modules/@wordpress/private-apis": {
- "version": "0.24.13",
- "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.24.13.tgz",
- "integrity": "sha512-RgvGB6VQpPnEGU8Y61tzpgPFYDRAW28+2gcdOXYiqSVdZfGBL6+hBs5bMbLSJYRU9G5pl5q4Eb0lHlkMgHW5FA==",
+ "version": "0.32.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.32.0.tgz",
+ "integrity": "sha512-P7nxI/bGMDQhtlTfSe1Y2SDfrd20K5UMnTHbq+hmIkzBGRpNPbdGeNu2bZaZtIvmXk1OCR0Fkef+e6QqkOfYPg==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -7870,9 +7576,9 @@
}
},
"node_modules/@wordpress/redux-routine": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-4.42.13.tgz",
- "integrity": "sha512-R+8W8CcjhHXPRlfPCdtElO2lsZzObR6DWvO49BjfJcKs0QPvKaO3ofjsadRgv+gg1+nXiE7rH6LmHbZ4eLanGw==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-4.50.0.tgz",
+ "integrity": "sha512-giHjQYhmFDCpeNEnsZKP0JNPBnpuQwsoxLmHAUUSNFWAmd4rtnNnG6M8HuqOLmgYTvEa8Hlx3Bl+reTGvrtI2g==",
"dependencies": {
"@babel/runtime": "^7.16.0",
"is-plain-object": "^5.0.0",
@@ -7887,22 +7593,22 @@
}
},
"node_modules/@wordpress/reusable-blocks": {
- "version": "4.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-4.19.14.tgz",
- "integrity": "sha512-WhQNDtq2ohGlGlodNyEbvMux631D+7jRABwodvoC42dVJyHR3lH1O8uhnQeKyPl91YWLxJ6+mHmrPInEo2fAcQ==",
+ "version": "4.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-4.27.2.tgz",
+ "integrity": "sha512-kkhZyYFj4rbf7lPOqDMfaNO3fqLEyHYKjWITWzRMUPtLeIHin/DHepVz6Z6NERANHpbP0mD4BDoBEGYJ9/brbA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0"
},
"engines": {
"node": ">=12"
@@ -7913,19 +7619,19 @@
}
},
"node_modules/@wordpress/rich-text": {
- "version": "6.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-6.19.13.tgz",
- "integrity": "sha512-7kCbTLiy+dIOToBktkrftCfVLsqCN0dY9uE6rz/TRsKS6+pnF6fUhqHLBV5OFf0tttKjHykSj5ixFDejqWCvrQ==",
+ "version": "6.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-6.27.0.tgz",
+ "integrity": "sha512-B7t++SldcI4nb+lO2m9oEdyD8y2FbH5DKY5F2G3xpcEnw4EKSt4SsTzeclMQ/2zzlEHPRKU/IR29SeOIJ1H8JQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/keycodes": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/keycodes": "^3.50.0",
"memize": "^2.1.0",
"rememo": "^4.0.2"
},
@@ -7937,14 +7643,14 @@
}
},
"node_modules/@wordpress/router": {
- "version": "0.11.13",
- "resolved": "https://registry.npmjs.org/@wordpress/router/-/router-0.11.13.tgz",
- "integrity": "sha512-OZyuFOuX6nW5fQ1kq250EqCCA1Ad6KSH0wlaC68kCF06VFft2JNiATba7rC9Uq3ozM9HjPCtkbJ1dAW4PQdS1g==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/router/-/router-0.19.0.tgz",
+ "integrity": "sha512-S2z4WrgrfMNAl6amIjekGV1V6XGnjolYmRgUH/VTN45CQUV/o5ABo04xI/L3uvUnaRpH022n/yQX5H1p1kKhdA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/element": "^5.19.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0",
"history": "^5.1.0"
},
"engines": {
@@ -7955,28 +7661,28 @@
}
},
"node_modules/@wordpress/scripts": {
- "version": "26.13.13",
- "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-26.13.13.tgz",
- "integrity": "sha512-G2K56PmjRPI0ddgmrnopp3AVMLACqfrFvz+NyGbYCPWQoYL3xnphrS+w3uPwuxcuBtgR34yr+xCvrMnJsY3Wag==",
+ "version": "27.1.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-27.1.0.tgz",
+ "integrity": "sha512-jewyOxqaNrsct5R1NXv2lT8CA70vzrvpdZHYERCcH9LzKuvrcc32Telm9Jqso6ay1ZgHeIbjHSCd2+r2sBG7hw==",
"dev": true,
"dependencies": {
"@babel/core": "^7.16.0",
- "@pmmmwh/react-refresh-webpack-plugin": "^0.5.2",
+ "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
"@svgr/webpack": "^8.0.1",
- "@wordpress/babel-preset-default": "^7.26.13",
- "@wordpress/browserslist-config": "^5.25.13",
- "@wordpress/dependency-extraction-webpack-plugin": "^4.25.13",
- "@wordpress/e2e-test-utils-playwright": "^0.10.13",
- "@wordpress/eslint-plugin": "^16.0.13",
- "@wordpress/jest-preset-default": "^11.13.13",
- "@wordpress/npm-package-json-lint-config": "^4.27.13",
- "@wordpress/postcss-plugins-preset": "^4.26.13",
- "@wordpress/prettier-config": "^2.25.13",
- "@wordpress/stylelint-config": "^21.25.13",
+ "@wordpress/babel-preset-default": "^7.34.0",
+ "@wordpress/browserslist-config": "^5.33.0",
+ "@wordpress/dependency-extraction-webpack-plugin": "^5.1.0",
+ "@wordpress/e2e-test-utils-playwright": "^0.18.0",
+ "@wordpress/eslint-plugin": "^17.7.0",
+ "@wordpress/jest-preset-default": "^11.21.0",
+ "@wordpress/npm-package-json-lint-config": "^4.35.0",
+ "@wordpress/postcss-plugins-preset": "^4.34.0",
+ "@wordpress/prettier-config": "^3.7.0",
+ "@wordpress/stylelint-config": "^21.33.0",
"adm-zip": "^0.5.9",
"babel-jest": "^29.6.2",
"babel-loader": "^8.2.3",
- "browserslist": "^4.21.9",
+ "browserslist": "^4.21.10",
"chalk": "^4.0.0",
"check-node-version": "^4.1.0",
"clean-webpack-plugin": "^3.0.0",
@@ -7991,7 +7697,7 @@
"fast-glob": "^3.2.7",
"filenamify": "^4.2.0",
"jest": "^29.6.2",
- "jest-dev-server": "^6.0.2",
+ "jest-dev-server": "^9.0.1",
"jest-environment-jsdom": "^29.6.2",
"jest-environment-node": "^29.6.2",
"markdownlint-cli": "^0.31.1",
@@ -8000,12 +7706,12 @@
"minimist": "^1.2.0",
"npm-package-json-lint": "^6.4.0",
"npm-packlist": "^3.0.0",
- "playwright-core": "1.32.0",
+ "playwright-core": "1.39.0",
"postcss": "^8.4.5",
"postcss-loader": "^6.2.1",
- "prettier": "npm:wp-prettier@3.0.3-beta-3",
+ "prettier": "npm:wp-prettier@3.0.3",
"puppeteer-core": "^13.2.0",
- "react-refresh": "^0.10.0",
+ "react-refresh": "^0.14.0",
"read-pkg-up": "^7.0.1",
"resolve-bin": "^0.4.0",
"sass": "^1.35.2",
@@ -8014,24 +7720,184 @@
"stylelint": "^14.2.0",
"terser-webpack-plugin": "^5.3.9",
"url-loader": "^4.1.1",
- "webpack": "^5.47.1",
- "webpack-bundle-analyzer": "^4.4.2",
- "webpack-cli": "^4.9.1",
- "webpack-dev-server": "^4.4.0"
+ "webpack": "^5.88.2",
+ "webpack-bundle-analyzer": "^4.9.1",
+ "webpack-cli": "^5.1.4",
+ "webpack-dev-server": "^4.15.1"
},
"bin": {
"wp-scripts": "bin/wp-scripts.js"
},
"engines": {
- "node": ">=14",
+ "node": ">=18",
"npm": ">=6.14.4"
},
"peerDependencies": {
- "@playwright/test": "^1.32.0",
+ "@playwright/test": "^1.39.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
},
+ "node_modules/@wordpress/scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin": {
+ "version": "0.5.11",
+ "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz",
+ "integrity": "sha512-7j/6vdTym0+qZ6u4XbSAxrWBGYSdCfTzySkj7WAFgDLmSyWlOrWvpyzxlFh5jtw9dn0oL/jtW+06XfFiisN3JQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-html-community": "^0.0.8",
+ "common-path-prefix": "^3.0.0",
+ "core-js-pure": "^3.23.3",
+ "error-stack-parser": "^2.0.6",
+ "find-up": "^5.0.0",
+ "html-entities": "^2.1.0",
+ "loader-utils": "^2.0.4",
+ "schema-utils": "^3.0.0",
+ "source-map": "^0.7.3"
+ },
+ "engines": {
+ "node": ">= 10.13"
+ },
+ "peerDependencies": {
+ "@types/webpack": "4.x || 5.x",
+ "react-refresh": ">=0.10.0 <1.0.0",
+ "sockjs-client": "^1.4.0",
+ "type-fest": ">=0.17.0 <5.0.0",
+ "webpack": ">=4.43.0 <6.0.0",
+ "webpack-dev-server": "3.x || 4.x",
+ "webpack-hot-middleware": "2.x",
+ "webpack-plugin-serve": "0.x || 1.x"
+ },
+ "peerDependenciesMeta": {
+ "@types/webpack": {
+ "optional": true
+ },
+ "sockjs-client": {
+ "optional": true
+ },
+ "type-fest": {
+ "optional": true
+ },
+ "webpack-dev-server": {
+ "optional": true
+ },
+ "webpack-hot-middleware": {
+ "optional": true
+ },
+ "webpack-plugin-serve": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@wordpress/scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/@wordpress/scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/ajv-keywords": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+ "dev": true,
+ "peerDependencies": {
+ "ajv": "^6.9.1"
+ }
+ },
+ "node_modules/@wordpress/scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@wordpress/scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "node_modules/@wordpress/scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@wordpress/scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@wordpress/scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@wordpress/scripts/node_modules/@pmmmwh/react-refresh-webpack-plugin/node_modules/schema-utils": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+ "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.8",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.2"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
"node_modules/@wordpress/scripts/node_modules/ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
@@ -8255,11 +8121,23 @@
"node": ">=8"
}
},
+ "node_modules/@wordpress/scripts/node_modules/playwright-core": {
+ "version": "1.39.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz",
+ "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==",
+ "dev": true,
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/@wordpress/scripts/node_modules/prettier": {
"name": "wp-prettier",
- "version": "3.0.3-beta-3",
- "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-3.0.3-beta-3.tgz",
- "integrity": "sha512-R3+TD7j0rnqEpMgylrUrHdi1W6ypwh4QGeFOZQ9YjP9WvNnZzBAS71yry1h7xIcG/bVaNKBCoWNqbqJY6vkOKQ==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-3.0.3.tgz",
+ "integrity": "sha512-X4UlrxDTH8oom9qXlcjnydsjAOD2BmB6yFmvS4Z2zdTzqqpRWb+fbqrH412+l+OUXmbzJlSXjlMFYPgYG12IAA==",
"dev": true,
"bin": {
"prettier": "bin/prettier.cjs"
@@ -8271,15 +8149,6 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
- "node_modules/@wordpress/scripts/node_modules/react-refresh": {
- "version": "0.10.0",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz",
- "integrity": "sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/@wordpress/scripts/node_modules/read-pkg-up": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz",
@@ -8328,6 +8197,15 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@wordpress/scripts/node_modules/source-map": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+ "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/@wordpress/scripts/node_modules/source-map-loader": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz",
@@ -8371,20 +8249,20 @@
}
},
"node_modules/@wordpress/server-side-render": {
- "version": "4.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-4.19.14.tgz",
- "integrity": "sha512-As3Xc3TDM0R0siAFaldobRdZnPfQQMXvlQxalFJgs/kSoYOmcdc46mR5Wgmfn7r0Kc/Z5uOHLbvm4mWekE0a2A==",
+ "version": "4.27.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-4.27.1.tgz",
+ "integrity": "sha512-hovofyT0z75NSK/CSkkSbbTdkq9Afc1MKbEVGXTGpqq5sKOa7IAcxWjzmh8byTgT8x7GEaAyHZUr31p4l0CGnQ==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/url": "^3.51.0",
"fast-deep-equal": "^3.1.3"
},
"engines": {
@@ -8396,9 +8274,9 @@
}
},
"node_modules/@wordpress/shortcode": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-3.42.13.tgz",
- "integrity": "sha512-pq+xdRdND7vEuqskPoZx+VAOHsmatqHcox3dElFU5lxlx/3fvKC7NIrFCn+glxFGGxO5hY5JfUOC70x8tm7uMA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-3.50.0.tgz",
+ "integrity": "sha512-RnlqS2OsNUaI6VOLwyUiaL3trAJcWjtoiW21BjIXODbTkEreRJgBJnch7wdFpGimJmKIWBwRD8jQ4hdTND8xVw==",
"dependencies": {
"@babel/runtime": "^7.16.0",
"memize": "^2.0.1"
@@ -8408,9 +8286,9 @@
}
},
"node_modules/@wordpress/style-engine": {
- "version": "1.25.13",
- "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-1.25.13.tgz",
- "integrity": "sha512-4ixhGNVNrtt6zppLWnPCKSl4O4X+TO48PbLEbLDvN2NvUK1Yp1wChiX+NFIBa1dJp1zDlrxaTjttCqC1bs3MUA==",
+ "version": "1.33.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-1.33.1.tgz",
+ "integrity": "sha512-mkur1jw3Trz76iwxU6DalTFsJyF5P/NTdU9xniMT8bo1H9HspgKrzqXAaxkTL9F9BXkyiYs+ctVekJYRUKlgcw==",
"dependencies": {
"@babel/runtime": "^7.16.0",
"change-case": "^4.1.2"
@@ -8420,9 +8298,9 @@
}
},
"node_modules/@wordpress/stylelint-config": {
- "version": "21.26.0",
- "resolved": "https://registry.npmjs.org/@wordpress/stylelint-config/-/stylelint-config-21.26.0.tgz",
- "integrity": "sha512-xTnvoNk9aCdRl1ntBxnmhdmghwzRNurp5Y9LjUCwrYutxnj8t/CCKhPyjgIgHxz+RwKgnpGKupKLVvuHxu1CzQ==",
+ "version": "21.33.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/stylelint-config/-/stylelint-config-21.33.0.tgz",
+ "integrity": "sha512-DwjXrjRBva0tkYILvDV7rjl3VaKXxvchlxnFfFs6l2DWL/Qo31CJ+f2rVw4XSWuuWxY1EsyIn9tOBS9URloWTQ==",
"dev": true,
"dependencies": {
"stylelint-config-recommended": "^6.0.0",
@@ -8436,12 +8314,18 @@
}
},
"node_modules/@wordpress/sync": {
- "version": "0.4.13",
- "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-0.4.13.tgz",
- "integrity": "sha512-3Lq7MENUpCaSvR6WOLOovNmRMXGmFcdnbMjSZlHh0sx3ycWbKpXlGyfQWJ20MZRiO/qTOOrj4VW4GejqqJSEZw==",
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-0.12.0.tgz",
+ "integrity": "sha512-45gU1Gu/ys3zqYO4dDQf6eG5gGgJK9nXa62IUtUWFXIH4FN29XlvGppMVK/zzhJwejF/XnDuT7mQuVEFCZGswA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
+ "@types/simple-peer": "^9.11.5",
+ "@wordpress/url": "^3.51.0",
+ "import-locals": "^2.0.0",
+ "lib0": "^0.2.42",
+ "simple-peer": "^9.11.0",
"y-indexeddb": "~9.0.11",
+ "y-protocols": "^1.0.5",
"y-webrtc": "~10.2.5",
"yjs": "~13.6.6"
},
@@ -8450,9 +8334,9 @@
}
},
"node_modules/@wordpress/token-list": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-2.42.13.tgz",
- "integrity": "sha512-eAKU/5U7c/Acqcqnurpp79lrwCAm+Tb8PfSBTmtGs1fJsR1xtJh4d6IZw5MLDFiqLuVRT65ec3T4Sjqb6N4CMQ==",
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-2.50.0.tgz",
+ "integrity": "sha512-LTjXkoljQpJIHqs0isTUzIc1fMu68y0N9HcDIdsCMGkmKptWUCETtb+DItnraxDDLuyWNuTYf840S83a3XAVRA==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -8461,21 +8345,21 @@
}
},
"node_modules/@wordpress/undo-manager": {
- "version": "0.2.13",
- "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-0.2.13.tgz",
- "integrity": "sha512-SFIYRs65GEjr0eeh7BZcETaH32qQVm78aFMZXnYTHzBmTXxoJ98XRgEGWXRJU92RXBcjom+1gARKChJoV5dlNw==",
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-0.10.0.tgz",
+ "integrity": "sha512-ODDqAL6BSvD+J7FV+sQTAaVHiPChh/4KBnKg8pb2ogg+Weq6VynthxDxGpQnN8FcMKB9ZoyS3SNIl8pVXLKIwA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/is-shallow-equal": "^4.42.13"
+ "@wordpress/is-shallow-equal": "^4.50.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/url": {
- "version": "3.43.13",
- "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.43.13.tgz",
- "integrity": "sha512-GrIkGZoCgd+87CyAjgGzShoI6m/Kvknmc6syqrN34J1LdrEE+vPNMjM+NvUVvyPdvgG7/iFzRM8D/ZEUvaTm9A==",
+ "version": "3.51.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.51.0.tgz",
+ "integrity": "sha512-OjucjlP1763gfKbe8lv/k3RCisyX8AfNBrhASk7JqxAj6rFhb1ZZO7YmAgB2m+WoGB5v7fkOli0FZyDqISdYyg==",
"dependencies": {
"@babel/runtime": "^7.16.0",
"remove-accents": "^0.5.0"
@@ -8485,14 +8369,14 @@
}
},
"node_modules/@wordpress/viewport": {
- "version": "5.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-5.19.13.tgz",
- "integrity": "sha512-xYWTcaQLhZrDZA0lpl9TivbU4RPw+CUfuRc3NEBiQY0GDDfuLe8n1Pb9AkmAP5PLNyxZhHjKLBGojfchOGhzdg==",
+ "version": "5.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-5.27.0.tgz",
+ "integrity": "sha512-ET8X3Ln0K6wrBba+u0AjBD/mP02SuvwhK/EVaI3uAhNlGnkx+J3PdtShbu63lHmp0SG+J27CDjEqfcZ6CdAnfA==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13"
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0"
},
"engines": {
"node": ">=12"
@@ -8502,30 +8386,30 @@
}
},
"node_modules/@wordpress/warning": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.42.13.tgz",
- "integrity": "sha512-SYi37xiR7Wq4Vde4JBkCYJIyfUQzyuABrwh7aon1XwcUhWP072tv4/LKP6F+zWYC5M8pPdRqjznxgwZ2mNzcyw==",
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.50.0.tgz",
+ "integrity": "sha512-y7Zf48roDfiPgbRAWGXDwN3C8sfbEdneGq+HvXCW6rIeGYnDLdEkpX9i7RfultkFFPVeSP3FpMKVMkto2nbqzA==",
"engines": {
"node": ">=12"
}
},
"node_modules/@wordpress/widgets": {
- "version": "3.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/widgets/-/widgets-3.19.14.tgz",
- "integrity": "sha512-nFyXrCBVp24joFa96sAdNwkWnnf23t960ebnoW+Wk+lMT0PsGfGjiMIRmtks2cfqbQuQYFdO/8go+DSE54ekAg==",
+ "version": "3.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/widgets/-/widgets-3.27.2.tgz",
+ "integrity": "sha512-z/OsrXbBY8PanemOHdtup1OlfdBmbc6dMfXqZ3pelH75z4n73JtPhVEqM/FJFdwP737fV1gU1nvMB17VtnyXKw==",
"dependencies": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/notices": "^4.10.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/notices": "^4.18.0",
"classnames": "^2.3.1"
},
"peerDependencies": {
@@ -8534,9 +8418,9 @@
}
},
"node_modules/@wordpress/wordcount": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-3.42.13.tgz",
- "integrity": "sha512-yapganGNO/9JjfWTcMNECjIOKlnLOJR2VTh4UFBL/lSi2GM1AE7bjnXsV2pD0H/3mwdhAomRCUV6BA3nG5UUfA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-3.50.0.tgz",
+ "integrity": "sha512-lRfIX3B9ha//bqsUihym2BnOiAsdDQr22vdy0wZIpm5G2tFvTddCKHy0YClf52IJK0z61WqbNuF9hrvzWWxL+g==",
"dependencies": {
"@babel/runtime": "^7.16.0"
},
@@ -8581,27 +8465,6 @@
"node": ">= 0.6"
}
},
- "node_modules/accepts/node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/accepts/node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/acorn": {
"version": "8.10.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
@@ -8973,9 +8836,9 @@
}
},
"node_modules/array-flatten": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
- "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"dev": true
},
"node_modules/array-includes": {
@@ -9302,12 +9165,28 @@
}
},
"node_modules/axios": {
- "version": "0.25.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
- "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
+ "version": "1.6.5",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
+ "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
+ "dev": true,
+ "dependencies": {
+ "follow-redirects": "^1.15.4",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ }
+ },
+ "node_modules/axios/node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dev": true,
"dependencies": {
- "follow-redirects": "^1.14.7"
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
}
},
"node_modules/axobject-query": {
@@ -9719,15 +9598,6 @@
"tweetnacl": "^0.14.3"
}
},
- "node_modules/big-integer": {
- "version": "1.6.51",
- "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
- "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
- "dev": true,
- "engines": {
- "node": ">=0.6"
- }
- },
"node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -10211,13 +10081,11 @@
"dev": true
},
"node_modules/bonjour-service": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz",
- "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz",
+ "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==",
"dev": true,
"dependencies": {
- "array-flatten": "^2.1.2",
- "dns-equal": "^1.0.0",
"fast-deep-equal": "^3.1.3",
"multicast-dns": "^7.2.5"
}
@@ -10228,18 +10096,6 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true
},
- "node_modules/bplist-parser": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
- "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==",
- "dev": true,
- "dependencies": {
- "big-integer": "^1.6.44"
- },
- "engines": {
- "node": ">= 5.10.0"
- }
- },
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -10409,21 +10265,6 @@
"semver": "^7.0.0"
}
},
- "node_modules/bundle-name": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
- "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==",
- "dev": true,
- "dependencies": {
- "run-applescript": "^5.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
@@ -10623,9 +10464,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001549",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz",
- "integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==",
+ "version": "1.0.30001579",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz",
+ "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==",
"dev": true,
"funding": [
{
@@ -11254,9 +11095,9 @@
"integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw=="
},
"node_modules/colorette": {
- "version": "2.0.19",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
- "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+ "version": "2.0.20",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"dev": true
},
"node_modules/colors": {
@@ -11452,25 +11293,17 @@
}
},
"node_modules/content-disposition": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
- "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"dev": true,
- "optional": true,
"dependencies": {
- "safe-buffer": "5.1.2"
+ "safe-buffer": "5.2.1"
},
"engines": {
"node": ">= 0.6"
}
},
- "node_modules/content-disposition/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true,
- "optional": true
- },
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
@@ -11660,10 +11493,9 @@
}
},
"node_modules/core-js-pure": {
- "version": "3.21.1",
- "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz",
- "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==",
- "deprecated": "core-js-pure@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js-pure.",
+ "version": "3.35.1",
+ "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.35.1.tgz",
+ "integrity": "sha512-zcIdi/CL3MWbBJYo5YCeVAAx+Sy9yJE9I3/u9LkFABwbeaPhTMRWraM8mYFp9jW5Z50hOy7FVzCc8dCrpZqtIQ==",
"dev": true,
"hasInstallScript": true,
"funding": {
@@ -12251,6 +12083,12 @@
"node": "*"
}
},
+ "node_modules/debounce": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
+ "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==",
+ "dev": true
+ },
"node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -12581,13 +12419,13 @@
}
},
"node_modules/deepsignal": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/deepsignal/-/deepsignal-1.3.6.tgz",
- "integrity": "sha512-yjd+vtiznL6YaMptOsKnEKkPr60OEApa+LRe+Qe6Ile/RfCOrELKk/YM3qVpXFZiyOI3Ng67GDEyjAlqVc697g==",
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/deepsignal/-/deepsignal-1.4.0.tgz",
+ "integrity": "sha512-x0XUMT48s+xQRLc2fPFfxnYLCJ46vffw47OQ5NcHFzacOjfW5eA0NrEmI0bhQHL6MgUHkBVT4TIiWTVwzTEwpg==",
"peerDependencies": {
"@preact/signals": "^1.1.4",
- "@preact/signals-core": "^1.3.1",
- "@preact/signals-react": "^1.3.3",
+ "@preact/signals-core": "^1.5.1",
+ "@preact/signals-react": "^1.3.8 || ^2.0.0",
"preact": "^10.16.0"
},
"peerDependenciesMeta": {
@@ -12605,206 +12443,6 @@
}
}
},
- "node_modules/default-browser": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz",
- "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==",
- "dev": true,
- "dependencies": {
- "bundle-name": "^3.0.0",
- "default-browser-id": "^3.0.0",
- "execa": "^7.1.1",
- "titleize": "^3.0.0"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser-id": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz",
- "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==",
- "dev": true,
- "dependencies": {
- "bplist-parser": "^0.2.0",
- "untildify": "^4.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser/node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/default-browser/node_modules/execa": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz",
- "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.1",
- "human-signals": "^4.3.0",
- "is-stream": "^3.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^5.1.0",
- "onetime": "^6.0.0",
- "signal-exit": "^3.0.7",
- "strip-final-newline": "^3.0.0"
- },
- "engines": {
- "node": "^14.18.0 || ^16.14.0 || >=18.0.0"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/execa?sponsor=1"
- }
- },
- "node_modules/default-browser/node_modules/get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser/node_modules/human-signals": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
- "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
- "dev": true,
- "engines": {
- "node": ">=14.18.0"
- }
- },
- "node_modules/default-browser/node_modules/is-stream": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
- "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
- "dev": true,
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser/node_modules/mimic-fn": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
- "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser/node_modules/npm-run-path": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
- "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
- "dev": true,
- "dependencies": {
- "path-key": "^4.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser/node_modules/npm-run-path/node_modules/path-key": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
- "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser/node_modules/onetime": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
- "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
- "dev": true,
- "dependencies": {
- "mimic-fn": "^4.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/default-browser/node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/default-browser/node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/default-browser/node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/default-browser/node_modules/strip-final-newline": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
- "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/default-gateway": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
@@ -13188,16 +12826,10 @@
"node": ">=8"
}
},
- "node_modules/dns-equal": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
- "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==",
- "dev": true
- },
"node_modules/dns-packet": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz",
- "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==",
+ "version": "5.6.1",
+ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz",
+ "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==",
"dev": true,
"dependencies": {
"@leichtgewicht/ip-codec": "^2.0.1"
@@ -13418,11 +13050,6 @@
"node": ">=4"
}
},
- "node_modules/downloadjs": {
- "version": "1.4.7",
- "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz",
- "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q=="
- },
"node_modules/downshift": {
"version": "6.1.12",
"resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.12.tgz",
@@ -13595,9 +13222,9 @@
}
},
"node_modules/envinfo": {
- "version": "7.8.1",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
- "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz",
+ "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==",
"dev": true,
"bin": {
"envinfo": "dist/cli.js"
@@ -13723,6 +13350,11 @@
"integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==",
"dev": true
},
+ "node_modules/es-module-shims": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-1.8.2.tgz",
+ "integrity": "sha512-7vIYVzpOhXtpc3Yn03itB+GSgVZFW7oL4kdydA+iL+IEi7HiSLBUxM05QFw4SxTl6e++pMpGqZPo2+vdNs3TbA=="
+ },
"node_modules/es-set-tostringtag": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
@@ -13955,9 +13587,9 @@
}
},
"node_modules/eslint-plugin-import": {
- "version": "2.29.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz",
- "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==",
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
+ "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
"dev": true,
"dependencies": {
"array-includes": "^3.1.7",
@@ -13976,7 +13608,7 @@
"object.groupby": "^1.0.1",
"object.values": "^1.1.7",
"semver": "^6.3.1",
- "tsconfig-paths": "^3.14.2"
+ "tsconfig-paths": "^3.15.0"
},
"engines": {
"node": ">=4"
@@ -14016,9 +13648,9 @@
}
},
"node_modules/eslint-plugin-jest": {
- "version": "27.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.0.tgz",
- "integrity": "sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==",
+ "version": "27.6.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.3.tgz",
+ "integrity": "sha512-+YsJFVH6R+tOiO3gCJon5oqn4KWc+mDq2leudk8mrp8RFubLOo9CVyi3cib4L7XMpxExmkmBZQTPDYVBzgpgOA==",
"dev": true,
"dependencies": {
"@typescript-eslint/utils": "^5.10.0"
@@ -14153,9 +13785,9 @@
}
},
"node_modules/eslint-plugin-jsdoc": {
- "version": "46.9.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.9.0.tgz",
- "integrity": "sha512-UQuEtbqLNkPf5Nr/6PPRCtr9xypXY+g8y/Q7gPa0YK7eDhh0y2lWprXRnaYbW7ACgIUvpDKy9X2bZqxtGzBG9Q==",
+ "version": "46.10.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz",
+ "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==",
"dev": true,
"dependencies": {
"@es-joy/jsdoccomment": "~0.41.0",
@@ -14166,13 +13798,13 @@
"esquery": "^1.5.0",
"is-builtin-module": "^3.2.1",
"semver": "^7.5.4",
- "spdx-expression-parse": "^3.0.1"
+ "spdx-expression-parse": "^4.0.0"
},
"engines": {
"node": ">=16"
},
"peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0"
+ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
}
},
"node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": {
@@ -14187,6 +13819,16 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
+ "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
+ "dev": true,
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
"node_modules/eslint-plugin-jsx-a11y": {
"version": "6.8.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz",
@@ -14239,23 +13881,24 @@
}
},
"node_modules/eslint-plugin-prettier": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz",
- "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==",
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz",
+ "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==",
"dev": true,
"dependencies": {
"prettier-linter-helpers": "^1.0.0",
- "synckit": "^0.8.5"
+ "synckit": "^0.8.6"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
- "url": "https://opencollective.com/prettier"
+ "url": "https://opencollective.com/eslint-plugin-prettier"
},
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
+ "eslint-config-prettier": "*",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
@@ -15103,24 +14746,6 @@
"node": ">= 0.10.0"
}
},
- "node_modules/express/node_modules/array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
- "dev": true
- },
- "node_modules/express/node_modules/content-disposition": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
- "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "5.2.1"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/express/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -16068,6 +15693,15 @@
"node": ">= 0.10"
}
},
+ "node_modules/flat": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true,
+ "bin": {
+ "flat": "cli.js"
+ }
+ },
"node_modules/flat-cache": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
@@ -16103,9 +15737,9 @@
"dev": true
},
"node_modules/follow-redirects": {
- "version": "1.15.2",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
- "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
+ "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
"dev": true,
"funding": [
{
@@ -16308,9 +15942,9 @@
}
},
"node_modules/fs-monkey": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz",
- "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==",
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz",
+ "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==",
"dev": true
},
"node_modules/fs.realpath": {
@@ -18155,6 +17789,11 @@
"react-is": "^16.7.0"
}
},
+ "node_modules/hoist-non-react-statics/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ },
"node_modules/homedir-polyfill": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
@@ -18798,6 +18437,11 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/import-locals": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-locals/-/import-locals-2.0.0.tgz",
+ "integrity": "sha512-1/bPE89IZhyf7dr5Pkz7b4UyVXy5pEt7PTEfye15UEn3AK8+2zwcDCfKk9Pwun4ltfhOSszOrReSsFcDKw/yoA=="
+ },
"node_modules/imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -18968,12 +18612,12 @@
}
},
"node_modules/interpret": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
- "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
+ "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
"dev": true,
"engines": {
- "node": ">= 0.10"
+ "node": ">=10.13.0"
}
},
"node_modules/intl-messageformat": {
@@ -19021,9 +18665,9 @@
"dev": true
},
"node_modules/ipaddr.js": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
- "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz",
+ "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==",
"dev": true,
"engines": {
"node": ">= 10"
@@ -19346,39 +18990,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/is-inside-container": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
- "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
- "dev": true,
- "dependencies": {
- "is-docker": "^3.0.0"
- },
- "bin": {
- "is-inside-container": "cli.js"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-inside-container/node_modules/is-docker": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
- "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
- "dev": true,
- "bin": {
- "is-docker": "cli.js"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/is-jpg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-jpg/-/is-jpg-2.0.0.tgz",
@@ -20606,18 +20217,21 @@
}
},
"node_modules/jest-dev-server": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-6.2.0.tgz",
- "integrity": "sha512-ZWh8CuvxwjhYfvw4tGeftziqIvw/26R6AG3OTgNTQeXul8aZz48RQjDpnlDwnWX53jxJJl9fcigqIdSU5lYZuw==",
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-9.0.2.tgz",
+ "integrity": "sha512-Zc/JB0IlNNrpXkhBw+h86cGrde/Mey52KvF+FER2eyrtYJTHObOwW7Iarxm3rPyTKby5+3Y2QZtl8pRz/5GCxg==",
"dev": true,
"dependencies": {
"chalk": "^4.1.2",
"cwd": "^0.10.0",
"find-process": "^1.4.7",
"prompts": "^2.4.2",
- "spawnd": "^6.2.0",
+ "spawnd": "^9.0.2",
"tree-kill": "^1.2.2",
- "wait-on": "^6.0.1"
+ "wait-on": "^7.2.0"
+ },
+ "engines": {
+ "node": ">=16"
}
},
"node_modules/jest-dev-server/node_modules/ansi-styles": {
@@ -20679,9 +20293,9 @@
}
},
"node_modules/jest-dev-server/node_modules/rxjs": {
- "version": "7.8.0",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
- "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
+ "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
"dev": true,
"dependencies": {
"tslib": "^2.1.0"
@@ -20700,22 +20314,22 @@
}
},
"node_modules/jest-dev-server/node_modules/wait-on": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz",
- "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz",
+ "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==",
"dev": true,
"dependencies": {
- "axios": "^0.25.0",
- "joi": "^17.6.0",
+ "axios": "^1.6.1",
+ "joi": "^17.11.0",
"lodash": "^4.17.21",
- "minimist": "^1.2.5",
- "rxjs": "^7.5.4"
+ "minimist": "^1.2.8",
+ "rxjs": "^7.8.1"
},
"bin": {
"wait-on": "bin/wait-on"
},
"engines": {
- "node": ">=10.0.0"
+ "node": ">=12.0.0"
}
},
"node_modules/jest-diff": {
@@ -22130,15 +21744,15 @@
}
},
"node_modules/joi": {
- "version": "17.7.0",
- "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz",
- "integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==",
+ "version": "17.12.0",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.0.tgz",
+ "integrity": "sha512-HSLsmSmXz+PV9PYoi3p7cgIbj06WnEBNT28n+bbBNcPZXZFqCzzvGqpTBPujx/Z0nh1+KNQPDrNgdmQ8dq0qYw==",
"dev": true,
"dependencies": {
- "@hapi/hoek": "^9.0.0",
- "@hapi/topo": "^5.0.0",
- "@sideway/address": "^4.1.3",
- "@sideway/formula": "^3.0.0",
+ "@hapi/hoek": "^9.3.0",
+ "@hapi/topo": "^5.1.0",
+ "@sideway/address": "^4.1.4",
+ "@sideway/formula": "^3.0.1",
"@sideway/pinpoint": "^2.0.0"
}
},
@@ -22744,6 +22358,16 @@
"node": ">=0.10"
}
},
+ "node_modules/launch-editor": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz",
+ "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==",
+ "dev": true,
+ "dependencies": {
+ "picocolors": "^1.0.0",
+ "shell-quote": "^1.8.1"
+ }
+ },
"node_modules/lazy-cache": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
@@ -22776,9 +22400,9 @@
}
},
"node_modules/lib0": {
- "version": "0.2.87",
- "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.87.tgz",
- "integrity": "sha512-TbB63XJixvNToW2IHWAFsCJj9tVnajmwjE14p69i51Rx8byOQd2IP4ourE8v4d7vhyO++nVm1sQk3ePslfbucg==",
+ "version": "0.2.88",
+ "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.88.tgz",
+ "integrity": "sha512-KyroiEvCeZcZEMx5Ys+b4u4eEBbA1ch7XUaBhYpwa/nPMrzTjUhI4RfcytmQfYoTBPcdyx+FX6WFNIoNuJzJfQ==",
"dependencies": {
"isomorphic.js": "^0.2.4"
},
@@ -24331,12 +23955,12 @@
}
},
"node_modules/memfs": {
- "version": "3.4.13",
- "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz",
- "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz",
+ "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==",
"dev": true,
"dependencies": {
- "fs-monkey": "^1.0.3"
+ "fs-monkey": "^1.0.4"
},
"engines": {
"node": ">= 4.0.0"
@@ -24464,21 +24088,21 @@
}
},
"node_modules/mime-db": {
- "version": "1.45.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
- "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
- "version": "2.1.28",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
- "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"dependencies": {
- "mime-db": "1.45.0"
+ "mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
@@ -24603,10 +24227,13 @@
}
},
"node_modules/minimist": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
- "dev": true
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
},
"node_modules/minimist-options": {
"version": "4.1.0",
@@ -24747,9 +24374,9 @@
"integrity": "sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA=="
},
"node_modules/mrmime": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
- "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
+ "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
"dev": true,
"engines": {
"node": ">=10"
@@ -24784,7 +24411,6 @@
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
- "dev": true,
"funding": [
{
"type": "github",
@@ -26407,8 +26033,7 @@
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -26600,7 +26225,6 @@
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
- "dev": true,
"funding": [
{
"type": "opencollective",
@@ -27056,6 +26680,14 @@
"postcss": "^8.2.15"
}
},
+ "node_modules/postcss-prefixwrap": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/postcss-prefixwrap/-/postcss-prefixwrap-1.44.0.tgz",
+ "integrity": "sha512-h9MJGaIvT5hnzFc7Vuo+2ulBw6ecmmfcd8SKKH2TziUzcIA04gUoXIbptuM+tR+htmsQIKNEluiQlmCQ2p5a2g==",
+ "peerDependencies": {
+ "postcss": "*"
+ }
+ },
"node_modules/postcss-reduce-initial": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz",
@@ -27356,16 +26988,26 @@
"postcss": "^8.2.15"
}
},
+ "node_modules/postcss-urlrebase": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-urlrebase/-/postcss-urlrebase-1.3.0.tgz",
+ "integrity": "sha512-LOFN43n1IewKriXiypMNNinXeptttSyGGRLPbBMdQzuTvvCEo5mz/gG06y/HqrkN7p3ayHQf2R2bTBv639FOaQ==",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.3.0"
+ }
+ },
"node_modules/postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
- "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
- "dev": true
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
"node_modules/preact": {
- "version": "10.19.1",
- "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.1.tgz",
- "integrity": "sha512-ZSsUr6EFlwWH0btdXMj6+X+hJAZ1v+aUzKlfwBGokKB1ZO6Shz+D16LxQhM8f+E/UgkKbVe2tsWXtGTUMCkGpQ==",
+ "version": "10.19.3",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.3.tgz",
+ "integrity": "sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
@@ -27447,12 +27089,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/pretty-format/node_modules/react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
- },
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -27495,6 +27131,11 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/prop-types/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ },
"node_modules/proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
@@ -27980,9 +27621,9 @@
"integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ=="
},
"node_modules/react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/react-refresh": {
"version": "0.14.0",
@@ -27993,30 +27634,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/react-remove-scroll": {
- "version": "2.5.5",
- "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
- "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==",
- "dependencies": {
- "react-remove-scroll-bar": "^2.3.3",
- "react-style-singleton": "^2.2.1",
- "tslib": "^2.1.0",
- "use-callback-ref": "^1.3.0",
- "use-sidecar": "^1.1.2"
- },
- "engines": {
- "node": ">=10"
- },
- "peerDependencies": {
- "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
"node_modules/react-remove-scroll-bar": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz",
@@ -28805,124 +28422,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/run-applescript": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz",
- "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==",
- "dev": true,
- "dependencies": {
- "execa": "^5.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/run-applescript/node_modules/cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/run-applescript/node_modules/execa": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
- "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
- "dev": true,
- "dependencies": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.0",
- "human-signals": "^2.1.0",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.1",
- "onetime": "^5.1.2",
- "signal-exit": "^3.0.3",
- "strip-final-newline": "^2.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sindresorhus/execa?sponsor=1"
- }
- },
- "node_modules/run-applescript/node_modules/get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/run-applescript/node_modules/is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/run-applescript/node_modules/npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "dependencies": {
- "path-key": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/run-applescript/node_modules/path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/run-applescript/node_modules/shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "dependencies": {
- "shebang-regex": "^3.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/run-applescript/node_modules/shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@@ -29345,11 +28844,12 @@
"dev": true
},
"node_modules/selfsigned": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz",
- "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz",
+ "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==",
"dev": true,
"dependencies": {
+ "@types/node-forge": "^1.3.0",
"node-forge": "^1"
},
"engines": {
@@ -29675,6 +29175,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/shell-quote": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
+ "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
+ "dev": true,
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/showdown": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/showdown/-/showdown-1.9.1.tgz",
@@ -29833,14 +29342,14 @@
}
},
"node_modules/sirv": {
- "version": "1.0.19",
- "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz",
- "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
+ "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
"dev": true,
"dependencies": {
- "@polka/url": "^1.0.0-next.20",
- "mrmime": "^1.0.0",
- "totalist": "^1.0.0"
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
},
"engines": {
"node": ">= 10"
@@ -30198,7 +29707,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -30265,14 +29773,28 @@
"dev": true
},
"node_modules/spawnd": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-6.2.0.tgz",
- "integrity": "sha512-qX/I4lQy4KgVEcNle0kuc4FxFWHISzBhZW1YemPfwmrmQjyZmfTK/OhBKkhrD2ooAaFZEm1maEBLE6/6enwt+g==",
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-9.0.2.tgz",
+ "integrity": "sha512-nl8DVHEDQ57IcKakzpjanspVChkMpGLuVwMR/eOn9cXE55Qr6luD2Kn06sA0ootRMdgrU4tInN6lA6ohTNvysw==",
"dev": true,
"dependencies": {
- "exit": "^0.1.2",
- "signal-exit": "^3.0.7",
+ "signal-exit": "^4.1.0",
"tree-kill": "^1.2.2"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/spawnd/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/spdx-correct": {
@@ -30338,9 +29860,9 @@
}
},
"node_modules/spdy-transport/node_modules/readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"dependencies": {
"inherits": "^2.0.3",
@@ -31461,13 +30983,13 @@
"dev": true
},
"node_modules/synckit": {
- "version": "0.8.5",
- "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
- "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==",
+ "version": "0.8.8",
+ "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz",
+ "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==",
"dev": true,
"dependencies": {
- "@pkgr/utils": "^2.3.1",
- "tslib": "^2.5.0"
+ "@pkgr/core": "^0.1.0",
+ "tslib": "^2.6.2"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
@@ -31821,18 +31343,6 @@
"ms": "^2.1.1"
}
},
- "node_modules/titleize": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz",
- "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -31921,9 +31431,9 @@
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
},
"node_modules/totalist": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz",
- "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+ "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
"dev": true,
"engines": {
"node": ">=6"
@@ -31950,14 +31460,6 @@
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
"dev": true
},
- "node_modules/traverse": {
- "version": "0.6.7",
- "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz",
- "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
@@ -32002,9 +31504,9 @@
}
},
"node_modules/tsconfig-paths": {
- "version": "3.14.2",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
- "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
"dev": true,
"dependencies": {
"@types/json5": "^0.0.29",
@@ -32072,11 +31574,6 @@
"node": "*"
}
},
- "node_modules/turbo-combine-reducers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/turbo-combine-reducers/-/turbo-combine-reducers-1.0.2.tgz",
- "integrity": "sha512-gHbdMZlA6Ym6Ur5pSH/UWrNQMIM9IqTH6SoL1DbHpqEdQ8i+cFunSmSlFykPt0eGQwZ4d/XTHOl74H0/kFBVWw=="
- },
"node_modules/tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
@@ -32413,15 +31910,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/untildify": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
- "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/update-browserslist-db": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
@@ -32582,19 +32070,6 @@
}
}
},
- "node_modules/use-isomorphic-layout-effect": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
- "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
- "peerDependencies": {
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
"node_modules/use-lilius": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/use-lilius/-/use-lilius-2.0.3.tgz",
@@ -32858,15 +32333,6 @@
"node": ">= 6"
}
},
- "node_modules/wait-on/node_modules/minimist": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
- "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
- "dev": true,
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/wait-on/node_modules/rxjs": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
@@ -32921,6 +32387,12 @@
"node": ">= 8"
}
},
+ "node_modules/web-vitals": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.5.1.tgz",
+ "integrity": "sha512-xQ9lvIpfLxUj0eSmT79ZjRoU5wIRfIr7pNukL7ZE4EcWZSmfZQqOlhuAGfkVa3EFmzPHZhWhXfm2i5ys+THVPg==",
+ "dev": true
+ },
"node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
@@ -32975,20 +32447,23 @@
}
},
"node_modules/webpack-bundle-analyzer": {
- "version": "4.8.0",
- "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.8.0.tgz",
- "integrity": "sha512-ZzoSBePshOKhr+hd8u6oCkZVwpVaXgpw23ScGLFpR6SjYI7+7iIWYarjN6OEYOfRt8o7ZyZZQk0DuMizJ+LEIg==",
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz",
+ "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==",
"dev": true,
"dependencies": {
"@discoveryjs/json-ext": "0.5.7",
"acorn": "^8.0.4",
"acorn-walk": "^8.0.0",
- "chalk": "^4.1.0",
"commander": "^7.2.0",
+ "debounce": "^1.2.1",
+ "escape-string-regexp": "^4.0.0",
"gzip-size": "^6.0.0",
- "lodash": "^4.17.20",
+ "html-escaper": "^2.0.2",
+ "is-plain-object": "^5.0.0",
"opener": "^1.5.2",
- "sirv": "^1.0.7",
+ "picocolors": "^1.0.0",
+ "sirv": "^2.0.3",
"ws": "^7.3.1"
},
"bin": {
@@ -32998,55 +32473,6 @@
"node": ">= 10.13.0"
}
},
- "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
"node_modules/webpack-bundle-analyzer/node_modules/commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
@@ -33056,66 +32482,55 @@
"node": ">= 10"
}
},
- "node_modules/webpack-bundle-analyzer/node_modules/has-flag": {
+ "node_modules/webpack-bundle-analyzer/node_modules/escape-string-regexp": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true,
"engines": {
- "node": ">=8"
- }
- },
- "node_modules/webpack-bundle-analyzer/node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
+ "node": ">=10"
},
- "engines": {
- "node": ">=8"
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/webpack-cli": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
- "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",
+ "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
"dev": true,
"dependencies": {
"@discoveryjs/json-ext": "^0.5.0",
- "@webpack-cli/configtest": "^1.2.0",
- "@webpack-cli/info": "^1.5.0",
- "@webpack-cli/serve": "^1.7.0",
+ "@webpack-cli/configtest": "^2.1.1",
+ "@webpack-cli/info": "^2.0.2",
+ "@webpack-cli/serve": "^2.0.5",
"colorette": "^2.0.14",
- "commander": "^7.0.0",
+ "commander": "^10.0.1",
"cross-spawn": "^7.0.3",
+ "envinfo": "^7.7.3",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
- "interpret": "^2.2.0",
- "rechoir": "^0.7.0",
+ "interpret": "^3.1.1",
+ "rechoir": "^0.8.0",
"webpack-merge": "^5.7.3"
},
"bin": {
"webpack-cli": "bin/cli.js"
},
"engines": {
- "node": ">=10.13.0"
+ "node": ">=14.15.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
},
"peerDependencies": {
- "webpack": "4.x.x || 5.x.x"
+ "webpack": "5.x.x"
},
"peerDependenciesMeta": {
"@webpack-cli/generators": {
"optional": true
},
- "@webpack-cli/migrate": {
- "optional": true
- },
"webpack-bundle-analyzer": {
"optional": true
},
@@ -33125,12 +32540,12 @@
}
},
"node_modules/webpack-cli/node_modules/commander": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
- "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+ "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
"dev": true,
"engines": {
- "node": ">= 10"
+ "node": ">=14"
}
},
"node_modules/webpack-cli/node_modules/cross-spawn": {
@@ -33156,6 +32571,18 @@
"node": ">=8"
}
},
+ "node_modules/webpack-cli/node_modules/rechoir": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
+ "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
+ "dev": true,
+ "dependencies": {
+ "resolve": "^1.20.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
"node_modules/webpack-cli/node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -33234,37 +32661,16 @@
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
- "node_modules/webpack-dev-middleware/node_modules/mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true,
- "engines": {
- "node": ">= 0.6"
- }
- },
- "node_modules/webpack-dev-middleware/node_modules/mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
- "dependencies": {
- "mime-db": "1.52.0"
- },
- "engines": {
- "node": ">= 0.6"
- }
- },
"node_modules/webpack-dev-middleware/node_modules/schema-utils": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
- "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
- "ajv": "^8.8.0",
+ "ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
- "ajv-keywords": "^5.0.0"
+ "ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 12.13.0"
@@ -33275,9 +32681,9 @@
}
},
"node_modules/webpack-dev-server": {
- "version": "4.11.1",
- "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz",
- "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==",
+ "version": "4.15.1",
+ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz",
+ "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==",
"dev": true,
"dependencies": {
"@types/bonjour": "^3.5.9",
@@ -33286,7 +32692,7 @@
"@types/serve-index": "^1.9.1",
"@types/serve-static": "^1.13.10",
"@types/sockjs": "^0.3.33",
- "@types/ws": "^8.5.1",
+ "@types/ws": "^8.5.5",
"ansi-html-community": "^0.0.8",
"bonjour-service": "^1.0.11",
"chokidar": "^3.5.3",
@@ -33299,6 +32705,7 @@
"html-entities": "^2.3.2",
"http-proxy-middleware": "^2.0.3",
"ipaddr.js": "^2.0.1",
+ "launch-editor": "^2.6.0",
"open": "^8.0.9",
"p-retry": "^4.5.0",
"rimraf": "^3.0.2",
@@ -33308,7 +32715,7 @@
"sockjs": "^0.3.24",
"spdy": "^4.0.2",
"webpack-dev-middleware": "^5.3.1",
- "ws": "^8.4.2"
+ "ws": "^8.13.0"
},
"bin": {
"webpack-dev-server": "bin/webpack-dev-server.js"
@@ -33324,6 +32731,9 @@
"webpack": "^4.37.0 || ^5.0.0"
},
"peerDependenciesMeta": {
+ "webpack": {
+ "optional": true
+ },
"webpack-cli": {
"optional": true
}
@@ -33379,15 +32789,15 @@
}
},
"node_modules/webpack-dev-server/node_modules/schema-utils": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
- "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.9",
- "ajv": "^8.8.0",
+ "ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
- "ajv-keywords": "^5.0.0"
+ "ajv-keywords": "^5.1.0"
},
"engines": {
"node": ">= 12.13.0"
@@ -33398,9 +32808,9 @@
}
},
"node_modules/webpack-dev-server/node_modules/ws": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz",
- "integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
+ "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"dev": true,
"engines": {
"node": ">=10.0.0"
@@ -33437,12 +32847,13 @@
}
},
"node_modules/webpack-merge": {
- "version": "5.8.0",
- "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
- "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
+ "version": "5.10.0",
+ "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz",
+ "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==",
"dev": true,
"dependencies": {
"clone-deep": "^4.0.1",
+ "flat": "^5.0.2",
"wildcard": "^2.0.0"
},
"engines": {
@@ -33678,9 +33089,9 @@
"integrity": "sha512-Ba9tGNYxXwaqKEi9sJJvPMKuo063umUPsHN0JJsjrs2j8KDSzkWLMZGZ+MH1Jf1Fq4OWZ5HsESJID6nRza2ang=="
},
"node_modules/wildcard": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
- "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
+ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
"dev": true
},
"node_modules/wrap-ansi": {
@@ -33719,7 +33130,7 @@
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
- "devOptional": true,
+ "dev": true,
"engines": {
"node": ">=8.3.0"
},
@@ -33832,13 +33243,13 @@
}
},
"node_modules/y-webrtc": {
- "version": "10.2.5",
- "resolved": "https://registry.npmjs.org/y-webrtc/-/y-webrtc-10.2.5.tgz",
- "integrity": "sha512-ZyBNvTI5L28sQ2PQI0T/JvyWgvuTq05L21vGkIlcvNLNSJqAaLCBJRe3FHEqXoaogqWmRcEAKGfII4ErNXMnNw==",
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/y-webrtc/-/y-webrtc-10.2.6.tgz",
+ "integrity": "sha512-1kZ4YYwksFZi8+l8mTebVX9vW6Q5MnqxMkvNU700X5dBE38usurt/JgeXSIQRpK3NwUYYb9y63Jn9FMpMH6/vA==",
"dependencies": {
"lib0": "^0.2.42",
"simple-peer": "^9.11.0",
- "y-protocols": "^1.0.5"
+ "y-protocols": "^1.0.6"
},
"bin": {
"y-webrtc-signaling": "bin/server.js"
@@ -33851,7 +33262,31 @@
"url": "https://github.com/sponsors/dmonad"
},
"optionalDependencies": {
- "ws": "^7.2.0"
+ "ws": "^8.14.2"
+ },
+ "peerDependencies": {
+ "yjs": "^13.6.8"
+ }
+ },
+ "node_modules/y-webrtc/node_modules/ws": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
+ "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
+ "optional": true,
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
}
},
"node_modules/y18n": {
@@ -33910,11 +33345,11 @@
}
},
"node_modules/yjs": {
- "version": "13.6.8",
- "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.8.tgz",
- "integrity": "sha512-ZPq0hpJQb6f59B++Ngg4cKexDJTvfOgeiv0sBc4sUm8CaBWH7OQC4kcCgrqbjJ/B2+6vO49exvTmYfdlPtcjbg==",
+ "version": "13.6.11",
+ "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.11.tgz",
+ "integrity": "sha512-FvRRJKX9u270dOLkllGF/UDCWwmIv2Z+ucM4v1QO1TuxdmoiMnSUXH1HAcOKOrkBEhQtPTkxep7tD2DrQB+l0g==",
"dependencies": {
- "lib0": "^0.2.74"
+ "lib0": "^0.2.86"
},
"engines": {
"node": ">=16.0.0",
@@ -33956,24 +33391,24 @@
}
},
"@ariakit/core": {
- "version": "0.2.7",
- "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.2.7.tgz",
- "integrity": "sha512-Hs0N1EMYq88WW4v9xnSIHNR38TvbQuoUX6FYFmeLCZSTIXQBiET7lr1DQXwOOmdEtRtlxQ5HsxbTkxeOkPv+eg=="
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@ariakit/core/-/core-0.3.11.tgz",
+ "integrity": "sha512-+MnOeqnA4FLI/7vqsZLbZQHHN4ofd9kvkNjz44fNi0gqmD+ZbMWiDkFAvZII75dYnxYw5ZPpWjA4waK22VBWig=="
},
"@ariakit/react": {
- "version": "0.2.12",
- "resolved": "https://registry.npmjs.org/@ariakit/react/-/react-0.2.12.tgz",
- "integrity": "sha512-4rAgMyUURHW78EKgRCanhyRUtsiYCOxO65BBHF4mg3tZsDeOvu9kBG5IAXX8mUgakTcyr0EKXuOtGThaj7gobA==",
+ "version": "0.3.14",
+ "resolved": "https://registry.npmjs.org/@ariakit/react/-/react-0.3.14.tgz",
+ "integrity": "sha512-h71BPMZ2eW+E2ESbdYxSAEMR1DozYzd5eHE5IOzGd9Egi5u7EZxqmuW4CXVXZ1Y6vbaDMV3SudgPh7iHS/ArFw==",
"requires": {
- "@ariakit/react-core": "0.2.12"
+ "@ariakit/react-core": "0.3.14"
}
},
"@ariakit/react-core": {
- "version": "0.2.12",
- "resolved": "https://registry.npmjs.org/@ariakit/react-core/-/react-core-0.2.12.tgz",
- "integrity": "sha512-3KSKlX10nnhCvjsbPW0CAnqG+6grryfwnMkeJJ/h34FSV7hEfUMexmIjKBVZyfBG08Xj8NjSK8kkx9c3ChkXeA==",
+ "version": "0.3.14",
+ "resolved": "https://registry.npmjs.org/@ariakit/react-core/-/react-core-0.3.14.tgz",
+ "integrity": "sha512-16Qj6kDPglpdWtU5roY9q+G66naOjauTY5HvUIaL2aLY0187ATaRrABIKoMMzTtJyhvsud4jFlzivz+/zCQ8yw==",
"requires": {
- "@ariakit/core": "0.2.7",
+ "@ariakit/core": "0.3.11",
"@floating-ui/dom": "^1.0.0",
"use-sync-external-store": "^1.2.0"
}
@@ -36495,71 +35930,11 @@
"fastq": "^1.6.0"
}
},
- "@pkgr/utils": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz",
- "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.3",
- "fast-glob": "^3.3.0",
- "is-glob": "^4.0.3",
- "open": "^9.1.0",
- "picocolors": "^1.0.0",
- "tslib": "^2.6.0"
- },
- "dependencies": {
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "define-lazy-prop": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
- "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
- "dev": true
- },
- "open": {
- "version": "9.1.0",
- "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz",
- "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==",
- "dev": true,
- "requires": {
- "default-browser": "^4.0.0",
- "define-lazy-prop": "^3.0.0",
- "is-inside-container": "^1.0.0",
- "is-wsl": "^2.2.0"
- }
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true
- }
- }
+ "@pkgr/core": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz",
+ "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==",
+ "dev": true
},
"@playwright/test": {
"version": "1.32.0",
@@ -36641,9 +36016,9 @@
}
},
"@polka/url": {
- "version": "1.0.0-next.21",
- "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
- "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
+ "version": "1.0.0-next.24",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz",
+ "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==",
"dev": true
},
"@popperjs/core": {
@@ -36652,17 +36027,17 @@
"integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
},
"@preact/signals": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@preact/signals/-/signals-1.2.1.tgz",
- "integrity": "sha512-hRPvp1C2ooDzOHqfnhdpHgoIFDbYFAXLhoid3+jSItuPPD/J0r/UsiWKv/8ZO/oEhjRaP0M5niuRYsWqmY2GEA==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@preact/signals/-/signals-1.2.2.tgz",
+ "integrity": "sha512-ColCqdo4cRP18bAuIR4Oik5rDpiyFtPIJIygaYPMEAwTnl4buWkBOflGBSzhYyPyJfKpkwlekrvK+1pzQ2ldWw==",
"requires": {
"@preact/signals-core": "^1.4.0"
}
},
"@preact/signals-core": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.5.0.tgz",
- "integrity": "sha512-U2diO1Z4i1n2IoFgMYmRdHWGObNrcuTRxyNEn7deSq2cru0vj0583HYQZHsAqcs7FE+hQyX3mjIV7LAfHCvy8w=="
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/@preact/signals-core/-/signals-core-1.5.1.tgz",
+ "integrity": "sha512-dE6f+WCX5ZUDwXzUIWNMhhglmuLpqJhuy3X3xHrhZYI0Hm2LyQwOu0l9mdPiWrVNsE+Q7txOnJPgtIqHCYoBVA=="
},
"@puppeteer/browsers": {
"version": "0.5.0",
@@ -36801,27 +36176,6 @@
"@babel/runtime": "^7.13.10"
}
},
- "@radix-ui/react-arrow": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.0.2.tgz",
- "integrity": "sha512-fqYwhhI9IarZ0ll2cUSfKuXHlJK0qE4AfnRrPBbRwEH/4mGQn04/QFGomLi8TXWIdv9WJk//KgGm+aDxVIr1wA==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-primitive": "1.0.2"
- }
- },
- "@radix-ui/react-collection": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.0.2.tgz",
- "integrity": "sha512-s8WdQQ6wNXpaxdZ308KSr8fEWGrg4un8i4r/w7fhiS4ElRNjk5rRcl0/C6TANG2LvLOGIxtzo/jAg6Qf73TEBw==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-slot": "1.0.1"
- }
- },
"@radix-ui/react-compose-refs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.0.tgz",
@@ -36934,42 +36288,6 @@
}
}
},
- "@radix-ui/react-direction": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.0.0.tgz",
- "integrity": "sha512-2HV05lGUgYcA6xgLQ4BKPDmtL+QbIZYH5fCOTAOOcJ5O0QbWS3i9lKaurLzliYUDhORI2Qr3pyjhJh44lKA3rQ==",
- "requires": {
- "@babel/runtime": "^7.13.10"
- }
- },
- "@radix-ui/react-dismissable-layer": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.0.3.tgz",
- "integrity": "sha512-nXZOvFjOuHS1ovumntGV7NNoLaEp9JEvTht3MBjP44NSW5hUKj/8OnfN3+8WmB+CEhN44XaGhpHoSsUIEl5P7Q==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/primitive": "1.0.0",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-callback-ref": "1.0.0",
- "@radix-ui/react-use-escape-keydown": "1.0.2"
- }
- },
- "@radix-ui/react-dropdown-menu": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.0.4.tgz",
- "integrity": "sha512-y6AT9+MydyXcByivdK1+QpjWoKaC7MLjkS/cH1Q3keEyMvDkiY85m8o2Bi6+Z1PPUlCsMULopxagQOSfN0wahg==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/primitive": "1.0.0",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-id": "1.0.0",
- "@radix-ui/react-menu": "2.0.4",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-controllable-state": "1.0.0"
- }
- },
"@radix-ui/react-focus-guards": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.0.tgz",
@@ -36978,17 +36296,6 @@
"@babel/runtime": "^7.13.10"
}
},
- "@radix-ui/react-focus-scope": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.2.tgz",
- "integrity": "sha512-spwXlNTfeIprt+kaEWE/qYuYT3ZAqJiAGjN/JgdvgVDTu8yc+HuX+WOWXrKliKnLnwck0F6JDkqIERncnih+4A==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-callback-ref": "1.0.0"
- }
- },
"@radix-ui/react-id": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.0.0.tgz",
@@ -36998,83 +36305,6 @@
"@radix-ui/react-use-layout-effect": "1.0.0"
}
},
- "@radix-ui/react-menu": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.0.4.tgz",
- "integrity": "sha512-mzKR47tZ1t193trEqlQoJvzY4u9vYfVH16ryBrVrCAGZzkgyWnMQYEZdUkM7y8ak9mrkKtJiqB47TlEnubeOFQ==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/primitive": "1.0.0",
- "@radix-ui/react-collection": "1.0.2",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-direction": "1.0.0",
- "@radix-ui/react-dismissable-layer": "1.0.3",
- "@radix-ui/react-focus-guards": "1.0.0",
- "@radix-ui/react-focus-scope": "1.0.2",
- "@radix-ui/react-id": "1.0.0",
- "@radix-ui/react-popper": "1.1.1",
- "@radix-ui/react-portal": "1.0.2",
- "@radix-ui/react-presence": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-roving-focus": "1.0.3",
- "@radix-ui/react-slot": "1.0.1",
- "@radix-ui/react-use-callback-ref": "1.0.0",
- "aria-hidden": "^1.1.1",
- "react-remove-scroll": "2.5.5"
- }
- },
- "@radix-ui/react-popper": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.1.1.tgz",
- "integrity": "sha512-keYDcdMPNMjSC8zTsZ8wezUMiWM9Yj14wtF3s0PTIs9srnEPC9Kt2Gny1T3T81mmSeyDjZxsD9N5WCwNNb712w==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@floating-ui/react-dom": "0.7.2",
- "@radix-ui/react-arrow": "1.0.2",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-callback-ref": "1.0.0",
- "@radix-ui/react-use-layout-effect": "1.0.0",
- "@radix-ui/react-use-rect": "1.0.0",
- "@radix-ui/react-use-size": "1.0.0",
- "@radix-ui/rect": "1.0.0"
- },
- "dependencies": {
- "@floating-ui/core": {
- "version": "0.7.3",
- "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.3.tgz",
- "integrity": "sha512-buc8BXHmG9l82+OQXOFU3Kr2XQx9ys01U/Q9HMIrZ300iLc8HLMgh7dcCqgYzAzf4BkoQvDcXf5Y+CuEZ5JBYg=="
- },
- "@floating-ui/dom": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.4.tgz",
- "integrity": "sha512-419BMceRLq0RrmTSDxn8hf9R3VCJv2K9PUfugh5JyEFmdjzDo+e8U5EdR8nzKq8Yj1htzLm3b6eQEEam3/rrtg==",
- "requires": {
- "@floating-ui/core": "^0.7.3"
- }
- },
- "@floating-ui/react-dom": {
- "version": "0.7.2",
- "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.2.tgz",
- "integrity": "sha512-1T0sJcpHgX/u4I1OzIEhlcrvkUN8ln39nz7fMoE/2HDHrPiMFoOGR7++GYyfUmIQHkkrTinaeQsO3XWubjSvGg==",
- "requires": {
- "@floating-ui/dom": "^0.5.3",
- "use-isomorphic-layout-effect": "^1.1.1"
- }
- }
- }
- },
- "@radix-ui/react-portal": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.0.2.tgz",
- "integrity": "sha512-swu32idoCW7KA2VEiUZGBSu9nB6qwGdV6k6HYhUoOo3M1FFpD+VgLzUqtt3mwL1ssz7r2x8MggpLSQach2Xy/Q==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-primitive": "1.0.2"
- }
- },
"@radix-ui/react-presence": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.0.0.tgz",
@@ -37085,41 +36315,6 @@
"@radix-ui/react-use-layout-effect": "1.0.0"
}
},
- "@radix-ui/react-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-1.0.2.tgz",
- "integrity": "sha512-zY6G5Qq4R8diFPNwtyoLRZBxzu1Z+SXMlfYpChN7Dv8gvmx9X3qhDqiLWvKseKVJMuedFeU/Sa0Sy/Ia+t06Dw==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-slot": "1.0.1"
- }
- },
- "@radix-ui/react-roving-focus": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.3.tgz",
- "integrity": "sha512-stjCkIoMe6h+1fWtXlA6cRfikdBzCLp3SnVk7c48cv/uy3DTGoXhN76YaOYUJuy3aEDvDIKwKR5KSmvrtPvQPQ==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/primitive": "1.0.0",
- "@radix-ui/react-collection": "1.0.2",
- "@radix-ui/react-compose-refs": "1.0.0",
- "@radix-ui/react-context": "1.0.0",
- "@radix-ui/react-direction": "1.0.0",
- "@radix-ui/react-id": "1.0.0",
- "@radix-ui/react-primitive": "1.0.2",
- "@radix-ui/react-use-callback-ref": "1.0.0",
- "@radix-ui/react-use-controllable-state": "1.0.0"
- }
- },
- "@radix-ui/react-slot": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.1.tgz",
- "integrity": "sha512-avutXAFL1ehGvAXtPquu0YK5oz6ctS474iM3vNGQIkswrVhdrS52e3uoMQBzZhNRAIE0jBnUyXWNmSjGHhCFcw==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-compose-refs": "1.0.0"
- }
- },
"@radix-ui/react-use-callback-ref": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz",
@@ -37137,15 +36332,6 @@
"@radix-ui/react-use-callback-ref": "1.0.0"
}
},
- "@radix-ui/react-use-escape-keydown": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.0.2.tgz",
- "integrity": "sha512-DXGim3x74WgUv+iMNCF+cAo8xUHHeqvjx8zs7trKf+FkQKPQXLk2sX7Gx1ysH7Q76xCpZuxIJE7HLPxRE+Q+GA==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-use-callback-ref": "1.0.0"
- }
- },
"@radix-ui/react-use-layout-effect": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.0.tgz",
@@ -37154,32 +36340,6 @@
"@babel/runtime": "^7.13.10"
}
},
- "@radix-ui/react-use-rect": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.0.0.tgz",
- "integrity": "sha512-TB7pID8NRMEHxb/qQJpvSt3hQU4sqNPM1VCTjTRjEOa7cEop/QMuq8S6fb/5Tsz64kqSvB9WnwsDHtjnrM9qew==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/rect": "1.0.0"
- }
- },
- "@radix-ui/react-use-size": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.0.0.tgz",
- "integrity": "sha512-imZ3aYcoYCKhhgNpkNDh/aTiU05qw9hX+HHI1QDBTyIlcFjgeFlKKySNGMwTp7nYFLQg/j0VA2FmCY4WPDDHMg==",
- "requires": {
- "@babel/runtime": "^7.13.10",
- "@radix-ui/react-use-layout-effect": "1.0.0"
- }
- },
- "@radix-ui/rect": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.0.0.tgz",
- "integrity": "sha512-d0O68AYy/9oeEy1DdC07bz1/ZXX+DqCskRd3i4JzLSTXwefzaepQrKjXC7aNM8lTHjFLDO0pDgaEiQ7jEk+HVg==",
- "requires": {
- "@babel/runtime": "^7.13.10"
- }
- },
"@react-spring/animated": {
"version": "9.7.1",
"resolved": "https://registry.npmjs.org/@react-spring/animated/-/animated-9.7.1.tgz",
@@ -37833,9 +36993,9 @@
}
},
"@types/body-parser": {
- "version": "1.19.2",
- "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
- "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
+ "version": "1.19.5",
+ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
+ "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
"dev": true,
"requires": {
"@types/connect": "*",
@@ -37843,27 +37003,27 @@
}
},
"@types/bonjour": {
- "version": "3.5.10",
- "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz",
- "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==",
+ "version": "3.5.13",
+ "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz",
+ "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/connect": {
- "version": "3.4.35",
- "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
- "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+ "version": "3.4.38",
+ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
+ "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/connect-history-api-fallback": {
- "version": "1.3.5",
- "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz",
- "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==",
+ "version": "1.5.4",
+ "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz",
+ "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==",
"dev": true,
"requires": {
"@types/express-serve-static-core": "*",
@@ -37897,9 +37057,9 @@
"dev": true
},
"@types/express": {
- "version": "4.17.17",
- "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
- "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz",
+ "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==",
"dev": true,
"requires": {
"@types/body-parser": "*",
@@ -37909,14 +37069,15 @@
}
},
"@types/express-serve-static-core": {
- "version": "4.17.33",
- "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz",
- "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==",
+ "version": "4.17.41",
+ "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.41.tgz",
+ "integrity": "sha512-OaJ7XLaelTgrvlZD8/aa0vvvxZdUmlCn6MtWeB7TkiKW70BQLc9XEPpDLPdbo52ZhXUCrznlWdCHWxJWtdyajA==",
"dev": true,
"requires": {
"@types/node": "*",
"@types/qs": "*",
- "@types/range-parser": "*"
+ "@types/range-parser": "*",
+ "@types/send": "*"
}
},
"@types/glob": {
@@ -37938,10 +37099,26 @@
"@types/node": "*"
}
},
+ "@types/gradient-parser": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/@types/gradient-parser/-/gradient-parser-0.1.3.tgz",
+ "integrity": "sha512-XDbrTSBlQV9nxE1GiDL3FaOPy4G/KaJkhDutBX48Kg8CYZMBARyyDFGCWfWJn4pobmInmwud1xxH7VJMAr0CKQ=="
+ },
+ "@types/highlight-words-core": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@types/highlight-words-core/-/highlight-words-core-1.2.1.tgz",
+ "integrity": "sha512-9VZUA5omXBfn+hDxFjUDu1FOJTBM3LmvqfDey+Z6Aa8B8/JmF5SMj6FBrjfgJ/Q3YXOZd3qyTDfJyMZSs/wCUA=="
+ },
+ "@types/http-errors": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz",
+ "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==",
+ "dev": true
+ },
"@types/http-proxy": {
- "version": "1.17.9",
- "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz",
- "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==",
+ "version": "1.17.14",
+ "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.14.tgz",
+ "integrity": "sha512-SSrD0c1OQzlFX7pGu1eXxSEjemej64aaNPRhhVYUGqXh0BtldAAx37MG8btcumvpgKyZp1F5Gn3JkktdxiFv6w==",
"dev": true,
"requires": {
"@types/node": "*"
@@ -38017,9 +37194,9 @@
"dev": true
},
"@types/mime": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
- "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==",
+ "version": "1.3.5",
+ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
+ "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
"dev": true
},
"@types/minimatch": {
@@ -38042,8 +37219,16 @@
"@types/node": {
"version": "14.14.20",
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.20.tgz",
- "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==",
- "dev": true
+ "integrity": "sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A=="
+ },
+ "@types/node-forge": {
+ "version": "1.3.11",
+ "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz",
+ "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
},
"@types/normalize-package-data": {
"version": "2.4.1",
@@ -38069,15 +37254,15 @@
"optional": true
},
"@types/qs": {
- "version": "6.9.7",
- "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
- "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
+ "version": "6.9.11",
+ "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.11.tgz",
+ "integrity": "sha512-oGk0gmhnEJK4Yyk+oI7EfXsLayXatCWPHary1MtcmbAifkobT9cM9yutG/hZKIseOU0MqbIwQ/u2nn/Gb+ltuQ==",
"dev": true
},
"@types/range-parser": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
- "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
+ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
"dev": true
},
"@types/react": {
@@ -38110,34 +37295,53 @@
"integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
},
"@types/semver": {
- "version": "7.5.5",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz",
- "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==",
+ "version": "7.5.6",
+ "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz",
+ "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==",
"dev": true
},
+ "@types/send": {
+ "version": "0.17.4",
+ "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz",
+ "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==",
+ "dev": true,
+ "requires": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
"@types/serve-index": {
- "version": "1.9.1",
- "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz",
- "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==",
+ "version": "1.9.4",
+ "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz",
+ "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==",
"dev": true,
"requires": {
"@types/express": "*"
}
},
"@types/serve-static": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz",
- "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==",
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.5.tgz",
+ "integrity": "sha512-PDRk21MnK70hja/YF8AHfC7yIsiQHn1rcXx7ijCFBX/k+XQJhQT/gw3xekXKJvx+5SXaMMS8oqQy09Mzvz2TuQ==",
"dev": true,
"requires": {
+ "@types/http-errors": "*",
"@types/mime": "*",
"@types/node": "*"
}
},
+ "@types/simple-peer": {
+ "version": "9.11.8",
+ "resolved": "https://registry.npmjs.org/@types/simple-peer/-/simple-peer-9.11.8.tgz",
+ "integrity": "sha512-rvqefdp2rvIA6wiomMgKWd2UZNPe6LM2EV5AuY3CPQJF+8TbdrL5TjYdMf0VAjGczzlkH4l1NjDkihwbj3Xodw==",
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/sockjs": {
- "version": "0.3.33",
- "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz",
- "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==",
+ "version": "0.3.36",
+ "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz",
+ "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==",
"dev": true,
"requires": {
"@types/node": "*"
@@ -38226,9 +37430,9 @@
}
},
"@types/ws": {
- "version": "8.5.4",
- "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
- "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
+ "version": "8.5.10",
+ "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
+ "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==",
"dev": true,
"requires": {
"@types/node": "*"
@@ -38260,16 +37464,16 @@
}
},
"@typescript-eslint/eslint-plugin": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.11.0.tgz",
- "integrity": "sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.19.1.tgz",
+ "integrity": "sha512-roQScUGFruWod9CEyoV5KlCYrubC/fvG8/1zXuT0WTcxX87GnMMmnksMwSg99lo1xiKrBzw2icsJPMAw1OtKxg==",
"dev": true,
"requires": {
"@eslint-community/regexpp": "^4.5.1",
- "@typescript-eslint/scope-manager": "6.11.0",
- "@typescript-eslint/type-utils": "6.11.0",
- "@typescript-eslint/utils": "6.11.0",
- "@typescript-eslint/visitor-keys": "6.11.0",
+ "@typescript-eslint/scope-manager": "6.19.1",
+ "@typescript-eslint/type-utils": "6.19.1",
+ "@typescript-eslint/utils": "6.19.1",
+ "@typescript-eslint/visitor-keys": "6.19.1",
"debug": "^4.3.4",
"graphemer": "^1.4.0",
"ignore": "^5.2.4",
@@ -38279,83 +37483,104 @@
}
},
"@typescript-eslint/parser": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.11.0.tgz",
- "integrity": "sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz",
+ "integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==",
"dev": true,
"requires": {
- "@typescript-eslint/scope-manager": "6.11.0",
- "@typescript-eslint/types": "6.11.0",
- "@typescript-eslint/typescript-estree": "6.11.0",
- "@typescript-eslint/visitor-keys": "6.11.0",
+ "@typescript-eslint/scope-manager": "6.19.1",
+ "@typescript-eslint/types": "6.19.1",
+ "@typescript-eslint/typescript-estree": "6.19.1",
+ "@typescript-eslint/visitor-keys": "6.19.1",
"debug": "^4.3.4"
}
},
"@typescript-eslint/scope-manager": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.11.0.tgz",
- "integrity": "sha512-0A8KoVvIURG4uhxAdjSaxy8RdRE//HztaZdG8KiHLP8WOXSk0vlF7Pvogv+vlJA5Rnjj/wDcFENvDaHb+gKd1A==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz",
+ "integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "6.11.0",
- "@typescript-eslint/visitor-keys": "6.11.0"
+ "@typescript-eslint/types": "6.19.1",
+ "@typescript-eslint/visitor-keys": "6.19.1"
}
},
"@typescript-eslint/type-utils": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.11.0.tgz",
- "integrity": "sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.19.1.tgz",
+ "integrity": "sha512-0vdyld3ecfxJuddDjACUvlAeYNrHP/pDeQk2pWBR2ESeEzQhg52DF53AbI9QCBkYE23lgkhLCZNkHn2hEXXYIg==",
"dev": true,
"requires": {
- "@typescript-eslint/typescript-estree": "6.11.0",
- "@typescript-eslint/utils": "6.11.0",
+ "@typescript-eslint/typescript-estree": "6.19.1",
+ "@typescript-eslint/utils": "6.19.1",
"debug": "^4.3.4",
"ts-api-utils": "^1.0.1"
}
},
"@typescript-eslint/types": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.11.0.tgz",
- "integrity": "sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz",
+ "integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==",
"dev": true
},
"@typescript-eslint/typescript-estree": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.11.0.tgz",
- "integrity": "sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz",
+ "integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "6.11.0",
- "@typescript-eslint/visitor-keys": "6.11.0",
+ "@typescript-eslint/types": "6.19.1",
+ "@typescript-eslint/visitor-keys": "6.19.1",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
+ "minimatch": "9.0.3",
"semver": "^7.5.4",
"ts-api-utils": "^1.0.1"
+ },
+ "dependencies": {
+ "brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "minimatch": {
+ "version": "9.0.3",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
+ "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^2.0.1"
+ }
+ }
}
},
"@typescript-eslint/utils": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.11.0.tgz",
- "integrity": "sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.19.1.tgz",
+ "integrity": "sha512-JvjfEZuP5WoMqwh9SPAPDSHSg9FBHHGhjPugSRxu5jMfjvBpq5/sGTD+9M9aQ5sh6iJ8AY/Kk/oUYVEMAPwi7w==",
"dev": true,
"requires": {
"@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12",
"@types/semver": "^7.5.0",
- "@typescript-eslint/scope-manager": "6.11.0",
- "@typescript-eslint/types": "6.11.0",
- "@typescript-eslint/typescript-estree": "6.11.0",
+ "@typescript-eslint/scope-manager": "6.19.1",
+ "@typescript-eslint/types": "6.19.1",
+ "@typescript-eslint/typescript-estree": "6.19.1",
"semver": "^7.5.4"
}
},
"@typescript-eslint/visitor-keys": {
- "version": "6.11.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.11.0.tgz",
- "integrity": "sha512-+SUN/W7WjBr05uRxPggJPSzyB8zUpaYo2hByKasWbqr3PM8AXfZt8UHdNpBS1v9SA62qnSSMF3380SwDqqprgQ==",
+ "version": "6.19.1",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz",
+ "integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==",
"dev": true,
"requires": {
- "@typescript-eslint/types": "6.11.0",
+ "@typescript-eslint/types": "6.19.1",
"eslint-visitor-keys": "^3.4.1"
},
"dependencies": {
@@ -38527,78 +37752,75 @@
}
},
"@webpack-cli/configtest": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
- "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.1.1.tgz",
+ "integrity": "sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==",
"dev": true
},
"@webpack-cli/info": {
- "version": "1.5.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
- "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
- "dev": true,
- "requires": {
- "envinfo": "^7.7.3"
- }
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.2.tgz",
+ "integrity": "sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==",
+ "dev": true
},
"@webpack-cli/serve": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
- "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.5.tgz",
+ "integrity": "sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==",
"dev": true
},
"@wordpress/a11y": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-3.42.13.tgz",
- "integrity": "sha512-57KH89dbt8ipimoBGezKQHLvwSsJHW/W4HpvzZFqnPHvnlNNYoVC9UuqiBavxdB2WkzMPmNYFKsM7kOInEdyTA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-3.50.0.tgz",
+ "integrity": "sha512-eQiPGnxqiL1LgnHztFG0RGSFZ5phwR8B8Fr4lbJsFalsc9R/tOcjewvf2KN0yi2UlRA5ssAeiTP+tYmeAqtOHQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/dom-ready": "^3.42.13",
- "@wordpress/i18n": "^4.42.13"
+ "@wordpress/dom-ready": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0"
}
},
"@wordpress/annotations": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/annotations/-/annotations-2.42.13.tgz",
- "integrity": "sha512-S/bCU8AOYzVMKBSMMtmoB9Dw1kiOS3KNfFzdCLpiyzNhfqXPWp7ciM5WJTHJRdzobeTOh1CIJ6x5WHhBqO/t8w==",
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/annotations/-/annotations-2.50.0.tgz",
+ "integrity": "sha512-E9cu8xuGvIRw3LVtuS+XSzAXVBF41sgvxpVJAz/5FEibzxUHPy8flu5tTKf+mi4WGZxC4AJGNP1bhZRj7cynZQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/data": "^9.12.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/rich-text": "^6.19.13",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/rich-text": "^6.27.0",
"rememo": "^4.0.2",
"uuid": "^9.0.1"
}
},
"@wordpress/api-fetch": {
- "version": "6.39.13",
- "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.39.13.tgz",
- "integrity": "sha512-DFaiNq5bEOVqYDpcqXqdxjyBDboeElma6e7FNSX2APVZZt/8xxeb4eI9X0877i6B15G5blyHsjSit5rq88iqtg==",
+ "version": "6.47.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.47.0.tgz",
+ "integrity": "sha512-NA/jWDXoVtJmiVBYhlxts2UrgKJpJM+zTGzLCfRQCZUzpJYm3LonB8x+uCQ78nEyxCY397Esod3jnbquYjOr0Q==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/url": "^3.51.0"
}
},
"@wordpress/autop": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-3.42.13.tgz",
- "integrity": "sha512-vQjEvJaYZ5OyMJ6IdbVL/RUqOy/VTe6E1BCkdRW8amJTm8koTkbBbOFWSsVoXh6jFoq2mDAqC7Tt2vL0yMA4rQ==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-3.50.0.tgz",
+ "integrity": "sha512-4E0vq2MvSOVDKXs4OulIbTdKU6S5O9QjT4qc63rAd0uiKGBYV12ViPzmwbJ6k38zOO0PKdcwlVCj55Gq4aoPDw==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/babel-plugin-import-jsx-pragma": {
- "version": "4.26.0",
- "resolved": "https://registry.npmjs.org/@wordpress/babel-plugin-import-jsx-pragma/-/babel-plugin-import-jsx-pragma-4.26.0.tgz",
- "integrity": "sha512-XZCTBqEmOlM87/6wkgtHhnHaj8cJPOY5avyjKtMDwoBbcXAmHUknbphZG7KEWIiVIilyxKyHnsTxjTplkqTtCQ==",
+ "version": "4.33.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/babel-plugin-import-jsx-pragma/-/babel-plugin-import-jsx-pragma-4.33.0.tgz",
+ "integrity": "sha512-CjzruFKWgzU/mO/nnQJ2l9UlzZQpqS60UC6l2vNdJ9oD2nKHR5Oou6kNic3QhWDVJrBf2JUiJJ0TC280bykXmA==",
"dev": true
},
"@wordpress/babel-preset-default": {
- "version": "7.26.13",
- "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-7.26.13.tgz",
- "integrity": "sha512-kW9sg3lwbrhYzVR24n7cUEC2Sx1Pj4UNnITbXqVmxnVok0CK7IkvstMlbtLDbULh9o2f92OPNMwdAStErEjT7g==",
+ "version": "7.34.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-7.34.0.tgz",
+ "integrity": "sha512-yjFOllyTktFHtcIEgU3ghXBn8lItzr5mPLf0xdSpe0cHceFYL1hT1oprhgRL+olZweaO96Yfm0qUCCKQfJBWsA==",
"dev": true,
"requires": {
"@babel/core": "^7.16.0",
@@ -38607,94 +37829,94 @@
"@babel/preset-env": "^7.16.0",
"@babel/preset-typescript": "^7.16.0",
"@babel/runtime": "^7.16.0",
- "@wordpress/babel-plugin-import-jsx-pragma": "^4.25.13",
- "@wordpress/browserslist-config": "^5.25.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/warning": "^2.42.13",
- "browserslist": "^4.21.9",
- "core-js": "^3.31.0"
+ "@wordpress/babel-plugin-import-jsx-pragma": "^4.33.0",
+ "@wordpress/browserslist-config": "^5.33.0",
+ "@wordpress/warning": "^2.50.0",
+ "browserslist": "^4.21.10",
+ "core-js": "^3.31.0",
+ "react": "^18.2.0"
}
},
"@wordpress/base-styles": {
- "version": "4.34.0",
- "resolved": "https://registry.npmjs.org/@wordpress/base-styles/-/base-styles-4.34.0.tgz",
- "integrity": "sha512-LYiNFWl+6yJDVQ7hSNJu2kVuM1p3C3aTB769lXnMSxi3gubzxqjZqz9i9XQ3UjO9EFiDSvgbOXa8YhvTUfNnkQ==",
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/base-styles/-/base-styles-4.41.0.tgz",
+ "integrity": "sha512-MjPAZeAqvyskDXDp2wGZ0DjtYOQLOydI1WqVIZS4wnIdhsQWQD//VMeXgLrcmCzNyQg+iKTx3o+BzmXVTOD0+w==",
"dev": true
},
"@wordpress/blob": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-3.42.13.tgz",
- "integrity": "sha512-W5TaJK9Vl8LInjdxRRq5hE08r34JKybVjm7UuSIPOppNErLu9g6edcGHsv3b/7f5so3TcSnPsLfDkPgwSFTjXA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-3.50.0.tgz",
+ "integrity": "sha512-QvBhsW9WPdsOJhJ0BxzZ83i+cH/gAdjJ1iHY4Rkb02qbZEz4jhdvucGQf2oVnWwvAsFiFPKWk7CwAM5XjoahCA==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/block-directory": {
- "version": "4.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-4.19.16.tgz",
- "integrity": "sha512-7YOqeZt8ExyMidbblzht7x5jnfpZVD6N69VuDrvdlB/8eB7gl62tKZdNXHwWoZccSWJb+xUTZL01k2HpJulcPQ==",
+ "version": "4.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-4.27.2.tgz",
+ "integrity": "sha512-EblzP8BbkqAeFomH3/L9wdmbz1iw0n2siBMdZNZKHifwWv0iLFQfZlMZo4ImgWwC4YE3is7zSGpkWJ1kHMbj7w==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/edit-post": "^7.19.16",
- "@wordpress/editor": "^13.19.14",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/edit-post": "^7.27.2",
+ "@wordpress/editor": "^13.27.2",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0",
"change-case": "^4.1.2"
}
},
"@wordpress/block-editor": {
- "version": "12.10.14",
- "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-12.10.14.tgz",
- "integrity": "sha512-x56FPZZfJPk/Vd1aKIdpBIllrUuAVgwom+mYH0OohCmUzCBp1Eg8Urg5nshZpiLXpHt2dXycQCLu2Mpb+YpOJw==",
+ "version": "12.18.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-12.18.2.tgz",
+ "integrity": "sha512-LDZIcp5Bl2FCyfkf07XgfM0kzY+AYhyTS4kt2U4GRSeUey79AM+GIYXb8TM2Y68B09HP/rpntBW4e/cBqjHfjw==",
"requires": {
"@babel/runtime": "^7.16.0",
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
"@react-spring/web": "^9.4.5",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/commands": "^0.13.14",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/shortcode": "^3.42.13",
- "@wordpress/style-engine": "^1.25.13",
- "@wordpress/token-list": "^2.42.13",
- "@wordpress/url": "^3.43.13",
- "@wordpress/warning": "^2.42.13",
- "@wordpress/wordcount": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/style-engine": "^1.33.1",
+ "@wordpress/token-list": "^2.50.0",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/warning": "^2.50.0",
+ "@wordpress/wordcount": "^3.50.0",
"change-case": "^4.1.2",
"classnames": "^2.3.1",
"colord": "^2.7.0",
@@ -38702,50 +37924,54 @@
"diff": "^4.0.2",
"dom-scroll-into-view": "^1.2.1",
"fast-deep-equal": "^3.1.3",
- "inherits": "^2.0.3",
+ "memize": "^2.1.0",
+ "postcss": "^8.4.21",
+ "postcss-prefixwrap": "^1.41.0",
+ "postcss-urlrebase": "^1.0.0",
"react-autosize-textarea": "^7.1.0",
"react-easy-crop": "^4.5.1",
"rememo": "^4.0.2",
- "remove-accents": "^0.5.0",
- "traverse": "^0.6.6"
+ "remove-accents": "^0.5.0"
}
},
"@wordpress/block-library": {
- "version": "8.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-8.19.16.tgz",
- "integrity": "sha512-6NqTHjEYk3X+jzw6JS3pOgVYl2HPlr0iAI3Ch9sdOxozAm1+VrE5DKeM//rf9QpR7wWJ6je4F/eNjZ2WJIYTfw==",
+ "version": "8.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-8.27.2.tgz",
+ "integrity": "sha512-Wabc1nmCMuTr/BgS63iHaQYtvfVO9Z30SwLaMVLHwGe7Hrvtb19pSOwKb/PIuoiWrlqJ/sZEZPXFENAJB5FVYA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/autop": "^3.42.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interactivity": "^2.3.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/primitives": "^3.40.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/reusable-blocks": "^4.19.14",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/server-side-render": "^4.19.14",
- "@wordpress/url": "^3.43.13",
- "@wordpress/viewport": "^5.19.13",
- "@wordpress/wordcount": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/autop": "^3.50.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interactivity": "^4.0.1",
+ "@wordpress/interactivity-router": "^1.0.1",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/patterns": "^1.11.2",
+ "@wordpress/primitives": "^3.48.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/reusable-blocks": "^4.27.2",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/server-side-render": "^4.27.1",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/viewport": "^5.27.0",
+ "@wordpress/wordcount": "^3.50.0",
"change-case": "^4.1.2",
"classnames": "^2.3.1",
"colord": "^2.7.0",
@@ -38758,40 +37984,41 @@
}
},
"@wordpress/block-serialization-default-parser": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-4.42.13.tgz",
- "integrity": "sha512-+ggjHxrjbpIwknsfKy18HXOVGWHeFykxlElE9dYVspJvr734mMMTQuIeL5WM+vZUy5NWv0oHF0VykX0MHyy60w==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-4.50.0.tgz",
+ "integrity": "sha512-ihf2vr+w2zHBOvYTPQZXDiR2IMvso8yJJtzKIHA2ZEgVQ+VVLb4X86n34hfWXtPA3i2KDW+t1WCtq56aNq3Zag==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/blocks": {
- "version": "12.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-12.19.13.tgz",
- "integrity": "sha512-KdNcYb5Cr4sgzOkJM+KpPZeLLFr8e06CkRDp0EQk7VGSsoScXpqIcMEtMcKNQp1XPuJ6npMr/BacC5qNjyHA1A==",
+ "version": "12.27.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-12.27.1.tgz",
+ "integrity": "sha512-9uZtuTG6+fiFV2bLn8b1gzv4BgMpBu4SDQGnvzc5f9U5GL5oYns3PP8vXDOwM2cK1DEmqPsohQWhRnz8QYZDtw==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/autop": "^3.42.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/block-serialization-default-parser": "^4.42.13",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/shortcode": "^3.42.13",
+ "@wordpress/autop": "^3.50.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/block-serialization-default-parser": "^4.50.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/shortcode": "^3.50.0",
"change-case": "^4.1.2",
"colord": "^2.7.0",
- "deepmerge": "^4.3.0",
"fast-deep-equal": "^3.1.3",
"hpq": "^1.3.0",
"is-plain-object": "^5.0.0",
"memize": "^2.1.0",
+ "react-is": "^18.2.0",
"rememo": "^4.0.2",
"remove-accents": "^0.5.0",
"showdown": "^1.9.1",
@@ -38800,35 +38027,35 @@
}
},
"@wordpress/browserslist-config": {
- "version": "5.26.0",
- "resolved": "https://registry.npmjs.org/@wordpress/browserslist-config/-/browserslist-config-5.26.0.tgz",
- "integrity": "sha512-rpkxAnPOc4HuxKZBwZ1iV1oC0Rd21azzBDyS8OoVUW6V8DAv4eYfHNFGkyds7Z+nI6dI15Rl7xJYJhHJKVaJvg==",
+ "version": "5.33.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/browserslist-config/-/browserslist-config-5.33.0.tgz",
+ "integrity": "sha512-dv1ZlpqGk8gaSBJPP/Z/1uOuxjtP0EBsHVKInLRu6FWLTJkK8rnCeC3xJT3/2TtJ0rasLC79RoytfhXTOODVwg==",
"dev": true
},
"@wordpress/commands": {
- "version": "0.13.14",
- "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-0.13.14.tgz",
- "integrity": "sha512-aSOuRbsr+YYFvRbkXaubHdlAtf/xpG1mUWXEw9VMWCag77hiK6vk04Xb3N8ad8eo8am0N/iRgn8V8IS4LyBTyA==",
+ "version": "0.21.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-0.21.0.tgz",
+ "integrity": "sha512-MzMUGCT9cQXto1jrA5lHAtnieTyAhcuNIxfyxlcE+316KNQfbyD8bc7KOzSV2sxXD/rfHuCxvHjfomFyyP+4kA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/components": "^25.8.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/private-apis": "^0.24.13",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/private-apis": "^0.32.0",
"classnames": "^2.3.1",
"cmdk": "^0.2.0",
"rememo": "^4.0.2"
}
},
"@wordpress/components": {
- "version": "25.8.14",
- "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-25.8.14.tgz",
- "integrity": "sha512-wRQSRlLXsL4bEd1JhCQPSdIb0bO4WDAloQufeyIbXUIK9CDgN/jmkv+vrgKrpP3Nqu1sBAFzW1qd9WEXfSBgXw==",
+ "version": "25.16.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-25.16.0.tgz",
+ "integrity": "sha512-voQuMsO5JbH+JW33TnWurwwvpSb8IQ4XU5wyVMubX4TUwadt+/2ToNJbZIDXoaJPei7vbM81Ft+pH+zGlN8CyA==",
"requires": {
- "@ariakit/react": "^0.2.12",
+ "@ariakit/react": "^0.3.12",
"@babel/runtime": "^7.16.0",
"@emotion/cache": "^11.7.1",
"@emotion/css": "^11.7.1",
@@ -38837,25 +38064,26 @@
"@emotion/styled": "^11.6.0",
"@emotion/utils": "^1.0.0",
"@floating-ui/react-dom": "^2.0.1",
- "@radix-ui/react-dropdown-menu": "2.0.4",
+ "@types/gradient-parser": "0.1.3",
+ "@types/highlight-words-core": "1.2.1",
"@use-gesture/react": "^10.2.24",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/primitives": "^3.40.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/warning": "^2.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/primitives": "^3.48.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/warning": "^2.50.0",
"change-case": "^4.1.2",
"classnames": "^2.3.1",
"colord": "^2.7.0",
@@ -38880,63 +38108,64 @@
}
},
"@wordpress/compose": {
- "version": "6.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-6.19.13.tgz",
- "integrity": "sha512-3HDdccND+EoEr7tHQ75eCDh07e5TdFh0KFIdWGweq9gU5Z/tssRW8QEyU9J+xEz+DTL/hvFilQ681f58eUZi1g==",
+ "version": "6.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-6.27.0.tgz",
+ "integrity": "sha512-jbEQQ2znRyJTwUNR4m5BKaDyIsuK9TMZx0SKqP+FTfGqT3y7scOnQrHpK0kZdPji++/1cBbn3gSPBLCEmtmHRw==",
"requires": {
"@babel/runtime": "^7.16.0",
"@types/mousetrap": "^1.6.8",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/priority-queue": "^2.42.13",
- "@wordpress/undo-manager": "^0.2.13",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/priority-queue": "^2.50.0",
+ "@wordpress/undo-manager": "^0.10.0",
"change-case": "^4.1.2",
- "clipboard": "^2.0.8",
+ "clipboard": "^2.0.11",
"mousetrap": "^1.6.5",
"use-memo-one": "^1.1.1"
}
},
"@wordpress/core-commands": {
- "version": "0.11.14",
- "resolved": "https://registry.npmjs.org/@wordpress/core-commands/-/core-commands-0.11.14.tgz",
- "integrity": "sha512-f2DA9lUji96OC5UD85Gbv2vz14R0TR+FSXzXAa68F/EBPFkiaxs2huhruhRvZKbasxugk/vjTBbQuwZ8rinROA==",
+ "version": "0.19.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/core-commands/-/core-commands-0.19.2.tgz",
+ "integrity": "sha512-9ewP1fxB8MB5u15zMZBfShgGN2qJl+fBXCWR9MXB3gi8gA/Kd600W5I/jh2nLJuCRou09SsRzI6s+ihnir/V4A==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/commands": "^0.13.14",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/router": "^0.11.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/router": "^0.19.0",
+ "@wordpress/url": "^3.51.0"
}
},
"@wordpress/core-data": {
- "version": "6.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-6.19.14.tgz",
- "integrity": "sha512-wdstu/qMBKwXnFRX4wMeTkxvHsOgbXm7ZJ0Lgtj+jE86O086Ook7suxacOdMcCaAKNCfMqoGBHtjsNQk3SWE1Q==",
+ "version": "6.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-6.27.2.tgz",
+ "integrity": "sha512-Jsy+vW/izrd/T36D/4b266ScobCezNYX2Me/clCmHGB4eRW3drXZPbMnWZLNEDagYr87sQcM1Namasb69dnDhA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/sync": "^0.4.13",
- "@wordpress/undo-manager": "^0.2.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/sync": "^0.12.0",
+ "@wordpress/undo-manager": "^0.10.0",
+ "@wordpress/url": "^3.51.0",
"change-case": "^4.1.2",
"equivalent-key-map": "^0.2.2",
"fast-deep-equal": "^3.1.3",
@@ -38946,126 +38175,143 @@
}
},
"@wordpress/customize-widgets": {
- "version": "4.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/customize-widgets/-/customize-widgets-4.19.16.tgz",
- "integrity": "sha512-UK4RrEBFwdn8WcY7qXXbRcncuWXLMpB9gjiBVhwPmM5m1//A0wsOQu2kAkZeACuhYoEJ/N6g4yZh2ZnldJVR3w==",
+ "version": "4.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/customize-widgets/-/customize-widgets-4.27.2.tgz",
+ "integrity": "sha512-zq/PacEqW8eMX6LKeMHn39JNU2ZJ3GiCH3+oOeI3eewN8/aGrtJJh1btSL0liLTDXo6dqnQ8AXHjGu9/J/XDSg==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/block-library": "^8.19.16",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interface": "^5.19.14",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/widgets": "^3.19.14",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/block-library": "^8.27.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interface": "^5.27.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/widgets": "^3.27.2",
"classnames": "^2.3.1",
"fast-deep-equal": "^3.1.3"
}
},
"@wordpress/data": {
- "version": "9.12.13",
- "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-9.12.13.tgz",
- "integrity": "sha512-8SIsPFrnQ1LIZRWseOF+9uQ9thy8oB7NSOq+bkRCo+qldagooBTZUFp8Y++evFbPOotmTy6XGSPYf7HV9qBHVw==",
+ "version": "9.20.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-9.20.0.tgz",
+ "integrity": "sha512-3cm2te6NUj/X1zzmRO+WhueCanjocniX6sJFVzkg5mGXme6wFI8iSOnGPKlMkGcZGd0fVei1ydBKaIUMjrPBTQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
- "@wordpress/priority-queue": "^2.42.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/redux-routine": "^4.42.13",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
+ "@wordpress/priority-queue": "^2.50.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/redux-routine": "^4.50.0",
"deepmerge": "^4.3.0",
"equivalent-key-map": "^0.2.2",
"is-plain-object": "^5.0.0",
"is-promise": "^4.0.0",
"redux": "^4.1.2",
"rememo": "^4.0.2",
- "turbo-combine-reducers": "^1.0.2",
"use-memo-one": "^1.1.1"
}
},
"@wordpress/data-controls": {
- "version": "3.11.13",
- "resolved": "https://registry.npmjs.org/@wordpress/data-controls/-/data-controls-3.11.13.tgz",
- "integrity": "sha512-BW7yBPePnS5SVMVTTWeHG1U4RwV4X46NVOvX4/Vvq8CBjLmvqbiXZZxLMYI4xBi1y6+XRDjORHXP3WMJzwTdEg==",
+ "version": "3.19.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/data-controls/-/data-controls-3.19.0.tgz",
+ "integrity": "sha512-ceUK8kB8r8s8XFYlYWGVLuaoDJx5IAXND6q7B6MX1gKndqnSNi1766Q9iAEwOT9eVMai0lDLNq7mdK2ktVh4bw==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13"
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0"
+ }
+ },
+ "@wordpress/dataviews": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/dataviews/-/dataviews-0.4.1.tgz",
+ "integrity": "sha512-9ZTP5l9lyLMK95uEuAbOkILPIa2XvYxm2qa5Yo6SEUJbKnOVGCGH1fcNX1GuzHHrJwclYA3TeGgMaYoXpudjjw==",
+ "requires": {
+ "@babel/runtime": "^7.16.0",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/primitives": "^3.48.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "classnames": "^2.3.1",
+ "remove-accents": "^0.5.0"
}
},
"@wordpress/date": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-4.42.13.tgz",
- "integrity": "sha512-SrJL7WbnQwSmogyNiFA+ZKNuECPvneCZOVzC/76DIV7seVDbpdJky/3UAkQLMgvYzym5PK3A8vkENPgAykrh3g==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-4.50.0.tgz",
+ "integrity": "sha512-FhfaG6YRXWmni66RjwhCB7rQNlLJ05+qTa/jXrj2UNWDNv/sfZ6Ky+b/rKrrUnLaIs9pGiW1195cSxsAS4EY3w==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/deprecated": "^3.42.13",
+ "@wordpress/deprecated": "^3.50.0",
"moment": "^2.29.4",
"moment-timezone": "^0.5.40"
}
},
"@wordpress/dependency-extraction-webpack-plugin": {
- "version": "4.25.13",
- "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-4.25.13.tgz",
- "integrity": "sha512-ke3CkU9wWgMpAsf5E1zG7aN/pr9P3qdDaIOgU2kXbjSLxrbhgBeK4mCgT/uxCJu0uqaieYkZWRcNmxXKMbF9hw==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-5.1.0.tgz",
+ "integrity": "sha512-W2W+9JNAaGirAtGDSf83pjEKb63DLhgpJGgvMOpEPoRPtucgO6CCm3uMoNkJTpKoxJQ2tSZEymAhF/YdLm+ScQ==",
"dev": true,
"requires": {
- "json2php": "^0.0.7",
- "webpack-sources": "^3.2.2"
+ "json2php": "^0.0.7"
}
},
"@wordpress/deprecated": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-3.42.13.tgz",
- "integrity": "sha512-Jxivx5eTKhjVNW1/rqShM1dzDKm/9wKp9jPlF58uAXpQSIaH8Q09D6Pgzi72DsDyefL8SV/QllLQbo0bVenydg==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-3.50.0.tgz",
+ "integrity": "sha512-DL01l0Wlo3df9OcSGHP11Ot/nq0HytbdmD+iPkiCCRI6Xctepbs/DzRR2CO3qLrJkWn6RReFwZWZZjzI7lZUqg==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/hooks": "^3.42.13"
+ "@wordpress/hooks": "^3.50.0"
}
},
"@wordpress/dom": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-3.42.13.tgz",
- "integrity": "sha512-E7TnWuSOrxY5sn57+6Bf5v7JAL9PmNrOljf8Jj7FDsRdH6tCXf8BDqyIBz53cmzv/bsWOklQKIOeU/BQoEItHw==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-3.50.0.tgz",
+ "integrity": "sha512-rMnV1ysGOHbKnmjLQYwGkT1co1iEkC3YsKrEObP8mklw1R7rbCy7fc2brIz7kqcHU1DRyg/+7wOCMkg8a/EV/Q==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/deprecated": "^3.42.13"
+ "@wordpress/deprecated": "^3.50.0"
}
},
"@wordpress/dom-ready": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.42.13.tgz",
- "integrity": "sha512-mtqstqT1YFfIGl8rQipG9d8UwvGIZUP4Y8E1Tq3V9CAMV6ChJEYCZIGs/asHjqJSebNnXEWUEzQKAbPnIhnW3Q==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.50.0.tgz",
+ "integrity": "sha512-97tJpat1emXnwfGlJMiG6p37CpHJXDLmM/SIbsGJ0Oj8P4/TXbTuE9DNT1H8B1wKe5zD7kICjp48y91ugmgSrQ==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/e2e-test-utils": {
- "version": "10.13.13",
- "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-10.13.13.tgz",
- "integrity": "sha512-QibCpLfRW6Stm5BDd1zxc0eqX3uOE1yINPs8K7esUIHL8AqnCPEJUPa86NnOIaA2t8E52f+bhlTxzM7ZsaffoQ==",
+ "version": "10.21.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-10.21.0.tgz",
+ "integrity": "sha512-Oh62GkqAKBIyD0IO3/Oa0l42yL/jbpTRDyh8H+t6gZbHWYTDvEGEr/LOqI9bk5Lwk7Jt5jpN6136FDwyMzHSXw==",
"dev": true,
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/url": "^3.51.0",
"change-case": "^4.1.2",
"form-data": "^4.0.0",
"node-fetch": "^2.6.0"
@@ -39085,76 +38331,22 @@
}
},
"@wordpress/e2e-test-utils-playwright": {
- "version": "0.10.13",
- "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.10.13.tgz",
- "integrity": "sha512-5zqIsG6Nn6N0DBlK9GyvYKxUrK7dEBHFInRnIqqfimWAQmz07iBCJU34njs9lQi+/GzKfXS+2XgBI7dDQnbfwQ==",
+ "version": "0.18.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.18.0.tgz",
+ "integrity": "sha512-Z8uH1dUzy/STQjOU6eb9nquVK4RC1rUx0gXY/GN1IVNDJvGN/yJxT/gNKmfiL7KpmHvNp2Q5M4bnUT9uiNcM+Q==",
"dev": true,
"requires": {
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/url": "^3.51.0",
"change-case": "^4.1.2",
"form-data": "^4.0.0",
"get-port": "^5.1.1",
"lighthouse": "^10.4.0",
- "mime": "^3.0.0"
+ "mime": "^3.0.0",
+ "web-vitals": "^3.5.0"
},
"dependencies": {
- "@wordpress/api-fetch": {
- "version": "6.40.0",
- "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.40.0.tgz",
- "integrity": "sha512-sNk6vZW02ldci1EpNIjmm61323x/0n2Ra/cDHuehZf8avOH/OV0zF0dXxttT8M9Fncz+XZDSIHopm76dU3Phug==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.16.0",
- "@wordpress/i18n": "^4.43.0",
- "@wordpress/url": "^3.44.0"
- }
- },
- "@wordpress/hooks": {
- "version": "3.43.0",
- "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.43.0.tgz",
- "integrity": "sha512-SHSiyFUEsggihl0pDvY1l72q+fHMDyFHtIR3GCt0uV2ifctvoa/PIYdVwrxpGQaGdNEV25XCZ4kNldqJmfTddw==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.16.0"
- }
- },
- "@wordpress/i18n": {
- "version": "4.43.0",
- "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.43.0.tgz",
- "integrity": "sha512-XHU/vGgI+pgjJU9WzWDHke1u948z8i3OPpKUNdxc/gMcTkKaKM4D8DW1+VMSQHyU6pneP8+ph7EF+1RIehP3lQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.16.0",
- "@wordpress/hooks": "^3.43.0",
- "gettext-parser": "^1.3.1",
- "memize": "^2.1.0",
- "sprintf-js": "^1.1.1",
- "tannin": "^1.2.0"
- }
- },
- "@wordpress/keycodes": {
- "version": "3.43.0",
- "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.43.0.tgz",
- "integrity": "sha512-B6rYPiKFdQTlnJfm93R+usQnjEODUX/K4+hMvY5ZZOinvxe7KyU/xyFGz7gRrS8WmIEYcJowqSmAlGgVs4XwKQ==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.16.0",
- "@wordpress/i18n": "^4.43.0",
- "change-case": "^4.1.2"
- }
- },
- "@wordpress/url": {
- "version": "3.44.0",
- "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.44.0.tgz",
- "integrity": "sha512-QNtTPFg/cGHTJLOvOtQCvCgn5quFQgJml8A88I05o4dyUH/tc92rb8LNXi0qcVz/z4JPrx2g3+Ki8heYellP4A==",
- "dev": true,
- "requires": {
- "@babel/runtime": "^7.16.0",
- "remove-accents": "^0.5.0"
- }
- },
"form-data": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
@@ -39175,95 +38367,96 @@
}
},
"@wordpress/edit-post": {
- "version": "7.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-7.19.16.tgz",
- "integrity": "sha512-PK0XVHLrn6Bg47O8sq7UIBykJOJGF2xsbkOjhRVniD+6EYdYifpGYHTC9nHogEfw691xcz+vAqS87D01x3SfEQ==",
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-7.27.2.tgz",
+ "integrity": "sha512-GEWPr2TkzOH2OZx+WVtn+DGrkE+H5GOq1w+vAtoCEq1lLIdkGJe+YAieJKkSz/rqah25YzmRcyBgfYSL2iaULg==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/block-library": "^8.19.16",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/commands": "^0.13.14",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-commands": "^0.11.14",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/editor": "^13.19.14",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interface": "^5.19.14",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/url": "^3.43.13",
- "@wordpress/viewport": "^5.19.13",
- "@wordpress/warning": "^2.42.13",
- "@wordpress/widgets": "^3.19.14",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/block-library": "^8.27.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-commands": "^0.19.2",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/editor": "^13.27.2",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interface": "^5.27.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/viewport": "^5.27.0",
+ "@wordpress/warning": "^2.50.0",
+ "@wordpress/widgets": "^3.27.2",
"classnames": "^2.3.1",
"memize": "^2.1.0",
"rememo": "^4.0.2"
}
},
"@wordpress/edit-site": {
- "version": "5.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/edit-site/-/edit-site-5.19.16.tgz",
- "integrity": "sha512-shraoCd4LCNngtBn9E7U6Na/l+zrU0nTXztgZSuVsqSGktAgHBi7pXMUTsCGqO/vp9fnmW9LU3tQ9XgLEogjkg==",
+ "version": "5.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/edit-site/-/edit-site-5.27.2.tgz",
+ "integrity": "sha512-/lZhqadnX/A7owFre4ZxcKjlj7pisdxVAQJgtB9OYSdpreG2x8sGNKvLhv686BTKzSffS1TzvmKbNl7e+pQZDA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/block-library": "^8.19.16",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/commands": "^0.13.14",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-commands": "^0.11.14",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/editor": "^13.19.14",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interface": "^5.19.14",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/patterns": "^1.3.14",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/primitives": "^3.40.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/reusable-blocks": "^4.19.14",
- "@wordpress/router": "^0.11.13",
- "@wordpress/style-engine": "^1.25.13",
- "@wordpress/url": "^3.43.13",
- "@wordpress/viewport": "^5.19.13",
- "@wordpress/widgets": "^3.19.14",
- "@wordpress/wordcount": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/block-library": "^8.27.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-commands": "^0.19.2",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/dataviews": "^0.4.1",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/editor": "^13.27.2",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interface": "^5.27.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/patterns": "^1.11.2",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/primitives": "^3.48.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/reusable-blocks": "^4.27.2",
+ "@wordpress/router": "^0.19.0",
+ "@wordpress/style-engine": "^1.33.1",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/viewport": "^5.27.0",
+ "@wordpress/widgets": "^3.27.2",
+ "@wordpress/wordcount": "^3.50.0",
"change-case": "^4.1.2",
"classnames": "^2.3.1",
"colord": "^2.9.2",
"deepmerge": "^4.3.0",
- "downloadjs": "^1.4.7",
"fast-deep-equal": "^3.1.3",
"is-plain-object": "^5.0.0",
"memize": "^2.1.0",
@@ -39273,75 +38466,77 @@
}
},
"@wordpress/edit-widgets": {
- "version": "5.19.16",
- "resolved": "https://registry.npmjs.org/@wordpress/edit-widgets/-/edit-widgets-5.19.16.tgz",
- "integrity": "sha512-1yTkLHQjf/LEmxlw2y0bqgkZcqO2Gs0H8QK1JHEJdHrAK+R5nBd55Jq4Wb2IU+QsUAaGvQzuF+FfHAA4YkLUwQ==",
+ "version": "5.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/edit-widgets/-/edit-widgets-5.27.2.tgz",
+ "integrity": "sha512-AE5qgDCd5u16C3/EZQAP3STcxfpTZg2Ed6iHmN+PBg1RCEP11rv31aMaXy2+7Z+80bGsXwicmZAlqHxzm2vc2g==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/block-library": "^8.19.16",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/interface": "^5.19.14",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/patterns": "^1.3.14",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/reusable-blocks": "^4.19.14",
- "@wordpress/url": "^3.43.13",
- "@wordpress/widgets": "^3.19.14",
- "classnames": "^2.3.1"
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/block-library": "^8.27.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/interface": "^5.27.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/patterns": "^1.11.2",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/reusable-blocks": "^4.27.2",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/widgets": "^3.27.2",
+ "classnames": "^2.3.1",
+ "rememo": "^4.0.2"
}
},
"@wordpress/editor": {
- "version": "13.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-13.19.14.tgz",
- "integrity": "sha512-t1RFJl0Bf+qJpBHtiUl0qoxJjpNNGcpSZLejnhR97+i32l/4ewg8+z69zwFtW4ChNQjLnAFnpQZ5pT/CqkkKpQ==",
+ "version": "13.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-13.27.2.tgz",
+ "integrity": "sha512-Wk1dwG5bkmDD74zip36yC1NO3EleXe/t35Z9GHfLaiZkUYlhZV2gv66QrrGN7Y59Zl68j+b4lRGLkUxEMWkleA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/date": "^4.42.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/dom": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/keyboard-shortcuts": "^4.19.13",
- "@wordpress/keycodes": "^3.42.13",
- "@wordpress/media-utils": "^4.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/patterns": "^1.3.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/reusable-blocks": "^4.19.14",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/server-side-render": "^4.19.14",
- "@wordpress/url": "^3.43.13",
- "@wordpress/wordcount": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/commands": "^0.21.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/date": "^4.50.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/dom": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/keyboard-shortcuts": "^4.27.0",
+ "@wordpress/keycodes": "^3.50.0",
+ "@wordpress/media-utils": "^4.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/patterns": "^1.11.2",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/reusable-blocks": "^4.27.2",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/server-side-render": "^4.27.1",
+ "@wordpress/url": "^3.51.0",
+ "@wordpress/wordcount": "^3.50.0",
"classnames": "^2.3.1",
"date-fns": "^2.28.0",
"memize": "^2.1.0",
@@ -39351,14 +38546,14 @@
}
},
"@wordpress/element": {
- "version": "5.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.19.13.tgz",
- "integrity": "sha512-8VSGNrJkSf0coC2xciFBFodVa6eQOLPKMThVAz1eIDtQwbAcFo9001tjkMXgyhcn/FMoxdhaGGOxg4VeUvgJSw==",
+ "version": "5.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.27.0.tgz",
+ "integrity": "sha512-IA5LTAfx5bDNXULPmctcNb/04i4JcnIReG0RAuPgrZ8lbMZWUxGFymh10PEQjs7ZJ++qGsI6E+6JISpjkRaDQQ==",
"requires": {
"@babel/runtime": "^7.16.0",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
- "@wordpress/escape-html": "^2.42.13",
+ "@wordpress/escape-html": "^2.50.0",
"change-case": "^4.1.2",
"is-plain-object": "^5.0.0",
"react": "^18.2.0",
@@ -39366,24 +38561,24 @@
}
},
"@wordpress/escape-html": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.42.13.tgz",
- "integrity": "sha512-0I7loSc8M1vjqg6vXb6lCumaGzbbAeoI26NEpATcEq24MLgd8+UiidyHII4UNgdloRoq1Jj3e83AjDhFpAVfAg==",
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.50.0.tgz",
+ "integrity": "sha512-hBvoMCEZocziZDGCmBanSO+uupnd054mxd7FQ6toQ4UnsZ4JwXSmEC72W2Ed+cRGB1DeJDD0dY9iC0b4xkumsQ==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/eslint-plugin": {
- "version": "16.0.13",
- "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-16.0.13.tgz",
- "integrity": "sha512-Qk5Y7ifT0lfOOx5RQrEGa/DSw01CP+D2bCKr20SXLt3KDstViBlqjBiI1Yxv7EeS+AvaNbQO5M8Mm4B5mUB3kQ==",
+ "version": "17.7.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-17.7.0.tgz",
+ "integrity": "sha512-JSFaCogE0WlZpl0SV4q8DK8G6jwDjEzXRzOsgesWilea4OuVp1KxCamkddTorRNM3QAbjrGuPJ4NYaGrNG9QsA==",
"dev": true,
"requires": {
"@babel/eslint-parser": "^7.16.0",
"@typescript-eslint/eslint-plugin": "^6.4.1",
"@typescript-eslint/parser": "^6.4.1",
- "@wordpress/babel-preset-default": "^7.26.13",
- "@wordpress/prettier-config": "^2.25.13",
+ "@wordpress/babel-preset-default": "^7.34.0",
+ "@wordpress/prettier-config": "^3.7.0",
"cosmiconfig": "^7.0.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-import": "^2.25.2",
@@ -39399,9 +38594,9 @@
},
"dependencies": {
"globals": {
- "version": "13.23.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz",
- "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==",
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
"dev": true,
"requires": {
"type-fest": "^0.20.2"
@@ -39410,47 +38605,48 @@
}
},
"@wordpress/format-library": {
- "version": "4.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/format-library/-/format-library-4.19.14.tgz",
- "integrity": "sha512-NyJ1nmb6PODE5hXM9oOEBlYA48k6c2DlGcUTXkSzDcdLPRVinTeWDfPL4kpze30JcQPv9m6Y5/EfWp48bDnByA==",
+ "version": "4.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/format-library/-/format-library-4.27.2.tgz",
+ "integrity": "sha512-pgLWc+8QuRyWc3GtEL1X18u4FNmWI3Y821TbKW1MjnfMDYNhN7Vpypqk4AFuxq2PY0NxzmM0PGdcoqUXRGdldQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/rich-text": "^6.19.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/rich-text": "^6.27.0",
+ "@wordpress/url": "^3.51.0"
}
},
"@wordpress/hooks": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.42.13.tgz",
- "integrity": "sha512-KITkyj2DhbbBevqLzGx4GCtq8XX/GjkMWe0NP7SkcX9d4rkEdON96eKwwoMUD6keL03Tijg87kIYZAU5Xsr8bA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.50.0.tgz",
+ "integrity": "sha512-YIhwT1y0ss7Byfz46NBx08EUmXzWMu+g5DCY7FMuDNhwxSEoZMB8edKMiwNmFk4mFKBCnXM1d5FeONUPIUkJwg==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/html-entities": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.42.13.tgz",
- "integrity": "sha512-015rUF0FOSGXbUBq+sc++vo3UTGZZkl23z7tGxrTTXZG10AjcTVd3oMnpvffJeiBjrtEAJz/gq3QKpFXihvmww==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.50.0.tgz",
+ "integrity": "sha512-DBRgShv6FLtDpapoTgmEx//6uHeq+mk5zKhAWAAqu6+/6LqOm/TCoUTxb0E2xtHh4oRBgU5nYC92pObRaczFdQ==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/i18n": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.42.13.tgz",
- "integrity": "sha512-4zYz5BbueJ3c19DYhO7cXf9GF2K5Fysd+c2r0rcE0lr2RqMqmyDdL49930L7XJw+mT4ql8g/8p+i3FOzPCsg9A==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.50.0.tgz",
+ "integrity": "sha512-FkA2se6HMQm4eFC+/kTWvWQqs51VxpZuvY2MlWUp/L1r1d/dMBHXu049x86+/+6yk3ZNqiK5h6j6Z76dvPHZ4w==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/hooks": "^3.42.13",
+ "@wordpress/hooks": "^3.50.0",
"gettext-parser": "^1.3.1",
"memize": "^2.1.0",
"sprintf-js": "^1.1.1",
@@ -39458,57 +38654,66 @@
}
},
"@wordpress/icons": {
- "version": "9.33.13",
- "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.33.13.tgz",
- "integrity": "sha512-4M34sMRIlyL7a3CDRI7rAfysZQm2VW1ptB4aGDf5tVMXd//hCRkj/OGE++AYkTYQNckli9uqhTkv2xoOOw1F6Q==",
+ "version": "9.41.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.41.0.tgz",
+ "integrity": "sha512-L4fp9ZdxGBpMk3o2YqABgiPHNoHyu9Enid7JNkCdWP8iUgk7dEiDvo/XoiWPTAeNbF6W8Nqu54635mq01es0NQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/element": "^5.19.13",
- "@wordpress/primitives": "^3.40.13"
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/primitives": "^3.48.0"
}
},
"@wordpress/interactivity": {
- "version": "2.3.13",
- "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-2.3.13.tgz",
- "integrity": "sha512-WNmw/r+G1XllTZwKwpRDFJoGPm8cRztbU+MJhAogKzUOcrCu4Bp8xArroPSzlKr3aUuEquT/3WsWsFmHsSHYjg==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-4.0.1.tgz",
+ "integrity": "sha512-sw9Cqoj+MNF9FAU5nJC3nAqoH7kgUvh6HwaEMaLdSlK0qEcp05ba5x7geDSNi5cUWY4QSk1r9DH2jKUg9zfpNg==",
+ "requires": {
+ "@preact/signals": "^1.2.2",
+ "deepsignal": "^1.4.0",
+ "preact": "^10.19.3"
+ }
+ },
+ "@wordpress/interactivity-router": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/interactivity-router/-/interactivity-router-1.0.1.tgz",
+ "integrity": "sha512-XShZV0+Sqs+1C26nVyns6nT8kjAGRBJNArVPceZlkkpsX7DIRZcEZ2larWxOuQFWk67lzIRiXd5V51L71b8XrQ==",
"requires": {
- "@preact/signals": "^1.1.3",
- "deepsignal": "^1.3.6",
- "preact": "^10.13.2"
+ "@wordpress/interactivity": "^4.0.1"
}
},
"@wordpress/interface": {
- "version": "5.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-5.19.14.tgz",
- "integrity": "sha512-WsIsSKJuhAcXD3YbmUoncL1JZ6hKAJXs7Lb/bjrOJxCts/YOy5yMF3/I05r8f1Tfw/pS8wlHMRjIXH/gvnvWVA==",
+ "version": "5.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-5.27.0.tgz",
+ "integrity": "sha512-ZybF4tuuuFOgGsB0n9u5ajrWKf/PYaS8d2yu2T+6ukliLnXI6AMMCXvM534H0VZa7DMLjMYKRXtfs7QqR/p95Q==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/plugins": "^6.10.14",
- "@wordpress/preferences": "^3.19.14",
- "@wordpress/viewport": "^5.19.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/plugins": "^6.18.0",
+ "@wordpress/preferences": "^3.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/viewport": "^5.27.0",
"classnames": "^2.3.1"
}
},
"@wordpress/is-shallow-equal": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-4.42.13.tgz",
- "integrity": "sha512-C3Pdan4alanyaQJ4Ucg7GZvkgDv7mXQZXe0xIYmKUNCnohS3wcFXmaLE6VGvf3I2OhRz8WLh5uxno/suJ8cyRw==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-4.50.0.tgz",
+ "integrity": "sha512-lX0fMa1f/TwWYYF+Oj0MG2Eze4Bb+vsnhXX6X1l+Ri3PG34wWGonjq729qHbJRDwm8o1y9GeswCgESIpuAm9wg==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/jest-console": {
- "version": "7.14.0",
- "resolved": "https://registry.npmjs.org/@wordpress/jest-console/-/jest-console-7.14.0.tgz",
- "integrity": "sha512-o7EZZ+StfLg/qgTRn47O0WY2V1I+xNJCiN13a/fHZtXdRgPJ9qajf7tkDYz+MKPf8MhdMfHhgIr9sQrWhLCzDA==",
+ "version": "7.21.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/jest-console/-/jest-console-7.21.0.tgz",
+ "integrity": "sha512-o2vZRlwwJ6WoxRwnFFT5iZzfdc2d9MZvrtwB093RWPNcyK5qVtApji4VN/ieHijB4bjEHGalm0UKfKpt0EDlUQ==",
"dev": true,
"requires": {
"@babel/runtime": "^7.16.0",
@@ -39516,203 +38721,207 @@
}
},
"@wordpress/jest-preset-default": {
- "version": "11.14.0",
- "resolved": "https://registry.npmjs.org/@wordpress/jest-preset-default/-/jest-preset-default-11.14.0.tgz",
- "integrity": "sha512-eGenm5xUpPcsgWMSFXYWg+RQlcAZa6zo7sT9bBK8HVIGqORTr3TTtWeHVGFL48UooL5PibUc+GxQdlW97YOwlQ==",
+ "version": "11.21.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/jest-preset-default/-/jest-preset-default-11.21.0.tgz",
+ "integrity": "sha512-XAztKOROu02iBsz+Qosv/RYuPWB1XwwlU+FiA5Y68tRztrqFy4b/il+DFg4Jue/zXF7UECWUvosd5ow/GmKa6Q==",
"dev": true,
"requires": {
- "@wordpress/jest-console": "^7.14.0",
+ "@wordpress/jest-console": "^7.21.0",
"babel-jest": "^29.6.2"
}
},
"@wordpress/keyboard-shortcuts": {
- "version": "4.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-4.19.13.tgz",
- "integrity": "sha512-5u/pMERHn1b17d3HqDWWulJp08MLlNG1idsuJiLzbQBrYW3wLPd23fPG1QObUSH/texVDvi/W4/9N4hsbZlXEg==",
+ "version": "4.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-4.27.0.tgz",
+ "integrity": "sha512-mpYhaSAMHXbRMp9hP08LejX/u1nLQaZONhwGSytqIhN1DQwpBbNbmV8ZNm1dnevUsYqEfPVVov6HFyPxYQ6m4w==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/keycodes": "^3.42.13",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/keycodes": "^3.50.0",
"rememo": "^4.0.2"
}
},
"@wordpress/keycodes": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.42.13.tgz",
- "integrity": "sha512-3lGlnYj+ky5OOnFjTW6NSxFFeNk/ESUF2Gbhz888HV+QF55SPvRfb+G7kjAzxRomIpdwACYsn80PdqabxLVqgw==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.50.0.tgz",
+ "integrity": "sha512-ykWpyCbgwcaT8i5kSfotYtd2oOHyMDpWEYR73InYrzEhl7pnS3wD7hi/KfeKLvMfYhbysUXlCVr6q/oH+qK/DQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/i18n": "^4.42.13",
- "change-case": "^4.1.2"
+ "@wordpress/i18n": "^4.50.0"
}
},
"@wordpress/list-reusable-blocks": {
- "version": "4.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/list-reusable-blocks/-/list-reusable-blocks-4.19.14.tgz",
- "integrity": "sha512-GuorU374D0Ft7RtIZWWc7ltIkV3ThjU/u+LwbNzh5y7iaVs4l64qvqopqoj/IoRVdahpnLEO3MNxj9InlUiNeg==",
+ "version": "4.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/list-reusable-blocks/-/list-reusable-blocks-4.27.0.tgz",
+ "integrity": "sha512-szDQnIdU34yIvNel+Kk1oBOugiqwXNm4jF77T90kaWB/SIQFW80CFYoIjIYQc63r9v3wi0D483KpXoci1AUSeQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
"change-case": "^4.1.2"
}
},
"@wordpress/media-utils": {
- "version": "4.33.13",
- "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-4.33.13.tgz",
- "integrity": "sha512-+QJvDbBEtjMC6V2kJ04dEZkmElDneueW6HxGcx9lD786N0pcHwHZCnY9mLN+Tg/2f6Y8/9u0emvbFFuX0FLE8w==",
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-4.41.0.tgz",
+ "integrity": "sha512-wCxk8DAhmZ/3/a+oPRrieGurMOKDrYoDnnA0jhTm2D45kvn9y+NfnNBvLo2q1Is1ZiVTtNq54IRUXcdOjZgR9A==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/blob": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13"
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blob": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0"
}
},
"@wordpress/notices": {
- "version": "4.10.13",
- "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-4.10.13.tgz",
- "integrity": "sha512-6U0im51yJFXLLMzL6zZ+eyeJIeY2cyiUCDdziJSI1ZrsfV2ml9o4nB3EYYOxZBaVvJg66vY3wIQ/osMFwTW6xg==",
+ "version": "4.18.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-4.18.0.tgz",
+ "integrity": "sha512-Y2XpY6niJ7NuqPBtGYvDYSPCfw/y4yxv60ahu1kYd8r5BamKSchTYwKSnV0yrx/IUfNO04VAsNq9NCUQG12pRA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/data": "^9.12.13"
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/data": "^9.20.0"
}
},
"@wordpress/npm-package-json-lint-config": {
- "version": "4.28.0",
- "resolved": "https://registry.npmjs.org/@wordpress/npm-package-json-lint-config/-/npm-package-json-lint-config-4.28.0.tgz",
- "integrity": "sha512-lxrs1F4scwDuF8AJLK+SHtLWuhRVjzvl8EW/++ZQWRt7op99m41QQUqUwwCQC09cDcYlGddXeAczRijx5eLREg==",
+ "version": "4.35.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/npm-package-json-lint-config/-/npm-package-json-lint-config-4.35.0.tgz",
+ "integrity": "sha512-QmkhYM4/s+2r3RuolVRRmoUa5o3lFgcHA6I3A9akaSVGZr//4p2p+iXOGmNub9njgGlj7j8SAPN8GUsCO/VqZQ==",
"dev": true
},
"@wordpress/nux": {
- "version": "8.4.14",
- "resolved": "https://registry.npmjs.org/@wordpress/nux/-/nux-8.4.14.tgz",
- "integrity": "sha512-JcxUtWOzl7lTuv39BWRwzwPDvVEhFECGzK819i3kExbTjmsVHCHtsdB7khPrdAYZOm2GXzR1le+/UFfkGuHS2Q==",
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/nux/-/nux-8.12.0.tgz",
+ "integrity": "sha512-fMnm9f+lmaCV5YoRHjqQNVU0P+FxthY8Lt84ZW1owlPjpJqdYZX/bKtp+bfWFgR3/Th26/uO4WxZqQzj8V1Pjg==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
"rememo": "^4.0.2"
}
},
"@wordpress/patterns": {
- "version": "1.3.14",
- "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-1.3.14.tgz",
- "integrity": "sha512-eaZWZlaF/MlxqDY7KYzL8cApY4b4f89wuqHVSmjv52UfvaqxW0vd09ddX+jwkcXysDHFzwM63takIIVZwYn9Lg==",
+ "version": "1.11.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-1.11.2.tgz",
+ "integrity": "sha512-cN7xjw5pfKq73mVF0q0ebZh4DmAab5SlQ9CvM7PtB03JOl3GMwVIDV5Tnbbhfi1KIsFwep2/CGft3xwuJlS3FQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/html-entities": "^3.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/html-entities": "^3.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0",
+ "nanoid": "^3.3.4"
}
},
"@wordpress/plugins": {
- "version": "6.10.14",
- "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-6.10.14.tgz",
- "integrity": "sha512-Duxh0OxpSuUFTMHa500iitrD21/JeTklc8/Hf3ApCpn4SdDzFR4IrwUdoJk0jGDY79cTwBVeWts5GhObbJByng==",
+ "version": "6.18.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-6.18.0.tgz",
+ "integrity": "sha512-m2BRJ5BApIMwT2Ck5E5yD8pS3RiIoOvWhzsYWrRqRfwjRhc6K46BreCbkiHgduBaFgzDIWpujlUHkYtdl27RoQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/hooks": "^3.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/is-shallow-equal": "^4.42.13",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/hooks": "^3.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/is-shallow-equal": "^4.50.0",
"memize": "^2.0.1"
}
},
"@wordpress/postcss-plugins-preset": {
- "version": "4.27.0",
- "resolved": "https://registry.npmjs.org/@wordpress/postcss-plugins-preset/-/postcss-plugins-preset-4.27.0.tgz",
- "integrity": "sha512-4hk8UWfJvv21u/Et0NypfR1r22LVWGXMit3QM0MD7d6XQ4dNNbzqW2c9TfM36SdcR9KY5PZ8d5V1IrkheNUb/w==",
+ "version": "4.34.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/postcss-plugins-preset/-/postcss-plugins-preset-4.34.0.tgz",
+ "integrity": "sha512-OLQBSLE2q11Ik+WdcO2QfGr/O4X/zJYOGXNsychx/EaMamLzJInFcRL6kGbPX41zPINhadq5x2vFIZI2EC+Uyg==",
"dev": true,
"requires": {
- "@wordpress/base-styles": "^4.34.0",
+ "@wordpress/base-styles": "^4.41.0",
"autoprefixer": "^10.2.5"
}
},
"@wordpress/preferences": {
- "version": "3.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-3.19.14.tgz",
- "integrity": "sha512-xLu+G22Vlm4KajE/Eimq8qLzBoxMZ7BJLp8WobFC3yyzdU9R785dug9t9et4r45NxWJr8aVWkFzhEBzAadHjnA==",
+ "version": "3.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-3.27.0.tgz",
+ "integrity": "sha512-LMhOHX5FI4CJHv2YhtpiEtHfLqL/pjKAMja/v7skkHPlrh64Sgzi/gep016/My5SjcR64JUD1Na2U2j/BnrBNQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/private-apis": "^0.32.0",
"classnames": "^2.3.1"
}
},
"@wordpress/preferences-persistence": {
- "version": "1.34.13",
- "resolved": "https://registry.npmjs.org/@wordpress/preferences-persistence/-/preferences-persistence-1.34.13.tgz",
- "integrity": "sha512-23bUN1WdJ9mtfU51uoPBrSwbYHaW2zG+HDlH+leZURdPe48jbWSA8LRPwni5z3Kc9zh8D0vXkvt0hg1/RcNgUQ==",
+ "version": "1.42.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/preferences-persistence/-/preferences-persistence-1.42.0.tgz",
+ "integrity": "sha512-n/VBhZHUEXWoBGsvHUf5uq6b872Lzn+cenfB2ex/etcWLXiVUkEl3rlzocyS50g2YoNQg/zQOn1hoSh+AgCm8Q==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13"
+ "@wordpress/api-fetch": "^6.47.0"
}
},
"@wordpress/prettier-config": {
- "version": "2.25.13",
- "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-2.25.13.tgz",
- "integrity": "sha512-iz58o0X91E24j0VFtzwn5qG84w+s4VlRCuZWa/lPL6pfGtOSw30c60wCrYKCA1IWIIAWdpRAYfEh7errPyKiPQ==",
+ "version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-3.7.0.tgz",
+ "integrity": "sha512-JRTc5p7UxtcPkqdSDXSFJoJnVuS510uiRVz8anXEl5nuOx5p+SJAzi9QPrxTgOE8bN3wRABH4eIhfOcta4CFdg==",
"dev": true
},
"@wordpress/primitives": {
- "version": "3.40.13",
- "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.40.13.tgz",
- "integrity": "sha512-dYYrPceV8w78AHJfPe5wkxnT7P0tG/4yDcr9/HvznFHkzQFnW8kG8Nci20RV/+ENxfNiuWqfWyICI2y7myIoGw==",
+ "version": "3.48.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.48.0.tgz",
+ "integrity": "sha512-uBoMxpl+FiZF6aRXH/+Hwol4EAL6QqlNSaGF1IzEwklFzdRF1m5wTM4vh21w8Bq7lgxiuAqyueY7X5u32v+zPw==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/element": "^5.19.13",
+ "@wordpress/element": "^5.27.0",
"classnames": "^2.3.1"
}
},
"@wordpress/priority-queue": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-2.42.13.tgz",
- "integrity": "sha512-vrkjBcJnuzhpfWLFF4LfdNVrM3s73KW3KOZBTuN6oizJVYKyQaaPSLmDdORuXFc017MMasO5N/fYk/qJyll5bg==",
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-2.50.0.tgz",
+ "integrity": "sha512-21E842EVFYUd1ZrNTLAW57IyloDCUZr6h1Te6BgqKoeKOEteoTQwA9BemMzZJUiThUSZymW94ot0Omb+C8VX2g==",
"requires": {
"@babel/runtime": "^7.16.0",
"requestidlecallback": "^0.3.0"
}
},
"@wordpress/private-apis": {
- "version": "0.24.13",
- "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.24.13.tgz",
- "integrity": "sha512-RgvGB6VQpPnEGU8Y61tzpgPFYDRAW28+2gcdOXYiqSVdZfGBL6+hBs5bMbLSJYRU9G5pl5q4Eb0lHlkMgHW5FA==",
+ "version": "0.32.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.32.0.tgz",
+ "integrity": "sha512-P7nxI/bGMDQhtlTfSe1Y2SDfrd20K5UMnTHbq+hmIkzBGRpNPbdGeNu2bZaZtIvmXk1OCR0Fkef+e6QqkOfYPg==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/redux-routine": {
- "version": "4.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-4.42.13.tgz",
- "integrity": "sha512-R+8W8CcjhHXPRlfPCdtElO2lsZzObR6DWvO49BjfJcKs0QPvKaO3ofjsadRgv+gg1+nXiE7rH6LmHbZ4eLanGw==",
+ "version": "4.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-4.50.0.tgz",
+ "integrity": "sha512-giHjQYhmFDCpeNEnsZKP0JNPBnpuQwsoxLmHAUUSNFWAmd4rtnNnG6M8HuqOLmgYTvEa8Hlx3Bl+reTGvrtI2g==",
"requires": {
"@babel/runtime": "^7.16.0",
"is-plain-object": "^5.0.0",
@@ -39721,77 +38930,77 @@
}
},
"@wordpress/reusable-blocks": {
- "version": "4.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-4.19.14.tgz",
- "integrity": "sha512-WhQNDtq2ohGlGlodNyEbvMux631D+7jRABwodvoC42dVJyHR3lH1O8uhnQeKyPl91YWLxJ6+mHmrPInEo2fAcQ==",
+ "version": "4.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-4.27.2.tgz",
+ "integrity": "sha512-kkhZyYFj4rbf7lPOqDMfaNO3fqLEyHYKjWITWzRMUPtLeIHin/DHepVz6Z6NERANHpbP0mD4BDoBEGYJ9/brbA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/notices": "^4.10.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/url": "^3.43.13"
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/notices": "^4.18.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0"
}
},
"@wordpress/rich-text": {
- "version": "6.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-6.19.13.tgz",
- "integrity": "sha512-7kCbTLiy+dIOToBktkrftCfVLsqCN0dY9uE6rz/TRsKS6+pnF6fUhqHLBV5OFf0tttKjHykSj5ixFDejqWCvrQ==",
+ "version": "6.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-6.27.0.tgz",
+ "integrity": "sha512-B7t++SldcI4nb+lO2m9oEdyD8y2FbH5DKY5F2G3xpcEnw4EKSt4SsTzeclMQ/2zzlEHPRKU/IR29SeOIJ1H8JQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/a11y": "^3.42.13",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/escape-html": "^2.42.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/keycodes": "^3.42.13",
+ "@wordpress/a11y": "^3.50.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/escape-html": "^2.50.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/keycodes": "^3.50.0",
"memize": "^2.1.0",
"rememo": "^4.0.2"
}
},
"@wordpress/router": {
- "version": "0.11.13",
- "resolved": "https://registry.npmjs.org/@wordpress/router/-/router-0.11.13.tgz",
- "integrity": "sha512-OZyuFOuX6nW5fQ1kq250EqCCA1Ad6KSH0wlaC68kCF06VFft2JNiATba7rC9Uq3ozM9HjPCtkbJ1dAW4PQdS1g==",
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/router/-/router-0.19.0.tgz",
+ "integrity": "sha512-S2z4WrgrfMNAl6amIjekGV1V6XGnjolYmRgUH/VTN45CQUV/o5ABo04xI/L3uvUnaRpH022n/yQX5H1p1kKhdA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/element": "^5.19.13",
- "@wordpress/private-apis": "^0.24.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/private-apis": "^0.32.0",
+ "@wordpress/url": "^3.51.0",
"history": "^5.1.0"
}
},
"@wordpress/scripts": {
- "version": "26.13.13",
- "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-26.13.13.tgz",
- "integrity": "sha512-G2K56PmjRPI0ddgmrnopp3AVMLACqfrFvz+NyGbYCPWQoYL3xnphrS+w3uPwuxcuBtgR34yr+xCvrMnJsY3Wag==",
+ "version": "27.1.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-27.1.0.tgz",
+ "integrity": "sha512-jewyOxqaNrsct5R1NXv2lT8CA70vzrvpdZHYERCcH9LzKuvrcc32Telm9Jqso6ay1ZgHeIbjHSCd2+r2sBG7hw==",
"dev": true,
"requires": {
"@babel/core": "^7.16.0",
- "@pmmmwh/react-refresh-webpack-plugin": "^0.5.2",
+ "@pmmmwh/react-refresh-webpack-plugin": "^0.5.11",
"@svgr/webpack": "^8.0.1",
- "@wordpress/babel-preset-default": "^7.26.13",
- "@wordpress/browserslist-config": "^5.25.13",
- "@wordpress/dependency-extraction-webpack-plugin": "^4.25.13",
- "@wordpress/e2e-test-utils-playwright": "^0.10.13",
- "@wordpress/eslint-plugin": "^16.0.13",
- "@wordpress/jest-preset-default": "^11.13.13",
- "@wordpress/npm-package-json-lint-config": "^4.27.13",
- "@wordpress/postcss-plugins-preset": "^4.26.13",
- "@wordpress/prettier-config": "^2.25.13",
- "@wordpress/stylelint-config": "^21.25.13",
+ "@wordpress/babel-preset-default": "^7.34.0",
+ "@wordpress/browserslist-config": "^5.33.0",
+ "@wordpress/dependency-extraction-webpack-plugin": "^5.1.0",
+ "@wordpress/e2e-test-utils-playwright": "^0.18.0",
+ "@wordpress/eslint-plugin": "^17.7.0",
+ "@wordpress/jest-preset-default": "^11.21.0",
+ "@wordpress/npm-package-json-lint-config": "^4.35.0",
+ "@wordpress/postcss-plugins-preset": "^4.34.0",
+ "@wordpress/prettier-config": "^3.7.0",
+ "@wordpress/stylelint-config": "^21.33.0",
"adm-zip": "^0.5.9",
"babel-jest": "^29.6.2",
"babel-loader": "^8.2.3",
- "browserslist": "^4.21.9",
+ "browserslist": "^4.21.10",
"chalk": "^4.0.0",
"check-node-version": "^4.1.0",
"clean-webpack-plugin": "^3.0.0",
@@ -39806,7 +39015,7 @@
"fast-glob": "^3.2.7",
"filenamify": "^4.2.0",
"jest": "^29.6.2",
- "jest-dev-server": "^6.0.2",
+ "jest-dev-server": "^9.0.1",
"jest-environment-jsdom": "^29.6.2",
"jest-environment-node": "^29.6.2",
"markdownlint-cli": "^0.31.1",
@@ -39815,12 +39024,12 @@
"minimist": "^1.2.0",
"npm-package-json-lint": "^6.4.0",
"npm-packlist": "^3.0.0",
- "playwright-core": "1.32.0",
+ "playwright-core": "1.39.0",
"postcss": "^8.4.5",
"postcss-loader": "^6.2.1",
- "prettier": "npm:wp-prettier@3.0.3-beta-3",
+ "prettier": "npm:wp-prettier@3.0.3",
"puppeteer-core": "^13.2.0",
- "react-refresh": "^0.10.0",
+ "react-refresh": "^0.14.0",
"read-pkg-up": "^7.0.1",
"resolve-bin": "^0.4.0",
"sass": "^1.35.2",
@@ -39829,12 +39038,103 @@
"stylelint": "^14.2.0",
"terser-webpack-plugin": "^5.3.9",
"url-loader": "^4.1.1",
- "webpack": "^5.47.1",
- "webpack-bundle-analyzer": "^4.4.2",
- "webpack-cli": "^4.9.1",
- "webpack-dev-server": "^4.4.0"
- },
- "dependencies": {
+ "webpack": "^5.88.2",
+ "webpack-bundle-analyzer": "^4.9.1",
+ "webpack-cli": "^5.1.4",
+ "webpack-dev-server": "^4.15.1"
+ },
+ "dependencies": {
+ "@pmmmwh/react-refresh-webpack-plugin": {
+ "version": "0.5.11",
+ "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz",
+ "integrity": "sha512-7j/6vdTym0+qZ6u4XbSAxrWBGYSdCfTzySkj7WAFgDLmSyWlOrWvpyzxlFh5jtw9dn0oL/jtW+06XfFiisN3JQ==",
+ "dev": true,
+ "requires": {
+ "ansi-html-community": "^0.0.8",
+ "common-path-prefix": "^3.0.0",
+ "core-js-pure": "^3.23.3",
+ "error-stack-parser": "^2.0.6",
+ "find-up": "^5.0.0",
+ "html-entities": "^2.1.0",
+ "loader-utils": "^2.0.4",
+ "schema-utils": "^3.0.0",
+ "source-map": "^0.7.3"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-keywords": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+ "dev": true
+ },
+ "find-up": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+ "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+ "dev": true,
+ "requires": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
+ },
+ "locate-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+ "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+ "dev": true,
+ "requires": {
+ "p-locate": "^5.0.0"
+ }
+ },
+ "p-limit": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+ "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+ "dev": true,
+ "requires": {
+ "yocto-queue": "^0.1.0"
+ }
+ },
+ "p-locate": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+ "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+ "dev": true,
+ "requires": {
+ "p-limit": "^3.0.2"
+ }
+ },
+ "schema-utils": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+ "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.8",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.2"
+ }
+ }
+ }
+ },
"ajv": {
"version": "8.12.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
@@ -39990,16 +39290,16 @@
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
- "prettier": {
- "version": "npm:wp-prettier@3.0.3-beta-3",
- "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-3.0.3-beta-3.tgz",
- "integrity": "sha512-R3+TD7j0rnqEpMgylrUrHdi1W6ypwh4QGeFOZQ9YjP9WvNnZzBAS71yry1h7xIcG/bVaNKBCoWNqbqJY6vkOKQ==",
+ "playwright-core": {
+ "version": "1.39.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz",
+ "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==",
"dev": true
},
- "react-refresh": {
- "version": "0.10.0",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.10.0.tgz",
- "integrity": "sha512-PgidR3wST3dDYKr6b4pJoqQFpPGNKDSCDx4cZoshjXipw3LzO7mG1My2pwEzz2JVkF+inx3xRpDeQLFQGH/hsQ==",
+ "prettier": {
+ "version": "npm:wp-prettier@3.0.3",
+ "resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-3.0.3.tgz",
+ "integrity": "sha512-X4UlrxDTH8oom9qXlcjnydsjAOD2BmB6yFmvS4Z2zdTzqqpRWb+fbqrH412+l+OUXmbzJlSXjlMFYPgYG12IAA==",
"dev": true
},
"read-pkg-up": {
@@ -40031,6 +39331,12 @@
"integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
"dev": true
},
+ "source-map": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+ "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+ "dev": true
+ },
"source-map-loader": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.2.tgz",
@@ -40060,45 +39366,45 @@
}
},
"@wordpress/server-side-render": {
- "version": "4.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-4.19.14.tgz",
- "integrity": "sha512-As3Xc3TDM0R0siAFaldobRdZnPfQQMXvlQxalFJgs/kSoYOmcdc46mR5Wgmfn7r0Kc/Z5uOHLbvm4mWekE0a2A==",
+ "version": "4.27.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-4.27.1.tgz",
+ "integrity": "sha512-hovofyT0z75NSK/CSkkSbbTdkq9Afc1MKbEVGXTGpqq5sKOa7IAcxWjzmh8byTgT8x7GEaAyHZUr31p4l0CGnQ==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/deprecated": "^3.42.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/url": "^3.43.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/deprecated": "^3.50.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/url": "^3.51.0",
"fast-deep-equal": "^3.1.3"
}
},
"@wordpress/shortcode": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-3.42.13.tgz",
- "integrity": "sha512-pq+xdRdND7vEuqskPoZx+VAOHsmatqHcox3dElFU5lxlx/3fvKC7NIrFCn+glxFGGxO5hY5JfUOC70x8tm7uMA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-3.50.0.tgz",
+ "integrity": "sha512-RnlqS2OsNUaI6VOLwyUiaL3trAJcWjtoiW21BjIXODbTkEreRJgBJnch7wdFpGimJmKIWBwRD8jQ4hdTND8xVw==",
"requires": {
"@babel/runtime": "^7.16.0",
"memize": "^2.0.1"
}
},
"@wordpress/style-engine": {
- "version": "1.25.13",
- "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-1.25.13.tgz",
- "integrity": "sha512-4ixhGNVNrtt6zppLWnPCKSl4O4X+TO48PbLEbLDvN2NvUK1Yp1wChiX+NFIBa1dJp1zDlrxaTjttCqC1bs3MUA==",
+ "version": "1.33.1",
+ "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-1.33.1.tgz",
+ "integrity": "sha512-mkur1jw3Trz76iwxU6DalTFsJyF5P/NTdU9xniMT8bo1H9HspgKrzqXAaxkTL9F9BXkyiYs+ctVekJYRUKlgcw==",
"requires": {
"@babel/runtime": "^7.16.0",
"change-case": "^4.1.2"
}
},
"@wordpress/stylelint-config": {
- "version": "21.26.0",
- "resolved": "https://registry.npmjs.org/@wordpress/stylelint-config/-/stylelint-config-21.26.0.tgz",
- "integrity": "sha512-xTnvoNk9aCdRl1ntBxnmhdmghwzRNurp5Y9LjUCwrYutxnj8t/CCKhPyjgIgHxz+RwKgnpGKupKLVvuHxu1CzQ==",
+ "version": "21.33.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/stylelint-config/-/stylelint-config-21.33.0.tgz",
+ "integrity": "sha512-DwjXrjRBva0tkYILvDV7rjl3VaKXxvchlxnFfFs6l2DWL/Qo31CJ+f2rVw4XSWuuWxY1EsyIn9tOBS9URloWTQ==",
"dev": true,
"requires": {
"stylelint-config-recommended": "^6.0.0",
@@ -40106,82 +39412,88 @@
}
},
"@wordpress/sync": {
- "version": "0.4.13",
- "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-0.4.13.tgz",
- "integrity": "sha512-3Lq7MENUpCaSvR6WOLOovNmRMXGmFcdnbMjSZlHh0sx3ycWbKpXlGyfQWJ20MZRiO/qTOOrj4VW4GejqqJSEZw==",
+ "version": "0.12.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-0.12.0.tgz",
+ "integrity": "sha512-45gU1Gu/ys3zqYO4dDQf6eG5gGgJK9nXa62IUtUWFXIH4FN29XlvGppMVK/zzhJwejF/XnDuT7mQuVEFCZGswA==",
"requires": {
"@babel/runtime": "^7.16.0",
+ "@types/simple-peer": "^9.11.5",
+ "@wordpress/url": "^3.51.0",
+ "import-locals": "^2.0.0",
+ "lib0": "^0.2.42",
+ "simple-peer": "^9.11.0",
"y-indexeddb": "~9.0.11",
+ "y-protocols": "^1.0.5",
"y-webrtc": "~10.2.5",
"yjs": "~13.6.6"
}
},
"@wordpress/token-list": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-2.42.13.tgz",
- "integrity": "sha512-eAKU/5U7c/Acqcqnurpp79lrwCAm+Tb8PfSBTmtGs1fJsR1xtJh4d6IZw5MLDFiqLuVRT65ec3T4Sjqb6N4CMQ==",
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-2.50.0.tgz",
+ "integrity": "sha512-LTjXkoljQpJIHqs0isTUzIc1fMu68y0N9HcDIdsCMGkmKptWUCETtb+DItnraxDDLuyWNuTYf840S83a3XAVRA==",
"requires": {
"@babel/runtime": "^7.16.0"
}
},
"@wordpress/undo-manager": {
- "version": "0.2.13",
- "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-0.2.13.tgz",
- "integrity": "sha512-SFIYRs65GEjr0eeh7BZcETaH32qQVm78aFMZXnYTHzBmTXxoJ98XRgEGWXRJU92RXBcjom+1gARKChJoV5dlNw==",
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-0.10.0.tgz",
+ "integrity": "sha512-ODDqAL6BSvD+J7FV+sQTAaVHiPChh/4KBnKg8pb2ogg+Weq6VynthxDxGpQnN8FcMKB9ZoyS3SNIl8pVXLKIwA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/is-shallow-equal": "^4.42.13"
+ "@wordpress/is-shallow-equal": "^4.50.0"
}
},
"@wordpress/url": {
- "version": "3.43.13",
- "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.43.13.tgz",
- "integrity": "sha512-GrIkGZoCgd+87CyAjgGzShoI6m/Kvknmc6syqrN34J1LdrEE+vPNMjM+NvUVvyPdvgG7/iFzRM8D/ZEUvaTm9A==",
+ "version": "3.51.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.51.0.tgz",
+ "integrity": "sha512-OjucjlP1763gfKbe8lv/k3RCisyX8AfNBrhASk7JqxAj6rFhb1ZZO7YmAgB2m+WoGB5v7fkOli0FZyDqISdYyg==",
"requires": {
"@babel/runtime": "^7.16.0",
"remove-accents": "^0.5.0"
}
},
"@wordpress/viewport": {
- "version": "5.19.13",
- "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-5.19.13.tgz",
- "integrity": "sha512-xYWTcaQLhZrDZA0lpl9TivbU4RPw+CUfuRc3NEBiQY0GDDfuLe8n1Pb9AkmAP5PLNyxZhHjKLBGojfchOGhzdg==",
+ "version": "5.27.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-5.27.0.tgz",
+ "integrity": "sha512-ET8X3Ln0K6wrBba+u0AjBD/mP02SuvwhK/EVaI3uAhNlGnkx+J3PdtShbu63lHmp0SG+J27CDjEqfcZ6CdAnfA==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13"
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0"
}
},
"@wordpress/warning": {
- "version": "2.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.42.13.tgz",
- "integrity": "sha512-SYi37xiR7Wq4Vde4JBkCYJIyfUQzyuABrwh7aon1XwcUhWP072tv4/LKP6F+zWYC5M8pPdRqjznxgwZ2mNzcyw=="
+ "version": "2.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.50.0.tgz",
+ "integrity": "sha512-y7Zf48roDfiPgbRAWGXDwN3C8sfbEdneGq+HvXCW6rIeGYnDLdEkpX9i7RfultkFFPVeSP3FpMKVMkto2nbqzA=="
},
"@wordpress/widgets": {
- "version": "3.19.14",
- "resolved": "https://registry.npmjs.org/@wordpress/widgets/-/widgets-3.19.14.tgz",
- "integrity": "sha512-nFyXrCBVp24joFa96sAdNwkWnnf23t960ebnoW+Wk+lMT0PsGfGjiMIRmtks2cfqbQuQYFdO/8go+DSE54ekAg==",
+ "version": "3.27.2",
+ "resolved": "https://registry.npmjs.org/@wordpress/widgets/-/widgets-3.27.2.tgz",
+ "integrity": "sha512-z/OsrXbBY8PanemOHdtup1OlfdBmbc6dMfXqZ3pelH75z4n73JtPhVEqM/FJFdwP737fV1gU1nvMB17VtnyXKw==",
"requires": {
"@babel/runtime": "^7.16.0",
- "@wordpress/api-fetch": "^6.39.13",
- "@wordpress/block-editor": "^12.10.14",
- "@wordpress/blocks": "^12.19.13",
- "@wordpress/components": "^25.8.14",
- "@wordpress/compose": "^6.19.13",
- "@wordpress/core-data": "^6.19.14",
- "@wordpress/data": "^9.12.13",
- "@wordpress/element": "^5.19.13",
- "@wordpress/i18n": "^4.42.13",
- "@wordpress/icons": "^9.33.13",
- "@wordpress/notices": "^4.10.13",
+ "@wordpress/api-fetch": "^6.47.0",
+ "@wordpress/block-editor": "^12.18.2",
+ "@wordpress/blocks": "^12.27.1",
+ "@wordpress/components": "^25.16.0",
+ "@wordpress/compose": "^6.27.0",
+ "@wordpress/core-data": "^6.27.2",
+ "@wordpress/data": "^9.20.0",
+ "@wordpress/element": "^5.27.0",
+ "@wordpress/i18n": "^4.50.0",
+ "@wordpress/icons": "^9.41.0",
+ "@wordpress/notices": "^4.18.0",
"classnames": "^2.3.1"
}
},
"@wordpress/wordcount": {
- "version": "3.42.13",
- "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-3.42.13.tgz",
- "integrity": "sha512-yapganGNO/9JjfWTcMNECjIOKlnLOJR2VTh4UFBL/lSi2GM1AE7bjnXsV2pD0H/3mwdhAomRCUV6BA3nG5UUfA==",
+ "version": "3.50.0",
+ "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-3.50.0.tgz",
+ "integrity": "sha512-lRfIX3B9ha//bqsUihym2BnOiAsdDQr22vdy0wZIpm5G2tFvTddCKHy0YClf52IJK0z61WqbNuF9hrvzWWxL+g==",
"requires": {
"@babel/runtime": "^7.16.0"
}
@@ -40218,23 +39530,6 @@
"requires": {
"mime-types": "~2.1.34",
"negotiator": "0.6.3"
- },
- "dependencies": {
- "mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true
- },
- "mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
- "requires": {
- "mime-db": "1.52.0"
- }
- }
}
},
"acorn": {
@@ -40499,9 +39794,9 @@
"optional": true
},
"array-flatten": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
- "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"dev": true
},
"array-includes": {
@@ -40730,12 +40025,27 @@
"dev": true
},
"axios": {
- "version": "0.25.0",
- "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
- "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
+ "version": "1.6.5",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz",
+ "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==",
"dev": true,
"requires": {
- "follow-redirects": "^1.14.7"
+ "follow-redirects": "^1.15.4",
+ "form-data": "^4.0.0",
+ "proxy-from-env": "^1.1.0"
+ },
+ "dependencies": {
+ "form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dev": true,
+ "requires": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ }
+ }
}
},
"axobject-query": {
@@ -41048,12 +40358,6 @@
"tweetnacl": "^0.14.3"
}
},
- "big-integer": {
- "version": "1.6.51",
- "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz",
- "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==",
- "dev": true
- },
"big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -41463,13 +40767,11 @@
"integrity": "sha512-Yi1Xaml0EvNA0OYWxXiYNqY24AfWkbA6w5vxE7GWxtKfzIbZM+Qw+aSmkgsbWzbHiy/RCSkUZBplVxTA+E4jJg=="
},
"bonjour-service": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz",
- "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz",
+ "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==",
"dev": true,
"requires": {
- "array-flatten": "^2.1.2",
- "dns-equal": "^1.0.0",
"fast-deep-equal": "^3.1.3",
"multicast-dns": "^7.2.5"
}
@@ -41480,15 +40782,6 @@
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
"dev": true
},
- "bplist-parser": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz",
- "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==",
- "dev": true,
- "requires": {
- "big-integer": "^1.6.44"
- }
- },
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -41611,15 +40904,6 @@
"semver": "^7.0.0"
}
},
- "bundle-name": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz",
- "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==",
- "dev": true,
- "requires": {
- "run-applescript": "^5.0.0"
- }
- },
"bytes": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
@@ -41784,9 +41068,9 @@
}
},
"caniuse-lite": {
- "version": "1.0.30001549",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz",
- "integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==",
+ "version": "1.0.30001579",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz",
+ "integrity": "sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==",
"dev": true
},
"capital-case": {
@@ -42265,9 +41549,9 @@
"integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw=="
},
"colorette": {
- "version": "2.0.19",
- "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
- "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+ "version": "2.0.20",
+ "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz",
+ "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"dev": true
},
"colors": {
@@ -42446,22 +41730,12 @@
}
},
"content-disposition": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
- "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+ "version": "0.5.4",
+ "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+ "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
"dev": true,
- "optional": true,
"requires": {
- "safe-buffer": "5.1.2"
- },
- "dependencies": {
- "safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true,
- "optional": true
- }
+ "safe-buffer": "5.2.1"
}
},
"content-type": {
@@ -42598,9 +41872,9 @@
}
},
"core-js-pure": {
- "version": "3.21.1",
- "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz",
- "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==",
+ "version": "3.35.1",
+ "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.35.1.tgz",
+ "integrity": "sha512-zcIdi/CL3MWbBJYo5YCeVAAx+Sy9yJE9I3/u9LkFABwbeaPhTMRWraM8mYFp9jW5Z50hOy7FVzCc8dCrpZqtIQ==",
"dev": true
},
"core-js-url-browser": {
@@ -43054,6 +42328,12 @@
"integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==",
"dev": true
},
+ "debounce": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
+ "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==",
+ "dev": true
+ },
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
@@ -43316,138 +42596,9 @@
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A=="
},
"deepsignal": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/deepsignal/-/deepsignal-1.3.6.tgz",
- "integrity": "sha512-yjd+vtiznL6YaMptOsKnEKkPr60OEApa+LRe+Qe6Ile/RfCOrELKk/YM3qVpXFZiyOI3Ng67GDEyjAlqVc697g=="
- },
- "default-browser": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz",
- "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==",
- "dev": true,
- "requires": {
- "bundle-name": "^3.0.0",
- "default-browser-id": "^3.0.0",
- "execa": "^7.1.1",
- "titleize": "^3.0.0"
- },
- "dependencies": {
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "execa": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz",
- "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.1",
- "human-signals": "^4.3.0",
- "is-stream": "^3.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^5.1.0",
- "onetime": "^6.0.0",
- "signal-exit": "^3.0.7",
- "strip-final-newline": "^3.0.0"
- }
- },
- "get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true
- },
- "human-signals": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz",
- "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==",
- "dev": true
- },
- "is-stream": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
- "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
- "dev": true
- },
- "mimic-fn": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
- "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
- "dev": true
- },
- "npm-run-path": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz",
- "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==",
- "dev": true,
- "requires": {
- "path-key": "^4.0.0"
- },
- "dependencies": {
- "path-key": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
- "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
- "dev": true
- }
- }
- },
- "onetime": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
- "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
- "dev": true,
- "requires": {
- "mimic-fn": "^4.0.0"
- }
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true
- },
- "strip-final-newline": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
- "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
- "dev": true
- }
- }
- },
- "default-browser-id": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz",
- "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==",
- "dev": true,
- "requires": {
- "bplist-parser": "^0.2.0",
- "untildify": "^4.0.0"
- }
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/deepsignal/-/deepsignal-1.4.0.tgz",
+ "integrity": "sha512-x0XUMT48s+xQRLc2fPFfxnYLCJ46vffw47OQ5NcHFzacOjfW5eA0NrEmI0bhQHL6MgUHkBVT4TIiWTVwzTEwpg=="
},
"default-gateway": {
"version": "6.0.3",
@@ -43737,16 +42888,10 @@
"path-type": "^4.0.0"
}
},
- "dns-equal": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
- "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==",
- "dev": true
- },
"dns-packet": {
- "version": "5.4.0",
- "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz",
- "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==",
+ "version": "5.6.1",
+ "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz",
+ "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==",
"dev": true,
"requires": {
"@leichtgewicht/ip-codec": "^2.0.1"
@@ -43918,11 +43063,6 @@
}
}
},
- "downloadjs": {
- "version": "1.4.7",
- "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz",
- "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q=="
- },
"downshift": {
"version": "6.1.12",
"resolved": "https://registry.npmjs.org/downshift/-/downshift-6.1.12.tgz",
@@ -44066,9 +43206,9 @@
"dev": true
},
"envinfo": {
- "version": "7.8.1",
- "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz",
- "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==",
+ "version": "7.11.0",
+ "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz",
+ "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==",
"dev": true
},
"equivalent-key-map": {
@@ -44182,6 +43322,11 @@
"integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==",
"dev": true
},
+ "es-module-shims": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/es-module-shims/-/es-module-shims-1.8.2.tgz",
+ "integrity": "sha512-7vIYVzpOhXtpc3Yn03itB+GSgVZFW7oL4kdydA+iL+IEi7HiSLBUxM05QFw4SxTl6e++pMpGqZPo2+vdNs3TbA=="
+ },
"es-set-tostringtag": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
@@ -44569,9 +43714,9 @@
}
},
"eslint-plugin-import": {
- "version": "2.29.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz",
- "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==",
+ "version": "2.29.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
+ "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
"dev": true,
"requires": {
"array-includes": "^3.1.7",
@@ -44590,7 +43735,7 @@
"object.groupby": "^1.0.1",
"object.values": "^1.1.7",
"semver": "^6.3.1",
- "tsconfig-paths": "^3.14.2"
+ "tsconfig-paths": "^3.15.0"
},
"dependencies": {
"debug": {
@@ -44620,9 +43765,9 @@
}
},
"eslint-plugin-jest": {
- "version": "27.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.0.tgz",
- "integrity": "sha512-MTlusnnDMChbElsszJvrwD1dN3x6nZl//s4JD23BxB6MgR66TZlL064su24xEIS3VACfAoHV1vgyMgPw8nkdng==",
+ "version": "27.6.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-27.6.3.tgz",
+ "integrity": "sha512-+YsJFVH6R+tOiO3gCJon5oqn4KWc+mDq2leudk8mrp8RFubLOo9CVyi3cib4L7XMpxExmkmBZQTPDYVBzgpgOA==",
"dev": true,
"requires": {
"@typescript-eslint/utils": "^5.10.0"
@@ -44694,9 +43839,9 @@
}
},
"eslint-plugin-jsdoc": {
- "version": "46.9.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.9.0.tgz",
- "integrity": "sha512-UQuEtbqLNkPf5Nr/6PPRCtr9xypXY+g8y/Q7gPa0YK7eDhh0y2lWprXRnaYbW7ACgIUvpDKy9X2bZqxtGzBG9Q==",
+ "version": "46.10.1",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz",
+ "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==",
"dev": true,
"requires": {
"@es-joy/jsdoccomment": "~0.41.0",
@@ -44707,7 +43852,7 @@
"esquery": "^1.5.0",
"is-builtin-module": "^3.2.1",
"semver": "^7.5.4",
- "spdx-expression-parse": "^3.0.1"
+ "spdx-expression-parse": "^4.0.0"
},
"dependencies": {
"escape-string-regexp": {
@@ -44715,6 +43860,16 @@
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
+ },
+ "spdx-expression-parse": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
+ "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
+ "dev": true,
+ "requires": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
}
}
},
@@ -44757,13 +43912,13 @@
"dev": true
},
"eslint-plugin-prettier": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz",
- "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==",
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz",
+ "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==",
"dev": true,
"requires": {
"prettier-linter-helpers": "^1.0.0",
- "synckit": "^0.8.5"
+ "synckit": "^0.8.6"
}
},
"eslint-plugin-react": {
@@ -45183,21 +44338,6 @@
"vary": "~1.1.2"
},
"dependencies": {
- "array-flatten": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
- "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
- "dev": true
- },
- "content-disposition": {
- "version": "0.5.4",
- "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
- "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
- "dev": true,
- "requires": {
- "safe-buffer": "5.2.1"
- }
- },
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@@ -45941,6 +45081,12 @@
"integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==",
"dev": true
},
+ "flat": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz",
+ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==",
+ "dev": true
+ },
"flat-cache": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
@@ -45969,9 +45115,9 @@
"dev": true
},
"follow-redirects": {
- "version": "1.15.2",
- "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
- "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+ "version": "1.15.5",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
+ "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==",
"dev": true
},
"for-each": {
@@ -46108,9 +45254,9 @@
}
},
"fs-monkey": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz",
- "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==",
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz",
+ "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==",
"dev": true
},
"fs.realpath": {
@@ -47500,6 +46646,13 @@
"integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
"requires": {
"react-is": "^16.7.0"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ }
}
},
"homedir-polyfill": {
@@ -47992,6 +47145,11 @@
"resolve-cwd": "^3.0.0"
}
},
+ "import-locals": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-locals/-/import-locals-2.0.0.tgz",
+ "integrity": "sha512-1/bPE89IZhyf7dr5Pkz7b4UyVXy5pEt7PTEfye15UEn3AK8+2zwcDCfKk9Pwun4ltfhOSszOrReSsFcDKw/yoA=="
+ },
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
@@ -48131,9 +47289,9 @@
}
},
"interpret": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
- "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
+ "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
"dev": true
},
"intl-messageformat": {
@@ -48177,9 +47335,9 @@
"dev": true
},
"ipaddr.js": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
- "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz",
+ "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==",
"dev": true
},
"irregular-plurals": {
@@ -48399,23 +47557,6 @@
"is-extglob": "^2.1.1"
}
},
- "is-inside-container": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
- "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
- "dev": true,
- "requires": {
- "is-docker": "^3.0.0"
- },
- "dependencies": {
- "is-docker": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
- "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
- "dev": true
- }
- }
- },
"is-jpg": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-jpg/-/is-jpg-2.0.0.tgz",
@@ -49298,18 +48439,18 @@
}
},
"jest-dev-server": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-6.2.0.tgz",
- "integrity": "sha512-ZWh8CuvxwjhYfvw4tGeftziqIvw/26R6AG3OTgNTQeXul8aZz48RQjDpnlDwnWX53jxJJl9fcigqIdSU5lYZuw==",
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-9.0.2.tgz",
+ "integrity": "sha512-Zc/JB0IlNNrpXkhBw+h86cGrde/Mey52KvF+FER2eyrtYJTHObOwW7Iarxm3rPyTKby5+3Y2QZtl8pRz/5GCxg==",
"dev": true,
"requires": {
"chalk": "^4.1.2",
"cwd": "^0.10.0",
"find-process": "^1.4.7",
"prompts": "^2.4.2",
- "spawnd": "^6.2.0",
+ "spawnd": "^9.0.2",
"tree-kill": "^1.2.2",
- "wait-on": "^6.0.1"
+ "wait-on": "^7.2.0"
},
"dependencies": {
"ansi-styles": {
@@ -49353,9 +48494,9 @@
"dev": true
},
"rxjs": {
- "version": "7.8.0",
- "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
- "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
+ "version": "7.8.1",
+ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
+ "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
"dev": true,
"requires": {
"tslib": "^2.1.0"
@@ -49371,16 +48512,16 @@
}
},
"wait-on": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz",
- "integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==",
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz",
+ "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==",
"dev": true,
"requires": {
- "axios": "^0.25.0",
- "joi": "^17.6.0",
+ "axios": "^1.6.1",
+ "joi": "^17.11.0",
"lodash": "^4.17.21",
- "minimist": "^1.2.5",
- "rxjs": "^7.5.4"
+ "minimist": "^1.2.8",
+ "rxjs": "^7.8.1"
}
}
}
@@ -50438,15 +49579,15 @@
}
},
"joi": {
- "version": "17.7.0",
- "resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz",
- "integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==",
+ "version": "17.12.0",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.12.0.tgz",
+ "integrity": "sha512-HSLsmSmXz+PV9PYoi3p7cgIbj06WnEBNT28n+bbBNcPZXZFqCzzvGqpTBPujx/Z0nh1+KNQPDrNgdmQ8dq0qYw==",
"dev": true,
"requires": {
- "@hapi/hoek": "^9.0.0",
- "@hapi/topo": "^5.0.0",
- "@sideway/address": "^4.1.3",
- "@sideway/formula": "^3.0.0",
+ "@hapi/hoek": "^9.3.0",
+ "@hapi/topo": "^5.1.0",
+ "@sideway/address": "^4.1.4",
+ "@sideway/formula": "^3.0.1",
"@sideway/pinpoint": "^2.0.0"
}
},
@@ -50933,6 +50074,16 @@
"language-subtag-registry": "^0.3.20"
}
},
+ "launch-editor": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz",
+ "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==",
+ "dev": true,
+ "requires": {
+ "picocolors": "^1.0.0",
+ "shell-quote": "^1.8.1"
+ }
+ },
"lazy-cache": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
@@ -50956,9 +50107,9 @@
}
},
"lib0": {
- "version": "0.2.87",
- "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.87.tgz",
- "integrity": "sha512-TbB63XJixvNToW2IHWAFsCJj9tVnajmwjE14p69i51Rx8byOQd2IP4ourE8v4d7vhyO++nVm1sQk3ePslfbucg==",
+ "version": "0.2.88",
+ "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.88.tgz",
+ "integrity": "sha512-KyroiEvCeZcZEMx5Ys+b4u4eEBbA1ch7XUaBhYpwa/nPMrzTjUhI4RfcytmQfYoTBPcdyx+FX6WFNIoNuJzJfQ==",
"requires": {
"isomorphic.js": "^0.2.4"
}
@@ -52158,12 +51309,12 @@
"dev": true
},
"memfs": {
- "version": "3.4.13",
- "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz",
- "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==",
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz",
+ "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==",
"dev": true,
"requires": {
- "fs-monkey": "^1.0.3"
+ "fs-monkey": "^1.0.4"
}
},
"memize": {
@@ -52266,18 +51417,18 @@
"dev": true
},
"mime-db": {
- "version": "1.45.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz",
- "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==",
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true
},
"mime-types": {
- "version": "2.1.28",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz",
- "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==",
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"requires": {
- "mime-db": "1.45.0"
+ "mime-db": "1.52.0"
}
},
"mimic-fn": {
@@ -52365,9 +51516,9 @@
}
},
"minimist": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
- "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==",
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true
},
"minimist-options": {
@@ -52485,9 +51636,9 @@
"integrity": "sha512-QNo4kEepaIBwiT8CDhP98umTetp+JNfQYBWvC1pc6/OAibuXtRcxZ58Qz8skvEHYvURne/7R8T5VoOI7rDsEUA=="
},
"mrmime": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
- "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz",
+ "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==",
"dev": true
},
"ms": {
@@ -52515,8 +51666,7 @@
"nanoid": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
- "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
- "dev": true
+ "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA=="
},
"nanomatch": {
"version": "1.2.13",
@@ -53739,8 +52889,7 @@
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
- "dev": true
+ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"picomatch": {
"version": "2.3.1",
@@ -53882,7 +53031,6 @@
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
- "dev": true,
"requires": {
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
@@ -54148,6 +53296,11 @@
"postcss-value-parser": "^4.2.0"
}
},
+ "postcss-prefixwrap": {
+ "version": "1.44.0",
+ "resolved": "https://registry.npmjs.org/postcss-prefixwrap/-/postcss-prefixwrap-1.44.0.tgz",
+ "integrity": "sha512-h9MJGaIvT5hnzFc7Vuo+2ulBw6ecmmfcd8SKKH2TziUzcIA04gUoXIbptuM+tR+htmsQIKNEluiQlmCQ2p5a2g=="
+ },
"postcss-reduce-initial": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz",
@@ -54341,16 +53494,23 @@
"postcss-selector-parser": "^6.0.5"
}
},
+ "postcss-urlrebase": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/postcss-urlrebase/-/postcss-urlrebase-1.3.0.tgz",
+ "integrity": "sha512-LOFN43n1IewKriXiypMNNinXeptttSyGGRLPbBMdQzuTvvCEo5mz/gG06y/HqrkN7p3ayHQf2R2bTBv639FOaQ==",
+ "requires": {
+ "postcss-value-parser": "^4.2.0"
+ }
+ },
"postcss-value-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
- "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
- "dev": true
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
"preact": {
- "version": "10.19.1",
- "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.1.tgz",
- "integrity": "sha512-ZSsUr6EFlwWH0btdXMj6+X+hJAZ1v+aUzKlfwBGokKB1ZO6Shz+D16LxQhM8f+E/UgkKbVe2tsWXtGTUMCkGpQ=="
+ "version": "10.19.3",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.3.tgz",
+ "integrity": "sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ=="
},
"prelude-ls": {
"version": "1.2.1",
@@ -54402,12 +53562,6 @@
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true
- },
- "react-is": {
- "version": "18.2.0",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
- "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==",
- "dev": true
}
}
},
@@ -54445,6 +53599,13 @@
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
+ },
+ "dependencies": {
+ "react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ }
}
},
"proto-list": {
@@ -54789,9 +53950,9 @@
}
},
"react-is": {
- "version": "16.13.1",
- "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ "version": "18.2.0",
+ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"react-refresh": {
"version": "0.14.0",
@@ -54799,18 +53960,6 @@
"integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
"dev": true
},
- "react-remove-scroll": {
- "version": "2.5.5",
- "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.5.tgz",
- "integrity": "sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==",
- "requires": {
- "react-remove-scroll-bar": "^2.3.3",
- "react-style-singleton": "^2.2.1",
- "tslib": "^2.1.0",
- "use-callback-ref": "^1.3.0",
- "use-sidecar": "^1.1.2"
- }
- },
"react-remove-scroll-bar": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.4.tgz",
@@ -55415,87 +54564,6 @@
}
}
},
- "run-applescript": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz",
- "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==",
- "dev": true,
- "requires": {
- "execa": "^5.0.0"
- },
- "dependencies": {
- "cross-spawn": {
- "version": "7.0.3",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
- "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
- "dev": true,
- "requires": {
- "path-key": "^3.1.0",
- "shebang-command": "^2.0.0",
- "which": "^2.0.1"
- }
- },
- "execa": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
- "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
- "dev": true,
- "requires": {
- "cross-spawn": "^7.0.3",
- "get-stream": "^6.0.0",
- "human-signals": "^2.1.0",
- "is-stream": "^2.0.0",
- "merge-stream": "^2.0.0",
- "npm-run-path": "^4.0.1",
- "onetime": "^5.1.2",
- "signal-exit": "^3.0.3",
- "strip-final-newline": "^2.0.0"
- }
- },
- "get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
- "dev": true
- },
- "is-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
- "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
- "dev": true
- },
- "npm-run-path": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
- "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
- "dev": true,
- "requires": {
- "path-key": "^3.0.0"
- }
- },
- "path-key": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
- "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
- "dev": true
- },
- "shebang-command": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
- "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
- "dev": true,
- "requires": {
- "shebang-regex": "^3.0.0"
- }
- },
- "shebang-regex": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
- "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
- "dev": true
- }
- }
- },
"run-async": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@@ -55790,11 +54858,12 @@
"dev": true
},
"selfsigned": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz",
- "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==",
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz",
+ "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==",
"dev": true,
"requires": {
+ "@types/node-forge": "^1.3.0",
"node-forge": "^1"
}
},
@@ -56069,6 +55138,12 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
+ "shell-quote": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
+ "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
+ "dev": true
+ },
"showdown": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/showdown/-/showdown-1.9.1.tgz",
@@ -56178,14 +55253,14 @@
"dev": true
},
"sirv": {
- "version": "1.0.19",
- "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz",
- "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==",
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz",
+ "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==",
"dev": true,
"requires": {
- "@polka/url": "^1.0.0-next.20",
- "mrmime": "^1.0.0",
- "totalist": "^1.0.0"
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
}
},
"sisteransi": {
@@ -56471,8 +55546,7 @@
"source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
- "dev": true
+ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
},
"source-map-loader": {
"version": "4.0.1",
@@ -56523,14 +55597,21 @@
"dev": true
},
"spawnd": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-6.2.0.tgz",
- "integrity": "sha512-qX/I4lQy4KgVEcNle0kuc4FxFWHISzBhZW1YemPfwmrmQjyZmfTK/OhBKkhrD2ooAaFZEm1maEBLE6/6enwt+g==",
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-9.0.2.tgz",
+ "integrity": "sha512-nl8DVHEDQ57IcKakzpjanspVChkMpGLuVwMR/eOn9cXE55Qr6luD2Kn06sA0ootRMdgrU4tInN6lA6ohTNvysw==",
"dev": true,
"requires": {
- "exit": "^0.1.2",
- "signal-exit": "^3.0.7",
+ "signal-exit": "^4.1.0",
"tree-kill": "^1.2.2"
+ },
+ "dependencies": {
+ "signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true
+ }
}
},
"spdx-correct": {
@@ -56593,9 +55674,9 @@
},
"dependencies": {
"readable-stream": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
- "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
"requires": {
"inherits": "^2.0.3",
@@ -57460,13 +56541,13 @@
"dev": true
},
"synckit": {
- "version": "0.8.5",
- "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz",
- "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==",
+ "version": "0.8.8",
+ "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz",
+ "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==",
"dev": true,
"requires": {
- "@pkgr/utils": "^2.3.1",
- "tslib": "^2.5.0"
+ "@pkgr/core": "^0.1.0",
+ "tslib": "^2.6.2"
}
},
"table": {
@@ -57750,12 +56831,6 @@
}
}
},
- "titleize": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz",
- "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==",
- "dev": true
- },
"tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -57826,9 +56901,9 @@
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
},
"totalist": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz",
- "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==",
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+ "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
"dev": true
},
"tough-cookie": {
@@ -57849,11 +56924,6 @@
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
"dev": true
},
- "traverse": {
- "version": "0.6.7",
- "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.7.tgz",
- "integrity": "sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg=="
- },
"tree-kill": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
@@ -57883,9 +56953,9 @@
"dev": true
},
"tsconfig-paths": {
- "version": "3.14.2",
- "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
- "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
+ "version": "3.15.0",
+ "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
+ "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
"dev": true,
"requires": {
"@types/json5": "^0.0.29",
@@ -57942,11 +57012,6 @@
"safe-buffer": "^5.0.1"
}
},
- "turbo-combine-reducers": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/turbo-combine-reducers/-/turbo-combine-reducers-1.0.2.tgz",
- "integrity": "sha512-gHbdMZlA6Ym6Ur5pSH/UWrNQMIM9IqTH6SoL1DbHpqEdQ8i+cFunSmSlFykPt0eGQwZ4d/XTHOl74H0/kFBVWw=="
- },
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
@@ -58203,12 +57268,6 @@
}
}
},
- "untildify": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz",
- "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==",
- "dev": true
- },
"update-browserslist-db": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
@@ -58308,11 +57367,6 @@
"tslib": "^2.0.0"
}
},
- "use-isomorphic-layout-effect": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
- "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA=="
- },
"use-lilius": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/use-lilius/-/use-lilius-2.0.3.tgz",
@@ -58483,12 +57537,6 @@
"mime-types": "^2.1.12"
}
},
- "minimist": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz",
- "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==",
- "dev": true
- },
"rxjs": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
@@ -58541,6 +57589,12 @@
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz",
"integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q=="
},
+ "web-vitals": {
+ "version": "3.5.1",
+ "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.5.1.tgz",
+ "integrity": "sha512-xQ9lvIpfLxUj0eSmT79ZjRoU5wIRfIr7pNukL7ZE4EcWZSmfZQqOlhuAGfkVa3EFmzPHZhWhXfm2i5ys+THVPg==",
+ "dev": true
+ },
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
@@ -58588,104 +57642,65 @@
}
},
"webpack-bundle-analyzer": {
- "version": "4.8.0",
- "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.8.0.tgz",
- "integrity": "sha512-ZzoSBePshOKhr+hd8u6oCkZVwpVaXgpw23ScGLFpR6SjYI7+7iIWYarjN6OEYOfRt8o7ZyZZQk0DuMizJ+LEIg==",
+ "version": "4.10.1",
+ "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz",
+ "integrity": "sha512-s3P7pgexgT/HTUSYgxJyn28A+99mmLq4HsJepMPzu0R8ImJc52QNqaFYW1Z2z2uIb1/J3eYgaAWVpaC+v/1aAQ==",
"dev": true,
"requires": {
"@discoveryjs/json-ext": "0.5.7",
"acorn": "^8.0.4",
"acorn-walk": "^8.0.0",
- "chalk": "^4.1.0",
"commander": "^7.2.0",
+ "debounce": "^1.2.1",
+ "escape-string-regexp": "^4.0.0",
"gzip-size": "^6.0.0",
- "lodash": "^4.17.20",
+ "html-escaper": "^2.0.2",
+ "is-plain-object": "^5.0.0",
"opener": "^1.5.2",
- "sirv": "^1.0.7",
+ "picocolors": "^1.0.0",
+ "sirv": "^2.0.3",
"ws": "^7.3.1"
},
"dependencies": {
- "ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "requires": {
- "color-convert": "^2.0.1"
- }
- },
- "chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "requires": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- }
- },
- "color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "requires": {
- "color-name": "~1.1.4"
- }
- },
- "color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
"commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true
},
- "has-flag": {
+ "escape-string-regexp": {
"version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
"dev": true
- },
- "supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "requires": {
- "has-flag": "^4.0.0"
- }
}
}
},
"webpack-cli": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
- "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.1.4.tgz",
+ "integrity": "sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==",
"dev": true,
"requires": {
"@discoveryjs/json-ext": "^0.5.0",
- "@webpack-cli/configtest": "^1.2.0",
- "@webpack-cli/info": "^1.5.0",
- "@webpack-cli/serve": "^1.7.0",
+ "@webpack-cli/configtest": "^2.1.1",
+ "@webpack-cli/info": "^2.0.2",
+ "@webpack-cli/serve": "^2.0.5",
"colorette": "^2.0.14",
- "commander": "^7.0.0",
+ "commander": "^10.0.1",
"cross-spawn": "^7.0.3",
+ "envinfo": "^7.7.3",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
- "interpret": "^2.2.0",
- "rechoir": "^0.7.0",
+ "interpret": "^3.1.1",
+ "rechoir": "^0.8.0",
"webpack-merge": "^5.7.3"
},
"dependencies": {
"commander": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
- "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
+ "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
"dev": true
},
"cross-spawn": {
@@ -58705,6 +57720,15 @@
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
+ "rechoir": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
+ "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
+ "dev": true,
+ "requires": {
+ "resolve": "^1.20.0"
+ }
+ },
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -58762,39 +57786,24 @@
"integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
"dev": true
},
- "mime-db": {
- "version": "1.52.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
- "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true
- },
- "mime-types": {
- "version": "2.1.35",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
- "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
- "requires": {
- "mime-db": "1.52.0"
- }
- },
"schema-utils": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
- "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.9",
- "ajv": "^8.8.0",
+ "ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
- "ajv-keywords": "^5.0.0"
+ "ajv-keywords": "^5.1.0"
}
}
}
},
"webpack-dev-server": {
- "version": "4.11.1",
- "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz",
- "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==",
+ "version": "4.15.1",
+ "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz",
+ "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==",
"dev": true,
"requires": {
"@types/bonjour": "^3.5.9",
@@ -58803,7 +57812,7 @@
"@types/serve-index": "^1.9.1",
"@types/serve-static": "^1.13.10",
"@types/sockjs": "^0.3.33",
- "@types/ws": "^8.5.1",
+ "@types/ws": "^8.5.5",
"ansi-html-community": "^0.0.8",
"bonjour-service": "^1.0.11",
"chokidar": "^3.5.3",
@@ -58816,6 +57825,7 @@
"html-entities": "^2.3.2",
"http-proxy-middleware": "^2.0.3",
"ipaddr.js": "^2.0.1",
+ "launch-editor": "^2.6.0",
"open": "^8.0.9",
"p-retry": "^4.5.0",
"rimraf": "^3.0.2",
@@ -58825,7 +57835,7 @@
"sockjs": "^0.3.24",
"spdy": "^4.0.2",
"webpack-dev-middleware": "^5.3.1",
- "ws": "^8.4.2"
+ "ws": "^8.13.0"
},
"dependencies": {
"ajv": {
@@ -58865,21 +57875,21 @@
}
},
"schema-utils": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
- "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.9",
- "ajv": "^8.8.0",
+ "ajv": "^8.9.0",
"ajv-formats": "^2.1.1",
- "ajv-keywords": "^5.0.0"
+ "ajv-keywords": "^5.1.0"
}
},
"ws": {
- "version": "8.12.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.12.1.tgz",
- "integrity": "sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==",
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
+ "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"dev": true
}
}
@@ -58897,12 +57907,13 @@
}
},
"webpack-merge": {
- "version": "5.8.0",
- "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
- "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
+ "version": "5.10.0",
+ "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz",
+ "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==",
"dev": true,
"requires": {
"clone-deep": "^4.0.1",
+ "flat": "^5.0.2",
"wildcard": "^2.0.0"
},
"dependencies": {
@@ -59082,9 +58093,9 @@
"integrity": "sha512-Ba9tGNYxXwaqKEi9sJJvPMKuo063umUPsHN0JJsjrs2j8KDSzkWLMZGZ+MH1Jf1Fq4OWZ5HsESJID6nRza2ang=="
},
"wildcard": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
- "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
+ "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
"dev": true
},
"wrap-ansi": {
@@ -59117,7 +58128,7 @@
"version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
- "devOptional": true
+ "dev": true
},
"xdg-basedir": {
"version": "4.0.0",
@@ -59177,14 +58188,22 @@
}
},
"y-webrtc": {
- "version": "10.2.5",
- "resolved": "https://registry.npmjs.org/y-webrtc/-/y-webrtc-10.2.5.tgz",
- "integrity": "sha512-ZyBNvTI5L28sQ2PQI0T/JvyWgvuTq05L21vGkIlcvNLNSJqAaLCBJRe3FHEqXoaogqWmRcEAKGfII4ErNXMnNw==",
+ "version": "10.2.6",
+ "resolved": "https://registry.npmjs.org/y-webrtc/-/y-webrtc-10.2.6.tgz",
+ "integrity": "sha512-1kZ4YYwksFZi8+l8mTebVX9vW6Q5MnqxMkvNU700X5dBE38usurt/JgeXSIQRpK3NwUYYb9y63Jn9FMpMH6/vA==",
"requires": {
"lib0": "^0.2.42",
"simple-peer": "^9.11.0",
- "ws": "^7.2.0",
- "y-protocols": "^1.0.5"
+ "ws": "^8.14.2",
+ "y-protocols": "^1.0.6"
+ },
+ "dependencies": {
+ "ws": {
+ "version": "8.16.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
+ "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
+ "optional": true
+ }
}
},
"y18n": {
@@ -59240,11 +58259,11 @@
}
},
"yjs": {
- "version": "13.6.8",
- "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.8.tgz",
- "integrity": "sha512-ZPq0hpJQb6f59B++Ngg4cKexDJTvfOgeiv0sBc4sUm8CaBWH7OQC4kcCgrqbjJ/B2+6vO49exvTmYfdlPtcjbg==",
+ "version": "13.6.11",
+ "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.11.tgz",
+ "integrity": "sha512-FvRRJKX9u270dOLkllGF/UDCWwmIv2Z+ucM4v1QO1TuxdmoiMnSUXH1HAcOKOrkBEhQtPTkxep7tD2DrQB+l0g==",
"requires": {
- "lib0": "^0.2.74"
+ "lib0": "^0.2.86"
}
},
"yocto-queue": {
diff --git a/package.json b/package.json
index 6a9db6624057d..de72ea186a656 100644
--- a/package.json
+++ b/package.json
@@ -27,11 +27,12 @@
"@lodder/grunt-postcss": "^3.1.1",
"@playwright/test": "1.32.0",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.5",
- "@wordpress/babel-preset-default": "7.26.13",
- "@wordpress/dependency-extraction-webpack-plugin": "4.25.13",
- "@wordpress/e2e-test-utils": "10.13.13",
- "@wordpress/e2e-test-utils-playwright": "0.10.13",
- "@wordpress/scripts": "26.13.13",
+ "@wordpress/babel-preset-default": "7.34.0",
+ "@wordpress/dependency-extraction-webpack-plugin": "5.1.0",
+ "@wordpress/e2e-test-utils": "10.21.0",
+ "@wordpress/e2e-test-utils-playwright": "0.18.0",
+ "@wordpress/prettier-config": "3.7.0",
+ "@wordpress/scripts": "27.1.0",
"autoprefixer": "10.4.16",
"chalk": "5.3.0",
"check-node-version": "4.2.1",
@@ -79,74 +80,77 @@
"dependencies": {
"@emotion/is-prop-valid": "0.8.8",
"@emotion/memoize": "0.7.4",
- "@wordpress/a11y": "3.42.13",
- "@wordpress/annotations": "2.42.13",
- "@wordpress/api-fetch": "6.39.13",
- "@wordpress/autop": "3.42.13",
- "@wordpress/blob": "3.42.13",
- "@wordpress/block-directory": "4.19.16",
- "@wordpress/block-editor": "12.10.14",
- "@wordpress/block-library": "8.19.16",
- "@wordpress/block-serialization-default-parser": "4.42.13",
- "@wordpress/blocks": "12.19.13",
- "@wordpress/commands": "0.13.14",
- "@wordpress/components": "25.8.14",
- "@wordpress/compose": "6.19.13",
- "@wordpress/core-commands": "0.11.14",
- "@wordpress/core-data": "6.19.14",
- "@wordpress/customize-widgets": "4.19.16",
- "@wordpress/data": "9.12.13",
- "@wordpress/data-controls": "3.11.13",
- "@wordpress/date": "4.42.13",
- "@wordpress/deprecated": "3.42.13",
- "@wordpress/dom": "3.42.13",
- "@wordpress/dom-ready": "3.42.13",
- "@wordpress/edit-post": "7.19.16",
- "@wordpress/edit-site": "5.19.16",
- "@wordpress/edit-widgets": "5.19.16",
- "@wordpress/editor": "13.19.14",
- "@wordpress/element": "5.19.13",
- "@wordpress/escape-html": "2.42.13",
- "@wordpress/format-library": "4.19.14",
- "@wordpress/hooks": "3.42.13",
- "@wordpress/html-entities": "3.42.13",
- "@wordpress/i18n": "4.42.13",
- "@wordpress/icons": "9.33.13",
- "@wordpress/interactivity": "2.3.13",
- "@wordpress/interface": "5.19.14",
- "@wordpress/is-shallow-equal": "4.42.13",
- "@wordpress/keyboard-shortcuts": "4.19.13",
- "@wordpress/keycodes": "3.42.13",
- "@wordpress/list-reusable-blocks": "4.19.14",
- "@wordpress/media-utils": "4.33.13",
- "@wordpress/notices": "4.10.13",
- "@wordpress/nux": "8.4.14",
- "@wordpress/patterns": "1.3.14",
- "@wordpress/plugins": "6.10.14",
- "@wordpress/preferences": "3.19.14",
- "@wordpress/preferences-persistence": "1.34.13",
- "@wordpress/primitives": "3.40.13",
- "@wordpress/priority-queue": "2.42.13",
- "@wordpress/private-apis": "0.24.13",
- "@wordpress/redux-routine": "4.42.13",
- "@wordpress/reusable-blocks": "4.19.14",
- "@wordpress/rich-text": "6.19.13",
- "@wordpress/router": "0.11.13",
- "@wordpress/server-side-render": "4.19.14",
- "@wordpress/shortcode": "3.42.13",
- "@wordpress/style-engine": "1.25.13",
- "@wordpress/sync": "0.4.13",
- "@wordpress/token-list": "2.42.13",
- "@wordpress/undo-manager": "0.2.13",
- "@wordpress/url": "3.43.13",
- "@wordpress/viewport": "5.19.13",
- "@wordpress/warning": "2.42.13",
- "@wordpress/widgets": "3.19.14",
- "@wordpress/wordcount": "3.42.13",
+ "@wordpress/a11y": "3.50.0",
+ "@wordpress/annotations": "2.50.0",
+ "@wordpress/api-fetch": "6.47.0",
+ "@wordpress/autop": "3.50.0",
+ "@wordpress/blob": "3.50.0",
+ "@wordpress/block-directory": "4.27.2",
+ "@wordpress/block-editor": "12.18.2",
+ "@wordpress/block-library": "8.27.2",
+ "@wordpress/block-serialization-default-parser": "4.50.0",
+ "@wordpress/blocks": "12.27.1",
+ "@wordpress/commands": "0.21.0",
+ "@wordpress/components": "25.16.0",
+ "@wordpress/compose": "6.27.0",
+ "@wordpress/core-commands": "0.19.2",
+ "@wordpress/core-data": "6.27.2",
+ "@wordpress/customize-widgets": "4.27.2",
+ "@wordpress/data": "9.20.0",
+ "@wordpress/data-controls": "3.19.0",
+ "@wordpress/dataviews": "0.4.1",
+ "@wordpress/date": "4.50.0",
+ "@wordpress/deprecated": "3.50.0",
+ "@wordpress/dom": "3.50.0",
+ "@wordpress/dom-ready": "3.50.0",
+ "@wordpress/edit-post": "7.27.2",
+ "@wordpress/edit-site": "5.27.2",
+ "@wordpress/edit-widgets": "5.27.2",
+ "@wordpress/editor": "13.27.2",
+ "@wordpress/element": "5.27.0",
+ "@wordpress/escape-html": "2.50.0",
+ "@wordpress/format-library": "4.27.2",
+ "@wordpress/hooks": "3.50.0",
+ "@wordpress/html-entities": "3.50.0",
+ "@wordpress/i18n": "4.50.0",
+ "@wordpress/icons": "9.41.0",
+ "@wordpress/interactivity": "4.0.1",
+ "@wordpress/interactivity-router": "1.0.1",
+ "@wordpress/interface": "5.27.0",
+ "@wordpress/is-shallow-equal": "4.50.0",
+ "@wordpress/keyboard-shortcuts": "4.27.0",
+ "@wordpress/keycodes": "3.50.0",
+ "@wordpress/list-reusable-blocks": "4.27.0",
+ "@wordpress/media-utils": "4.41.0",
+ "@wordpress/notices": "4.18.0",
+ "@wordpress/nux": "8.12.0",
+ "@wordpress/patterns": "1.11.2",
+ "@wordpress/plugins": "6.18.0",
+ "@wordpress/preferences": "3.27.0",
+ "@wordpress/preferences-persistence": "1.42.0",
+ "@wordpress/primitives": "3.48.0",
+ "@wordpress/priority-queue": "2.50.0",
+ "@wordpress/private-apis": "0.32.0",
+ "@wordpress/redux-routine": "4.50.0",
+ "@wordpress/reusable-blocks": "4.27.2",
+ "@wordpress/rich-text": "6.27.0",
+ "@wordpress/router": "0.19.0",
+ "@wordpress/server-side-render": "4.27.1",
+ "@wordpress/shortcode": "3.50.0",
+ "@wordpress/style-engine": "1.33.1",
+ "@wordpress/sync": "0.12.0",
+ "@wordpress/token-list": "2.50.0",
+ "@wordpress/undo-manager": "0.10.0",
+ "@wordpress/url": "3.51.0",
+ "@wordpress/viewport": "5.27.0",
+ "@wordpress/warning": "2.50.0",
+ "@wordpress/widgets": "3.27.2",
+ "@wordpress/wordcount": "3.50.0",
"backbone": "1.5.0",
"clipboard": "2.0.11",
"core-js-url-browser": "3.6.4",
"element-closest": "^3.0.2",
+ "es-module-shims": "1.8.2",
"formdata-polyfill": "4.0.10",
"framer-motion": "10.16.4",
"hoverintent": "2.2.1",
@@ -166,6 +170,7 @@
"polyfill-library": "4.8.0",
"react": "18.2.0",
"react-dom": "18.2.0",
+ "react-is": "18.2.0",
"regenerator-runtime": "0.14.0",
"tslib": "2.6.2",
"underscore": "1.13.6",
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index ccb04303218ae..840bdad8fe977 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -59,6 +59,7 @@
/src/wp-includes/class-requests\.php
/src/wp-includes/class-simplepie\.php
/src/wp-includes/class-snoopy\.php
+ /src/wp-includes/class-avif-info\.php
/src/wp-includes/deprecated\.php
/src/wp-includes/ms-deprecated\.php
/src/wp-includes/pluggable-deprecated\.php
diff --git a/src/js/_enqueues/vendor/plupload/handlers.js b/src/js/_enqueues/vendor/plupload/handlers.js
index b82a6e88479ad..71e248fb5ed9f 100644
--- a/src/js/_enqueues/vendor/plupload/handlers.js
+++ b/src/js/_enqueues/vendor/plupload/handlers.js
@@ -608,6 +608,11 @@ jQuery( document ).ready( function( $ ) {
wpQueueError( pluploadL10n.noneditable_image );
up.removeFile( file );
return;
+ } else if ( file.type === 'image/avif' && up.settings.avif_upload_error ) {
+ // Disallow uploading of AVIF images if the server cannot edit them.
+ wpQueueError( pluploadL10n.noneditable_image );
+ up.removeFile( file );
+ return;
}
fileQueued( file );
diff --git a/src/js/_enqueues/vendor/plupload/wp-plupload.js b/src/js/_enqueues/vendor/plupload/wp-plupload.js
index 0fdebf77d1858..c0eb570657bf4 100644
--- a/src/js/_enqueues/vendor/plupload/wp-plupload.js
+++ b/src/js/_enqueues/vendor/plupload/wp-plupload.js
@@ -363,6 +363,11 @@ window.wp = window.wp || {};
error( pluploadL10n.noneditable_image, {}, file, 'no-retry' );
up.removeFile( file );
return;
+ } else if ( file.type === 'image/avif' && up.settings.avif_upload_error ) {
+ // Disallow uploading of AVIF images if the server cannot edit them.
+ error( pluploadL10n.noneditable_image, {}, file, 'no-retry' );
+ up.removeFile( file );
+ return;
}
// Generate attributes for a new `Attachment` model.
diff --git a/src/js/_enqueues/vendor/thickbox/thickbox.js b/src/js/_enqueues/vendor/thickbox/thickbox.js
index 5470467a1e0a8..e8b95677c1ad4 100644
--- a/src/js/_enqueues/vendor/thickbox/thickbox.js
+++ b/src/js/_enqueues/vendor/thickbox/thickbox.js
@@ -76,7 +76,7 @@ function tb_show(caption, url, imageGroup) {//function called when the user clic
baseURL = url;
}
- var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$|\.webp$/;
+ var urlString = /\.jpg$|\.jpeg$|\.png$|\.gif$|\.bmp$|\.webp$|\.avif$/;
var urlType = baseURL.toLowerCase().match(urlString);
if(urlType == '.jpg' ||
@@ -84,7 +84,8 @@ function tb_show(caption, url, imageGroup) {//function called when the user clic
urlType == '.png' ||
urlType == '.gif' ||
urlType == '.bmp' ||
- urlType == '.webp'
+ urlType == '.webp' ||
+ urlType == '.avif'
){//code to show images
TB_PrevCaption = "";
diff --git a/src/js/_enqueues/wp/updates.js b/src/js/_enqueues/wp/updates.js
index a994fda694ae9..a11f47ab54871 100644
--- a/src/js/_enqueues/wp/updates.js
+++ b/src/js/_enqueues/wp/updates.js
@@ -413,6 +413,31 @@
}
};
+ /**
+ * Sends a message from a modal to the main screen to update buttons in plugin cards.
+ *
+ * @since 6.5.0
+ *
+ * @param {Object} data An object of data to use for the button.
+ * @param {string} data.slug The plugin's slug.
+ * @param {string} data.text The text to use for the button.
+ * @param {string} data.ariaLabel The value for the button's aria-label attribute. An empty string removes the attribute.
+ * @param {string=} data.status Optional. An identifier for the status.
+ * @param {string=} data.removeClasses Optional. A space-separated list of classes to remove from the button.
+ * @param {string=} data.addClasses Optional. A space-separated list of classes to add to the button.
+ * @param {string=} data.href Optional. The button's URL.
+ * @param {string=} data.pluginName Optional. The plugin's name.
+ * @param {string=} data.plugin Optional. The plugin file, relative to the plugins directory.
+ */
+ wp.updates.setCardButtonStatus = function( data ) {
+ var target = window.parent === window ? null : window.parent;
+
+ $.support.postMessage = !! window.postMessage;
+ if ( false !== $.support.postMessage && null !== target && -1 === window.parent.location.pathname.indexOf( 'index.php' ) ) {
+ target.postMessage( JSON.stringify( data ), window.location.origin );
+ }
+ };
+
/**
* Decrements the update counts throughout the various menus.
*
@@ -452,7 +477,8 @@
*/
wp.updates.updatePlugin = function( args ) {
var $updateRow, $card, $message, message,
- $adminBarUpdates = $( '#wp-admin-bar-updates' );
+ $adminBarUpdates = $( '#wp-admin-bar-updates' ),
+ buttonText = __( 'Updating...' );
args = _.extend( {
success: wp.updates.updatePluginSuccess,
@@ -468,7 +494,7 @@
$updateRow.find( '.plugin-title strong' ).text()
);
} else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
- $card = $( '.plugin-card-' + args.slug );
+ $card = $( '.plugin-card-' + args.slug + ', #plugin-information-footer' );
$message = $card.find( '.update-now' ).addClass( 'updating-message' );
message = sprintf(
/* translators: %s: Plugin name and version. */
@@ -488,10 +514,22 @@
$message
.attr( 'aria-label', message )
- .text( __( 'Updating...' ) );
+ .text( buttonText );
$document.trigger( 'wp-plugin-updating', args );
+ if ( 'plugin-information-footer' === $card.attr('id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'updating-plugin',
+ slug: args.slug,
+ addClasses: 'updating-message',
+ text: buttonText,
+ ariaLabel: message
+ }
+ );
+ }
+
return wp.updates.ajax( 'update-plugin', args );
};
@@ -511,7 +549,13 @@
*/
wp.updates.updatePluginSuccess = function( response ) {
var $pluginRow, $updateMessage, newText,
- $adminBarUpdates = $( '#wp-admin-bar-updates' );
+ $adminBarUpdates = $( '#wp-admin-bar-updates' ),
+ buttonText = _x( 'Updated!', 'plugin' ),
+ ariaLabel = sprintf(
+ /* translators: %s: Plugin name and version. */
+ _x( '%s updated!', 'plugin' ),
+ response.pluginName
+ );
if ( 'plugins' === pagenow || 'plugins-network' === pagenow ) {
$pluginRow = $( 'tr[data-plugin="' + response.plugin + '"]' )
@@ -528,7 +572,7 @@
// Clear the "time to next auto-update" text.
$pluginRow.find( '.auto-update-time' ).empty();
} else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
- $updateMessage = $( '.plugin-card-' + response.slug ).find( '.update-now' )
+ $updateMessage = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.update-now' )
.removeClass( 'updating-message' )
.addClass( 'button-disabled updated-message' );
}
@@ -536,19 +580,25 @@
$adminBarUpdates.removeClass( 'spin' );
$updateMessage
- .attr(
- 'aria-label',
- sprintf(
- /* translators: %s: Plugin name and version. */
- _x( '%s updated!', 'plugin' ),
- response.pluginName
- )
- )
- .text( _x( 'Updated!', 'plugin' ) );
+ .attr( 'aria-label', ariaLabel )
+ .text( buttonText );
wp.a11y.speak( __( 'Update completed successfully.' ) );
- wp.updates.decrementCount( 'plugin' );
+ if ( 'plugin_install_from_iframe' !== $updateMessage.attr( 'id' ) ) {
+ wp.updates.decrementCount( 'plugin' );
+ } else {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'updated-plugin',
+ slug: response.slug,
+ removeClasses: 'updating-message',
+ addClasses: 'button-disabled updated-message',
+ text: buttonText,
+ ariaLabel: ariaLabel
+ }
+ );
+ }
$document.trigger( 'wp-plugin-update-success', response );
};
@@ -567,7 +617,7 @@
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.updatePluginError = function( response ) {
- var $pluginRow, $card, $message, errorMessage,
+ var $pluginRow, $card, $message, errorMessage, buttonText, ariaLabel,
$adminBarUpdates = $( '#wp-admin-bar-updates' );
if ( ! wp.updates.isValidResponse( response, 'update' ) ) {
@@ -608,28 +658,32 @@
$message.find( 'p' ).removeAttr( 'aria-label' );
}
} else if ( 'plugin-install' === pagenow || 'plugin-install-network' === pagenow ) {
- $card = $( '.plugin-card-' + response.slug )
- .addClass( 'plugin-card-update-failed' )
+ buttonText = __( 'Update failed.' );
+
+ $card = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' )
.append( wp.updates.adminNotice( {
className: 'update-message notice-error notice-alt is-dismissible',
message: errorMessage
} ) );
+ if ( $card.hasClass( 'plugin-card-' + response.slug ) ) {
+ $card.addClass( 'plugin-card-update-failed' );
+ }
+
$card.find( '.update-now' )
- .text( __( 'Update failed.' ) )
+ .text( buttonText )
.removeClass( 'updating-message' );
if ( response.pluginName ) {
- $card.find( '.update-now' )
- .attr(
- 'aria-label',
- sprintf(
- /* translators: %s: Plugin name and version. */
- _x( '%s update failed.', 'plugin' ),
- response.pluginName
- )
- );
+ ariaLabel = sprintf(
+ /* translators: %s: Plugin name and version. */
+ _x( '%s update failed.', 'plugin' ),
+ response.pluginName
+ );
+
+ $card.find( '.update-now' ).attr( 'aria-label', ariaLabel );
} else {
+ ariaLabel = '';
$card.find( '.update-now' ).removeAttr( 'aria-label' );
}
@@ -652,6 +706,18 @@
wp.a11y.speak( errorMessage, 'assertive' );
+ if ( 'plugin-information-footer' === $card.attr('id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'plugin-update-failed',
+ slug: response.slug,
+ removeClasses: 'updating-message',
+ text: buttonText,
+ ariaLabel: ariaLabel
+ }
+ );
+ }
+
$document.trigger( 'wp-plugin-update-error', response );
};
@@ -668,8 +734,10 @@
* decorated with an abort() method.
*/
wp.updates.installPlugin = function( args ) {
- var $card = $( '.plugin-card-' + args.slug ),
- $message = $card.find( '.install-now' );
+ var $card = $( '.plugin-card-' + args.slug + ', #plugin-information-footer' ),
+ $message = $card.find( '.install-now' ),
+ buttonText = __( 'Installing...' ),
+ ariaLabel;
args = _.extend( {
success: wp.updates.installPluginSuccess,
@@ -684,17 +752,16 @@
$message.data( 'originaltext', $message.html() );
}
+ ariaLabel = sprintf(
+ /* translators: %s: Plugin name and version. */
+ _x( 'Installing %s...', 'plugin' ),
+ $message.data( 'name' )
+ );
+
$message
.addClass( 'updating-message' )
- .attr(
- 'aria-label',
- sprintf(
- /* translators: %s: Plugin name and version. */
- _x( 'Installing %s...', 'plugin' ),
- $message.data( 'name' )
- )
- )
- .text( __( 'Installing...' ) );
+ .attr( 'aria-label', ariaLabel )
+ .text( buttonText );
wp.a11y.speak( __( 'Installing... please wait.' ) );
@@ -703,6 +770,18 @@
$document.trigger( 'wp-plugin-installing', args );
+ if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'installing-plugin',
+ slug: args.slug,
+ addClasses: 'updating-message',
+ text: buttonText,
+ ariaLabel: ariaLabel
+ }
+ );
+ }
+
return wp.updates.ajax( 'install-plugin', args );
};
@@ -717,20 +796,19 @@
* @param {string} response.activateUrl URL to activate the just installed plugin.
*/
wp.updates.installPluginSuccess = function( response ) {
- var $message = $( '.plugin-card-' + response.slug ).find( '.install-now' );
+ var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.install-now' ),
+ buttonText = _x( 'Installed!', 'plugin' ),
+ ariaLabel = sprintf(
+ /* translators: %s: Plugin name and version. */
+ _x( '%s installed!', 'plugin' ),
+ response.pluginName
+ );
$message
.removeClass( 'updating-message' )
.addClass( 'updated-message installed button-disabled' )
- .attr(
- 'aria-label',
- sprintf(
- /* translators: %s: Plugin name and version. */
- _x( '%s installed!', 'plugin' ),
- response.pluginName
- )
- )
- .text( _x( 'Installed!', 'plugin' ) );
+ .attr( 'aria-label', ariaLabel )
+ .text( buttonText );
wp.a11y.speak( __( 'Installation completed successfully.' ) );
@@ -738,36 +816,23 @@
if ( response.activateUrl ) {
setTimeout( function() {
+ wp.updates.checkPluginDependencies( {
+ slug: response.slug
+ } );
+ }, 1000 );
+ }
- // Transform the 'Install' button into an 'Activate' button.
- $message.removeClass( 'install-now installed button-disabled updated-message' )
- .addClass( 'activate-now button-primary' )
- .attr( 'href', response.activateUrl );
-
- if ( 'plugins-network' === pagenow ) {
- $message
- .attr(
- 'aria-label',
- sprintf(
- /* translators: %s: Plugin name. */
- _x( 'Network Activate %s', 'plugin' ),
- response.pluginName
- )
- )
- .text( __( 'Network Activate' ) );
- } else {
- $message
- .attr(
- 'aria-label',
- sprintf(
- /* translators: %s: Plugin name. */
- _x( 'Activate %s', 'plugin' ),
- response.pluginName
- )
- )
- .text( __( 'Activate' ) );
+ if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'installed-plugin',
+ slug: response.slug,
+ removeClasses: 'updating-message',
+ addClasses: 'updated-message installed button-disabled',
+ text: buttonText,
+ ariaLabel: ariaLabel
}
- }, 1000 );
+ );
}
};
@@ -783,8 +848,14 @@
* @param {string} response.errorMessage The error that occurred.
*/
wp.updates.installPluginError = function( response ) {
- var $card = $( '.plugin-card-' + response.slug ),
+ var $card = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ),
$button = $card.find( '.install-now' ),
+ buttonText = __( 'Installation failed.' ),
+ ariaLabel = sprintf(
+ /* translators: %s: Plugin name and version. */
+ _x( '%s installation failed', 'plugin' ),
+ $button.data( 'name' )
+ ),
errorMessage;
if ( ! wp.updates.isValidResponse( response, 'install' ) ) {
@@ -817,21 +888,334 @@
$button
.removeClass( 'updating-message' ).addClass( 'button-disabled' )
- .attr(
- 'aria-label',
- sprintf(
- /* translators: %s: Plugin name and version. */
- _x( '%s installation failed', 'plugin' ),
- $button.data( 'name' )
- )
- )
- .text( __( 'Installation failed.' ) );
+ .attr( 'aria-label', ariaLabel )
+ .text( buttonText );
wp.a11y.speak( errorMessage, 'assertive' );
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'plugin-install-failed',
+ slug: response.slug,
+ removeClasses: 'updating-message',
+ addClasses: 'button-disabled',
+ text: buttonText,
+ ariaLabel: ariaLabel
+ }
+ );
+
$document.trigger( 'wp-plugin-install-error', response );
};
+ /**
+ * Sends an Ajax request to the server to check a plugin's dependencies.
+ *
+ * @since 6.5.0
+ *
+ * @param {Object} args Arguments.
+ * @param {string} args.slug Plugin identifier in the WordPress.org Plugin repository.
+ * @param {checkPluginDependenciesSuccess=} args.success Optional. Success callback. Default: wp.updates.checkPluginDependenciesSuccess
+ * @param {checkPluginDependenciesError=} args.error Optional. Error callback. Default: wp.updates.checkPluginDependenciesError
+ * @return {$.promise} A jQuery promise that represents the request,
+ * decorated with an abort() method.
+ */
+ wp.updates.checkPluginDependencies = function( args ) {
+ args = _.extend( {
+ success: wp.updates.checkPluginDependenciesSuccess,
+ error: wp.updates.checkPluginDependenciesError
+ }, args );
+
+ wp.a11y.speak( __( 'Checking plugin dependencies... please wait.' ) );
+ $document.trigger( 'wp-checking-plugin-dependencies', args );
+
+ return wp.updates.ajax( 'check_plugin_dependencies', args );
+ };
+
+ /**
+ * Updates the UI appropriately after a successful plugin dependencies check.
+ *
+ * @since 6.5.0
+ *
+ * @param {Object} response Response from the server.
+ * @param {string} response.slug Slug of the checked plugin.
+ * @param {string} response.pluginName Name of the checked plugin.
+ * @param {string} response.plugin The plugin file, relative to the plugins directory.
+ * @param {string} response.activateUrl URL to activate the just checked plugin.
+ */
+ wp.updates.checkPluginDependenciesSuccess = function( response ) {
+ var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.install-now' ),
+ buttonText, ariaLabel;
+
+ // Transform the 'Install' button into an 'Activate' button.
+ $message
+ .removeClass( 'install-now installed button-disabled updated-message' )
+ .addClass( 'activate-now button-primary' )
+ .attr( 'href', response.activateUrl );
+
+ wp.a11y.speak( __( 'Plugin dependencies check completed successfully.' ) );
+ $document.trigger( 'wp-check-plugin-dependencies-success', response );
+
+ if ( 'plugins-network' === pagenow ) {
+ buttonText = _x( 'Network Activate' );
+ ariaLabel = sprintf(
+ /* translators: %s: Plugin name. */
+ _x( 'Network Activate %s', 'plugin' ),
+ response.pluginName
+ );
+
+ $message
+ .attr( 'aria-label', ariaLabel )
+ .text( buttonText );
+ } else {
+ buttonText = _x( 'Activate', 'plugin' );
+ ariaLabel = sprintf(
+ /* translators: %s: Plugin name. */
+ _x( 'Activate %s', 'plugin' ),
+ response.pluginName
+ );
+
+ $message
+ .attr( 'aria-label', ariaLabel )
+ .attr( 'data-name', response.pluginName )
+ .attr( 'data-slug', response.slug )
+ .attr( 'data-plugin', response.plugin )
+ .text( buttonText );
+ }
+
+ if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'dependencies-check-success',
+ slug: response.slug,
+ removeClasses: 'install-now installed button-disabled updated-message',
+ addClasses: 'activate-now button-primary',
+ text: buttonText,
+ ariaLabel: ariaLabel,
+ pluginName: response.pluginName,
+ plugin: response.plugin,
+ href: response.activateUrl
+ }
+ );
+ }
+ };
+
+ /**
+ * Updates the UI appropriately after a failed plugin dependencies check.
+ *
+ * @since 6.5.0
+ *
+ * @param {Object} response Response from the server.
+ * @param {string} response.slug Slug of the plugin to be checked.
+ * @param {string=} response.pluginName Optional. Name of the plugin to be checked.
+ * @param {string} response.errorCode Error code for the error that occurred.
+ * @param {string} response.errorMessage The error that occurred.
+ */
+ wp.updates.checkPluginDependenciesError = function( response ) {
+ var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.install-now' ),
+ buttonText = __( 'Activate' ),
+ ariaLabel = sprintf(
+ /* translators: 1: Plugin name, 2. The reason the plugin cannot be activated. */
+ _x( 'Cannot activate %1$s. %2$s', 'plugin' ),
+ response.pluginName,
+ response.errorMessage
+ ),
+ errorMessage;
+
+ if ( ! wp.updates.isValidResponse( response, 'check-dependencies' ) ) {
+ return;
+ }
+
+ errorMessage = sprintf(
+ /* translators: %s: Error string for a failed activation. */
+ __( 'Activation failed: %s' ),
+ response.errorMessage
+ );
+
+ wp.a11y.speak( errorMessage, 'assertive' );
+ $document.trigger( 'wp-check-plugin-dependencies-error', response );
+
+ $message
+ .removeClass( 'install-now installed updated-message' )
+ .addClass( 'activate-now button-primary' )
+ .attr( 'aria-label', ariaLabel )
+ .text( buttonText );
+
+ if ( 'plugin-information-footer' === $message.parent().attr('id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'dependencies-check-failed',
+ slug: response.slug,
+ removeClasses: 'install-now installed updated-message',
+ addClasses: 'activate-now button-primary',
+ text: buttonText,
+ ariaLabel: ariaLabel
+ }
+ );
+ }
+ };
+
+ /**
+ * Sends an Ajax request to the server to activate a plugin.
+ *
+ * @since 6.5.0
+ *
+ * @param {Object} args Arguments.
+ * @param {string} args.name The name of the plugin.
+ * @param {string} args.slug Plugin identifier in the WordPress.org Plugin repository.
+ * @param {string} args.plugin The plugin file, relative to the plugins directory.
+ * @param {activatePluginSuccess=} args.success Optional. Success callback. Default: wp.updates.activatePluginSuccess
+ * @param {activatePluginError=} args.error Optional. Error callback. Default: wp.updates.activatePluginError
+ * @return {$.promise} A jQuery promise that represents the request,
+ * decorated with an abort() method.
+ */
+ wp.updates.activatePlugin = function( args ) {
+ var $message = $( '.plugin-card-' + args.slug + ', #plugin-information-footer' ).find( '.activate-now, .activating-message' );
+
+ args = _.extend( {
+ success: wp.updates.activatePluginSuccess,
+ error: wp.updates.activatePluginError
+ }, args );
+
+ wp.a11y.speak( __( 'Activating... please wait.' ) );
+ $document.trigger( 'wp-activating-plugin', args );
+
+ if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'activating-plugin',
+ slug: args.slug,
+ removeClasses: 'installed updated-message button-primary',
+ addClasses: 'activating-message',
+ text: _x( 'Activating...', 'plugin' ),
+ ariaLabel: sprintf(
+ /* translators: %s: Plugin name. */
+ _x( 'Activating %s', 'plugin' ),
+ args.name
+ )
+ }
+ );
+ }
+
+ return wp.updates.ajax( 'activate-plugin', args );
+ };
+
+ /**
+ * Updates the UI appropriately after a successful plugin activation.
+ *
+ * @since 6.5.0
+ *
+ * @param {Object} response Response from the server.
+ * @param {string} response.slug Slug of the activated plugin.
+ * @param {string} response.pluginName Name of the activated plugin.
+ * @param {string} response.plugin The plugin file, relative to the plugins directory.
+ */
+ wp.updates.activatePluginSuccess = function( response ) {
+ var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.activating-message' ),
+ buttonText = _x( 'Activated!', 'plugin' ),
+ ariaLabel = sprintf(
+ /* translators: %s: The plugin name. */
+ '%s activated successfully.',
+ response.pluginName
+ );
+
+ wp.a11y.speak( __( 'Activation completed successfully.' ) );
+ $document.trigger( 'wp-plugin-activate-success', response );
+
+ $message
+ .removeClass( 'activating-message' )
+ .addClass( 'activated-message button-disabled' )
+ .attr( 'aria-label', ariaLabel )
+ .text( buttonText );
+
+ if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'activated-plugin',
+ slug: response.slug,
+ removeClasses: 'activating-message',
+ addClasses: 'activated-message button-disabled',
+ text: buttonText,
+ ariaLabel: ariaLabel
+ }
+ );
+ }
+
+ setTimeout( function() {
+ $message.removeClass( 'activated-message' )
+ .text( _x( 'Active', 'plugin' ) );
+
+ if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'plugin-active',
+ slug: response.slug,
+ removeClasses: 'activated-message',
+ text: _x( 'Active', 'plugin' ),
+ ariaLabel: sprintf(
+ /* translators: %s: The plugin name. */
+ '%s is active.',
+ response.pluginName
+ )
+ }
+ );
+ }
+ }, 1000 );
+ };
+
+ /**
+ * Updates the UI appropriately after a failed plugin activation.
+ *
+ * @since 6.5.0
+ *
+ * @param {Object} response Response from the server.
+ * @param {string} response.slug Slug of the plugin to be activated.
+ * @param {string=} response.pluginName Optional. Name of the plugin to be activated.
+ * @param {string} response.errorCode Error code for the error that occurred.
+ * @param {string} response.errorMessage The error that occurred.
+ */
+ wp.updates.activatePluginError = function( response ) {
+ var $message = $( '.plugin-card-' + response.slug + ', #plugin-information-footer' ).find( '.activating-message' ),
+ buttonText = __( 'Activation failed.' ),
+ ariaLabel = sprintf(
+ /* translators: %s: Plugin name. */
+ _x( '%s activation failed', 'plugin' ),
+ response.pluginName
+ ),
+ errorMessage;
+
+ if ( ! wp.updates.isValidResponse( response, 'activate' ) ) {
+ return;
+ }
+
+ errorMessage = sprintf(
+ /* translators: %s: Error string for a failed activation. */
+ __( 'Activation failed: %s' ),
+ response.errorMessage
+ );
+
+ wp.a11y.speak( errorMessage, 'assertive' );
+ $document.trigger( 'wp-plugin-activate-error', response );
+
+ $message
+ .removeClass( 'install-now installed activating-message' )
+ .addClass( 'button-disabled' )
+ .attr( 'aria-label', ariaLabel )
+ .text( buttonText );
+
+ if ( 'plugin-information-footer' === $message.parent().attr( 'id' ) ) {
+ wp.updates.setCardButtonStatus(
+ {
+ status: 'plugin-activation-failed',
+ slug: response.slug,
+ removeClasses: 'install-now installed activating-message',
+ addClasses: 'button-disabled',
+ text: buttonText,
+ ariaLabel: ariaLabel
+ }
+ );
+ }
+ };
+
/**
* Updates the UI appropriately after a successful importer install.
*
@@ -1970,6 +2354,16 @@
errorMessage = __( 'Installation failed: %s' );
break;
+ case 'check-dependencies':
+ /* translators: %s: Error string for a failed dependencies check. */
+ errorMessage = __( 'Dependencies check failed: %s' );
+ break;
+
+ case 'activate':
+ /* translators: %s: Error string for a failed activation. */
+ errorMessage = __( 'Activation failed: %s' );
+ break;
+
case 'delete':
/* translators: %s: Error string for a failed deletion. */
errorMessage = __( 'Deletion failed: %s' );
@@ -2025,7 +2419,7 @@
};
$( function() {
- var $pluginFilter = $( '#plugin-filter' ),
+ var $pluginFilter = $( '#plugin-filter, #plugin-information-footer' ),
$bulkActionForm = $( '#bulk-action-form' ),
$filesystemForm = $( '#request-filesystem-credentials-form' ),
$filesystemModal = $( '#request-filesystem-credentials-dialog' ),
@@ -2241,6 +2635,44 @@
} );
} );
+ /**
+ * Click handler for plugin activations in plugin activation view.
+ *
+ * @since 6.5.0
+ *
+ * @param {Event} event Event interface.
+ */
+ $pluginFilter.on( 'click', '.activate-now', function( event ) {
+ var $activateButton = $( event.target );
+
+ event.preventDefault();
+
+ if ( $activateButton.hasClass( 'activating-message' ) || $activateButton.hasClass( 'button-disabled' ) ) {
+ return;
+ }
+
+ $activateButton
+ .removeClass( 'activate-now button-primary' )
+ .addClass( 'activating-message' )
+ .attr(
+ 'aria-label',
+ sprintf(
+ /* translators: %s: Plugin name. */
+ _x( 'Activating %s', 'plugin' ),
+ $activateButton.data( 'name' )
+ )
+ )
+ .text( _x( 'Activating...', 'plugin' ) );
+
+ wp.updates.activatePlugin(
+ {
+ name: $activateButton.data( 'name' ),
+ slug: $activateButton.data( 'slug' ),
+ plugin: $activateButton.data( 'plugin' )
+ }
+ );
+ });
+
/**
* Click handler for importer plugins installs in the Import screen.
*
@@ -2766,35 +3198,6 @@
target.postMessage( JSON.stringify( update ), window.location.origin );
} );
- /**
- * Click handler for installing a plugin from the details modal on `plugin-install.php`.
- *
- * @since 4.6.0
- *
- * @param {Event} event Event interface.
- */
- $( '#plugin_install_from_iframe' ).on( 'click', function( event ) {
- var target = window.parent === window ? null : window.parent,
- install;
-
- $.support.postMessage = !! window.postMessage;
-
- if ( false === $.support.postMessage || null === target || -1 !== window.parent.location.pathname.indexOf( 'index.php' ) ) {
- return;
- }
-
- event.preventDefault();
-
- install = {
- action: 'install-plugin',
- data: {
- slug: $( this ).data( 'slug' )
- }
- };
-
- target.postMessage( JSON.stringify( install ), window.location.origin );
- } );
-
/**
* Handles postMessage events.
*
@@ -2818,7 +3221,45 @@
return;
}
- if ( ! message || 'undefined' === typeof message.action ) {
+ if ( ! message ) {
+ return;
+ }
+
+ if (
+ 'undefined' !== typeof message.status &&
+ 'undefined' !== typeof message.slug &&
+ 'undefined' !== typeof message.text &&
+ 'undefined' !== typeof message.ariaLabel
+ ) {
+ var $card = $( '.plugin-card-' + message.slug ),
+ $message = $card.find( '[data-slug="' + message.slug + '"]' );
+
+ if ( 'undefined' !== typeof message.removeClasses ) {
+ $message.removeClass( message.removeClasses );
+ }
+
+ if ( 'undefined' !== typeof message.addClasses ) {
+ $message.addClass( message.addClasses );
+ }
+
+ if ( '' === message.ariaLabel ) {
+ $message.removeAttr( 'aria-label' );
+ } else {
+ $message.attr( 'aria-label', message.ariaLabel );
+ }
+
+ if ( 'dependencies-check-success' === message.status ) {
+ $message
+ .attr( 'data-name', message.pluginName )
+ .attr( 'data-slug', message.slug )
+ .attr( 'data-plugin', message.plugin )
+ .attr( 'href', message.href );
+ }
+
+ $message.text( message.text );
+ }
+
+ if ( 'undefined' === typeof message.action || 'undefined' === typeof message.data.slug ) {
return;
}
@@ -2832,10 +3273,6 @@
case 'install-plugin':
case 'update-plugin':
- /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
- window.tb_remove();
- /* jscs:enable */
-
message.data = wp.updates._addCallbacks( message.data, message.action );
wp.updates.queue.push( message );
diff --git a/src/js/media/controllers/library.js b/src/js/media/controllers/library.js
index 2acc89a58692e..126ce8d7837fb 100644
--- a/src/js/media/controllers/library.js
+++ b/src/js/media/controllers/library.js
@@ -196,7 +196,7 @@ Library = wp.media.controller.State.extend(/** @lends wp.media.controller.Librar
isImageAttachment: function( attachment ) {
// If uploading, we know the filename but not the mime type.
if ( attachment.get('uploading') ) {
- return /\.(jpe?g|png|gif|webp)$/i.test( attachment.get('filename') );
+ return /\.(jpe?g|png|gif|webp|avif)$/i.test( attachment.get('filename') );
}
return attachment.get('type') === 'image';
diff --git a/src/js/media/views/attachment.js b/src/js/media/views/attachment.js
index a85b381c7017a..6f9f7f5001640 100644
--- a/src/js/media/views/attachment.js
+++ b/src/js/media/views/attachment.js
@@ -120,7 +120,7 @@ Attachment = View.extend(/** @lends wp.media.view.Attachment.prototype */{
options.can.save = !! options.nonces.update;
}
- if ( this.controller.state().get('allowLocalEdits') ) {
+ if ( this.controller.state().get('allowLocalEdits') && ! options.uploading ) {
options.allowLocalEdits = true;
}
diff --git a/src/wp-admin/admin-ajax.php b/src/wp-admin/admin-ajax.php
index fb191100299ce..b6645fd5ca0e8 100644
--- a/src/wp-admin/admin-ajax.php
+++ b/src/wp-admin/admin-ajax.php
@@ -117,6 +117,7 @@
'parse-media-shortcode',
'destroy-sessions',
'install-plugin',
+ 'activate-plugin',
'update-plugin',
'crop-image',
'generate-password',
@@ -169,6 +170,9 @@
add_action( 'wp_ajax_nopriv_heartbeat', 'wp_ajax_nopriv_heartbeat', 1 );
+// Register Plugin Dependencies Ajax calls.
+add_action( 'wp_ajax_check_plugin_dependencies', array( 'WP_Plugin_Dependencies', 'check_plugin_dependencies_during_ajax' ) );
+
$action = $_REQUEST['action'];
if ( is_user_logged_in() ) {
diff --git a/src/wp-admin/css/common.css b/src/wp-admin/css/common.css
index 2e6e605ce209e..98555d1c6c9a1 100644
--- a/src/wp-admin/css/common.css
+++ b/src/wp-admin/css/common.css
@@ -279,11 +279,9 @@ a:focus .media-icon img,
a:focus .plugin-icon,
.wp-person a:focus .gravatar {
color: #043959;
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
- /* Only visible in Windows High Contrast mode */
- outline: 1px solid transparent;
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
#adminmenu a:focus {
@@ -844,9 +842,9 @@ img.emoji {
}
.tagchecklist .ntdelbutton:focus .remove-tag-icon:before {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.key-labels label {
@@ -1460,10 +1458,9 @@ div.error p,
}
.notice-dismiss:focus {
- outline: none;
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.notice-success,
@@ -1500,6 +1497,22 @@ div.error {
background-color: #f0f6fc;
}
+#plugin-information-footer .update-now:not(.button-disabled):before {
+ color: #d63638;
+ content: "\f463";
+ display: inline-block;
+ font: normal 20px/1 dashicons;
+ margin: -3px 5px 0 -2px;
+ speak: never;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ vertical-align: middle;
+}
+
+#plugin-information-footer .notice {
+ margin-top: -5px;
+}
+
.update-message p:before,
.updating-message p:before,
.updated-message p:before,
@@ -1507,7 +1520,9 @@ div.error {
.button.updating-message:before,
.button.updated-message:before,
.button.installed:before,
-.button.installing:before {
+.button.installing:before,
+.button.activating-message:before,
+.button.activated-message:before {
display: inline-block;
font: normal 20px/1 'dashicons';
-webkit-font-smoothing: antialiased;
@@ -1544,7 +1559,8 @@ div.error {
.updating-message p:before,
.import-php .updating-message:before,
.button.updating-message:before,
-.button.installing:before {
+.button.installing:before,
+.button.activating-message:before {
color: #d63638;
content: "\f463";
}
@@ -1554,6 +1570,7 @@ div.error {
.import-php .updating-message:before,
.button.updating-message:before,
.button.installing:before,
+.button.activating-message:before,
.plugins .column-auto-updates .dashicons-update.spin,
.theme-overlay .theme-autoupdate .dashicons-update.spin {
animation: rotation 2s infinite linear;
@@ -1564,6 +1581,7 @@ div.error {
.import-php .updating-message:before,
.button.updating-message:before,
.button.installing:before,
+ .button.activating-message:before,
.plugins .column-auto-updates .dashicons-update.spin,
.theme-overlay .theme-autoupdate .dashicons-update.spin {
animation: none;
@@ -1577,7 +1595,8 @@ div.error {
/* Updated icon (check mark). */
.updated-message p:before,
.installed p:before,
-.button.updated-message:before {
+.button.updated-message:before,
+.button.activated-message:before {
color: #68de7c;
content: "\f147";
}
@@ -1662,19 +1681,37 @@ p.auto-update-status {
.button.updating-message:before,
.button.updated-message:before,
.button.installed:before,
-.button.installing:before {
+.button.installing:before,
+.button.activated-message:before,
+.button.activating-message:before {
margin: 3px 5px 0 -2px;
}
-.button-primary.updating-message:before {
+#plugin-information-footer .button.installed:before,
+#plugin-information-footer .button.installing:before,
+#plugin-information-footer .button.updating-message:before,
+#plugin-information-footer .button.updated-message:before,
+#plugin-information-footer .button.activated-message:before,
+#plugin-information-footer .button.activating-message:before {
+ margin: 9px 5px 0 -2px;
+}
+
+#plugin-information-footer .button.update-now.updating-message:before {
+ margin: -3px 5px 0 -2px;
+}
+
+.button-primary.updating-message:before,
+.button-primary.activating-message:before {
color: #fff;
}
-.button-primary.updated-message:before {
+.button-primary.updated-message:before,
+.button-primary.activated-message:before {
color: #9ec2e6;
}
-.button.updated-message {
+.button.updated-message,
+.button.activated-message {
transition-property: border, background, color;
transition-duration: .05s;
transition-timing-function: ease-in-out;
@@ -1764,8 +1801,10 @@ p.auto-update-status {
}
#screen-meta-links .show-settings:focus {
- border-color: #4f94d4;
- box-shadow: 0 0 3px rgba(34, 113, 177, 0.8);
+ border-color: #2271b1;
+ box-shadow: 0 0 0 1px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
#screen-meta-links .show-settings:active {
@@ -2103,8 +2142,8 @@ html.wp-toolbar {
.postbox .handle-order-higher,
.postbox .handle-order-lower,
.postbox .handlediv {
- width: 36px;
- height: 36px;
+ width: 1.62rem;
+ height: 1.62rem;
margin: 0;
padding: 0;
border: 0;
@@ -3021,7 +3060,6 @@ div.action-links {
}
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
#TB_window.plugin-details-modal.thickbox-loading:before {
@@ -3147,11 +3185,10 @@ img {
.postbox .handle-order-higher:focus,
.postbox .handle-order-lower:focus,
.postbox .handlediv:focus {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: inset 0 0 0 2px #2271b1;
+ border-radius: 50%;
/* Only visible in Windows High Contrast mode */
- outline: 1px solid transparent;
+ outline: 2px solid transparent;
}
.postbox .handle-order-higher:focus .order-higher-indicator::before,
@@ -3176,7 +3213,6 @@ img {
font-family: Consolas, Monaco, monospace;
font-size: 13px;
background: #f6f7f7;
- -o-tab-size: 4;
tab-size: 4;
}
@@ -3251,12 +3287,17 @@ img {
[role="treeitem"] {
outline: 0;
}
+
+[role="treeitem"] a:focus,
[role="treeitem"] .folder-label.focus {
color: #043959;
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ /* Reset default focus style. */
+ box-shadow: none;
+ /* Use an inset outline instead, so it's visible also over the current file item. */
+ outline: 2px solid #2271b1;
+ outline-offset: -2px;
}
+
[role="treeitem"].hover,
[role="treeitem"] .folder-label.hover {
background-color: #f0f0f1;
@@ -3398,6 +3439,10 @@ img {
text-decoration: none;
}
+#templateside li.current-file > a {
+ padding-bottom: 0;
+}
+
#templateside li:not(.howto) > a:first-of-type {
padding-top: 0;
}
@@ -3483,13 +3528,13 @@ img {
.accordion-section-title:hover:after {
color: #1d2327;
/* Only visible in Windows High Contrast mode */
- outline: 1px solid transparent;
+ outline: 2px solid transparent;
}
.widget-top .widget-action:focus .toggle-indicator:before {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.control-section .accordion-section-title:after,
@@ -3765,7 +3810,6 @@ img {
* HiDPI Displays
*/
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
/* Back-compat for pre-3.8 */
div.star-holder,
diff --git a/src/wp-admin/css/customize-controls.css b/src/wp-admin/css/customize-controls.css
index 9422d0cc8c65e..ca21fe2889a33 100644
--- a/src/wp-admin/css/customize-controls.css
+++ b/src/wp-admin/css/customize-controls.css
@@ -1566,10 +1566,9 @@ p.customize-section-description {
}
.customize-control-header .choice:focus {
- outline: none;
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 3px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.customize-control-header .uploaded div:last-child > .choice {
@@ -1604,7 +1603,6 @@ p.customize-section-description {
font-family: Consolas, Monaco, monospace;
font-size: 12px;
padding: 6px 8px;
- -o-tab-size: 2;
tab-size: 2;
}
.customize-control-code_editor textarea,
@@ -2680,9 +2678,9 @@ body.adding-widget .add-new-widget:before,
#available-widgets-filter .clear-results:focus,
#available-menu-items-search .clear-results:focus {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
#available-menu-items-search .search-icon:after,
diff --git a/src/wp-admin/css/customize-nav-menus.css b/src/wp-admin/css/customize-nav-menus.css
index 46ac3066efd1d..c645bb5f11d00 100644
--- a/src/wp-admin/css/customize-nav-menus.css
+++ b/src/wp-admin/css/customize-nav-menus.css
@@ -271,7 +271,7 @@
.customize-screen-options-toggle:focus,
#customize-controls .customize-info .customize-help-toggle:focus {
/* Only visible in Windows High Contrast mode */
- outline: 1px solid transparent;
+ outline: 2px solid transparent;
}
.customize-screen-options-toggle:before {
@@ -864,9 +864,9 @@ li.assigned-to-menu-location .add-new-menu-item {
.menu-delete:focus,
.menu-item-bar .item-delete:focus:before,
#available-menu-items .item-add:focus:before {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
diff --git a/src/wp-admin/css/deprecated-media.css b/src/wp-admin/css/deprecated-media.css
index 359fc59e3c3b5..36fafeb65f76b 100644
--- a/src/wp-admin/css/deprecated-media.css
+++ b/src/wp-admin/css/deprecated-media.css
@@ -404,7 +404,6 @@ table.not-image tr.image-only {
* HiDPI Displays
*/
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
.image-align-none-label {
diff --git a/src/wp-admin/css/edit.css b/src/wp-admin/css/edit.css
index 7973154666a42..757d676b727f5 100644
--- a/src/wp-admin/css/edit.css
+++ b/src/wp-admin/css/edit.css
@@ -1293,8 +1293,9 @@ div.tabs-panel-inactive {
}
div.tabs-panel-active:focus {
- box-shadow: inset 0 0 0 1px #4f94d4, inset 0 0 2px 1px rgba(79, 148, 212, 0.8);
- outline: 0 none;
+ box-shadow: inset 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
#front-page-warning,
@@ -1688,7 +1689,6 @@ table.links-table {
* HiDPI Displays
*/
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
#content-resize-handle,
#post-body .wp_themeSkin .mceStatusbar a.mceResize {
diff --git a/src/wp-admin/css/forms.css b/src/wp-admin/css/forms.css
index 7274b0bcd7fee..16f7cb899fcde 100644
--- a/src/wp-admin/css/forms.css
+++ b/src/wp-admin/css/forms.css
@@ -22,10 +22,6 @@ textarea {
resize: vertical;
}
-label {
- cursor: pointer;
-}
-
input,
select {
margin: 0 1px;
@@ -287,8 +283,10 @@ textarea.disabled {
input[type="file"]:disabled,
input[type="file"].disabled,
+input[type="file"][aria-disabled="true"],
input[type="range"]:disabled,
-input[type="range"].disabled {
+input[type="range"].disabled,
+input[type="range"][aria-disabled="true"] {
background: none;
box-shadow: none;
cursor: default;
@@ -296,13 +294,16 @@ input[type="range"].disabled {
input[type="checkbox"]:disabled,
input[type="checkbox"].disabled,
+input[type="checkbox"][aria-disabled="true"],
input[type="radio"]:disabled,
input[type="radio"].disabled,
+input[type="radio"][aria-disabled="true"],
input[type="checkbox"]:disabled:checked:before,
input[type="checkbox"].disabled:checked:before,
input[type="radio"]:disabled:checked:before,
input[type="radio"].disabled:checked:before {
opacity: 0.7;
+ cursor: default;
}
/*------------------------------------------------------------------------------
@@ -356,6 +357,10 @@ input[type="radio"].disabled:checked:before {
transform: none;
}
+.wp-core-ui select[aria-disabled="true"] {
+ cursor: default;
+}
+
/* Reset Firefox inner outline that appears on :focus. */
/* This ruleset overrides the color change on :focus thus needs to be after select:focus. */
.wp-core-ui select:-moz-focusring {
@@ -674,6 +679,13 @@ fieldset label,
border-color: #68de7c;
}
+#pass1:focus,
+#pass1-text:focus {
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
+}
+
.pw-weak {
display: none;
}
diff --git a/src/wp-admin/css/install.css b/src/wp-admin/css/install.css
index 144f99c97879c..29e85715f68a0 100644
--- a/src/wp-admin/css/install.css
+++ b/src/wp-admin/css/install.css
@@ -26,9 +26,9 @@ a:active {
a:focus {
color: #043959;
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
h1, h2 {
@@ -72,10 +72,6 @@ fieldset {
margin: 0;
}
-label {
- cursor: pointer;
-}
-
#logo {
margin: -130px auto 25px;
padding: 0 0 25px;
@@ -391,7 +387,6 @@ body.language-chooser {
* HiDPI Displays
*/
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
.spinner {
diff --git a/src/wp-admin/css/list-tables.css b/src/wp-admin/css/list-tables.css
index 07cbc6229d07a..098c31a6d1148 100644
--- a/src/wp-admin/css/list-tables.css
+++ b/src/wp-admin/css/list-tables.css
@@ -261,8 +261,10 @@
}
th .comment-grey-bubble {
- height: 16px;
width: 16px;
+ /* Make sure the link clickable area fills the entire table header. */
+ position: relative;
+ top: 2px;
}
th .comment-grey-bubble:before {
@@ -343,7 +345,6 @@ table.fixed {
.fixed .column-comments {
width: 5.5em;
- padding: 8px 0;
text-align: left;
}
@@ -537,9 +538,9 @@ th.sorted.desc:hover .sorting-indicator.asc:before {
}
.wp-list-table .toggle-row:focus:before {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.wp-list-table .toggle-row:active {
@@ -585,8 +586,7 @@ th.sorted.desc:hover .sorting-indicator.asc:before {
z-index: 1;
}
-.check-column input:where(:not(:disabled)):hover,
-.check-column:hover input:where(:not(:disabled)) {
+.check-column .label-covers-full-cell:hover + input:not(:disabled) {
box-shadow: 0 0 0 1px #2271b1;
}
@@ -650,9 +650,11 @@ th.sorted a {
padding: 8px;
}
-.fixed .column-comments.sortable a,
-.fixed .column-comments.sorted a {
- padding: 8px 0;
+th.sortable a:focus,
+th.sorted a:focus {
+ box-shadow: inset 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
th.sortable a span,
@@ -1548,10 +1550,96 @@ div.action-links,
line-height: 1.3;
}
-.plugin-card .name,
.plugin-card .desc {
- margin-left: 148px; /* icon + margin */
- margin-right: 128px; /* action links + margin */
+ margin-inline: 0;
+}
+
+.plugin-card .name, .plugin-card .desc > p {
+ margin-left: 148px;
+}
+
+@media (min-width: 1101px) {
+ .plugin-card .name, .plugin-card .desc > p {
+ margin-right: 128px;
+ }
+}
+
+@media (min-width: 481px) and (max-width: 781px) {
+ .plugin-card .name, .plugin-card .desc > p {
+ margin-right: 128px;
+ }
+}
+
+.plugin-card .column-description {
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+}
+
+.plugin-card .column-description > p {
+ margin-top: 0;
+}
+
+.plugin-card .column-description .authors {
+ order: 1;
+}
+
+.plugin-card .column-description .plugin-dependencies {
+ order: 2;
+}
+
+.plugin-card .column-description p:empty {
+ display: none;
+}
+
+.plugin-card .plugin-dependencies {
+ background-color: #e5f5fa;
+ border-left: 3px solid #72aee6;
+ margin-bottom: .5em;
+ padding: 15px;
+}
+
+.plugin-card .plugin-dependencies-explainer-text {
+ margin-block: 0;
+}
+
+.plugin-card .plugin-dependency {
+ align-items: center;
+ display: flex;
+ flex-wrap: wrap;
+ margin-top: .5em;
+ column-gap: 1%;
+ row-gap: .5em;
+}
+
+.plugin-card .plugin-dependency:nth-child(2),
+.plugin-card .plugin-dependency:last-child {
+ margin-top: 1em;
+}
+
+.plugin-card .plugin-dependency-name {
+ flex-basis: 74%;
+}
+
+.plugin-card .plugin-dependency .more-details-link {
+ margin-left: auto;
+}
+
+.rtl .plugin-card .plugin-dependency .more-details-link {
+ margin-right: auto;
+}
+
+@media (max-width: 939px) {
+ .plugin-card .plugin-dependency-name {
+ flex-basis: 69%;
+ }
+ .plugin-card .plugin-dependency .more-details-link {
+ }
+}
+
+.plugins #the-list .required-by,
+.plugins #the-list .requires {
+ margin-top: 1em;
}
.plugin-card .action-links {
@@ -2143,6 +2231,11 @@ div.action-links,
padding: 10px 9px; /* reset from other list tables that have a label at this width */
}
+ #wpbody-content .wp-list-table.plugins .plugin-deleted-tr td,
+ #wpbody-content .wp-list-table.plugins .no-items td {
+ display: table-cell;
+ }
+
/* Plugin description hidden via Screen Options */
#wpbody-content .wp-list-table.plugins .desc.hidden {
display: none;
diff --git a/src/wp-admin/css/login.css b/src/wp-admin/css/login.css
index fe790f0b42d1f..b9f488bd6c480 100644
--- a/src/wp-admin/css/login.css
+++ b/src/wp-admin/css/login.css
@@ -32,9 +32,9 @@ a:active {
a:focus {
color: #043959;
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
p {
diff --git a/src/wp-admin/css/media.css b/src/wp-admin/css/media.css
index 623f808887e03..4463ae373d32a 100644
--- a/src/wp-admin/css/media.css
+++ b/src/wp-admin/css/media.css
@@ -356,9 +356,7 @@
}
#find-posts-close:focus {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
outline-offset: -2px;
@@ -533,9 +531,7 @@ border color while dragging a file over the uploader drop area */
.media-frame.mode-grid .attachment:focus,
.media-frame.mode-grid .selected.attachment:focus,
.media-frame.mode-grid .attachment.details:focus {
- box-shadow:
- inset 0 0 2px 3px #f0f0f1,
- inset 0 0 0 7px #4f94d4;
+ box-shadow: inset 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
outline-offset: -6px;
@@ -1172,8 +1168,8 @@ border color while dragging a file over the uploader drop area */
.image-editor .imgedit-settings .imgedit-help-toggle:focus {
color: #2271b1;
- border-color: #4f94d4;
- box-shadow: 0 0 3px rgba(34, 113, 177, 0.8);
+ border-color: #2271b1;
+ box-shadow: 0 0 0 1px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
}
@@ -1272,7 +1268,6 @@ audio, video {
* HiDPI Displays
*/
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
.imgedit-wait:before {
background-image: url(../images/spinner-2x.gif);
diff --git a/src/wp-admin/css/nav-menus.css b/src/wp-admin/css/nav-menus.css
index 4fd178dbb0177..ff586a4ee7c98 100644
--- a/src/wp-admin/css/nav-menus.css
+++ b/src/wp-admin/css/nav-menus.css
@@ -103,7 +103,7 @@ ul.add-menu-item-tabs li {
#nav-menu-bulk-actions-bottom {
margin: 1em 0;
- margin: calc( 1em + 9px ) 0 ;
+ margin: calc( 1em + 9px ) 0;
}
.bulk-actions input.button {
@@ -732,9 +732,9 @@ body.menu-max-depth-11 { min-width: 1280px !important; }
}
.nav-menus-php .item-edit:focus:before {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
/* Menu editing */
@@ -991,7 +991,7 @@ body.menu-max-depth-11 { min-width: 1280px !important; }
@media only screen and (min-width: 783px) {
@supports (position: sticky) and (scroll-margin-bottom: 130px) {
-
+
#nav-menu-footer {
position: sticky;
bottom: 0;
diff --git a/src/wp-admin/css/revisions.css b/src/wp-admin/css/revisions.css
index e523ee431ce93..46cf263b5e67c 100644
--- a/src/wp-admin/css/revisions.css
+++ b/src/wp-admin/css/revisions.css
@@ -558,7 +558,6 @@ div.revisions-controls > .wp-slider > .ui-slider-handle {
* HiDPI Displays
*/
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
.revision-tick.completed-false {
background-image: url(../images/spinner-2x.gif);
diff --git a/src/wp-admin/css/themes.css b/src/wp-admin/css/themes.css
index 07f33565014e0..a68abbca04f94 100644
--- a/src/wp-admin/css/themes.css
+++ b/src/wp-admin/css/themes.css
@@ -176,12 +176,14 @@ body.js .theme-browser.search-loading {
}
.theme-browser .theme .more-details:focus {
- box-shadow: 0 0 0 1px #fff, 0 0 0 3px #2271b1;
+ box-shadow: 0 0 0 2px #2271b1;
}
.theme-browser .theme.focus {
- border-color: #4f94d4;
- box-shadow: 0 0 2px rgba(79, 148, 212, 0.8);
+ border-color: #2271b1;
+ box-shadow: 0 0 0 1px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.theme-browser .theme.focus .more-details {
@@ -1586,9 +1588,9 @@ body.full-overlay-active {
.wp-full-overlay .collapse-sidebar:hover .collapse-sidebar-arrow,
.wp-full-overlay .collapse-sidebar:focus .collapse-sidebar-arrow {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.wp-full-overlay .collapse-sidebar-label {
@@ -1938,7 +1940,6 @@ body.full-overlay-active {
* HiDPI Displays
*/
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
.wp-full-overlay .collapse-sidebar-arrow {
background-image: url(../images/arrows-2x.png);
diff --git a/src/wp-admin/css/widgets.css b/src/wp-admin/css/widgets.css
index 8faca8f9ac42d..e24140926eebc 100644
--- a/src/wp-admin/css/widgets.css
+++ b/src/wp-admin/css/widgets.css
@@ -336,9 +336,9 @@
}
.sidebar-name .handlediv:focus .toggle-indicator:before {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.sidebar-name h2,
diff --git a/src/wp-admin/images/bubble_bg-2x.gif b/src/wp-admin/images/bubble_bg-2x.gif
index 8e34e01dcd4ea..21302a34dc133 100644
Binary files a/src/wp-admin/images/bubble_bg-2x.gif and b/src/wp-admin/images/bubble_bg-2x.gif differ
diff --git a/src/wp-admin/images/loading.gif b/src/wp-admin/images/loading.gif
index fdc589f809793..79d140e838ac3 100644
Binary files a/src/wp-admin/images/loading.gif and b/src/wp-admin/images/loading.gif differ
diff --git a/src/wp-admin/images/media-button-music.gif b/src/wp-admin/images/media-button-music.gif
index 3bcda105c6f50..daa9101833a4f 100644
Binary files a/src/wp-admin/images/media-button-music.gif and b/src/wp-admin/images/media-button-music.gif differ
diff --git a/src/wp-admin/images/media-button-other.gif b/src/wp-admin/images/media-button-other.gif
index cfe16a83dfd79..0a8920066c7af 100644
Binary files a/src/wp-admin/images/media-button-other.gif and b/src/wp-admin/images/media-button-other.gif differ
diff --git a/src/wp-admin/images/wpspin_light-2x.gif b/src/wp-admin/images/wpspin_light-2x.gif
index 08e47e8211c4d..978f585b983b2 100644
Binary files a/src/wp-admin/images/wpspin_light-2x.gif and b/src/wp-admin/images/wpspin_light-2x.gif differ
diff --git a/src/wp-admin/images/wpspin_light.gif b/src/wp-admin/images/wpspin_light.gif
index fbf9be46c1094..b9b7ae4875168 100644
Binary files a/src/wp-admin/images/wpspin_light.gif and b/src/wp-admin/images/wpspin_light.gif differ
diff --git a/src/wp-admin/images/xit.gif b/src/wp-admin/images/xit.gif
index b11c5d43e9bce..9e62856adb47e 100644
Binary files a/src/wp-admin/images/xit.gif and b/src/wp-admin/images/xit.gif differ
diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php
index b8e8246eb7c52..7541b28d51fdc 100644
--- a/src/wp-admin/includes/ajax-actions.php
+++ b/src/wp-admin/includes/ajax-actions.php
@@ -4578,6 +4578,56 @@ function wp_ajax_install_plugin() {
wp_send_json_success( $status );
}
+/**
+ * Handles activating a plugin via AJAX.
+ *
+ * @since 6.5.0
+ */
+function wp_ajax_activate_plugin() {
+ check_ajax_referer( 'updates' );
+
+ if ( empty( $_POST['name'] ) || empty( $_POST['slug'] ) || empty( $_POST['plugin'] ) ) {
+ wp_send_json_error(
+ array(
+ 'slug' => '',
+ 'pluginName' => '',
+ 'plugin' => '',
+ 'errorCode' => 'no_plugin_specified',
+ 'errorMessage' => __( 'No plugin specified.' ),
+ )
+ );
+ }
+
+ $status = array(
+ 'activate' => 'plugin',
+ 'slug' => wp_unslash( $_POST['slug'] ),
+ 'pluginName' => wp_unslash( $_POST['name'] ),
+ 'plugin' => wp_unslash( $_POST['plugin'] ),
+ );
+
+ if ( ! current_user_can( 'activate_plugin', $status['plugin'] ) ) {
+ $status['errorMessage'] = __( 'Sorry, you are not allowed to activate plugins on this site.' );
+ wp_send_json_error( $status );
+ }
+
+ if ( is_plugin_active( $status['plugin'] ) ) {
+ $status['errorMessage'] = sprintf(
+ /* translators: %s: Plugin name. */
+ __( '%s is already active.' ),
+ $status['pluginName']
+ );
+ }
+
+ $activated = activate_plugin( $status['plugin'] );
+
+ if ( is_wp_error( $activated ) ) {
+ $status['errorMessage'] = $activated->get_error_message();
+ wp_send_json_error( $status );
+ }
+
+ wp_send_json_success( $status );
+}
+
/**
* Handles updating a plugin via AJAX.
*
diff --git a/src/wp-admin/includes/class-custom-image-header.php b/src/wp-admin/includes/class-custom-image-header.php
index a4b04bf3fc250..5c3271478b62f 100644
--- a/src/wp-admin/includes/class-custom-image-header.php
+++ b/src/wp-admin/includes/class-custom-image-header.php
@@ -934,7 +934,7 @@ public function step_2() {
-
+
diff --git a/src/wp-admin/includes/class-file-upload-upgrader.php b/src/wp-admin/includes/class-file-upload-upgrader.php
index 2b76e41ea61d1..1201c6d188920 100644
--- a/src/wp-admin/includes/class-file-upload-upgrader.php
+++ b/src/wp-admin/includes/class-file-upload-upgrader.php
@@ -69,6 +69,13 @@ public function __construct( $form, $urlholder ) {
wp_die( $file['error'] );
}
+ if ( 'pluginzip' === $form || 'themezip' === $form ) {
+ if ( ! wp_zip_file_is_valid( $file['file'] ) ) {
+ wp_delete_file( $file['file'] );
+ wp_die( __( 'Incompatible Archive.' ) );
+ }
+ }
+
$this->filename = $_FILES[ $form ]['name'];
$this->package = $file['file'];
diff --git a/src/wp-admin/includes/class-language-pack-upgrader.php b/src/wp-admin/includes/class-language-pack-upgrader.php
index 3c3d42a56a9c8..855dbe642ad25 100644
--- a/src/wp-admin/includes/class-language-pack-upgrader.php
+++ b/src/wp-admin/includes/class-language-pack-upgrader.php
@@ -409,12 +409,16 @@ public function clear_destination( $remote_destination ) {
$files = array(
$remote_destination . $language_update->language . '.po',
$remote_destination . $language_update->language . '.mo',
+ $remote_destination . $language_update->language . '.l10n.php',
$remote_destination . 'admin-' . $language_update->language . '.po',
$remote_destination . 'admin-' . $language_update->language . '.mo',
+ $remote_destination . 'admin-' . $language_update->language . '.l10n.php',
$remote_destination . 'admin-network-' . $language_update->language . '.po',
$remote_destination . 'admin-network-' . $language_update->language . '.mo',
+ $remote_destination . 'admin-network-' . $language_update->language . '.l10n.php',
$remote_destination . 'continents-cities-' . $language_update->language . '.po',
$remote_destination . 'continents-cities-' . $language_update->language . '.mo',
+ $remote_destination . 'continents-cities-' . $language_update->language . '.l10n.php',
);
$json_translation_files = glob( $language_directory . $language_update->language . '-*.json' );
@@ -427,6 +431,7 @@ public function clear_destination( $remote_destination ) {
$files = array(
$remote_destination . $language_update->slug . '-' . $language_update->language . '.po',
$remote_destination . $language_update->slug . '-' . $language_update->language . '.mo',
+ $remote_destination . $language_update->slug . '-' . $language_update->language . '.l10n.php',
);
$language_directory = $language_directory . $language_update->type . 's/';
diff --git a/src/wp-admin/includes/class-plugin-upgrader.php b/src/wp-admin/includes/class-plugin-upgrader.php
index 091cfebc188ff..97343fcf9ded8 100644
--- a/src/wp-admin/includes/class-plugin-upgrader.php
+++ b/src/wp-admin/includes/class-plugin-upgrader.php
@@ -155,6 +155,12 @@ public function install( $package, $args = array() ) {
// Force refresh of plugin update information.
wp_clean_plugins_cache( $parsed_args['clear_update_cache'] );
+ $all_plugin_data = get_option( 'plugin_data', array() );
+ $plugin_file = $this->new_plugin_data['file'];
+ unset( $this->new_plugin_data['file'] );
+ $all_plugin_data[ $plugin_file ] = $this->new_plugin_data;
+ update_option( 'plugin_data', $all_plugin_data );
+
if ( $parsed_args['overwrite_package'] ) {
/**
* Fires when the upgrader has successfully overwritten a currently installed
@@ -482,7 +488,16 @@ public function check_package( $source ) {
foreach ( $files as $file ) {
$info = get_plugin_data( $file, false, false );
if ( ! empty( $info['Name'] ) ) {
- $this->new_plugin_data = $info;
+ $basename = basename( $file );
+ $dirname = basename( dirname( $file ) );
+
+ if ( '.' === $dirname ) {
+ $plugin_file = $basename;
+ } else {
+ $plugin_file = "$dirname/$basename";
+ }
+ $this->new_plugin_data = ( $info );
+ $this->new_plugin_data['file'] = $plugin_file;
break;
}
}
diff --git a/src/wp-admin/includes/class-wp-plugin-install-list-table.php b/src/wp-admin/includes/class-wp-plugin-install-list-table.php
index 7823f00b70996..132af29452ec2 100644
--- a/src/wp-admin/includes/class-wp-plugin-install-list-table.php
+++ b/src/wp-admin/includes/class-wp-plugin-install-list-table.php
@@ -525,6 +525,8 @@ public function display_rows() {
// Remove any HTML from the description.
$description = strip_tags( $plugin['short_description'] );
+ $description .= $this->get_dependencies_notice( $plugin );
+
/**
* Filters the plugin card description on the Add Plugins screen.
*
@@ -555,102 +557,7 @@ public function display_rows() {
$action_links = array();
- if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
- $status = install_plugin_install_status( $plugin );
-
- switch ( $status['status'] ) {
- case 'install':
- if ( $status['url'] ) {
- if ( $compatible_php && $compatible_wp ) {
- $action_links[] = sprintf(
- '%s ',
- esc_attr( $plugin['slug'] ),
- esc_url( $status['url'] ),
- /* translators: %s: Plugin name and version. */
- esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ),
- esc_attr( $name ),
- __( 'Install Now' )
- );
- } else {
- $action_links[] = sprintf(
- '%s ',
- _x( 'Cannot Install', 'plugin' )
- );
- }
- }
- break;
-
- case 'update_available':
- if ( $status['url'] ) {
- if ( $compatible_php && $compatible_wp ) {
- $action_links[] = sprintf(
- '%s ',
- esc_attr( $status['file'] ),
- esc_attr( $plugin['slug'] ),
- esc_url( $status['url'] ),
- /* translators: %s: Plugin name and version. */
- esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $name ) ),
- esc_attr( $name ),
- __( 'Update Now' )
- );
- } else {
- $action_links[] = sprintf(
- '%s ',
- _x( 'Cannot Update', 'plugin' )
- );
- }
- }
- break;
-
- case 'latest_installed':
- case 'newer_installed':
- if ( is_plugin_active( $status['file'] ) ) {
- $action_links[] = sprintf(
- '%s ',
- _x( 'Active', 'plugin' )
- );
- } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
- if ( $compatible_php && $compatible_wp ) {
- $button_text = __( 'Activate' );
- /* translators: %s: Plugin name. */
- $button_label = _x( 'Activate %s', 'plugin' );
- $activate_url = add_query_arg(
- array(
- '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
- 'action' => 'activate',
- 'plugin' => $status['file'],
- ),
- network_admin_url( 'plugins.php' )
- );
-
- if ( is_network_admin() ) {
- $button_text = __( 'Network Activate' );
- /* translators: %s: Plugin name. */
- $button_label = _x( 'Network Activate %s', 'plugin' );
- $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
- }
-
- $action_links[] = sprintf(
- '%3$s ',
- esc_url( $activate_url ),
- esc_attr( sprintf( $button_label, $plugin['name'] ) ),
- $button_text
- );
- } else {
- $action_links[] = sprintf(
- '%s ',
- _x( 'Cannot Activate', 'plugin' )
- );
- }
- } else {
- $action_links[] = sprintf(
- '%s ',
- _x( 'Installed', 'plugin' )
- );
- }
- break;
- }
- }
+ $action_links[] = wp_get_plugin_action_button( $name, $plugin, $compatible_php, $compatible_wp );
$details_link = self_admin_url(
'plugin-install.php?tab=plugin-information&plugin=' . $plugin['slug'] .
@@ -828,4 +735,90 @@ public function display_rows() {
echo '';
}
}
+
+ /**
+ * Returns a notice containing a list of dependencies required by the plugin.
+ *
+ * @since 6.5.0
+ *
+ * @param array $plugin_data An array of plugin data. See {@see plugins_api()}
+ * for the list of possible values.
+ * @return string A notice containing a list of dependencies required by the plugin,
+ * or an empty string if none is required.
+ */
+ protected function get_dependencies_notice( $plugin_data ) {
+ if ( empty( $plugin_data['requires_plugins'] ) ) {
+ return '';
+ }
+
+ $no_name_markup = '%s
';
+ $has_name_markup = '%s %s
';
+
+ $dependencies_list = '';
+ foreach ( $plugin_data['requires_plugins'] as $dependency ) {
+ $dependency_data = WP_Plugin_Dependencies::get_dependency_data( $dependency );
+
+ if (
+ false !== $dependency_data &&
+ ! empty( $dependency_data['name'] ) &&
+ ! empty( $dependency_data['slug'] ) &&
+ ! empty( $dependency_data['version'] )
+ ) {
+ $more_details_link = $this->get_more_details_link( $dependency_data['name'], $dependency_data['slug'] );
+ $dependencies_list .= sprintf( $has_name_markup, esc_html( $dependency_data['name'] ), $more_details_link );
+ continue;
+ }
+
+ $result = plugins_api( 'plugin_information', array( 'slug' => $dependency ) );
+
+ if ( ! empty( $result->name ) ) {
+ $more_details_link = $this->get_more_details_link( $result->name, $result->slug );
+ $dependencies_list .= sprintf( $has_name_markup, esc_html( $result->name ), $more_details_link );
+ continue;
+ }
+
+ $dependencies_list .= sprintf( $no_name_markup, esc_html( $dependency ) );
+ }
+
+ $dependencies_notice = sprintf(
+ '',
+ '' . __( 'Additional plugins are required' ) . ' ',
+ $dependencies_list
+ );
+
+ return $dependencies_notice;
+ }
+
+ /**
+ * Creates a 'More details' link for the plugin.
+ *
+ * @since 6.5.0
+ *
+ * @param string $name The plugin's name.
+ * @param string $slug The plugin's slug.
+ * @return string The 'More details' link for the plugin.
+ */
+ protected function get_more_details_link( $name, $slug ) {
+ $url = add_query_arg(
+ array(
+ 'tab' => 'plugin-information',
+ 'plugin' => $slug,
+ 'TB_iframe' => 'true',
+ 'width' => '600',
+ 'height' => '550',
+ ),
+ network_admin_url( 'plugin-install.php' )
+ );
+
+ $more_details_link = sprintf(
+ '%4$s ',
+ esc_url( $url ),
+ /* translators: %s: Plugin name. */
+ sprintf( __( 'More information about %s' ), esc_html( $name ) ),
+ esc_attr( $name ),
+ __( 'More Details' )
+ );
+
+ return $more_details_link;
+ }
}
diff --git a/src/wp-admin/includes/class-wp-plugins-list-table.php b/src/wp-admin/includes/class-wp-plugins-list-table.php
index 5c92fba7aad1c..ad0e6d7eb864a 100644
--- a/src/wp-admin/includes/class-wp-plugins-list-table.php
+++ b/src/wp-admin/includes/class-wp-plugins-list-table.php
@@ -754,6 +754,11 @@ public function single_row( $item ) {
$compatible_php = is_php_version_compatible( $requires_php );
$compatible_wp = is_wp_version_compatible( $requires_wp );
+ $has_dependents = WP_Plugin_Dependencies::has_dependents( $plugin_file );
+ $has_active_dependents = WP_Plugin_Dependencies::has_active_dependents( $plugin_file );
+ $has_unmet_dependencies = WP_Plugin_Dependencies::has_unmet_dependencies( $plugin_file );
+ $has_circular_dependency = WP_Plugin_Dependencies::has_circular_dependency( $plugin_file );
+
if ( 'mustuse' === $context ) {
$is_active = true;
} elseif ( 'dropins' === $context ) {
@@ -796,26 +801,53 @@ public function single_row( $item ) {
if ( $screen->in_admin( 'network' ) ) {
if ( $is_active ) {
if ( current_user_can( 'manage_network_plugins' ) ) {
- $actions['deactivate'] = sprintf(
- '%s ',
- wp_nonce_url( 'plugins.php?action=deactivate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'deactivate-plugin_' . $plugin_file ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Network Deactivate' )
- );
+ if ( $has_active_dependents ) {
+ $actions['deactivate'] = __( 'Deactivate' ) .
+ '' .
+ __( 'You cannot deactivate this plugin as other plugins require it.' ) .
+ ' ';
+
+ } else {
+ $deactivate_url = 'plugins.php?action=deactivate' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['deactivate'] = sprintf(
+ '%s ',
+ wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Network Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
+ __( 'Network Deactivate' )
+ );
+ }
}
} else {
if ( current_user_can( 'manage_network_plugins' ) ) {
if ( $compatible_php && $compatible_wp ) {
- $actions['activate'] = sprintf(
- '%s ',
- wp_nonce_url( 'plugins.php?action=activate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'activate-plugin_' . $plugin_file ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Network Activate' )
- );
+ if ( $has_unmet_dependencies ) {
+ $actions['activate'] = __( 'Network Activate' ) .
+ '' .
+ __( 'You cannot activate this plugin as it has unmet requirements.' ) .
+ ' ';
+ } else {
+ $activate_url = 'plugins.php?action=activate' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['activate'] = sprintf(
+ '%s ',
+ wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Network Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
+ __( 'Network Activate' )
+ );
+ }
} else {
$actions['activate'] = sprintf(
'%s ',
@@ -825,14 +857,27 @@ public function single_row( $item ) {
}
if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
- $actions['delete'] = sprintf(
- '%s ',
- wp_nonce_url( 'plugins.php?action=delete-selected&checked[]=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'bulk-plugins' ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Delete' )
- );
+ if ( $has_dependents && ! $has_circular_dependency ) {
+ $actions['delete'] = __( 'Delete' ) .
+ '' .
+ __( 'You cannot delete this plugin as other plugins require it.' ) .
+ ' ';
+ } else {
+ $delete_url = 'plugins.php?action=delete-selected' .
+ '&checked[]=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['delete'] = sprintf(
+ '%s ',
+ wp_nonce_url( $delete_url, 'bulk-plugins' ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
+ __( 'Delete' )
+ );
+ }
}
}
} else {
@@ -846,20 +891,39 @@ public function single_row( $item ) {
);
} elseif ( $is_active ) {
if ( current_user_can( 'deactivate_plugin', $plugin_file ) ) {
- $actions['deactivate'] = sprintf(
- '%s ',
- wp_nonce_url( 'plugins.php?action=deactivate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'deactivate-plugin_' . $plugin_file ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Deactivate' )
- );
+ if ( $has_active_dependents ) {
+ $actions['deactivate'] = __( 'Deactivate' ) .
+ '' .
+ __( 'You cannot deactivate this plugin as other plugins depend on it.' ) .
+ ' ';
+ } else {
+ $deactivate_url = 'plugins.php?action=deactivate' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['deactivate'] = sprintf(
+ '%s ',
+ wp_nonce_url( $deactivate_url, 'deactivate-plugin_' . $plugin_file ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Deactivate %s', 'plugin' ), $plugin_data['Name'] ) ),
+ __( 'Deactivate' )
+ );
+ }
}
if ( current_user_can( 'resume_plugin', $plugin_file ) && is_plugin_paused( $plugin_file ) ) {
+ $resume_url = 'plugins.php?action=resume' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
$actions['resume'] = sprintf(
'%s ',
- wp_nonce_url( 'plugins.php?action=resume&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'resume-plugin_' . $plugin_file ),
+ wp_nonce_url( $resume_url, 'resume-plugin_' . $plugin_file ),
esc_attr( $plugin_id_attr ),
/* translators: %s: Plugin name. */
esc_attr( sprintf( _x( 'Resume %s', 'plugin' ), $plugin_data['Name'] ) ),
@@ -869,14 +933,27 @@ public function single_row( $item ) {
} else {
if ( current_user_can( 'activate_plugin', $plugin_file ) ) {
if ( $compatible_php && $compatible_wp ) {
- $actions['activate'] = sprintf(
- '%s ',
- wp_nonce_url( 'plugins.php?action=activate&plugin=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'activate-plugin_' . $plugin_file ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Activate' )
- );
+ if ( $has_unmet_dependencies ) {
+ $actions['activate'] = __( 'Activate' ) .
+ '' .
+ __( 'You cannot activate this plugin as it has unmet requirements.' ) .
+ ' ';
+ } else {
+ $activate_url = 'plugins.php?action=activate' .
+ '&plugin=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['activate'] = sprintf(
+ '%s ',
+ wp_nonce_url( $activate_url, 'activate-plugin_' . $plugin_file ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Activate %s', 'plugin' ), $plugin_data['Name'] ) ),
+ __( 'Activate' )
+ );
+ }
} else {
$actions['activate'] = sprintf(
'%s ',
@@ -886,14 +963,27 @@ public function single_row( $item ) {
}
if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
- $actions['delete'] = sprintf(
- '%s ',
- wp_nonce_url( 'plugins.php?action=delete-selected&checked[]=' . urlencode( $plugin_file ) . '&plugin_status=' . $context . '&paged=' . $page . '&s=' . $s, 'bulk-plugins' ),
- esc_attr( $plugin_id_attr ),
- /* translators: %s: Plugin name. */
- esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
- __( 'Delete' )
- );
+ if ( $has_dependents && ! $has_circular_dependency ) {
+ $actions['delete'] = __( 'Delete' ) .
+ '' .
+ __( 'You cannot delete this plugin as other plugins require it.' ) .
+ ' ';
+ } else {
+ $delete_url = 'plugins.php?action=delete-selected' .
+ '&checked[]=' . urlencode( $plugin_file ) .
+ '&plugin_status=' . $context .
+ '&paged=' . $page .
+ '&s=' . $s;
+
+ $actions['delete'] = sprintf(
+ '%s ',
+ wp_nonce_url( $delete_url, 'bulk-plugins' ),
+ esc_attr( $plugin_id_attr ),
+ /* translators: %s: Plugin name. */
+ esc_attr( sprintf( _x( 'Delete %s', 'plugin' ), $plugin_data['Name'] ) ),
+ __( 'Delete' )
+ );
+ }
}
} // End if $is_active.
} // End if $screen->in_admin( 'network' ).
@@ -988,17 +1078,28 @@ public function single_row( $item ) {
$class = $is_active ? 'active' : 'inactive';
$checkbox_id = 'checkbox_' . md5( $plugin_file );
+ $disabled = '';
- if ( $restrict_network_active || $restrict_network_only || in_array( $status, array( 'mustuse', 'dropins' ), true ) || ! $compatible_php ) {
+ if ( $has_active_dependents || $has_unmet_dependencies ) {
+ $disabled = 'disabled';
+ }
+
+ if (
+ $restrict_network_active ||
+ $restrict_network_only ||
+ in_array( $status, array( 'mustuse', 'dropins' ), true ) ||
+ ! $compatible_php
+ ) {
$checkbox = '';
} else {
$checkbox = sprintf(
- ' ' .
- '%3$s ',
- esc_attr( $plugin_file ),
+ '' .
+ '%2$s ' .
+ ' ',
$checkbox_id,
/* translators: Hidden accessibility text. %s: Plugin name. */
- sprintf( __( 'Select %s' ), $plugin_data['Name'] )
+ sprintf( __( 'Select %s' ), $plugin_data['Name'] ),
+ esc_attr( $plugin_file )
);
}
@@ -1007,8 +1108,11 @@ public function single_row( $item ) {
$plugin_name = $plugin_data['Name'];
}
- if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] )
- || ! $compatible_php || ! $compatible_wp
+ if (
+ ! empty( $totals['upgrade'] ) &&
+ ! empty( $plugin_data['update'] ) ||
+ ! $compatible_php ||
+ ! $compatible_wp
) {
$class .= ' update';
}
@@ -1057,15 +1161,19 @@ public function single_row( $item ) {
";
$plugin_meta = array();
+
if ( ! empty( $plugin_data['Version'] ) ) {
/* translators: %s: Plugin version number. */
$plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
}
+
if ( ! empty( $plugin_data['Author'] ) ) {
$author = $plugin_data['Author'];
+
if ( ! empty( $plugin_data['AuthorURI'] ) ) {
$author = '
' . $plugin_data['Author'] . ' ';
}
+
/* translators: %s: Plugin author name. */
$plugin_meta[] = sprintf( __( 'By %s' ), $author );
}
@@ -1149,6 +1257,24 @@ public function single_row( $item ) {
echo '
';
+ if ( $has_dependents ) {
+ $this->add_dependents_to_dependency_plugin_row( $plugin_file );
+ }
+
+ if ( WP_Plugin_Dependencies::has_dependencies( $plugin_file ) ) {
+ $this->add_dependencies_to_dependent_plugin_row( $plugin_file );
+ }
+
+ /**
+ * Fires after plugin row meta.
+ *
+ * @since 6.5.0
+ *
+ * @param string $plugin_file Refer to {@see 'plugin_row_meta'} filter.
+ * @param array $plugin_data Refer to {@see 'plugin_row_meta'} filter.
+ */
+ do_action( 'after_plugin_row_meta', $plugin_file, $plugin_data );
+
if ( $paused ) {
$notice_text = __( 'This plugin failed to load properly and is paused during recovery mode.' );
@@ -1391,4 +1517,111 @@ public function single_row( $item ) {
protected function get_primary_column_name() {
return 'name';
}
+
+ /**
+ * Prints a list of other plugins that depend on the plugin.
+ *
+ * @since 6.5.0
+ *
+ * @param string $dependency The dependency's filepath, relative to the plugins directory.
+ */
+ protected function add_dependents_to_dependency_plugin_row( $dependency ) {
+ $dependent_names = WP_Plugin_Dependencies::get_dependent_names( $dependency );
+
+ if ( empty( $dependent_names ) ) {
+ return;
+ }
+
+ $dependency_note = __( 'Note: this plugin cannot be deactivated or deleted until the plugins that require it are deactivated or deleted.' );
+ printf(
+ '',
+ __( 'Required by:' ),
+ esc_html( implode( ' | ', $dependent_names ) ),
+ $dependency_note
+ );
+ }
+
+ /**
+ * Prints a list of other plugins that the plugin depends on.
+ *
+ * @since 6.5.0
+ *
+ * @param string $dependent The dependent plugin's filepath, relative to the plugins directory.
+ */
+ protected function add_dependencies_to_dependent_plugin_row( $dependent ) {
+ $dependency_names = WP_Plugin_Dependencies::get_dependency_names( $dependent );
+
+ if ( array() === $dependency_names ) {
+ return;
+ }
+
+ $links = array();
+ foreach ( $dependency_names as $slug => $name ) {
+ $links[] = $this->get_dependency_view_details_link( $name, $slug );
+ }
+
+ $dependency_note = __( 'Note: this plugin cannot be activated until the plugins that are required by it are activated.' );
+
+ printf(
+ '',
+ __( 'Requires:' ),
+ implode( ' | ', $links ),
+ $dependency_note
+ );
+ }
+
+ /**
+ * Returns a 'View details' like link for a dependency.
+ *
+ * @since 6.5.0
+ *
+ * @param string $name The dependency's name.
+ * @param string $slug The dependency's slug.
+ * @return string A 'View details' link for the dependency.
+ */
+ protected function get_dependency_view_details_link( $name, $slug ) {
+ $dependency_data = WP_Plugin_Dependencies::get_dependency_data( $slug );
+
+ if ( false === $dependency_data
+ || $name === $slug
+ || $name !== $dependency_data['name']
+ || empty( $dependency_data['version'] )
+ ) {
+ return $name;
+ }
+
+ return $this->get_view_details_link( $name, $slug );
+ }
+
+ /**
+ * Returns a 'View details' link for the plugin.
+ *
+ * @since 6.5.0
+ *
+ * @param string $name The plugin's name.
+ * @param string $slug The plugin's slug.
+ * @return string A 'View details' link for the plugin.
+ */
+ protected function get_view_details_link( $name, $slug ) {
+ $url = add_query_arg(
+ array(
+ 'tab' => 'plugin-information',
+ 'plugin' => $slug,
+ 'TB_iframe' => 'true',
+ 'width' => '600',
+ 'height' => '550',
+ ),
+ network_admin_url( 'plugin-install.php' )
+ );
+
+ $name_attr = esc_attr( $name );
+ return sprintf(
+ "%s ",
+ esc_url( $url ),
+ /* translators: %s: Plugin name. */
+ sprintf( __( 'More information about %s' ), $name_attr ),
+ $name_attr,
+ esc_html( $name )
+ );
+ }
}
diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php
index c3863ba2ea5ba..583256955e250 100644
--- a/src/wp-admin/includes/file.php
+++ b/src/wp-admin/includes/file.php
@@ -1563,6 +1563,37 @@ function wp_trusted_keys() {
return apply_filters( 'wp_trusted_keys', $trusted_keys );
}
+/**
+ * Determines whether the given file is a valid ZIP file.
+ *
+ * This function does not test to ensure that a file exists. Non-existent files
+ * are not valid ZIPs, so those will also return false.
+ *
+ * @since 6.4.4
+ *
+ * @param string $file Full path to the ZIP file.
+ * @return bool Whether the file is a valid ZIP file.
+ */
+function wp_zip_file_is_valid( $file ) {
+ /** This filter is documented in wp-admin/includes/file.php */
+ if ( class_exists( 'ZipArchive', false ) && apply_filters( 'unzip_file_use_ziparchive', true ) ) {
+ $archive = new ZipArchive();
+ $archive_is_valid = $archive->open( $file, ZipArchive::CHECKCONS );
+ if ( true === $archive_is_valid ) {
+ $archive->close();
+ return true;
+ }
+ }
+
+ // Fall through to PclZip if ZipArchive is not available, or encountered an error opening the file.
+ require_once ABSPATH . 'wp-admin/includes/class-pclzip.php';
+
+ $archive = new PclZip( $file );
+ $archive_is_valid = is_array( $archive->properties() );
+
+ return $archive_is_valid;
+}
+
/**
* Unzips a specified ZIP file to a location on the filesystem via the WordPress
* Filesystem Abstraction.
diff --git a/src/wp-admin/includes/image-edit.php b/src/wp-admin/includes/image-edit.php
index 739b09f9a1fca..2d150e691c293 100644
--- a/src/wp-admin/includes/image-edit.php
+++ b/src/wp-admin/includes/image-edit.php
@@ -390,6 +390,12 @@ function wp_stream_image( $image, $mime_type, $attachment_id ) {
return imagewebp( $image, null, 90 );
}
return false;
+ case 'image/avif':
+ if ( function_exists( 'imageavif' ) ) {
+ header( 'Content-Type: image/avif' );
+ return imageavif( $image, null, 90 );
+ }
+ return false;
default:
return false;
}
@@ -494,6 +500,11 @@ function wp_save_image_file( $filename, $image, $mime_type, $post_id ) {
return imagewebp( $image, $filename );
}
return false;
+ case 'image/avif':
+ if ( function_exists( 'imageavif' ) ) {
+ return imageavif( $image, $filename );
+ }
+ return false;
default:
return false;
}
diff --git a/src/wp-admin/includes/image.php b/src/wp-admin/includes/image.php
index d60ec8508baf5..0f4ba818e6535 100644
--- a/src/wp-admin/includes/image.php
+++ b/src/wp-admin/includes/image.php
@@ -1006,7 +1006,7 @@ function file_is_valid_image( $path ) {
* @return bool True if suitable, false if not suitable.
*/
function file_is_displayable_image( $path ) {
- $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP );
+ $displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP, IMAGETYPE_ICO, IMAGETYPE_WEBP, IMAGETYPE_AVIF );
$info = wp_getimagesize( $path );
if ( empty( $info ) ) {
diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php
index 57df2bcbff0c3..193e67f7dd641 100644
--- a/src/wp-admin/includes/media.php
+++ b/src/wp-admin/includes/media.php
@@ -2198,6 +2198,11 @@ function media_upload_form( $errors = null ) {
$plupload_init['webp_upload_error'] = true;
}
+ // Check if AVIF images can be edited.
+ if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) {
+ $plupload_init['avif_upload_error'] = true;
+ }
+
/**
* Filters the default Plupload settings.
*
diff --git a/src/wp-admin/includes/plugin-install.php b/src/wp-admin/includes/plugin-install.php
index 7662076581c3e..2de2aabbc3a01 100644
--- a/src/wp-admin/includes/plugin-install.php
+++ b/src/wp-admin/includes/plugin-install.php
@@ -884,43 +884,176 @@ function install_plugin_information() {
echo "\n"; // #plugin-information-scrollable
echo "\n";
+
+ wp_print_request_filesystem_credentials_modal();
+ wp_print_admin_notice_templates();
+
+ iframe_footer();
+ exit;
+}
+
+/**
+ * Gets the markup for the plugin install action button.
+ *
+ * @since 6.5.0
+ *
+ * @param string $name Plugin name.
+ * @param array|object $data {
+ * An array or object of plugin data. Can be retrieved from the API.
+ *
+ * @type string $slug The plugin slug.
+ * @type string[] $requires_plugins An array of plugin dependency slugs.
+ * @type string $version The plugin's version string. Used when getting the install status.
+ * }
+ * @param bool $compatible_php The result of a PHP compatibility check.
+ * @param bool $compatible_wp The result of a WP compatibility check.
+ * @return string $button The markup for the dependency row button.
+ */
+function wp_get_plugin_action_button( $name, $data, $compatible_php, $compatible_wp ) {
+ $button = '';
+ $data = (object) $data;
+ $status = install_plugin_install_status( $data );
+ $requires_plugins = $data->requires_plugins ?? array();
+
+ // Determine the status of plugin dependencies.
+ $installed_plugins = get_plugins();
+ $active_plugins = get_option( 'active_plugins' );
+ $plugin_dependencies_count = count( $requires_plugins );
+ $installed_plugin_dependencies_count = 0;
+ $active_plugin_dependencies_count = 0;
+ foreach ( $requires_plugins as $dependency ) {
+ foreach ( array_keys( $installed_plugins ) as $installed_plugin_file ) {
+ if ( str_contains( $installed_plugin_file, '/' ) && explode( '/', $installed_plugin_file )[0] === $dependency ) {
+ ++$installed_plugin_dependencies_count;
+ }
+ }
+
+ foreach ( $active_plugins as $active_plugin_file ) {
+ if ( str_contains( $active_plugin_file, '/' ) && explode( '/', $active_plugin_file )[0] === $dependency ) {
+ ++$active_plugin_dependencies_count;
+ }
+ }
+ }
+ $all_plugin_dependencies_installed = $installed_plugin_dependencies_count === $plugin_dependencies_count;
+ $all_plugin_dependencies_active = $active_plugin_dependencies_count === $plugin_dependencies_count;
+
+ sprintf(
+ '%s ',
+ esc_attr( $data->slug ),
+ esc_url( $status['url'] ),
+ /* translators: %s: Plugin name and version. */
+ esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ),
+ esc_attr( $name ),
+ __( 'Install Now' )
+ );
+
+ if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
switch ( $status['status'] ) {
case 'install':
if ( $status['url'] ) {
- if ( $compatible_php && $compatible_wp ) {
- echo '' . __( 'Install Now' ) . ' ';
+ if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_installed && ! empty( $data->download_link ) ) {
+ $button = sprintf(
+ '%s ',
+ esc_attr( $data->slug ),
+ esc_url( $status['url'] ),
+ /* translators: %s: Plugin name and version. */
+ esc_attr( sprintf( _x( 'Install %s now', 'plugin' ), $name ) ),
+ esc_attr( $name ),
+ __( 'Install Now' )
+ );
} else {
- printf(
- '%s ',
- _x( 'Cannot Install', 'plugin' )
+ $button = sprintf(
+ '%s ',
+ _x( 'Install Now', 'plugin' )
);
}
}
break;
+
case 'update_available':
if ( $status['url'] ) {
- if ( $compatible_php ) {
- echo '' . __( 'Install Update Now' ) . ' ';
+ if ( $compatible_php && $compatible_wp ) {
+ $button = sprintf(
+ '%s ',
+ esc_attr( $status['file'] ),
+ esc_attr( $data->slug ),
+ esc_url( $status['url'] ),
+ /* translators: %s: Plugin name and version. */
+ esc_attr( sprintf( _x( 'Update %s now', 'plugin' ), $name ) ),
+ esc_attr( $name ),
+ __( 'Update Now' )
+ );
} else {
- printf(
- '%s ',
- _x( 'Cannot Update', 'plugin' )
+ $button = sprintf(
+ '%s ',
+ _x( 'Update Now', 'plugin' )
);
}
}
break;
- case 'newer_installed':
- /* translators: %s: Plugin version. */
- echo '' . sprintf( __( 'Newer Version (%s) Installed' ), esc_html( $status['version'] ) ) . ' ';
- break;
+
case 'latest_installed':
- echo '' . __( 'Latest Version Installed' ) . ' ';
+ case 'newer_installed':
+ if ( is_plugin_active( $status['file'] ) ) {
+ $button = sprintf(
+ '%s ',
+ _x( 'Active', 'plugin' )
+ );
+ } elseif ( current_user_can( 'activate_plugin', $status['file'] ) ) {
+ if ( $compatible_php && $compatible_wp && $all_plugin_dependencies_active ) {
+ $button_text = __( 'Activate' );
+ /* translators: %s: Plugin name. */
+ $button_label = _x( 'Activate %s', 'plugin' );
+ $activate_url = add_query_arg(
+ array(
+ '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $status['file'] ),
+ 'action' => 'activate',
+ 'plugin' => $status['file'],
+ ),
+ network_admin_url( 'plugins.php' )
+ );
+
+ if ( is_network_admin() ) {
+ $button_text = __( 'Network Activate' );
+ /* translators: %s: Plugin name. */
+ $button_label = _x( 'Network Activate %s', 'plugin' );
+ $activate_url = add_query_arg( array( 'networkwide' => 1 ), $activate_url );
+ }
+
+ $button = sprintf(
+ '%6$s ',
+ esc_url( $activate_url ),
+ esc_attr( $name ),
+ esc_attr( $data->slug ),
+ esc_attr( $status['file'] ),
+ esc_attr( sprintf( $button_label, $name ) ),
+ $button_text
+ );
+ } else {
+ $button = sprintf(
+ '%s ',
+ is_network_admin() ? _x( 'Network Activate %s', 'plugin' ) : _x( 'Activate', 'plugin' )
+ );
+ }
+ } else {
+ $button = sprintf(
+ '%s ',
+ _x( 'Installed', 'plugin' )
+ );
+ }
break;
}
- }
- echo "\n";
- iframe_footer();
- exit;
+ return $button;
+ }
}
diff --git a/src/wp-admin/includes/plugin.php b/src/wp-admin/includes/plugin.php
index f55bbd80eb5df..54a5b95f346b7 100644
--- a/src/wp-admin/includes/plugin.php
+++ b/src/wp-admin/includes/plugin.php
@@ -45,6 +45,7 @@
* @since 1.5.0
* @since 5.3.0 Added support for `Requires at least` and `Requires PHP` headers.
* @since 5.8.0 Added support for `Update URI` header.
+ * @since 6.5.0 Added support for `Requires Plugins` header.
*
* @param string $plugin_file Absolute path to the main plugin file.
* @param bool $markup Optional. If the returned data should have HTML markup applied.
@@ -53,39 +54,41 @@
* @return array {
* Plugin data. Values will be empty if not supplied by the plugin.
*
- * @type string $Name Name of the plugin. Should be unique.
- * @type string $PluginURI Plugin URI.
- * @type string $Version Plugin version.
- * @type string $Description Plugin description.
- * @type string $Author Plugin author's name.
- * @type string $AuthorURI Plugin author's website address (if set).
- * @type string $TextDomain Plugin textdomain.
- * @type string $DomainPath Plugin's relative directory path to .mo files.
- * @type bool $Network Whether the plugin can only be activated network-wide.
- * @type string $RequiresWP Minimum required version of WordPress.
- * @type string $RequiresPHP Minimum required version of PHP.
- * @type string $UpdateURI ID of the plugin for update purposes, should be a URI.
- * @type string $Title Title of the plugin and link to the plugin's site (if set).
- * @type string $AuthorName Plugin author's name.
+ * @type string $Name Name of the plugin. Should be unique.
+ * @type string $PluginURI Plugin URI.
+ * @type string $Version Plugin version.
+ * @type string $Description Plugin description.
+ * @type string $Author Plugin author's name.
+ * @type string $AuthorURI Plugin author's website address (if set).
+ * @type string $TextDomain Plugin textdomain.
+ * @type string $DomainPath Plugin's relative directory path to .mo files.
+ * @type bool $Network Whether the plugin can only be activated network-wide.
+ * @type string $RequiresWP Minimum required version of WordPress.
+ * @type string $RequiresPHP Minimum required version of PHP.
+ * @type string $UpdateURI ID of the plugin for update purposes, should be a URI.
+ * @type string $RequiresPlugins Comma separated list of dot org plugin slugs.
+ * @type string $Title Title of the plugin and link to the plugin's site (if set).
+ * @type string $AuthorName Plugin author's name.
* }
*/
function get_plugin_data( $plugin_file, $markup = true, $translate = true ) {
$default_headers = array(
- 'Name' => 'Plugin Name',
- 'PluginURI' => 'Plugin URI',
- 'Version' => 'Version',
- 'Description' => 'Description',
- 'Author' => 'Author',
- 'AuthorURI' => 'Author URI',
- 'TextDomain' => 'Text Domain',
- 'DomainPath' => 'Domain Path',
- 'Network' => 'Network',
- 'RequiresWP' => 'Requires at least',
- 'RequiresPHP' => 'Requires PHP',
- 'UpdateURI' => 'Update URI',
+ 'Name' => 'Plugin Name',
+ 'PluginURI' => 'Plugin URI',
+ 'Version' => 'Version',
+ 'Description' => 'Description',
+ 'Author' => 'Author',
+ 'AuthorURI' => 'Author URI',
+ 'TextDomain' => 'Text Domain',
+ 'DomainPath' => 'Domain Path',
+ 'Network' => 'Network',
+ 'RequiresWP' => 'Requires at least',
+ 'RequiresPHP' => 'Requires PHP',
+ 'UpdateURI' => 'Update URI',
+ 'RequiresPlugins' => 'Requires Plugins',
// Site Wide Only is deprecated in favor of Network.
- '_sitewide' => 'Site Wide Only',
+ '_sitewide' => 'Site Wide Only',
);
$plugin_data = get_file_data( $plugin_file, $default_headers, 'plugin' );
@@ -330,6 +333,7 @@ function get_plugins( $plugin_folder = '' ) {
return $wp_plugins;
}
+ $new_plugin_data = array();
foreach ( $plugin_files as $plugin_file ) {
if ( ! is_readable( "$plugin_root/$plugin_file" ) ) {
continue;
@@ -342,6 +346,13 @@ function get_plugins( $plugin_folder = '' ) {
continue;
}
+ $new_plugin_file = str_replace(
+ trailingslashit( WP_PLUGIN_DIR ),
+ '',
+ "$plugin_root/$plugin_file"
+ );
+
+ $new_plugin_data[ $new_plugin_file ] = $plugin_data;
$wp_plugins[ plugin_basename( $plugin_file ) ] = $plugin_data;
}
@@ -349,6 +360,7 @@ function get_plugins( $plugin_folder = '' ) {
$cache_plugins[ $plugin_folder ] = $wp_plugins;
wp_cache_set( 'plugins', $cache_plugins, 'plugins' );
+ update_option( 'plugin_data', $new_plugin_data );
return $wp_plugins;
}
@@ -951,6 +963,7 @@ function delete_plugins( $plugins, $deprecated = '' ) {
$plugins_dir = trailingslashit( $plugins_dir );
$plugin_translations = wp_get_installed_translations( 'plugins' );
+ $all_plugin_data = get_option( 'plugin_data', array() );
$errors = array();
@@ -995,6 +1008,7 @@ function delete_plugins( $plugins, $deprecated = '' ) {
$errors[] = $plugin_file;
continue;
}
+ unset( $all_plugin_data[ $plugin_file ] );
$plugin_slug = dirname( $plugin_file );
@@ -1009,6 +1023,7 @@ function delete_plugins( $plugins, $deprecated = '' ) {
foreach ( $translations as $translation => $data ) {
$wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.po' );
$wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.mo' );
+ $wp_filesystem->delete( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '.l10n.php' );
$json_translation_files = glob( WP_LANG_DIR . '/plugins/' . $plugin_slug . '-' . $translation . '-*.json' );
if ( $json_translation_files ) {
@@ -1042,6 +1057,7 @@ function delete_plugins( $plugins, $deprecated = '' ) {
return new WP_Error( 'could_not_remove_plugin', sprintf( $message, implode( ', ', $errors ) ) );
}
+ update_option( 'plugin_data', $all_plugin_data );
return true;
}
@@ -1113,13 +1129,14 @@ function validate_plugin( $plugin ) {
/**
* Validates the plugin requirements for WordPress version and PHP version.
*
- * Uses the information from `Requires at least` and `Requires PHP` headers
+ * Uses the information from `Requires at least`, `Requires PHP` and `Requires Plugins` headers
* defined in the plugin's main PHP file.
*
* @since 5.2.0
* @since 5.3.0 Added support for reading the headers from the plugin's
* main PHP file, with `readme.txt` as a fallback.
* @since 5.8.0 Removed support for using `readme.txt` as a fallback.
+ * @since 6.5.0 Added support for the 'Requires Plugins' header.
*
* @param string $plugin Path to the plugin file relative to the plugins directory.
* @return true|WP_Error True if requirements are met, WP_Error on failure.
@@ -1128,8 +1145,9 @@ function validate_plugin_requirements( $plugin ) {
$plugin_headers = get_plugin_data( WP_PLUGIN_DIR . '/' . $plugin );
$requirements = array(
- 'requires' => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '',
- 'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '',
+ 'requires' => ! empty( $plugin_headers['RequiresWP'] ) ? $plugin_headers['RequiresWP'] : '',
+ 'requires_php' => ! empty( $plugin_headers['RequiresPHP'] ) ? $plugin_headers['RequiresPHP'] : '',
+ 'requires_plugins' => ! empty( $plugin_headers['RequiresPlugins'] ) ? $plugin_headers['RequiresPlugins'] : '',
);
$compatible_wp = is_wp_version_compatible( $requirements['requires'] );
@@ -1184,6 +1202,31 @@ function validate_plugin_requirements( $plugin ) {
);
}
+ if ( WP_Plugin_Dependencies::has_unmet_dependencies( $plugin ) ) {
+ $dependencies = WP_Plugin_Dependencies::get_dependencies( $plugin );
+ $unmet_dependencies = array();
+
+ foreach ( $dependencies as $dependency ) {
+ $dependency_file = WP_Plugin_Dependencies::get_dependency_filepath( $dependency );
+
+ if ( false === $dependency_file ) {
+ $unmet_dependencies['not_installed'][] = $dependency;
+ } elseif ( is_plugin_inactive( $dependency_file ) ) {
+ $unmet_dependencies['inactive'][] = $dependency;
+ }
+ }
+
+ return new WP_Error(
+ 'plugin_missing_dependencies',
+ '' . sprintf(
+ /* translators: %s: Plugin name. */
+ _x( 'Error: %s requires plugins that are not installed or activated.', 'plugin' ),
+ $plugin_headers['Name']
+ ) . '
',
+ $unmet_dependencies
+ );
+ }
+
return true;
}
diff --git a/src/wp-admin/includes/post.php b/src/wp-admin/includes/post.php
index c93ac71bec525..90aaf2228e371 100644
--- a/src/wp-admin/includes/post.php
+++ b/src/wp-admin/includes/post.php
@@ -2303,6 +2303,7 @@ function get_block_editor_server_block_settings() {
'keywords' => 'keywords',
'example' => 'example',
'variations' => 'variations',
+ 'allowed_blocks' => 'allowedBlocks',
);
foreach ( $block_registry->get_all_registered() as $block_name => $block_type ) {
diff --git a/src/wp-admin/includes/schema.php b/src/wp-admin/includes/schema.php
index d339af3b17324..63655ccf174ca 100644
--- a/src/wp-admin/includes/schema.php
+++ b/src/wp-admin/includes/schema.php
@@ -599,14 +599,12 @@ function populate_options( array $options = array() ) {
$autoload = 'yes';
}
- if ( is_array( $value ) ) {
- $value = serialize( $value );
- }
-
if ( ! empty( $insert ) ) {
$insert .= ', ';
}
+ $value = maybe_serialize( sanitize_option( $option, $value ) );
+
$insert .= $wpdb->prepare( '(%s, %s, %s)', $option, $value, $autoload );
}
@@ -1252,6 +1250,7 @@ function populate_network_meta( $network_id, array $meta = array() ) {
'png',
'gif',
'webp',
+ 'avif',
// Video.
'mov',
'avi',
diff --git a/src/wp-admin/includes/theme.php b/src/wp-admin/includes/theme.php
index 91e92995ece81..70abab68ad799 100644
--- a/src/wp-admin/includes/theme.php
+++ b/src/wp-admin/includes/theme.php
@@ -114,6 +114,7 @@ function delete_theme( $stylesheet, $redirect = '' ) {
foreach ( $translations as $translation => $data ) {
$wp_filesystem->delete( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '.po' );
$wp_filesystem->delete( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '.mo' );
+ $wp_filesystem->delete( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '.l10n.php' );
$json_translation_files = glob( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '-*.json' );
if ( $json_translation_files ) {
diff --git a/src/wp-admin/includes/update-core.php b/src/wp-admin/includes/update-core.php
index 0c66ad3ee9db0..6d996adb52e38 100644
--- a/src/wp-admin/includes/update-core.php
+++ b/src/wp-admin/includes/update-core.php
@@ -1848,13 +1848,14 @@ function _upgrade_440_force_deactivate_incompatible_plugins() {
* @since 5.9.0 The minimum compatible version of Gutenberg is 11.9.
* @since 6.1.1 The minimum compatible version of Gutenberg is 14.1.
* @since 6.4.0 The minimum compatible version of Gutenberg is 16.5.
+ * @since 6.5.0 The minimum compatible version of Gutenberg is 17.6.
*/
function _upgrade_core_deactivate_incompatible_plugins() {
- if ( defined( 'GUTENBERG_VERSION' ) && version_compare( GUTENBERG_VERSION, '16.5', '<' ) ) {
+ if ( defined( 'GUTENBERG_VERSION' ) && version_compare( GUTENBERG_VERSION, '17.6', '<' ) ) {
$deactivated_gutenberg['gutenberg'] = array(
'plugin_name' => 'Gutenberg',
'version_deactivated' => GUTENBERG_VERSION,
- 'version_compatible' => '16.5',
+ 'version_compatible' => '17.6',
);
if ( is_plugin_active_for_network( 'gutenberg/gutenberg.php' ) ) {
$deactivated_plugins = get_site_option( 'wp_force_deactivated_plugins', array() );
diff --git a/src/wp-admin/menu.php b/src/wp-admin/menu.php
index 71fd94b2e3842..a756fa40f3624 100644
--- a/src/wp-admin/menu.php
+++ b/src/wp-admin/menu.php
@@ -205,10 +205,12 @@
if ( wp_is_block_theme() ) {
$submenu['themes.php'][6] = array( _x( 'Editor', 'site editor menu item' ), 'edit_theme_options', 'site-editor.php' );
+} else {
+ $submenu['themes.php'][6] = array( __( 'Patterns', 'site editor menu item' ), 'edit_theme_options', 'edit.php?post_type=wp_block' );
}
if ( ! wp_is_block_theme() && current_theme_supports( 'block-template-parts' ) ) {
- $submenu['themes.php'][6] = array(
+ $submenu['themes.php'][7] = array(
__( 'Template Parts' ),
'edit_theme_options',
'site-editor.php?path=/wp_template_part/all',
@@ -220,7 +222,7 @@
// Hide Customize link on block themes unless a plugin or theme
// is using 'customize_register' to add a setting.
if ( ! wp_is_block_theme() || has_action( 'customize_register' ) ) {
- $position = ( wp_is_block_theme() || current_theme_supports( 'block-template-parts' ) ) ? 7 : 6;
+ $position = ! wp_is_block_theme() && current_theme_supports( 'block-template-parts' ) ? 8 : 7;
$submenu['themes.php'][ $position ] = array( __( 'Customize' ), 'customize', esc_url( $customize_url ), '', 'hide-if-no-customize' );
}
diff --git a/src/wp-admin/plugin-editor.php b/src/wp-admin/plugin-editor.php
index 345f0c09e05c2..da57d95e74fff 100644
--- a/src/wp-admin/plugin-editor.php
+++ b/src/wp-admin/plugin-editor.php
@@ -295,7 +295,7 @@
-
+
diff --git a/src/wp-admin/plugin-install.php b/src/wp-admin/plugin-install.php
index 571b9a9875ab1..a8beb8249bbc7 100644
--- a/src/wp-admin/plugin-install.php
+++ b/src/wp-admin/plugin-install.php
@@ -134,6 +134,10 @@
* WordPress Administration Template Header.
*/
require_once ABSPATH . 'wp-admin/admin-header.php';
+
+WP_Plugin_Dependencies::display_admin_notice_for_unmet_dependencies();
+WP_Plugin_Dependencies::display_admin_notice_for_deactivated_dependents();
+WP_Plugin_Dependencies::display_admin_notice_for_circular_dependencies();
?>
">
diff --git a/src/wp-admin/plugins.php b/src/wp-admin/plugins.php
index 93f9c454abe14..f7514ab473b1b 100644
--- a/src/wp-admin/plugins.php
+++ b/src/wp-admin/plugins.php
@@ -739,6 +739,9 @@
}
?>
+
+
+
-
+
diff --git a/src/wp-admin/update-core.php b/src/wp-admin/update-core.php
index c34ac06f242e6..80fbd530b24b6 100644
--- a/src/wp-admin/update-core.php
+++ b/src/wp-admin/update-core.php
@@ -42,7 +42,7 @@ function list_core_update( $update ) {
if ( 'en_US' === $update->locale && 'en_US' === get_locale() ) {
$version_string = $update->current;
- } elseif ( 'en_US' === $update->locale && $update->packages->partial && $wp_version == $update->partial_version ) {
+ } elseif ( 'en_US' === $update->locale && $update->packages->partial && $wp_version === $update->partial_version ) {
$updates = get_core_updates();
if ( $updates && 1 === count( $updates ) ) {
// If the only available update is a partial builds, it doesn't need a language-specific version string.
@@ -179,9 +179,9 @@ function list_core_update( $update ) {
}
echo '';
- if ( 'en_US' !== $update->locale && ( ! isset( $wp_local_package ) || $wp_local_package != $update->locale ) ) {
+ if ( 'en_US' !== $update->locale && ( ! isset( $wp_local_package ) || $wp_local_package !== $update->locale ) ) {
echo '' . __( 'This localized version contains both the translation and various other localization fixes.' ) . '
';
- } elseif ( 'en_US' === $update->locale && 'en_US' !== get_locale() && ( ! $update->packages->partial && $wp_version == $update->partial_version ) ) {
+ } elseif ( 'en_US' === $update->locale && 'en_US' !== get_locale() && ( ! $update->packages->partial && $wp_version === $update->partial_version ) ) {
// Partial builds don't need language-specific warnings.
echo '
' . sprintf(
/* translators: %s: WordPress version. */
diff --git a/src/wp-admin/update.php b/src/wp-admin/update.php
index 29480c2840a57..090c37cfc4dfe 100644
--- a/src/wp-admin/update.php
+++ b/src/wp-admin/update.php
@@ -154,6 +154,10 @@
check_admin_referer( 'plugin-upload' );
+ if ( isset( $_FILES['pluginzip']['name'] ) && ! str_ends_with( strtolower( $_FILES['pluginzip']['name'] ), '.zip' ) ) {
+ wp_die( __( 'Only .zip archives may be uploaded.' ) );
+ }
+
$file_upload = new File_Upload_Upgrader( 'pluginzip', 'package' );
// Used in the HTML title tag.
@@ -302,6 +306,10 @@
check_admin_referer( 'theme-upload' );
+ if ( isset( $_FILES['themezip']['name'] ) && ! str_ends_with( strtolower( $_FILES['themezip']['name'] ), '.zip' ) ) {
+ wp_die( __( 'Only .zip archives may be uploaded.' ) );
+ }
+
$file_upload = new File_Upload_Upgrader( 'themezip', 'package' );
// Used in the HTML title tag.
diff --git a/src/wp-content/themes/twentyeleven/functions.php b/src/wp-content/themes/twentyeleven/functions.php
index 3ca5da5882f27..3c7fa3c3a8167 100644
--- a/src/wp-content/themes/twentyeleven/functions.php
+++ b/src/wp-content/themes/twentyeleven/functions.php
@@ -562,7 +562,7 @@ function twentyeleven_page_menu_args( $args ) {
/**
* Register sidebars and widgetized areas.
*
- * Also register the default Epherma widget.
+ * Also register the default Ephemera widget.
*
* @since Twenty Eleven 1.0
*/
diff --git a/src/wp-content/themes/twentyeleven/images/headers/chessboard-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/chessboard-thumbnail.jpg
index e8c84d3f4d9c6..cb6977e7b6697 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/chessboard-thumbnail.jpg and b/src/wp-content/themes/twentyeleven/images/headers/chessboard-thumbnail.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/chessboard.jpg b/src/wp-content/themes/twentyeleven/images/headers/chessboard.jpg
index 831961fff53ef..aebf01b2d228e 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/chessboard.jpg and b/src/wp-content/themes/twentyeleven/images/headers/chessboard.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/hanoi-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/hanoi-thumbnail.jpg
index 9fc963f59bcec..699b5780e47b0 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/hanoi-thumbnail.jpg and b/src/wp-content/themes/twentyeleven/images/headers/hanoi-thumbnail.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/hanoi.jpg b/src/wp-content/themes/twentyeleven/images/headers/hanoi.jpg
index 5b0fa3fb87575..83d7695c9028c 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/hanoi.jpg and b/src/wp-content/themes/twentyeleven/images/headers/hanoi.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/lanterns-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/lanterns-thumbnail.jpg
index 3790f96caaf13..6a6bf9a4d42c2 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/lanterns-thumbnail.jpg and b/src/wp-content/themes/twentyeleven/images/headers/lanterns-thumbnail.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/lanterns.jpg b/src/wp-content/themes/twentyeleven/images/headers/lanterns.jpg
index f71ce8f8cdf2d..96bea4c4ada42 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/lanterns.jpg and b/src/wp-content/themes/twentyeleven/images/headers/lanterns.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/pine-cone-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/pine-cone-thumbnail.jpg
index 248fe00a14d04..c0b0e88ea3be4 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/pine-cone-thumbnail.jpg and b/src/wp-content/themes/twentyeleven/images/headers/pine-cone-thumbnail.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/pine-cone.jpg b/src/wp-content/themes/twentyeleven/images/headers/pine-cone.jpg
index e55ce97f1d63b..a908fac799d08 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/pine-cone.jpg and b/src/wp-content/themes/twentyeleven/images/headers/pine-cone.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/shore-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/shore-thumbnail.jpg
index 5e5e740e9b422..07e91f1a4eaa0 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/shore-thumbnail.jpg and b/src/wp-content/themes/twentyeleven/images/headers/shore-thumbnail.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/shore.jpg b/src/wp-content/themes/twentyeleven/images/headers/shore.jpg
index 71a8c54fed14b..972cb6251140a 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/shore.jpg and b/src/wp-content/themes/twentyeleven/images/headers/shore.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/trolley-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/trolley-thumbnail.jpg
index d2ee200088f8c..ea70fe13b17ba 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/trolley-thumbnail.jpg and b/src/wp-content/themes/twentyeleven/images/headers/trolley-thumbnail.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/trolley.jpg b/src/wp-content/themes/twentyeleven/images/headers/trolley.jpg
index 110a764e5b643..67d63396de4d1 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/trolley.jpg and b/src/wp-content/themes/twentyeleven/images/headers/trolley.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/wheel-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/wheel-thumbnail.jpg
index d7fa9713588b4..2cf102fc980e4 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/wheel-thumbnail.jpg and b/src/wp-content/themes/twentyeleven/images/headers/wheel-thumbnail.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/wheel.jpg b/src/wp-content/themes/twentyeleven/images/headers/wheel.jpg
index c5b98789a81b1..31e5e17d79e40 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/wheel.jpg and b/src/wp-content/themes/twentyeleven/images/headers/wheel.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/willow-thumbnail.jpg b/src/wp-content/themes/twentyeleven/images/headers/willow-thumbnail.jpg
index 240fff8a16aa5..70f7fb2f021bb 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/willow-thumbnail.jpg and b/src/wp-content/themes/twentyeleven/images/headers/willow-thumbnail.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/headers/willow.jpg b/src/wp-content/themes/twentyeleven/images/headers/willow.jpg
index e867cc43df474..d1829f6762f01 100644
Binary files a/src/wp-content/themes/twentyeleven/images/headers/willow.jpg and b/src/wp-content/themes/twentyeleven/images/headers/willow.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/patterns/pattern-flower.jpg b/src/wp-content/themes/twentyeleven/images/patterns/pattern-flower.jpg
index 54bdcc593d215..1dd4865a37a1d 100644
Binary files a/src/wp-content/themes/twentyeleven/images/patterns/pattern-flower.jpg and b/src/wp-content/themes/twentyeleven/images/patterns/pattern-flower.jpg differ
diff --git a/src/wp-content/themes/twentyeleven/images/patterns/pattern-woman.jpg b/src/wp-content/themes/twentyeleven/images/patterns/pattern-woman.jpg
index 8af40f871a11b..4bf164c0313d9 100644
Binary files a/src/wp-content/themes/twentyeleven/images/patterns/pattern-woman.jpg and b/src/wp-content/themes/twentyeleven/images/patterns/pattern-woman.jpg differ
diff --git a/src/wp-content/themes/twentyfifteen/assets/pier-seagull.jpg b/src/wp-content/themes/twentyfifteen/assets/pier-seagull.jpg
index fad56465bb8b2..b71d9d380729c 100644
Binary files a/src/wp-content/themes/twentyfifteen/assets/pier-seagull.jpg and b/src/wp-content/themes/twentyfifteen/assets/pier-seagull.jpg differ
diff --git a/src/wp-content/themes/twentyfifteen/assets/pier-seagulls.jpg b/src/wp-content/themes/twentyfifteen/assets/pier-seagulls.jpg
index 01d52f1dc899c..6f318856fa6fc 100644
Binary files a/src/wp-content/themes/twentyfifteen/assets/pier-seagulls.jpg and b/src/wp-content/themes/twentyfifteen/assets/pier-seagulls.jpg differ
diff --git a/src/wp-content/themes/twentyfifteen/assets/pier-sunset.jpg b/src/wp-content/themes/twentyfifteen/assets/pier-sunset.jpg
index 75430630a0e79..f69dc562d2260 100644
Binary files a/src/wp-content/themes/twentyfifteen/assets/pier-sunset.jpg and b/src/wp-content/themes/twentyfifteen/assets/pier-sunset.jpg differ
diff --git a/src/wp-content/themes/twentyfifteen/css/blocks.css b/src/wp-content/themes/twentyfifteen/css/blocks.css
index 5967ea52e9f30..3487cc7b98ef4 100644
--- a/src/wp-content/themes/twentyfifteen/css/blocks.css
+++ b/src/wp-content/themes/twentyfifteen/css/blocks.css
@@ -470,7 +470,7 @@ p.has-drop-cap:not(:focus)::first-letter {
}
}
-/* Seperators */
+/* Separators */
.wp-block-separator {
border: 0;
diff --git a/src/wp-content/themes/twentyfourteen/images/bridge.jpg b/src/wp-content/themes/twentyfourteen/images/bridge.jpg
index d172bb2818995..a0bf15159f6ac 100644
Binary files a/src/wp-content/themes/twentyfourteen/images/bridge.jpg and b/src/wp-content/themes/twentyfourteen/images/bridge.jpg differ
diff --git a/src/wp-content/themes/twentyfourteen/images/clouds.jpg b/src/wp-content/themes/twentyfourteen/images/clouds.jpg
index f753465d6fb89..1e550a14a1bce 100644
Binary files a/src/wp-content/themes/twentyfourteen/images/clouds.jpg and b/src/wp-content/themes/twentyfourteen/images/clouds.jpg differ
diff --git a/src/wp-content/themes/twentyfourteen/images/person.jpg b/src/wp-content/themes/twentyfourteen/images/person.jpg
index 8dbad50819938..83febdaad03c7 100644
Binary files a/src/wp-content/themes/twentyfourteen/images/person.jpg and b/src/wp-content/themes/twentyfourteen/images/person.jpg differ
diff --git a/src/wp-content/themes/twentyfourteen/images/street.jpg b/src/wp-content/themes/twentyfourteen/images/street.jpg
index 71735a04b6f60..2111f1a750a9e 100644
Binary files a/src/wp-content/themes/twentyfourteen/images/street.jpg and b/src/wp-content/themes/twentyfourteen/images/street.jpg differ
diff --git a/src/wp-content/themes/twentyfourteen/images/sunset.jpg b/src/wp-content/themes/twentyfourteen/images/sunset.jpg
index 8c1b379fbaed3..892b195586df9 100644
Binary files a/src/wp-content/themes/twentyfourteen/images/sunset.jpg and b/src/wp-content/themes/twentyfourteen/images/sunset.jpg differ
diff --git a/src/wp-content/themes/twentynineteen/image.php b/src/wp-content/themes/twentynineteen/image.php
index a3580b4e668f3..defab756b252f 100644
--- a/src/wp-content/themes/twentynineteen/image.php
+++ b/src/wp-content/themes/twentynineteen/image.php
@@ -32,7 +32,7 @@
/**
* Filters the default twentynineteen image attachment size.
*
- * @since Twenty Sixteen 1.0
+ * @since Twenty Nineteen 1.0
*
* @param string $image_size Image size. Default 'large'.
*/
diff --git a/src/wp-content/themes/twentynineteen/images/pattern_01.jpg b/src/wp-content/themes/twentynineteen/images/pattern_01.jpg
index b6bc3b477892a..e01b19df0ed10 100644
Binary files a/src/wp-content/themes/twentynineteen/images/pattern_01.jpg and b/src/wp-content/themes/twentynineteen/images/pattern_01.jpg differ
diff --git a/src/wp-content/themes/twentynineteen/images/pattern_02.jpg b/src/wp-content/themes/twentynineteen/images/pattern_02.jpg
index 88d66f2f3a3b1..56c7f70943244 100644
Binary files a/src/wp-content/themes/twentynineteen/images/pattern_02.jpg and b/src/wp-content/themes/twentynineteen/images/pattern_02.jpg differ
diff --git a/src/wp-content/themes/twentynineteen/images/pattern_03.jpg b/src/wp-content/themes/twentynineteen/images/pattern_03.jpg
index 0b323a8a02869..bd69d37a29112 100644
Binary files a/src/wp-content/themes/twentynineteen/images/pattern_03.jpg and b/src/wp-content/themes/twentynineteen/images/pattern_03.jpg differ
diff --git a/src/wp-content/themes/twentynineteen/images/pattern_04.jpg b/src/wp-content/themes/twentynineteen/images/pattern_04.jpg
index 8e5a4936bd7ca..b7419fe4f4be2 100644
Binary files a/src/wp-content/themes/twentynineteen/images/pattern_04.jpg and b/src/wp-content/themes/twentynineteen/images/pattern_04.jpg differ
diff --git a/src/wp-content/themes/twentynineteen/screenshot.png b/src/wp-content/themes/twentynineteen/screenshot.png
index 7dc53c5f1dd49..fa27e95463571 100644
Binary files a/src/wp-content/themes/twentynineteen/screenshot.png and b/src/wp-content/themes/twentynineteen/screenshot.png differ
diff --git a/src/wp-content/themes/twentyseventeen/assets/images/coffee.jpg b/src/wp-content/themes/twentyseventeen/assets/images/coffee.jpg
index 13847cde7c16b..145d1f7116484 100644
Binary files a/src/wp-content/themes/twentyseventeen/assets/images/coffee.jpg and b/src/wp-content/themes/twentyseventeen/assets/images/coffee.jpg differ
diff --git a/src/wp-content/themes/twentyseventeen/assets/images/direct-light.jpg b/src/wp-content/themes/twentyseventeen/assets/images/direct-light.jpg
index a3255791e79a5..8f3d814c57b19 100644
Binary files a/src/wp-content/themes/twentyseventeen/assets/images/direct-light.jpg and b/src/wp-content/themes/twentyseventeen/assets/images/direct-light.jpg differ
diff --git a/src/wp-content/themes/twentyseventeen/assets/images/espresso.jpg b/src/wp-content/themes/twentyseventeen/assets/images/espresso.jpg
index 7514c96bdfaf9..a3bd2c6dc0049 100644
Binary files a/src/wp-content/themes/twentyseventeen/assets/images/espresso.jpg and b/src/wp-content/themes/twentyseventeen/assets/images/espresso.jpg differ
diff --git a/src/wp-content/themes/twentyseventeen/assets/images/header.jpg b/src/wp-content/themes/twentyseventeen/assets/images/header.jpg
index a3fd3e7122cbc..ef2c07aff98eb 100644
Binary files a/src/wp-content/themes/twentyseventeen/assets/images/header.jpg and b/src/wp-content/themes/twentyseventeen/assets/images/header.jpg differ
diff --git a/src/wp-content/themes/twentyseventeen/assets/images/sandwich.jpg b/src/wp-content/themes/twentyseventeen/assets/images/sandwich.jpg
index 6baddbf053749..cf81066b2eebc 100644
Binary files a/src/wp-content/themes/twentyseventeen/assets/images/sandwich.jpg and b/src/wp-content/themes/twentyseventeen/assets/images/sandwich.jpg differ
diff --git a/src/wp-content/themes/twentyseventeen/assets/images/stripes.jpg b/src/wp-content/themes/twentyseventeen/assets/images/stripes.jpg
index 26e3b6d10ce6c..2e0920ff7e257 100644
Binary files a/src/wp-content/themes/twentyseventeen/assets/images/stripes.jpg and b/src/wp-content/themes/twentyseventeen/assets/images/stripes.jpg differ
diff --git a/src/wp-content/themes/twentyseventeen/assets/images/white-border.jpg b/src/wp-content/themes/twentyseventeen/assets/images/white-border.jpg
index a1b11d77cd3f5..40773b14bd028 100644
Binary files a/src/wp-content/themes/twentyseventeen/assets/images/white-border.jpg and b/src/wp-content/themes/twentyseventeen/assets/images/white-border.jpg differ
diff --git a/src/wp-content/themes/twentyseventeen/inc/block-patterns.php b/src/wp-content/themes/twentyseventeen/inc/block-patterns.php
index 66e6fa0c87300..f013aa9a545cc 100644
--- a/src/wp-content/themes/twentyseventeen/inc/block-patterns.php
+++ b/src/wp-content/themes/twentyseventeen/inc/block-patterns.php
@@ -1,6 +1,6 @@
get( 'Version' ), 'all' );
+
// Add output of Customizer settings as inline style.
$customizer_css = twentytwenty_get_customizer_css( 'front-end' );
if ( $customizer_css ) {
@@ -417,6 +421,7 @@ function twentytwenty_sidebar_registration() {
*
* @since Twenty Twenty 1.0
* @since Twenty Twenty 2.4 Removed a script related to the obsolete Squared style of Button blocks.
+ * @since Twenty Twenty 2.6 Enqueue the CSS file for the variable font.
*/
function twentytwenty_block_editor_styles() {
@@ -430,6 +435,9 @@ function twentytwenty_block_editor_styles() {
wp_add_inline_style( 'twentytwenty-block-editor-styles', $customizer_css );
}
+ // Enqueue the CSS file for the variable font, Inter.
+ wp_enqueue_style( 'twentytwenty-fonts', get_theme_file_uri( '/assets/css/font-inter.css' ), array(), wp_get_theme()->get( 'Version' ), 'all' );
+
// Add inline style for non-latin fonts.
$custom_css = TwentyTwenty_Non_Latin_Languages::get_non_latin_css( 'block-editor' );
if ( $custom_css ) {
@@ -447,11 +455,13 @@ function twentytwenty_block_editor_styles() {
* Enqueue classic editor styles.
*
* @since Twenty Twenty 1.0
+ * @since Twenty Twenty 2.6 Enqueue the CSS file for the variable font.
*/
function twentytwenty_classic_editor_styles() {
$classic_editor_styles = array(
'/assets/css/editor-style-classic.css',
+ '/assets/css/font-inter.css',
);
add_editor_style( $classic_editor_styles );
diff --git a/src/wp-content/themes/twentytwentyfour/functions.php b/src/wp-content/themes/twentytwentyfour/functions.php
index baee062f6f14c..8536cb8423163 100644
--- a/src/wp-content/themes/twentytwentyfour/functions.php
+++ b/src/wp-content/themes/twentytwentyfour/functions.php
@@ -194,7 +194,7 @@ function twentytwentyfour_block_stylesheets() {
function twentytwentyfour_pattern_categories() {
register_block_pattern_category(
- 'page',
+ 'twentytwentyfour_page',
array(
'label' => _x( 'Pages', 'Block pattern category', 'twentytwentyfour' ),
'description' => __( 'A collection of full page layouts.', 'twentytwentyfour' ),
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/hidden-portfolio-hero.php b/src/wp-content/themes/twentytwentyfour/patterns/hidden-portfolio-hero.php
index b0922d2ec27f4..1af3e7dbd17c1 100644
--- a/src/wp-content/themes/twentytwentyfour/patterns/hidden-portfolio-hero.php
+++ b/src/wp-content/themes/twentytwentyfour/patterns/hidden-portfolio-hero.php
@@ -13,7 +13,7 @@
-
Leia Acosta, a passionate photographer who finds inspiration in capturing the fleeting beauty of life.', 'twentytwentyfour ' ) ); ?>
+ Leia Acosta, a passionate photographer who finds inspiration in capturing the fleeting beauty of life.', 'twentytwentyfour' ) ); ?>
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/page-about-business.php b/src/wp-content/themes/twentytwentyfour/patterns/page-about-business.php
index f04b20940c519..ad626980e177b 100644
--- a/src/wp-content/themes/twentytwentyfour/patterns/page-about-business.php
+++ b/src/wp-content/themes/twentytwentyfour/patterns/page-about-business.php
@@ -2,7 +2,7 @@
/**
* Title: About
* Slug: twentytwentyfour/page-about-business
- * Categories: page
+ * Categories: twentytwentyfour_page
* Keywords: starter
* Block Types: core/post-content
* Post Types: page, wp_template
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/page-home-blogging.php b/src/wp-content/themes/twentytwentyfour/patterns/page-home-blogging.php
index ae88e9006c74c..5cef5d4e5028c 100644
--- a/src/wp-content/themes/twentytwentyfour/patterns/page-home-blogging.php
+++ b/src/wp-content/themes/twentytwentyfour/patterns/page-home-blogging.php
@@ -2,7 +2,7 @@
/**
* Title: Blogging home
* Slug: twentytwentyfour/page-home-blogging
- * Categories: page
+ * Categories: twentytwentyfour_page
* Keywords: page, starter
* Post Types: page, wp_template
* Viewport width: 1400
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/page-home-business.php b/src/wp-content/themes/twentytwentyfour/patterns/page-home-business.php
index ca22952174553..415c42f1d913b 100644
--- a/src/wp-content/themes/twentytwentyfour/patterns/page-home-business.php
+++ b/src/wp-content/themes/twentytwentyfour/patterns/page-home-business.php
@@ -2,7 +2,7 @@
/**
* Title: Business home
* Slug: twentytwentyfour/page-home-business
- * Categories: page
+ * Categories: twentytwentyfour_page
* Keywords: starter
* Block Types: core/post-content
* Post Types: page, wp_template
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/page-home-portfolio-gallery.php b/src/wp-content/themes/twentytwentyfour/patterns/page-home-portfolio-gallery.php
index cce1fdb106845..a9ce9d760a682 100644
--- a/src/wp-content/themes/twentytwentyfour/patterns/page-home-portfolio-gallery.php
+++ b/src/wp-content/themes/twentytwentyfour/patterns/page-home-portfolio-gallery.php
@@ -2,7 +2,7 @@
/**
* Title: Portfolio home image gallery
* Slug: twentytwentyfour/page-home-gallery
- * Categories: page
+ * Categories: twentytwentyfour_page
* Keywords: starter
* Block Types: core/post-content
* Post Types: page, wp_template
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/page-home-portfolio.php b/src/wp-content/themes/twentytwentyfour/patterns/page-home-portfolio.php
index 4f3c473f0b21a..40d4fa1e751bd 100644
--- a/src/wp-content/themes/twentytwentyfour/patterns/page-home-portfolio.php
+++ b/src/wp-content/themes/twentytwentyfour/patterns/page-home-portfolio.php
@@ -2,7 +2,7 @@
/**
* Title: Portfolio home with post featured images
* Slug: twentytwentyfour/page-home-portfolio
- * Categories: page
+ * Categories: twentytwentyfour_page
* Keywords: starter
* Block Types: core/post-content
* Post Types: page, wp_template
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/page-newsletter-landing.php b/src/wp-content/themes/twentytwentyfour/patterns/page-newsletter-landing.php
index 24c6d9a86fb57..5ee552e5008df 100644
--- a/src/wp-content/themes/twentytwentyfour/patterns/page-newsletter-landing.php
+++ b/src/wp-content/themes/twentytwentyfour/patterns/page-newsletter-landing.php
@@ -2,7 +2,7 @@
/**
* Title: Newsletter landing
* Slug: twentytwentyfour/page-newsletter-landing
- * Categories: call-to-action, page, featured
+ * Categories: call-to-action, twentytwentyfour_page, featured
* Keywords: starter
* Block Types: core/post-content
* Post Types: page, wp_template
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/page-portfolio-overview.php b/src/wp-content/themes/twentytwentyfour/patterns/page-portfolio-overview.php
index 3e29b11387a27..b0bf21b480285 100644
--- a/src/wp-content/themes/twentytwentyfour/patterns/page-portfolio-overview.php
+++ b/src/wp-content/themes/twentytwentyfour/patterns/page-portfolio-overview.php
@@ -2,7 +2,7 @@
/**
* Title: Portfolio project overview
* Slug: twentytwentyfour/page-portfolio-overview
- * Categories: page, featured
+ * Categories: twentytwentyfour_page, featured
* Keywords: starter
* Block Types: core/post-content
* Post Types: page, wp_template
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/page-rsvp-landing.php b/src/wp-content/themes/twentytwentyfour/patterns/page-rsvp-landing.php
index 469a13426a477..8b3ba8316cf86 100644
--- a/src/wp-content/themes/twentytwentyfour/patterns/page-rsvp-landing.php
+++ b/src/wp-content/themes/twentytwentyfour/patterns/page-rsvp-landing.php
@@ -2,7 +2,7 @@
/**
* Title: RSVP landing
* Slug: twentytwentyfour/page-rsvp-landing
- * Categories: page
+ * Categories: twentytwentyfour_page
* Keywords: starter
* Block Types: core/post-content
* Post Types: page, wp_template
diff --git a/src/wp-content/themes/twentytwentyfour/readme.txt b/src/wp-content/themes/twentytwentyfour/readme.txt
index c1837d46368a7..fcb6cdc9f9d7e 100644
--- a/src/wp-content/themes/twentytwentyfour/readme.txt
+++ b/src/wp-content/themes/twentytwentyfour/readme.txt
@@ -33,7 +33,33 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
+
+This theme bundles the following third-party resources:
+
+=== Fonts ===
+
+Cardo Font
+Copyright (c) 2002-2011, David J. Perry (hospes02@scholarsfonts.net)
+License: SIL Open Font License, 1.1, https://opensource.org/licenses/OFL-1.1
+Source: http://scholarsfonts.net
+
+Instrument Sans Font
+Copyright 2022 The Instrument Sans Project Authors.
+License: SIL Open Font License, 1.1, https://opensource.org/licenses/OFL-1.1
+Source: https://github.com/Instrument/instrument-sans
+
+Inter Font
+Copyright 2020 The Inter Project Authors.
+License: SIL Open Font License, 1.1, https://opensource.org/licenses/OFL-1.1
+Source: https://github.com/rsms/inter
+
+Jost Font
+Copyright 2020 The Jost Project Authors.
+License: SIL Open Font License, 1.1, https://opensource.org/licenses/OFL-1.1
+Source: https://github.com/indestructible-type/Jost
+
=== Images ===
+
License: CC0 https://creativecommons.org/publicdomain/zero/1.0/
museum.webp - https://www.rawpixel.com/image/3297419/free-photo-image-interior-hallway-architecture
diff --git a/src/wp-content/themes/twentytwentyfour/screenshot.png b/src/wp-content/themes/twentytwentyfour/screenshot.png
index 40c5b99e9f874..74fa4c7a1e3e5 100644
Binary files a/src/wp-content/themes/twentytwentyfour/screenshot.png and b/src/wp-content/themes/twentytwentyfour/screenshot.png differ
diff --git a/src/wp-content/themes/twentytwentyfour/theme.json b/src/wp-content/themes/twentytwentyfour/theme.json
index 7988b1af5c15f..8acd7993c342e 100644
--- a/src/wp-content/themes/twentytwentyfour/theme.json
+++ b/src/wp-content/themes/twentytwentyfour/theme.json
@@ -247,7 +247,7 @@
{
"fontFamily": "Iowan Old Style, Apple Garamond, Baskerville, Times New Roman, Droid Serif, Times, Source Serif Pro, serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol",
"name": "System Serif",
- "slug": "system-Serif"
+ "slug": "system-serif"
}
],
"fontSizes": [
@@ -795,9 +795,7 @@
},
"outline": {
"color": "var(--wp--preset--color--contrast)",
- "offset": "2px",
- "style": "dotted",
- "width": "1px"
+ "offset": "2px"
},
"border": {
"color": "var(--wp--preset--color--contrast-2)"
@@ -908,7 +906,8 @@
"fontStyle": "normal",
"fontWeight": "400",
"lineHeight": "1.55"
- }
+ },
+ "css": ".wp-site-blocks *:focus{outline-width:2px;outline-style:solid}"
},
"templateParts": [
{
diff --git a/src/wp-content/themes/twentytwentyone/assets/images/Daffodils.jpg b/src/wp-content/themes/twentytwentyone/assets/images/Daffodils.jpg
index bd062b93cc74d..409522aeb1f53 100644
Binary files a/src/wp-content/themes/twentytwentyone/assets/images/Daffodils.jpg and b/src/wp-content/themes/twentytwentyone/assets/images/Daffodils.jpg differ
diff --git a/src/wp-content/themes/twentytwentyone/assets/images/Reading.jpg b/src/wp-content/themes/twentytwentyone/assets/images/Reading.jpg
index cfa732a57aa05..841e45ce50344 100644
Binary files a/src/wp-content/themes/twentytwentyone/assets/images/Reading.jpg and b/src/wp-content/themes/twentytwentyone/assets/images/Reading.jpg differ
diff --git a/src/wp-content/themes/twentytwentyone/assets/images/in-the-bois-de-boulogne.jpg b/src/wp-content/themes/twentytwentyone/assets/images/in-the-bois-de-boulogne.jpg
index cf74f5df046fb..0e03bde64ccd9 100644
Binary files a/src/wp-content/themes/twentytwentyone/assets/images/in-the-bois-de-boulogne.jpg and b/src/wp-content/themes/twentytwentyone/assets/images/in-the-bois-de-boulogne.jpg differ
diff --git a/src/wp-content/themes/twentytwentyone/assets/images/playing-in-the-sand.jpg b/src/wp-content/themes/twentytwentyone/assets/images/playing-in-the-sand.jpg
index 557ae0f7cdd44..6a90421102a96 100644
Binary files a/src/wp-content/themes/twentytwentyone/assets/images/playing-in-the-sand.jpg and b/src/wp-content/themes/twentytwentyone/assets/images/playing-in-the-sand.jpg differ
diff --git a/src/wp-content/themes/twentytwentyone/assets/images/roses-tremieres-hollyhocks-1884.jpg b/src/wp-content/themes/twentytwentyone/assets/images/roses-tremieres-hollyhocks-1884.jpg
index ff534164dcb34..0386999e241be 100644
Binary files a/src/wp-content/themes/twentytwentyone/assets/images/roses-tremieres-hollyhocks-1884.jpg and b/src/wp-content/themes/twentytwentyone/assets/images/roses-tremieres-hollyhocks-1884.jpg differ
diff --git a/src/wp-content/themes/twentytwentyone/assets/images/self-portrait-1885.jpg b/src/wp-content/themes/twentytwentyone/assets/images/self-portrait-1885.jpg
index 623598b60c4b2..f6adaed8d19af 100644
Binary files a/src/wp-content/themes/twentytwentyone/assets/images/self-portrait-1885.jpg and b/src/wp-content/themes/twentytwentyone/assets/images/self-portrait-1885.jpg differ
diff --git a/src/wp-content/themes/twentytwentyone/assets/images/the-garden-at-bougival-1884.jpg b/src/wp-content/themes/twentytwentyone/assets/images/the-garden-at-bougival-1884.jpg
index 6594d3d1bd868..4315638330856 100644
Binary files a/src/wp-content/themes/twentytwentyone/assets/images/the-garden-at-bougival-1884.jpg and b/src/wp-content/themes/twentytwentyone/assets/images/the-garden-at-bougival-1884.jpg differ
diff --git a/src/wp-content/themes/twentytwentyone/assets/images/villa-with-orange-trees-nice.jpg b/src/wp-content/themes/twentytwentyone/assets/images/villa-with-orange-trees-nice.jpg
index 5b78d968d5b57..652a24702a4d7 100644
Binary files a/src/wp-content/themes/twentytwentyone/assets/images/villa-with-orange-trees-nice.jpg and b/src/wp-content/themes/twentytwentyone/assets/images/villa-with-orange-trees-nice.jpg differ
diff --git a/src/wp-content/themes/twentytwentyone/assets/images/young-woman-in-mauve.jpg b/src/wp-content/themes/twentytwentyone/assets/images/young-woman-in-mauve.jpg
index df00d3147c6c7..cedf9cb5daf60 100644
Binary files a/src/wp-content/themes/twentytwentyone/assets/images/young-woman-in-mauve.jpg and b/src/wp-content/themes/twentytwentyone/assets/images/young-woman-in-mauve.jpg differ
diff --git a/src/wp-content/themes/twentytwentythree/screenshot.png b/src/wp-content/themes/twentytwentythree/screenshot.png
index d405921ea31a0..dee93e471f8d2 100644
Binary files a/src/wp-content/themes/twentytwentythree/screenshot.png and b/src/wp-content/themes/twentytwentythree/screenshot.png differ
diff --git a/src/wp-content/themes/twentytwentythree/theme.json b/src/wp-content/themes/twentytwentythree/theme.json
index 68e17a87e9adc..f28146fa05b86 100644
--- a/src/wp-content/themes/twentytwentythree/theme.json
+++ b/src/wp-content/themes/twentytwentythree/theme.json
@@ -730,7 +730,7 @@
{
"area": "uncategorized",
"name": "comments",
- "title": "Comments"
+ "title": "Comments Template Part"
},
{
"area": "uncategorized",
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-black.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-black.jpg
index 684affb490bfa..15194fe0ef8c9 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-black.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-black.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-gray.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-gray.jpg
index 4fde7652c330d..7f9092608cf1b 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-gray.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-gray.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-green.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-green.jpg
index f1b5505478129..86f626508d039 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-green.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-green.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-salmon.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-salmon.jpg
index 727c70ea6b335..d854f6d061aa8 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-salmon.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/bird-on-salmon.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/ducks.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/ducks.jpg
index 6c65eb4313aa3..ff8c3a2d3c0a2 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/ducks.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/ducks.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-a.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-a.jpg
index b533d0f140d3e..f2b0c1ded8f5a 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-a.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-a.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-b.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-b.jpg
index 9314e9fa2fd94..78df7e72f7cc0 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-b.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-b.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-c.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-c.jpg
index 3797692068362..ffca8031b3de5 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-c.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-gray-c.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-salmon.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-salmon.jpg
index 86731b9037e6d..28114804915c2 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-salmon.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/flight-path-on-salmon.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/assets/images/icon-bird.jpg b/src/wp-content/themes/twentytwentytwo/assets/images/icon-bird.jpg
index dbfa90e40a3ed..308cadc37bd0c 100644
Binary files a/src/wp-content/themes/twentytwentytwo/assets/images/icon-bird.jpg and b/src/wp-content/themes/twentytwentytwo/assets/images/icon-bird.jpg differ
diff --git a/src/wp-content/themes/twentytwentytwo/screenshot.png b/src/wp-content/themes/twentytwentytwo/screenshot.png
index 9e8710cde3419..0bba95b9b4a6e 100644
Binary files a/src/wp-content/themes/twentytwentytwo/screenshot.png and b/src/wp-content/themes/twentytwentytwo/screenshot.png differ
diff --git a/src/wp-content/themes/twentytwentytwo/theme.json b/src/wp-content/themes/twentytwentytwo/theme.json
index 41ffb72d98cbd..ec9ff8644e4af 100644
--- a/src/wp-content/themes/twentytwentytwo/theme.json
+++ b/src/wp-content/themes/twentytwentytwo/theme.json
@@ -1,4 +1,5 @@
{
+ "$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"customTemplates": [
{
diff --git a/src/wp-includes/Text/Diff.php b/src/wp-includes/Text/Diff.php
index 40dba1a4a37cf..eee4e4f8ea531 100644
--- a/src/wp-includes/Text/Diff.php
+++ b/src/wp-includes/Text/Diff.php
@@ -296,7 +296,7 @@ class Text_MappedDiff extends Text_Diff {
/**
* Computes a diff between sequences of strings.
*
- * This can be used to compute things like case-insensitve diffs, or diffs
+ * This can be used to compute things like case-insensitive diffs, or diffs
* which ignore changes in white-space.
*
* @param array $from_lines An array of strings.
diff --git a/src/wp-includes/assets/script-loader-packages.min.php b/src/wp-includes/assets/script-loader-packages.min.php
index 11257c8d1e0c0..2b05108405693 100644
--- a/src/wp-includes/assets/script-loader-packages.min.php
+++ b/src/wp-includes/assets/script-loader-packages.min.php
@@ -1 +1 @@
- array('dependencies' => array('wp-dom-ready', 'wp-i18n', 'wp-polyfill'), 'version' => '7032343a947cfccf5608'), 'annotations.min.js' => array('dependencies' => array('wp-data', 'wp-hooks', 'wp-i18n', 'wp-polyfill', 'wp-rich-text'), 'version' => 'c4843f8e435a9d7a87bb'), 'api-fetch.min.js' => array('dependencies' => array('wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '0fa4dabf8bf2c7adf21a'), 'autop.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'dacd785d109317df2707'), 'blob.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '10a1c5c0acdef3d15657'), 'block-directory.min.js' => array('dependencies' => array('wp-a11y', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '5b7cd5ab23c9d68e0b1e'), 'block-editor.min.js' => array('dependencies' => array('react', 'react-dom', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-shortcode', 'wp-style-engine', 'wp-token-list', 'wp-url', 'wp-warning', 'wp-wordcount'), 'version' => '8a070b748cf406a8d42e'), 'block-library.min.js' => array('dependencies' => array('wp-a11y', 'wp-api-fetch', 'wp-autop', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keycodes', 'wp-notices', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', 'wp-url', 'wp-viewport', 'wp-wordcount'), 'version' => '9c5365423f60fac3c287'), 'block-serialization-default-parser.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '30ffd7e7e199f10b2a6d'), 'blocks.min.js' => array('dependencies' => array('wp-autop', 'wp-blob', 'wp-block-serialization-default-parser', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-private-apis', 'wp-shortcode'), 'version' => '7204d43123223474471a'), 'commands.min.js' => array('dependencies' => array('react', 'react-dom', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-polyfill', 'wp-primitives', 'wp-private-apis'), 'version' => '07ff2b66990783ecd068'), 'components.min.js' => array('dependencies' => array('react', 'react-dom', 'wp-a11y', 'wp-compose', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keycodes', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-warning'), 'version' => '387d6480ace3103ccd8b'), 'compose.min.js' => array('dependencies' => array('react', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-is-shallow-equal', 'wp-keycodes', 'wp-polyfill', 'wp-priority-queue'), 'version' => '3189b344ff39fef940b7'), 'core-commands.min.js' => array('dependencies' => array('wp-commands', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-router', 'wp-url'), 'version' => 'ade490de79d35734e06d'), 'core-data.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-private-apis', 'wp-url'), 'version' => '99b262137df116eb6013'), 'customize-widgets.min.js' => array('dependencies' => array('wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-widgets'), 'version' => 'bb454c7f10757887ce5a'), 'data.min.js' => array('dependencies' => array('wp-compose', 'wp-deprecated', 'wp-element', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-priority-queue', 'wp-private-apis', 'wp-redux-routine'), 'version' => 'dc5f255634f3da29c8d5'), 'data-controls.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-data', 'wp-deprecated', 'wp-polyfill'), 'version' => 'fe4ccc8a1782ea8e2cb1'), 'date.min.js' => array('dependencies' => array('moment', 'wp-deprecated', 'wp-polyfill'), 'version' => '936c461ad5dce9c2c8ea'), 'deprecated.min.js' => array('dependencies' => array('wp-hooks', 'wp-polyfill'), 'version' => '73ad3591e7bc95f4777a'), 'dom.min.js' => array('dependencies' => array('wp-deprecated', 'wp-polyfill'), 'version' => '49ff2869626fbeaacc23'), 'dom-ready.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '392bdd43726760d1f3ca'), 'edit-post.min.js' => array('dependencies' => array('wp-a11y', 'wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-commands', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-viewport', 'wp-warning', 'wp-widgets'), 'version' => '6720d8a86f225f3ce492'), 'edit-site.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-commands', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-editor', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-reusable-blocks', 'wp-router', 'wp-url', 'wp-viewport', 'wp-widgets', 'wp-wordcount'), 'version' => 'c25cbb9d6b28255c1cb6'), 'edit-widgets.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-viewport', 'wp-widgets'), 'version' => '64e3e5b8558ec09ac4ba'), 'editor.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', 'wp-url', 'wp-wordcount'), 'version' => '5abe10197275cf7808ee'), 'element.min.js' => array('dependencies' => array('react', 'react-dom', 'wp-escape-html', 'wp-polyfill'), 'version' => 'ed1c7604880e8b574b40'), 'escape-html.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '03e27a7b6ae14f7afaa6'), 'format-library.min.js' => array('dependencies' => array('wp-a11y', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-rich-text', 'wp-url'), 'version' => '57955a6a6df65c1fb8b6'), 'hooks.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'c6aec9a8d4e5a5d543a1'), 'html-entities.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '36a4a255da7dd2e1bf8e'), 'i18n.min.js' => array('dependencies' => array('wp-hooks', 'wp-polyfill'), 'version' => '7701b0c3857f914212ef'), 'is-shallow-equal.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '20c2b06ecf04afb14fee'), 'keyboard-shortcuts.min.js' => array('dependencies' => array('wp-data', 'wp-element', 'wp-keycodes', 'wp-polyfill'), 'version' => '525da859946d4df24898'), 'keycodes.min.js' => array('dependencies' => array('wp-i18n', 'wp-polyfill'), 'version' => '3460bd0fac9859d6886c'), 'list-reusable-blocks.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-components', 'wp-compose', 'wp-element', 'wp-i18n', 'wp-polyfill'), 'version' => '4d77f2834116824e70c8'), 'media-utils.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-blob', 'wp-element', 'wp-i18n', 'wp-polyfill'), 'version' => 'bcd60e7a2fb568f38015'), 'notices.min.js' => array('dependencies' => array('wp-data', 'wp-polyfill'), 'version' => '38e88f4b627cf873edd0'), 'nux.min.js' => array('dependencies' => array('wp-components', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives'), 'version' => '59718fab5e39f9dd21b0'), 'patterns.min.js' => array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-url'), 'version' => 'efcce5c1b2c28e8b2865'), 'plugins.min.js' => array('dependencies' => array('wp-compose', 'wp-element', 'wp-hooks', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-primitives'), 'version' => 'c485ff6186cdddabcf91'), 'preferences.min.js' => array('dependencies' => array('wp-a11y', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives'), 'version' => 'ca088ba0a612bff77aa3'), 'preferences-persistence.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-polyfill'), 'version' => '6c6b220422eb35541489'), 'primitives.min.js' => array('dependencies' => array('wp-element', 'wp-polyfill'), 'version' => '6984e6eb5d6157c4fe44'), 'priority-queue.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '422e19e9d48b269c5219'), 'private-apis.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '11cb2ebaa70a9f1f0ab5'), 'redux-routine.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '0be1b2a6a79703e28531'), 'reusable-blocks.min.js' => array('dependencies' => array('wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-url'), 'version' => 'f43df5cec4d4061a74f0'), 'rich-text.min.js' => array('dependencies' => array('wp-a11y', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-escape-html', 'wp-i18n', 'wp-keycodes', 'wp-polyfill'), 'version' => '6222504ebedf0627981b'), 'router.min.js' => array('dependencies' => array('wp-element', 'wp-polyfill', 'wp-private-apis', 'wp-url'), 'version' => 'd1ae6718bab1f7073adb'), 'server-side-render.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '81299db67c0fa2c65479'), 'shortcode.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'c128a3008a96e820aa86'), 'style-engine.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '17cbc030cba88a42ccb5'), 'token-list.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '199103fc7cec3b9eef5a'), 'undo-manager.min.js' => array('dependencies' => array('wp-is-shallow-equal', 'wp-polyfill'), 'version' => '312610424b40059d9f44'), 'url.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'b4979979018b684be209'), 'viewport.min.js' => array('dependencies' => array('wp-compose', 'wp-data', 'wp-element', 'wp-polyfill'), 'version' => '1fbef8175bb335c5603b'), 'warning.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '122829a085511691f14d'), 'widgets.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-polyfill', 'wp-primitives'), 'version' => '938735ae45e739ac8b70'), 'wordcount.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '5a74890fd7c610679e34'));
+ array('dependencies' => array('wp-dom-ready', 'wp-i18n', 'wp-polyfill'), 'version' => 'd90eebea464f6c09bfd5'), 'annotations.min.js' => array('dependencies' => array('wp-data', 'wp-hooks', 'wp-i18n', 'wp-polyfill', 'wp-rich-text'), 'version' => 'ffc4fc3374b0ab000805'), 'api-fetch.min.js' => array('dependencies' => array('wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '4c185334c5ec26e149cc'), 'autop.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '9fb50649848277dd318d'), 'blob.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '9113eed771d446f4a556'), 'block-directory.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-plugins', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-url'), 'version' => '9159053f41b8ec09d91b'), 'block-editor.min.js' => array('dependencies' => array('react', 'react-dom', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-notices', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-style-engine', 'wp-token-list', 'wp-url', 'wp-warning', 'wp-wordcount'), 'version' => 'a982b7f1ddc404c9763b'), 'block-library.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-api-fetch', 'wp-autop', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keycodes', 'wp-notices', 'wp-patterns', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', 'wp-url', 'wp-viewport', 'wp-wordcount'), 'version' => '8a0c07fbc60b644cf03e'), 'block-serialization-default-parser.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '14d44daebf663d05d330'), 'blocks.min.js' => array('dependencies' => array('react', 'wp-autop', 'wp-blob', 'wp-block-serialization-default-parser', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-private-apis', 'wp-rich-text', 'wp-shortcode'), 'version' => '64a9ab28b62423f79e07'), 'commands.min.js' => array('dependencies' => array('react', 'react-dom', 'wp-components', 'wp-data', 'wp-element', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-polyfill', 'wp-primitives', 'wp-private-apis'), 'version' => '0674417708cae5031b37'), 'components.min.js' => array('dependencies' => array('react', 'react-dom', 'wp-a11y', 'wp-compose', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keycodes', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-warning'), 'version' => '629594950877ccba0f43'), 'compose.min.js' => array('dependencies' => array('react', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-is-shallow-equal', 'wp-keycodes', 'wp-polyfill', 'wp-priority-queue'), 'version' => '1f65d1d8719bc97357e7'), 'core-commands.min.js' => array('dependencies' => array('react', 'wp-commands', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-router', 'wp-url'), 'version' => 'dbbc54588f73c5b23fa3'), 'core-data.min.js' => array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-private-apis', 'wp-rich-text', 'wp-url'), 'version' => 'dba2ea4cdd526475d52a'), 'customize-widgets.min.js' => array('dependencies' => array('react', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-is-shallow-equal', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-widgets'), 'version' => 'a44197f146efda4b8ad1'), 'data.min.js' => array('dependencies' => array('react', 'wp-compose', 'wp-deprecated', 'wp-element', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-priority-queue', 'wp-private-apis', 'wp-redux-routine'), 'version' => '70790e390a9624c9cef4'), 'data-controls.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-data', 'wp-deprecated', 'wp-polyfill'), 'version' => '49f5587e8b90f9e7cc7e'), 'date.min.js' => array('dependencies' => array('moment', 'wp-deprecated', 'wp-polyfill'), 'version' => 'ddd596bc6f2a45364bf2'), 'deprecated.min.js' => array('dependencies' => array('wp-hooks', 'wp-polyfill'), 'version' => 'e1f84915c5e8ae38964c'), 'dom.min.js' => array('dependencies' => array('wp-deprecated', 'wp-polyfill'), 'version' => '4ecffbffba91b10c5c7a'), 'dom-ready.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'f77871ff7694fffea381'), 'edit-post.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-commands', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-editor', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-viewport', 'wp-warning', 'wp-widgets'), 'version' => 'e4fe739cfb5191e88233'), 'edit-site.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-commands', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-editor', 'wp-element', 'wp-escape-html', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-reusable-blocks', 'wp-router', 'wp-url', 'wp-viewport', 'wp-widgets', 'wp-wordcount'), 'version' => '3bf825ca8a8349b15d7d'), 'edit-widgets.min.js' => array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-block-library', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-plugins', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-url', 'wp-viewport', 'wp-widgets'), 'version' => '863e8bac0af20fba6e4a'), 'editor.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-api-fetch', 'wp-blob', 'wp-block-editor', 'wp-blocks', 'wp-commands', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-date', 'wp-deprecated', 'wp-dom', 'wp-element', 'wp-hooks', 'wp-html-entities', 'wp-i18n', 'wp-keyboard-shortcuts', 'wp-keycodes', 'wp-media-utils', 'wp-notices', 'wp-patterns', 'wp-polyfill', 'wp-preferences', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-server-side-render', 'wp-url', 'wp-wordcount'), 'version' => '817d3c3d465ea165610a'), 'element.min.js' => array('dependencies' => array('react', 'react-dom', 'wp-escape-html', 'wp-polyfill'), 'version' => '603185df201aa54181a6'), 'escape-html.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '6561a406d2d232a6fbd2'), 'format-library.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-rich-text', 'wp-url'), 'version' => 'f2c401cc63ed8a35897d'), 'hooks.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '2810c76e705dd1a53b18'), 'html-entities.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '2cd3358363e0675638fb'), 'i18n.min.js' => array('dependencies' => array('wp-hooks', 'wp-polyfill'), 'version' => 'aee497d955fe7a29a7d6'), 'is-shallow-equal.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'e0f9f1d78d83f5196979'), 'keyboard-shortcuts.min.js' => array('dependencies' => array('react', 'wp-data', 'wp-element', 'wp-keycodes', 'wp-polyfill'), 'version' => '4d239ebc17efd846a168'), 'keycodes.min.js' => array('dependencies' => array('wp-i18n', 'wp-polyfill'), 'version' => '034ff647a54b018581d3'), 'list-reusable-blocks.min.js' => array('dependencies' => array('react', 'wp-api-fetch', 'wp-blob', 'wp-components', 'wp-compose', 'wp-element', 'wp-i18n', 'wp-polyfill'), 'version' => 'b9d73b532124daefd2c7'), 'media-utils.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-blob', 'wp-element', 'wp-i18n', 'wp-polyfill'), 'version' => '03fbd6c4f505a9385efe'), 'notices.min.js' => array('dependencies' => array('wp-data', 'wp-polyfill'), 'version' => '673a68a7ac2f556ed50b'), 'nux.min.js' => array('dependencies' => array('react', 'wp-components', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives'), 'version' => '46c93a71c3e2c2bf37f0'), 'patterns.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-html-entities', 'wp-i18n', 'wp-notices', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-url'), 'version' => 'c81cbc7df425eaca0182'), 'plugins.min.js' => array('dependencies' => array('react', 'wp-compose', 'wp-element', 'wp-hooks', 'wp-is-shallow-equal', 'wp-polyfill', 'wp-primitives'), 'version' => '2d369cbfdcb887111e06'), 'preferences.min.js' => array('dependencies' => array('react', 'wp-a11y', 'wp-components', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-private-apis'), 'version' => '3f5baaf6d334123043d3'), 'preferences-persistence.min.js' => array('dependencies' => array('wp-api-fetch', 'wp-polyfill'), 'version' => '3f5184d775ed9dfb154f'), 'primitives.min.js' => array('dependencies' => array('wp-element', 'wp-polyfill'), 'version' => '81082ab8cc08e6b73043'), 'priority-queue.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '391948bb0355121a7f52'), 'private-apis.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '5e7fdf55d04b8c2aadef'), 'redux-routine.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '72ec9ed71190c996fe2e'), 'reusable-blocks.min.js' => array('dependencies' => array('react', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-polyfill', 'wp-primitives', 'wp-private-apis', 'wp-url'), 'version' => '008366ba172a4f4b92b4'), 'rich-text.min.js' => array('dependencies' => array('wp-a11y', 'wp-compose', 'wp-data', 'wp-deprecated', 'wp-element', 'wp-escape-html', 'wp-i18n', 'wp-keycodes', 'wp-polyfill'), 'version' => '88a44b54270a7c0b39eb'), 'router.min.js' => array('dependencies' => array('react', 'wp-element', 'wp-polyfill', 'wp-private-apis', 'wp-url'), 'version' => '92fd517f31b92695552a'), 'server-side-render.min.js' => array('dependencies' => array('react', 'wp-api-fetch', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-data', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-url'), 'version' => '8e53ef39c9065ebf9e46'), 'shortcode.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'b7747eee0efafd2f0c3b'), 'style-engine.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '5bd98acb9813a2d90abf'), 'token-list.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '05f8a6df6258f0081718'), 'undo-manager.min.js' => array('dependencies' => array('wp-is-shallow-equal', 'wp-polyfill'), 'version' => 'f1701372eeeb8b605515'), 'url.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'f93d00b28dd08ca5a662'), 'viewport.min.js' => array('dependencies' => array('react', 'wp-compose', 'wp-data', 'wp-polyfill'), 'version' => 'e555fda1d93ecf1fb1e0'), 'warning.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => 'ed7c8b0940914f4fe44b'), 'widgets.min.js' => array('dependencies' => array('react', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-polyfill', 'wp-primitives'), 'version' => 'c732b69b0507c9a5462b'), 'wordcount.min.js' => array('dependencies' => array('wp-polyfill'), 'version' => '55d8c2bf3dc99e7ea5ec'));
diff --git a/src/wp-includes/block-bindings.php b/src/wp-includes/block-bindings.php
new file mode 100644
index 0000000000000..d1f0421621bab
--- /dev/null
+++ b/src/wp-includes/block-bindings.php
@@ -0,0 +1,130 @@
+ __( 'My Custom Source', 'my-plugin' ),
+ * 'get_value_callback' => 'my_plugin_get_custom_source_value',
+ * ) );
+ * }
+ * add_action( 'init', 'my_plugin_register_block_bindings_sources' );
+ *
+ * ### Usage in a block
+ *
+ * In a block's `metadata.bindings` attribute, you can specify the source and
+ * its arguments. Such a block will use the source to override the block
+ * attribute's value. For example:
+ *
+ *
+ *
Fallback text that gets replaced.
+ *
+ *
+ * @since 6.5.0
+ *
+ * @param string $source_name The name of the source. It must be a string containing a namespace prefix, i.e.
+ * `my-plugin/my-custom-source`. It must only contain lowercase alphanumeric
+ * characters, the forward slash `/` and dashes.
+ * @param array $source_properties {
+ * The array of arguments that are used to register a source.
+ *
+ * @type string $label The label of the source.
+ * @type callback $get_value_callback A callback executed when the source is processed during block rendering.
+ * The callback should have the following signature:
+ *
+ * `function ($source_args, $block_instance,$attribute_name): mixed`
+ * - @param array $source_args Array containing source arguments
+ * used to look up the override value,
+ * i.e. {"key": "foo"}.
+ * - @param WP_Block $block_instance The block instance.
+ * - @param string $attribute_name The name of an attribute .
+ * The callback has a mixed return type; it may return a string to override
+ * the block's original value, null, false to remove an attribute, etc.
+ * }
+ * @return WP_Block_Bindings_Source|false Source when the registration was successful, or `false` on failure.
+ */
+function register_block_bindings_source( string $source_name, array $source_properties ) {
+ return WP_Block_Bindings_Registry::get_instance()->register( $source_name, $source_properties );
+}
+
+/**
+ * Unregisters a block bindings source.
+ *
+ * @since 6.5.0
+ *
+ * @param string $source_name Block bindings source name including namespace.
+ * @return WP_Block_Bindings_Source|false The unregistered block bindings source on success and `false` otherwise.
+ */
+function unregister_block_bindings_source( string $source_name ) {
+ return WP_Block_Bindings_Registry::get_instance()->unregister( $source_name );
+}
+
+/**
+ * Retrieves the list of all registered block bindings sources.
+ *
+ * @since 6.5.0
+ *
+ * @return WP_Block_Bindings_Source[] The array of registered block bindings sources.
+ */
+function get_all_registered_block_bindings_sources() {
+ return WP_Block_Bindings_Registry::get_instance()->get_all_registered();
+}
+
+/**
+ * Retrieves a registered block bindings source.
+ *
+ * @since 6.5.0
+ *
+ * @param string $source_name The name of the source.
+ * @return WP_Block_Bindings_Source|null The registered block bindings source, or `null` if it is not registered.
+ */
+function get_block_bindings_source( string $source_name ) {
+ return WP_Block_Bindings_Registry::get_instance()->get_registered( $source_name );
+}
diff --git a/src/wp-includes/block-bindings/pattern-overrides.php b/src/wp-includes/block-bindings/pattern-overrides.php
new file mode 100644
index 0000000000000..6f719101ef5dd
--- /dev/null
+++ b/src/wp-includes/block-bindings/pattern-overrides.php
@@ -0,0 +1,46 @@
+ "foo" ).
+ * @param WP_Block $block_instance The block instance.
+ * @param string $attribute_name The name of the target attribute.
+ * @return mixed The value computed for the source.
+ */
+function _block_bindings_pattern_overrides_get_value( array $source_args, $block_instance, string $attribute_name ) {
+ if ( empty( $block_instance->attributes['metadata']['id'] ) ) {
+ return null;
+ }
+ $block_id = $block_instance->attributes['metadata']['id'];
+ return _wp_array_get( $block_instance->context, array( 'pattern/overrides', $block_id, $attribute_name ), null );
+}
+
+/**
+ * Registers Pattern Overrides source in the Block Bindings registry.
+ *
+ * @since 6.5.0
+ * @access private
+ */
+function _register_block_bindings_pattern_overrides_source() {
+ register_block_bindings_source(
+ 'core/pattern-overrides',
+ array(
+ 'label' => _x( 'Pattern Overrides', 'block bindings source' ),
+ 'get_value_callback' => '_block_bindings_pattern_overrides_get_value',
+ )
+ );
+}
+
+add_action( 'init', '_register_block_bindings_pattern_overrides_source' );
diff --git a/src/wp-includes/block-bindings/post-meta.php b/src/wp-includes/block-bindings/post-meta.php
new file mode 100644
index 0000000000000..4be1ae96b7620
--- /dev/null
+++ b/src/wp-includes/block-bindings/post-meta.php
@@ -0,0 +1,58 @@
+ "foo" ).
+ * @return mixed The value computed for the source.
+ */
+function _block_bindings_post_meta_get_value( array $source_args ) {
+ if ( ! isset( $source_args['key'] ) ) {
+ return null;
+ }
+
+ // Use the postId attribute if available.
+ if ( isset( $source_args['postId'] ) ) {
+ $post_id = $source_args['postId'];
+ } else {
+ // $block_instance->context['postId'] is not available in the Image block.
+ $post_id = get_the_ID();
+ }
+
+ // If a post isn't public, we need to prevent unauthorized users from accessing the post meta.
+ $post = get_post( $post_id );
+ if ( ( ! is_post_publicly_viewable( $post ) && ! current_user_can( 'read_post', $post_id ) ) || post_password_required( $post ) ) {
+ return null;
+ }
+
+ return get_post_meta( $post_id, $source_args['key'], true );
+}
+
+/**
+ * Registers Post Meta source in the block bindings registry.
+ *
+ * @since 6.5.0
+ * @access private
+ */
+function _register_block_bindings_post_meta_source() {
+ register_block_bindings_source(
+ 'core/post-meta',
+ array(
+ 'label' => _x( 'Post Meta', 'block bindings source' ),
+ 'get_value_callback' => '_block_bindings_post_meta_get_value',
+ )
+ );
+}
+
+add_action( 'init', '_register_block_bindings_post_meta_source' );
diff --git a/src/wp-includes/block-patterns.php b/src/wp-includes/block-patterns.php
index 66bdfd68e7caa..e5c770e1d4330 100644
--- a/src/wp-includes/block-patterns.php
+++ b/src/wp-includes/block-patterns.php
@@ -135,6 +135,20 @@ function _register_core_block_patterns_and_categories() {
'description' => __( 'Different layouts containing video or audio.' ),
)
);
+ register_block_pattern_category(
+ 'videos',
+ array(
+ 'label' => _x( 'Videos', 'Block pattern category' ),
+ 'description' => __( 'Different layouts containing videos.' ),
+ )
+ );
+ register_block_pattern_category(
+ 'audio',
+ array(
+ 'label' => _x( 'Audio', 'Block pattern category' ),
+ 'description' => __( 'Different layouts containing audio.' ),
+ )
+ );
register_block_pattern_category(
'posts',
array(
diff --git a/src/wp-includes/block-supports/background.php b/src/wp-includes/block-supports/background.php
index 283833991f57b..9b82e6a9d598d 100644
--- a/src/wp-includes/block-supports/background.php
+++ b/src/wp-includes/block-supports/background.php
@@ -70,13 +70,13 @@ function wp_render_background_support( $block_content, $block ) {
return $block_content;
}
- $background_size = isset( $block_attributes['style']['background']['backgroundSize'] )
+ $background_size = isset( $block_attributes['style']['background']['backgroundSize'] )
? $block_attributes['style']['background']['backgroundSize']
: 'cover';
- $background_position = isset( $block_attributes['style']['background']['backgroundPosition'] )
+ $background_position = isset( $block_attributes['style']['background']['backgroundPosition'] )
? $block_attributes['style']['background']['backgroundPosition']
: null;
- $background_repeat = isset( $block_attributes['style']['background']['backgroundRepeat'] )
+ $background_repeat = isset( $block_attributes['style']['background']['backgroundRepeat'] )
? $block_attributes['style']['background']['backgroundRepeat']
: null;
diff --git a/src/wp-includes/block-supports/dimensions.php b/src/wp-includes/block-supports/dimensions.php
index a889e78a16973..da68f187c3915 100644
--- a/src/wp-includes/block-supports/dimensions.php
+++ b/src/wp-includes/block-supports/dimensions.php
@@ -83,6 +83,86 @@ function wp_apply_dimensions_support( $block_type, $block_attributes ) {
return $attributes;
}
+/**
+ * Renders server-side dimensions styles to the block wrapper.
+ * This block support uses the `render_block` hook to ensure that
+ * it is also applied to non-server-rendered blocks.
+ *
+ * @since 6.5.0
+ * @access private
+ *
+ * @param string $block_content Rendered block content.
+ * @param array $block Block object.
+ * @return string Filtered block content.
+ */
+function wp_render_dimensions_support( $block_content, $block ) {
+ $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
+ $block_attributes = ( isset( $block['attrs'] ) && is_array( $block['attrs'] ) ) ? $block['attrs'] : array();
+ $has_aspect_ratio_support = block_has_support( $block_type, array( 'dimensions', 'aspectRatio' ), false );
+
+ if (
+ ! $has_aspect_ratio_support ||
+ wp_should_skip_block_supports_serialization( $block_type, 'dimensions', 'aspectRatio' )
+ ) {
+ return $block_content;
+ }
+
+ $dimensions_block_styles = array();
+ $dimensions_block_styles['aspectRatio'] = $block_attributes['style']['dimensions']['aspectRatio'] ?? null;
+
+ // To ensure the aspect ratio does not get overridden by `minHeight` unset any existing rule.
+ if (
+ isset( $dimensions_block_styles['aspectRatio'] )
+ ) {
+ $dimensions_block_styles['minHeight'] = 'unset';
+ } elseif (
+ isset( $block_attributes['style']['dimensions']['minHeight'] ) ||
+ isset( $block_attributes['minHeight'] )
+ ) {
+ $dimensions_block_styles['aspectRatio'] = 'unset';
+ }
+
+ $styles = wp_style_engine_get_styles( array( 'dimensions' => $dimensions_block_styles ) );
+
+ if ( ! empty( $styles['css'] ) ) {
+ // Inject dimensions styles to the first element, presuming it's the wrapper, if it exists.
+ $tags = new WP_HTML_Tag_Processor( $block_content );
+
+ if ( $tags->next_tag() ) {
+ $existing_style = $tags->get_attribute( 'style' );
+ $updated_style = '';
+
+ if ( ! empty( $existing_style ) ) {
+ $updated_style = $existing_style;
+ if ( ! str_ends_with( $existing_style, ';' ) ) {
+ $updated_style .= ';';
+ }
+ }
+
+ $updated_style .= $styles['css'];
+ $tags->set_attribute( 'style', $updated_style );
+
+ if ( ! empty( $styles['classnames'] ) ) {
+ foreach ( explode( ' ', $styles['classnames'] ) as $class_name ) {
+ if (
+ str_contains( $class_name, 'aspect-ratio' ) &&
+ ! isset( $block_attributes['style']['dimensions']['aspectRatio'] )
+ ) {
+ continue;
+ }
+ $tags->add_class( $class_name );
+ }
+ }
+ }
+
+ return $tags->get_updated_html();
+ }
+
+ return $block_content;
+}
+
+add_filter( 'render_block', 'wp_render_dimensions_support', 10, 2 );
+
// Register the block support.
WP_Block_Supports::get_instance()->register(
'dimensions',
diff --git a/src/wp-includes/block-supports/layout.php b/src/wp-includes/block-supports/layout.php
index 67d6a3f1b77ac..f5acd75a72d7c 100644
--- a/src/wp-includes/block-supports/layout.php
+++ b/src/wp-includes/block-supports/layout.php
@@ -615,6 +615,9 @@ function wp_render_layout_support_flag( $block_content, $block ) {
$processor->add_class( $class_name );
}
return $processor->get_updated_html();
+ } elseif ( ! $block_supports_layout ) {
+ // Ensure layout classnames are not injected if there is no layout support.
+ return $block_content;
}
$global_settings = wp_get_global_settings();
@@ -834,7 +837,8 @@ function wp_render_layout_support_flag( $block_content, $block ) {
break;
}
- if ( false !== strpos( $processor->get_attribute( 'class' ), $inner_block_wrapper_classes ) ) {
+ $class_attribute = $processor->get_attribute( 'class' );
+ if ( is_string( $class_attribute ) && str_contains( $class_attribute, $inner_block_wrapper_classes ) ) {
break;
}
} while ( $processor->next_tag() );
diff --git a/src/wp-includes/block-supports/shadow.php b/src/wp-includes/block-supports/shadow.php
index 6fa05b248f4c4..0ccaf3fd44b76 100644
--- a/src/wp-includes/block-supports/shadow.php
+++ b/src/wp-includes/block-supports/shadow.php
@@ -58,9 +58,8 @@ function wp_apply_shadow_support( $block_type, $block_attributes ) {
$shadow_block_styles = array();
- $preset_shadow = array_key_exists( 'shadow', $block_attributes ) ? "var:preset|shadow|{$block_attributes['shadow']}" : null;
- $custom_shadow = isset( $block_attributes['style']['shadow'] ) ? $block_attributes['style']['shadow'] : null;
- $shadow_block_styles['shadow'] = $preset_shadow ? $preset_shadow : $custom_shadow;
+ $custom_shadow = $block_attributes['style']['shadow'] ?? null;
+ $shadow_block_styles['shadow'] = $custom_shadow;
$attributes = array();
$styles = wp_style_engine_get_styles( $shadow_block_styles );
diff --git a/src/wp-includes/block-supports/typography.php b/src/wp-includes/block-supports/typography.php
index bccde4f5c0221..e7d081c937ee4 100644
--- a/src/wp-includes/block-supports/typography.php
+++ b/src/wp-includes/block-supports/typography.php
@@ -398,6 +398,7 @@ function wp_get_typography_value_and_unit( $raw_value, $options = array() ) {
*
* @since 6.1.0
* @since 6.3.0 Checks for unsupported min/max viewport values that cause invalid clamp values.
+ * @since 6.5.0 Returns early when min and max viewport subtraction is zero to avoid division by zero.
* @access private
*
* @param array $args {
@@ -468,12 +469,18 @@ function wp_get_computed_fluid_typography_value( $args = array() ) {
return null;
}
+ // Calculates the linear factor denominator. If it's 0, we cannot calculate a fluid value.
+ $linear_factor_denominator = $maximum_viewport_width['value'] - $minimum_viewport_width['value'];
+ if ( empty( $linear_factor_denominator ) ) {
+ return null;
+ }
+
/*
* Build CSS rule.
* Borrowed from https://websemantics.uk/tools/responsive-font-calculator/.
*/
$view_port_width_offset = round( $minimum_viewport_width['value'] / 100, 3 ) . $font_size_unit;
- $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $maximum_viewport_width['value'] - $minimum_viewport_width['value'] ) );
+ $linear_factor = 100 * ( ( $maximum_font_size['value'] - $minimum_font_size['value'] ) / ( $linear_factor_denominator ) );
$linear_factor_scaled = round( $linear_factor * $scale_factor, 3 );
$linear_factor_scaled = empty( $linear_factor_scaled ) ? 1 : $linear_factor_scaled;
$fluid_target_font_size = implode( '', $minimum_font_size_rem ) . " + ((1vw - $view_port_width_offset) * $linear_factor_scaled)";
diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php
index e2cd7c1587b9f..3f912ad0611b6 100644
--- a/src/wp-includes/block-template-utils.php
+++ b/src/wp-includes/block-template-utils.php
@@ -251,7 +251,7 @@ function _get_block_templates_paths( $base_directory ) {
* @param string $template_type 'wp_template' or 'wp_template_part'.
* @param string $slug Template slug.
* @return array|null {
- * Array with template metadata if $template_type is one of 'wp_template' or 'wp_template_part'.
+ * Array with template metadata if $template_type is one of 'wp_template' or 'wp_template_part',
* null otherwise.
*
* @type string $slug Template slug.
diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php
index 431e2b015332c..b7c2c2c433190 100644
--- a/src/wp-includes/blocks.php
+++ b/src/wp-includes/blocks.php
@@ -64,6 +64,7 @@ function generate_block_asset_handle( $block_name, $field_name, $index = 0 ) {
'viewScript' => 'view-script',
'editorStyle' => 'editor-style',
'style' => 'style',
+ 'viewStyle' => 'view-style',
);
$asset_handle = str_replace( '/', '-', $block_name ) .
'-' . $field_mappings[ $field_name ];
@@ -123,12 +124,13 @@ function get_block_asset_url( $path ) {
/**
* Finds a script handle for the selected block metadata field. It detects
- * when a path to file was provided and finds a corresponding asset file
- * with details necessary to register the script under automatically
+ * when a path to file was provided and optionally finds a corresponding asset
+ * file with details necessary to register the script under automatically
* generated handle name. It returns unprocessed script handle otherwise.
*
* @since 5.5.0
* @since 6.1.0 Added `$index` parameter.
+ * @since 6.5.0 The asset file is optional.
*
* @param array $metadata Block metadata.
* @param string $field_name Field name to pick from metadata.
@@ -162,21 +164,6 @@ function register_block_script_handle( $metadata, $field_name, $index = 0 ) {
realpath( $script_asset_raw_path )
);
- if ( empty( $script_asset_path ) ) {
- _doing_it_wrong(
- __FUNCTION__,
- sprintf(
- /* translators: 1: Asset file location, 2: Field name, 3: Block name. */
- __( 'The asset file (%1$s) for the "%2$s" defined in "%3$s" block definition is missing.' ),
- $script_asset_raw_path,
- $field_name,
- $metadata['name']
- ),
- '5.5.0'
- );
- return false;
- }
-
$script_path_norm = wp_normalize_path( realpath( $path . '/' . $script_path ) );
$script_uri = get_block_asset_url( $script_path_norm );
@@ -185,7 +172,8 @@ function register_block_script_handle( $metadata, $field_name, $index = 0 ) {
$script_args['strategy'] = 'defer';
}
- $script_asset = require $script_asset_path;
+ // Asset file for blocks is optional. See https://core.trac.wordpress.org/ticket/60460.
+ $script_asset = ! empty( $script_asset_path ) ? require $script_asset_path : array();
$script_dependencies = isset( $script_asset['dependencies'] ) ? $script_asset['dependencies'] : array();
$result = wp_register_script(
$script_handle,
@@ -326,6 +314,7 @@ function get_block_metadata_i18n_schema() {
* @since 6.1.0 Added support for `render` field.
* @since 6.3.0 Added `selectors` field.
* @since 6.4.0 Added support for `blockHooks` field.
+ * @since 6.5.0 Added support for `allowedBlocks` and `viewStyle` fields.
*
* @param string $file_or_folder Path to the JSON file with metadata definition for
* the block or path to the folder where the `block.json` file is located.
@@ -422,6 +411,7 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
'styles' => 'styles',
'variations' => 'variations',
'example' => 'example',
+ 'allowedBlocks' => 'allowed_blocks',
);
$textdomain = ! empty( $metadata['textdomain'] ) ? $metadata['textdomain'] : null;
$i18n_schema = get_block_metadata_i18n_schema();
@@ -503,6 +493,7 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
$style_fields = array(
'editorStyle' => 'editor_style_handles',
'style' => 'style_handles',
+ 'viewStyle' => 'view_style_handles',
);
foreach ( $style_fields as $metadata_field_name => $settings_field_name ) {
if ( ! empty( $settings[ $metadata_field_name ] ) ) {
@@ -758,27 +749,33 @@ function get_hooked_blocks() {
}
/**
- * Conditionally returns the markup for a given hooked block type.
+ * Conditionally returns the markup for a given hooked block.
*
- * Accepts two arguments: A reference to an anchor block, and the name of a hooked block type.
+ * Accepts three arguments: A hooked block, its type, and a reference to an anchor block.
* If the anchor block has already been processed, and the given hooked block type is in the list
* of ignored hooked blocks, an empty string is returned.
*
+ * The hooked block type is specified separately as it's possible that a filter might've modified
+ * the hooked block such that `$hooked_block['blockName']` does no longer reflect the original type.
+ *
* This function is meant for internal use only.
*
* @since 6.5.0
* @access private
*
- * @param array $anchor_block The anchor block. Passed by reference.
- * @param string $hooked_block_type The name of the hooked block type.
- * @return string The markup for the given hooked block type, or an empty string if the block is ignored.
+ * @param array $hooked_block The hooked block, represented as a parsed block array.
+ * @param string $hooked_block_type The type of the hooked block. This could be different from
+ * $hooked_block['blockName'], as a filter might've modified the latter.
+ * @param array $anchor_block The anchor block, represented as a parsed block array.
+ * Passed by reference.
+ * @return string The markup for the given hooked block, or an empty string if the block is ignored.
*/
-function get_hooked_block_markup( &$anchor_block, $hooked_block_type ) {
+function get_hooked_block_markup( $hooked_block, $hooked_block_type, &$anchor_block ) {
if ( ! isset( $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) ) {
$anchor_block['attrs']['metadata']['ignoredHookedBlocks'] = array();
}
- if ( in_array( $hooked_block_type, $anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) ) {
+ if ( in_array( $hooked_block_type, $anchor_block['attrs']['metadata']['ignoredHookedBlocks'], true ) ) {
return '';
}
@@ -786,7 +783,72 @@ function get_hooked_block_markup( &$anchor_block, $hooked_block_type ) {
// However, its presence does not affect the frontend.
$anchor_block['attrs']['metadata']['ignoredHookedBlocks'][] = $hooked_block_type;
- return get_comment_delimited_block_content( $hooked_block_type, array(), '' );
+ return serialize_block( $hooked_block );
+}
+
+/**
+ * Returns the markup for blocks hooked to the given anchor block in a specific relative position.
+ *
+ * @since 6.5.0
+ * @access private
+ *
+ * @param array $parsed_anchor_block The anchor block, in parsed block array format.
+ * @param string $relative_position The relative position of the hooked blocks.
+ * Can be one of 'before', 'after', 'first_child', or 'last_child'.
+ * @param array $hooked_blocks An array of hooked block types, grouped by anchor block and relative position.
+ * @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to.
+ * @return string
+ */
+function insert_hooked_blocks( &$parsed_anchor_block, $relative_position, $hooked_blocks, $context ) {
+ $anchor_block_type = $parsed_anchor_block['blockName'];
+ $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
+ ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
+ : array();
+
+ /**
+ * Filters the list of hooked block types for a given anchor block type and relative position.
+ *
+ * @since 6.4.0
+ *
+ * @param string[] $hooked_block_types The list of hooked block types.
+ * @param string $relative_position The relative position of the hooked blocks.
+ * Can be one of 'before', 'after', 'first_child', or 'last_child'.
+ * @param string $anchor_block_type The anchor block type.
+ * @param WP_Block_Template|WP_Post|array $context The block template, template part, `wp_navigation` post type,
+ * or pattern that the anchor block belongs to.
+ */
+ $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
+
+ $markup = '';
+ foreach ( $hooked_block_types as $hooked_block_type ) {
+ $parsed_hooked_block = array(
+ 'blockName' => $hooked_block_type,
+ 'attrs' => array(),
+ 'innerBlocks' => array(),
+ 'innerContent' => array(),
+ );
+
+ /**
+ * Filters the parsed block array for a given hooked block.
+ *
+ * The dynamic portion of the hook name, `$hooked_block_type`, refers to the block type name of the specific hooked block.
+ *
+ * @since 6.5.0
+ *
+ * @param array $parsed_hooked_block The parsed block array for the given hooked block type.
+ * @param string $relative_position The relative position of the hooked block.
+ * @param array $parsed_anchor_block The anchor block, in parsed block array format.
+ * @param WP_Block_Template|WP_Post|array $context The block template, template part, `wp_navigation` post type,
+ * or pattern that the anchor block belongs to.
+ */
+ $parsed_hooked_block = apply_filters( "hooked_block_{$hooked_block_type}", $parsed_hooked_block, $relative_position, $parsed_anchor_block, $context );
+
+ // It's possible that the `hooked_block_{$hooked_block_type}` filter returned a block of a different type,
+ // so we need to pass the original $hooked_block_type as well.
+ $markup .= get_hooked_block_markup( $parsed_hooked_block, $hooked_block_type, $parsed_anchor_block );
+ }
+
+ return $markup;
}
/**
@@ -801,8 +863,9 @@ function get_hooked_block_markup( &$anchor_block, $hooked_block_type ) {
* @since 6.4.0
* @access private
*
- * @param array $hooked_blocks An array of blocks hooked to another given block.
- * @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to.
+ * @param array $hooked_blocks An array of blocks hooked to another given block.
+ * @param WP_Block_Template|WP_Post|array $context A block template, template part, `wp_navigation` post object,
+ * or pattern that the blocks belong to.
* @return callable A function that returns the serialized markup for the given block,
* including the markup for any hooked blocks before it.
*/
@@ -826,40 +889,10 @@ function make_before_block_visitor( $hooked_blocks, $context ) {
if ( $parent_block && ! $prev ) {
// Candidate for first-child insertion.
- $relative_position = 'first_child';
- $anchor_block_type = $parent_block['blockName'];
- $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
- ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
- : array();
-
- /**
- * Filters the list of hooked block types for a given anchor block type and relative position.
- *
- * @since 6.4.0
- *
- * @param string[] $hooked_block_types The list of hooked block types.
- * @param string $relative_position The relative position of the hooked blocks.
- * Can be one of 'before', 'after', 'first_child', or 'last_child'.
- * @param string $anchor_block_type The anchor block type.
- * @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to.
- */
- $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
- foreach ( $hooked_block_types as $hooked_block_type ) {
- $markup .= get_hooked_block_markup( $parent_block, $hooked_block_type );
- }
+ $markup .= insert_hooked_blocks( $parent_block, 'first_child', $hooked_blocks, $context );
}
- $relative_position = 'before';
- $anchor_block_type = $block['blockName'];
- $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
- ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
- : array();
-
- /** This filter is documented in wp-includes/blocks.php */
- $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
- foreach ( $hooked_block_types as $hooked_block_type ) {
- $markup .= get_hooked_block_markup( $block, $hooked_block_type );
- }
+ $markup .= insert_hooked_blocks( $block, 'before', $hooked_blocks, $context );
return $markup;
};
@@ -877,8 +910,9 @@ function make_before_block_visitor( $hooked_blocks, $context ) {
* @since 6.4.0
* @access private
*
- * @param array $hooked_blocks An array of blocks hooked to another block.
- * @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to.
+ * @param array $hooked_blocks An array of blocks hooked to another block.
+ * @param WP_Block_Template|WP_Post|array $context A block template, template part, `wp_navigation` post object,
+ * or pattern that the blocks belong to.
* @return callable A function that returns the serialized markup for the given block,
* including the markup for any hooked blocks after it.
*/
@@ -895,33 +929,11 @@ function make_after_block_visitor( $hooked_blocks, $context ) {
* @return string The serialized markup for the given block, with the markup for any hooked blocks appended to it.
*/
return function ( &$block, &$parent_block = null, $next = null ) use ( $hooked_blocks, $context ) {
- $markup = '';
-
- $relative_position = 'after';
- $anchor_block_type = $block['blockName'];
- $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
- ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
- : array();
-
- /** This filter is documented in wp-includes/blocks.php */
- $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
- foreach ( $hooked_block_types as $hooked_block_type ) {
- $markup .= get_hooked_block_markup( $block, $hooked_block_type );
- }
+ $markup = insert_hooked_blocks( $block, 'after', $hooked_blocks, $context );
if ( $parent_block && ! $next ) {
// Candidate for last-child insertion.
- $relative_position = 'last_child';
- $anchor_block_type = $parent_block['blockName'];
- $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] )
- ? $hooked_blocks[ $anchor_block_type ][ $relative_position ]
- : array();
-
- /** This filter is documented in wp-includes/blocks.php */
- $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context );
- foreach ( $hooked_block_types as $hooked_block_type ) {
- $markup .= get_hooked_block_markup( $parent_block, $hooked_block_type );
- }
+ $markup .= insert_hooked_blocks( $parent_block, 'last_child', $hooked_blocks, $context );
}
return $markup;
diff --git a/src/wp-includes/blocks/audio/block.json b/src/wp-includes/blocks/audio/block.json
index a4740e304451c..04df268a74a63 100644
--- a/src/wp-includes/blocks/audio/block.json
+++ b/src/wp-includes/blocks/audio/block.json
@@ -16,8 +16,8 @@
"__experimentalRole": "content"
},
"caption": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "figcaption",
"__experimentalRole": "content"
},
diff --git a/src/wp-includes/blocks/avatar/block.json b/src/wp-includes/blocks/avatar/block.json
index 3b4ac7c84f617..fa86541b2963f 100644
--- a/src/wp-includes/blocks/avatar/block.json
+++ b/src/wp-includes/blocks/avatar/block.json
@@ -30,7 +30,11 @@
"alignWide": false,
"spacing": {
"margin": true,
- "padding": true
+ "padding": true,
+ "__experimentalDefaultControls": {
+ "margin": false,
+ "padding": false
+ }
},
"__experimentalBorder": {
"__experimentalSkipSerialization": true,
diff --git a/src/wp-includes/blocks/block.php b/src/wp-includes/blocks/block.php
index d51b35d68b23d..444001fa49859 100644
--- a/src/wp-includes/blocks/block.php
+++ b/src/wp-includes/blocks/block.php
@@ -46,8 +46,28 @@ function render_block_core_block( $attributes ) {
$content = $wp_embed->run_shortcode( $reusable_block->post_content );
$content = $wp_embed->autoembed( $content );
+ $has_pattern_overrides = isset( $attributes['overrides'] );
+
+ /**
+ * We set the `pattern/overrides` context through the `render_block_context`
+ * filter so that it is available when a pattern's inner blocks are
+ * rendering via do_blocks given it only receives the inner content.
+ */
+ if ( $has_pattern_overrides ) {
+ $filter_block_context = static function ( $context ) use ( $attributes ) {
+ $context['pattern/overrides'] = $attributes['overrides'];
+ return $context;
+ };
+ add_filter( 'render_block_context', $filter_block_context, 1 );
+ }
+
$content = do_blocks( $content );
unset( $seen_refs[ $attributes['ref'] ] );
+
+ if ( $has_pattern_overrides ) {
+ remove_filter( 'render_block_context', $filter_block_context, 1 );
+ }
+
return $content;
}
diff --git a/src/wp-includes/blocks/block/block.json b/src/wp-includes/blocks/block/block.json
index 4cb53960725d2..b30c865e57a7f 100644
--- a/src/wp-includes/blocks/block/block.json
+++ b/src/wp-includes/blocks/block/block.json
@@ -10,11 +10,15 @@
"attributes": {
"ref": {
"type": "number"
+ },
+ "overrides": {
+ "type": "object"
}
},
"supports": {
"customClassName": false,
"html": false,
- "inserter": false
+ "inserter": false,
+ "renaming": false
}
}
diff --git a/src/wp-includes/blocks/blocks-json.php b/src/wp-includes/blocks/blocks-json.php
index 85656181b047b..99eb57a0eddf0 100644
--- a/src/wp-includes/blocks/blocks-json.php
+++ b/src/wp-includes/blocks/blocks-json.php
@@ -75,8 +75,8 @@
'__experimentalRole' => 'content'
),
'caption' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'figcaption',
'__experimentalRole' => 'content'
),
@@ -154,7 +154,11 @@
'alignWide' => false,
'spacing' => array(
'margin' => true,
- 'padding' => true
+ 'padding' => true,
+ '__experimentalDefaultControls' => array(
+ 'margin' => false,
+ 'padding' => false
+ )
),
'__experimentalBorder' => array(
'__experimentalSkipSerialization' => true,
@@ -192,12 +196,16 @@
'attributes' => array(
'ref' => array(
'type' => 'number'
+ ),
+ 'overrides' => array(
+ 'type' => 'object'
)
),
'supports' => array(
'customClassName' => false,
'html' => false,
- 'inserter' => false
+ 'inserter' => false,
+ 'renaming' => false
)
),
'button' => array(
@@ -214,6 +222,9 @@
'link'
),
'textdomain' => 'default',
+ 'usesContext' => array(
+ 'pattern/overrides'
+ ),
'attributes' => array(
'tagName' => array(
'type' => 'string',
@@ -245,8 +256,8 @@
'__experimentalRole' => 'content'
),
'text' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'a,button',
'__experimentalRole' => 'content'
),
@@ -516,8 +527,8 @@
'textdomain' => 'default',
'attributes' => array(
'content' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'code',
'__unstablePreserveWhiteSpace' => true
)
@@ -1314,7 +1325,7 @@
'ancestor' => array(
'core/comments'
),
- 'description' => 'Displays a title with the number of comments',
+ 'description' => 'Displays a title with the number of comments.',
'textdomain' => 'default',
'usesContext' => array(
'postId',
@@ -1397,9 +1408,6 @@
),
'alt' => array(
'type' => 'string',
- 'source' => 'attribute',
- 'selector' => 'img',
- 'attribute' => 'alt',
'default' => ''
),
'hasParallax' => array(
@@ -1420,6 +1428,9 @@
'customOverlayColor' => array(
'type' => 'string'
),
+ 'isUserOverlayColor' => array(
+ 'type' => 'boolean'
+ ),
'backgroundType' => array(
'type' => 'string',
'default' => 'image'
@@ -1508,6 +1519,9 @@
),
'enableContrastChecker' => false
),
+ 'dimensions' => array(
+ 'aspectRatio' => true
+ ),
'typography' => array(
'fontSize' => true,
'lineHeight' => true,
@@ -1548,8 +1562,8 @@
'default' => false
),
'summary' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'summary'
)
),
@@ -1615,8 +1629,8 @@
'__experimentalRole' => 'content'
),
'caption' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'figcaption',
'__experimentalRole' => 'content'
),
@@ -1679,8 +1693,8 @@
'attribute' => 'id'
),
'fileName' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'a:not([download])'
),
'textLinkHref' => array(
@@ -1700,8 +1714,8 @@
'default' => true
),
'downloadButtonText' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'a[download]'
),
'displayPreview' => array(
@@ -1730,7 +1744,6 @@
),
'interactivity' => true
),
- 'viewScript' => 'file:./view.min.js',
'editorStyle' => 'wp-block-file-editor',
'style' => 'wp-block-file'
),
@@ -1740,7 +1753,7 @@
'name' => 'core/footnotes',
'title' => 'Footnotes',
'category' => 'text',
- 'description' => '',
+ 'description' => 'Display footnotes added to the page.',
'keywords' => array(
'references'
),
@@ -1774,6 +1787,7 @@
'html' => false,
'multiple' => false,
'reusable' => false,
+ 'inserter' => false,
'spacing' => array(
'margin' => true,
'padding' => true,
@@ -1873,8 +1887,8 @@
'attribute' => 'data-id'
),
'caption' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => '.blocks-gallery-item__caption'
)
)
@@ -1903,14 +1917,18 @@
'maximum' => 8
),
'caption' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => '.blocks-gallery-caption'
),
'imageCrop' => array(
'type' => 'boolean',
'default' => true
),
+ 'randomOrder' => array(
+ 'type' => 'boolean',
+ 'default' => false
+ ),
'fixedHeight' => array(
'type' => 'boolean',
'default' => true
@@ -2018,7 +2036,6 @@
'__experimentalOnEnter' => true,
'__experimentalOnMerge' => true,
'__experimentalSettings' => true,
- '__experimentalMetadata' => true,
'align' => array(
'wide',
'full'
@@ -2027,7 +2044,11 @@
'ariaLabel' => true,
'html' => false,
'background' => array(
- 'backgroundImage' => true
+ 'backgroundImage' => true,
+ 'backgroundSize' => true,
+ '__experimentalDefaultControls' => array(
+ 'backgroundImage' => true
+ )
),
'color' => array(
'gradients' => true,
@@ -2101,15 +2122,17 @@
'subtitle'
),
'textdomain' => 'default',
+ 'usesContext' => array(
+ 'pattern/overrides'
+ ),
'attributes' => array(
'textAlign' => array(
'type' => 'string'
),
'content' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'h1,h2,h3,h4,h5,h6',
- 'default' => '',
'__experimentalRole' => 'content'
),
'level' => array(
@@ -2154,9 +2177,7 @@
'__experimentalTextDecoration' => true,
'__experimentalWritingMode' => true,
'__experimentalDefaultControls' => array(
- 'fontSize' => true,
- 'fontAppearance' => true,
- 'textTransform' => true
+ 'fontSize' => true
)
),
'__unstablePasteTextInline' => true,
@@ -2243,7 +2264,8 @@
'usesContext' => array(
'allowResize',
'imageCrop',
- 'fixedHeight'
+ 'fixedHeight',
+ 'pattern/overrides'
),
'description' => 'Insert an image to make a visual statement.',
'keywords' => array(
@@ -2253,9 +2275,6 @@
),
'textdomain' => 'default',
'attributes' => array(
- 'align' => array(
- 'type' => 'string'
- ),
'url' => array(
'type' => 'string',
'source' => 'attribute',
@@ -2272,8 +2291,8 @@
'__experimentalRole' => 'content'
),
'caption' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'figcaption',
'__experimentalRole' => 'content'
),
@@ -2339,6 +2358,14 @@
)
),
'supports' => array(
+ 'interactivity' => true,
+ 'align' => array(
+ 'left',
+ 'center',
+ 'right',
+ 'wide',
+ 'full'
+ ),
'anchor' => true,
'color' => array(
'text' => false,
@@ -2377,8 +2404,7 @@
)
),
'editorStyle' => 'wp-block-image-editor',
- 'style' => 'wp-block-image',
- 'viewScript' => 'file:./view.min.js'
+ 'style' => 'wp-block-image'
),
'latest-comments' => array(
'$schema' => 'https://schemas.wp.org/trunk/block.json',
@@ -2559,6 +2585,7 @@
'style' => 'wp-block-latest-posts'
),
'legacy-widget' => array(
+ '$schema' => 'https://schemas.wp.org/trunk/block.json',
'apiVersion' => 3,
'name' => 'core/legacy-widget',
'title' => 'Legacy Widget',
@@ -2686,16 +2713,23 @@
'type' => 'string'
),
'content' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'li',
- 'default' => '',
'__experimentalRole' => 'content'
)
),
'supports' => array(
'className' => false,
'__experimentalSelector' => 'li',
+ 'spacing' => array(
+ 'margin' => true,
+ 'padding' => true,
+ '__experimentalDefaultControls' => array(
+ 'margin' => false,
+ 'padding' => false
+ )
+ ),
'typography' => array(
'fontSize' => true,
'lineHeight' => true,
@@ -2736,6 +2770,14 @@
),
'supports' => array(
'className' => true,
+ 'spacing' => array(
+ 'margin' => true,
+ 'padding' => true,
+ '__experimentalDefaultControls' => array(
+ 'margin' => false,
+ 'padding' => false
+ )
+ ),
'typography' => array(
'fontSize' => true,
'lineHeight' => true,
@@ -2904,7 +2946,7 @@
),
'originalContent' => array(
'type' => 'string',
- 'source' => 'html'
+ 'source' => 'raw'
)
),
'supports' => array(
@@ -3101,9 +3143,9 @@
)
)
),
- 'interactivity' => true
+ 'interactivity' => true,
+ 'renaming' => false
),
- 'viewScript' => 'file:./view.min.js',
'editorStyle' => 'wp-block-navigation-editor',
'style' => 'wp-block-navigation'
),
@@ -3182,7 +3224,8 @@
'__experimentalDefaultControls' => array(
'fontSize' => true
)
- )
+ ),
+ 'renaming' => false
),
'editorStyle' => 'wp-block-navigation-link-editor',
'style' => 'wp-block-navigation-link'
@@ -3403,17 +3446,17 @@
),
'textdomain' => 'default',
'usesContext' => array(
- 'postId'
+ 'postId',
+ 'pattern/overrides'
),
'attributes' => array(
'align' => array(
'type' => 'string'
),
'content' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'p',
- 'default' => '',
'__experimentalRole' => 'content'
),
'dropCap' => array(
@@ -3442,7 +3485,6 @@
'text' => true
)
),
- '__experimentalConnections' => true,
'spacing' => array(
'margin' => true,
'padding' => true,
@@ -3480,7 +3522,8 @@
'description' => 'Show a block pattern.',
'supports' => array(
'html' => false,
- 'inserter' => false
+ 'inserter' => false,
+ 'renaming' => false
),
'textdomain' => 'default',
'attributes' => array(
@@ -3934,6 +3977,10 @@
),
'customGradient' => array(
'type' => 'string'
+ ),
+ 'useFirstImageFromPost' => array(
+ 'type' => 'boolean',
+ 'default' => false
)
),
'usesContext' => array(
@@ -4005,8 +4052,18 @@
'arrow' => array(
'type' => 'string',
'default' => 'none'
+ ),
+ 'inSameTerm' => array(
+ 'type' => 'boolean'
+ ),
+ 'taxonomy' => array(
+ 'type' => 'string',
+ 'default' => ''
)
),
+ 'usesContext' => array(
+ 'postType'
+ ),
'supports' => array(
'reusable' => false,
'html' => false,
@@ -4044,7 +4101,6 @@
'usesContext' => array(
'queryId',
'query',
- 'queryContext',
'displayLayout',
'templateSlug',
'previewPostType',
@@ -4218,9 +4274,7 @@
'__experimentalTextDecoration' => true,
'__experimentalLetterSpacing' => true,
'__experimentalDefaultControls' => array(
- 'fontSize' => true,
- 'fontAppearance' => true,
- 'textTransform' => true
+ 'fontSize' => true
)
)
),
@@ -4236,10 +4290,9 @@
'textdomain' => 'default',
'attributes' => array(
'content' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'pre',
- 'default' => '',
'__unstablePreserveWhiteSpace' => true,
'__experimentalRole' => 'content'
)
@@ -4283,16 +4336,15 @@
'textdomain' => 'default',
'attributes' => array(
'value' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'p',
'__experimentalRole' => 'content'
),
'citation' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'cite',
- 'default' => '',
'__experimentalRole' => 'content'
),
'textAlign' => array(
@@ -4316,6 +4368,10 @@
'text' => true
)
),
+ 'spacing' => array(
+ 'margin' => true,
+ 'padding' => true
+ ),
'typography' => array(
'fontSize' => true,
'lineHeight' => true,
@@ -4326,8 +4382,7 @@
'__experimentalTextDecoration' => true,
'__experimentalLetterSpacing' => true,
'__experimentalDefaultControls' => array(
- 'fontSize' => true,
- 'fontAppearance' => true
+ 'fontSize' => true
)
),
'__experimentalBorder' => array(
@@ -4413,8 +4468,7 @@
'layout' => true
),
'editorStyle' => 'wp-block-query-editor',
- 'style' => 'wp-block-query',
- 'viewScript' => 'file:./view.min.js'
+ 'style' => 'wp-block-query'
),
'query-no-results' => array(
'$schema' => 'https://schemas.wp.org/trunk/block.json',
@@ -4577,7 +4631,7 @@
'parent' => array(
'core/query-pagination'
),
- 'description' => 'Displays a list of page numbers for pagination',
+ 'description' => 'Displays a list of page numbers for pagination.',
'textdomain' => 'default',
'attributes' => array(
'midSize' => array(
@@ -4719,9 +4773,7 @@
'__experimentalTextTransform' => true,
'__experimentalTextDecoration' => true,
'__experimentalDefaultControls' => array(
- 'fontSize' => true,
- 'fontAppearance' => true,
- 'textTransform' => true
+ 'fontSize' => true
)
)
),
@@ -4749,10 +4801,9 @@
'__experimentalRole' => 'content'
),
'citation' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'cite',
- 'default' => '',
'__experimentalRole' => 'content'
),
'align' => array(
@@ -4774,8 +4825,7 @@
'__experimentalTextDecoration' => true,
'__experimentalLetterSpacing' => true,
'__experimentalDefaultControls' => array(
- 'fontSize' => true,
- 'fontAppearance' => true
+ 'fontSize' => true
)
),
'color' => array(
@@ -4786,6 +4836,12 @@
'background' => true,
'text' => true
)
+ ),
+ 'layout' => array(
+ 'allowEditing' => false
+ ),
+ 'spacing' => array(
+ 'blockGap' => true
)
),
'styles' => array(
@@ -4965,10 +5021,6 @@
)
),
- 'buttonBehavior' => array(
- 'type' => 'string',
- 'default' => 'expand-searchfield'
- ),
'isSearchFieldHidden' => array(
'type' => 'boolean',
'default' => false
@@ -5017,7 +5069,6 @@
),
'html' => false
),
- 'viewScript' => 'file:./view.min.js',
'editorStyle' => 'wp-block-search-editor',
'style' => 'wp-block-search'
),
@@ -5283,11 +5334,7 @@
'__experimentalFontWeight' => true,
'__experimentalLetterSpacing' => true,
'__experimentalDefaultControls' => array(
- 'fontSize' => true,
- 'lineHeight' => true,
- 'fontAppearance' => true,
- 'letterSpacing' => true,
- 'textTransform' => true
+ 'fontSize' => true
)
)
),
@@ -5496,10 +5543,9 @@
'default' => false
),
'caption' => array(
- 'type' => 'string',
- 'source' => 'html',
- 'selector' => 'figcaption',
- 'default' => ''
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
+ 'selector' => 'figcaption'
),
'head' => array(
'type' => 'array',
@@ -5518,8 +5564,8 @@
'selector' => 'td,th',
'query' => array(
'content' => array(
- 'type' => 'string',
- 'source' => 'html'
+ 'type' => 'rich-text',
+ 'source' => 'rich-text'
),
'tag' => array(
'type' => 'string',
@@ -5567,8 +5613,8 @@
'selector' => 'td,th',
'query' => array(
'content' => array(
- 'type' => 'string',
- 'source' => 'html'
+ 'type' => 'rich-text',
+ 'source' => 'rich-text'
),
'tag' => array(
'type' => 'string',
@@ -5616,8 +5662,8 @@
'selector' => 'td,th',
'query' => array(
'content' => array(
- 'type' => 'string',
- 'source' => 'html'
+ 'type' => 'rich-text',
+ 'source' => 'rich-text'
),
'tag' => array(
'type' => 'string',
@@ -5794,7 +5840,8 @@
'supports' => array(
'align' => true,
'html' => false,
- 'reusable' => false
+ 'reusable' => false,
+ 'renaming' => false
),
'editorStyle' => 'wp-block-template-part-editor'
),
@@ -5900,10 +5947,9 @@
'textdomain' => 'default',
'attributes' => array(
'content' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'pre',
- 'default' => '',
'__unstablePreserveWhiteSpace' => true,
'__experimentalRole' => 'content'
),
@@ -5931,8 +5977,7 @@
'__experimentalTextTransform' => true,
'__experimentalTextDecoration' => true,
'__experimentalDefaultControls' => array(
- 'fontSize' => true,
- 'fontAppearance' => true
+ 'fontSize' => true
)
),
'spacing' => array(
@@ -5972,8 +6017,8 @@
'attribute' => 'autoplay'
),
'caption' => array(
- 'type' => 'string',
- 'source' => 'html',
+ 'type' => 'rich-text',
+ 'source' => 'rich-text',
'selector' => 'figcaption',
'__experimentalRole' => 'content'
),
@@ -6053,6 +6098,7 @@
'style' => 'wp-block-video'
),
'widget-group' => array(
+ '$schema' => 'https://schemas.wp.org/trunk/block.json',
'apiVersion' => 3,
'name' => 'core/widget-group',
'category' => 'widgets',
diff --git a/src/wp-includes/blocks/button/block.json b/src/wp-includes/blocks/button/block.json
index eec327b4ca48e..f04d4642bb98e 100644
--- a/src/wp-includes/blocks/button/block.json
+++ b/src/wp-includes/blocks/button/block.json
@@ -8,6 +8,7 @@
"description": "Prompt visitors to take action with a button-style link.",
"keywords": [ "link" ],
"textdomain": "default",
+ "usesContext": [ "pattern/overrides" ],
"attributes": {
"tagName": {
"type": "string",
@@ -36,8 +37,8 @@
"__experimentalRole": "content"
},
"text": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "a,button",
"__experimentalRole": "content"
},
diff --git a/src/wp-includes/blocks/calendar.php b/src/wp-includes/blocks/calendar.php
index f1f7967235620..04b888972b1dd 100644
--- a/src/wp-includes/blocks/calendar.php
+++ b/src/wp-includes/blocks/calendar.php
@@ -33,10 +33,8 @@ function render_block_core_calendar( $attributes ) {
str_contains( $permalink_structure, '%monthnum%' ) &&
str_contains( $permalink_structure, '%year%' )
) {
- // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
$monthnum = $attributes['month'];
- // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
- $year = $attributes['year'];
+ $year = $attributes['year'];
}
}
@@ -70,10 +68,8 @@ function render_block_core_calendar( $attributes ) {
$calendar
);
- // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
$monthnum = $previous_monthnum;
- // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
- $year = $previous_year;
+ $year = $previous_year;
return $output;
}
diff --git a/src/wp-includes/blocks/categories.php b/src/wp-includes/blocks/categories.php
index 7e3979b7aefe2..c35376505b134 100644
--- a/src/wp-includes/blocks/categories.php
+++ b/src/wp-includes/blocks/categories.php
@@ -70,8 +70,7 @@ function render_block_core_categories( $attributes ) {
function build_dropdown_script_block_core_categories( $dropdown_id ) {
ob_start();
?>
-
', '' ), '', ob_get_clean() ) );
}
/**
diff --git a/src/wp-includes/blocks/code/block.json b/src/wp-includes/blocks/code/block.json
index 80df74b5062b5..bd5db3c918b96 100644
--- a/src/wp-includes/blocks/code/block.json
+++ b/src/wp-includes/blocks/code/block.json
@@ -8,8 +8,8 @@
"textdomain": "default",
"attributes": {
"content": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "code",
"__unstablePreserveWhiteSpace": true
}
diff --git a/src/wp-includes/blocks/comments-title/block.json b/src/wp-includes/blocks/comments-title/block.json
index 12b105afe9a31..4107f5d590cde 100644
--- a/src/wp-includes/blocks/comments-title/block.json
+++ b/src/wp-includes/blocks/comments-title/block.json
@@ -5,7 +5,7 @@
"title": "Comments Title",
"category": "theme",
"ancestor": [ "core/comments" ],
- "description": "Displays a title with the number of comments",
+ "description": "Displays a title with the number of comments.",
"textdomain": "default",
"usesContext": [ "postId", "postType" ],
"attributes": {
diff --git a/src/wp-includes/blocks/cover/block.json b/src/wp-includes/blocks/cover/block.json
index e88dd2d65a372..80562da309899 100644
--- a/src/wp-includes/blocks/cover/block.json
+++ b/src/wp-includes/blocks/cover/block.json
@@ -19,9 +19,6 @@
},
"alt": {
"type": "string",
- "source": "attribute",
- "selector": "img",
- "attribute": "alt",
"default": ""
},
"hasParallax": {
@@ -42,6 +39,9 @@
"customOverlayColor": {
"type": "string"
},
+ "isUserOverlayColor": {
+ "type": "boolean"
+ },
"backgroundType": {
"type": "string",
"default": "image"
@@ -114,6 +114,9 @@
"__experimentalSkipSerialization": [ "gradients" ],
"enableContrastChecker": false
},
+ "dimensions": {
+ "aspectRatio": true
+ },
"typography": {
"fontSize": true,
"lineHeight": true,
diff --git a/src/wp-includes/blocks/details/block.json b/src/wp-includes/blocks/details/block.json
index d449d42e1e10c..a71d3af2a5ed3 100644
--- a/src/wp-includes/blocks/details/block.json
+++ b/src/wp-includes/blocks/details/block.json
@@ -13,8 +13,8 @@
"default": false
},
"summary": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "summary"
}
},
diff --git a/src/wp-includes/blocks/embed/block.json b/src/wp-includes/blocks/embed/block.json
index 9ca54db871db1..5aac8bbd6b8ca 100644
--- a/src/wp-includes/blocks/embed/block.json
+++ b/src/wp-includes/blocks/embed/block.json
@@ -12,8 +12,8 @@
"__experimentalRole": "content"
},
"caption": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "figcaption",
"__experimentalRole": "content"
},
diff --git a/src/wp-includes/blocks/file.php b/src/wp-includes/blocks/file.php
index 042ea89970736..06eb10cf1d895 100644
--- a/src/wp-includes/blocks/file.php
+++ b/src/wp-includes/blocks/file.php
@@ -14,25 +14,8 @@
*
* @return string Returns the block content.
*/
-function render_block_core_file( $attributes, $content, $block ) {
- $should_load_view_script = ! empty( $attributes['displayPreview'] );
- $view_js_file = 'wp-block-file-view';
- // If the script already exists, there is no point in removing it from viewScript.
- if ( ! wp_script_is( $view_js_file ) ) {
- $script_handles = $block->block_type->view_script_handles;
-
- // If the script is not needed, and it is still in the `view_script_handles`, remove it.
- if ( ! $should_load_view_script && in_array( $view_js_file, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) );
- }
- // If the script is needed, but it was previously removed, add it again.
- if ( $should_load_view_script && ! in_array( $view_js_file, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) );
- }
- }
-
+function render_block_core_file( $attributes, $content ) {
// Update object's aria-label attribute if present in block HTML.
-
// Match an aria-label attribute from an object tag.
$pattern = '@
aria-label="(?[^"]+)?")@i';
$content = preg_replace_callback(
@@ -53,13 +36,15 @@ static function ( $matches ) {
$content
);
- // If it uses the Interactivity API, add the directives.
- if ( $should_load_view_script ) {
+ // If it's interactive, enqueue the script module and add the directives.
+ if ( ! empty( $attributes['displayPreview'] ) ) {
+ wp_enqueue_script_module( '@wordpress/block-library/file' );
+
$processor = new WP_HTML_Tag_Processor( $content );
$processor->next_tag();
- $processor->set_attribute( 'data-wp-interactive', '' );
+ $processor->set_attribute( 'data-wp-interactive', '{"namespace":"core/file"}' );
$processor->next_tag( 'object' );
- $processor->set_attribute( 'data-wp-bind--hidden', '!selectors.core.file.hasPdfPreview' );
+ $processor->set_attribute( 'data-wp-bind--hidden', '!state.hasPdfPreview' );
$processor->set_attribute( 'hidden', true );
return $processor->get_updated_html();
}
@@ -67,25 +52,6 @@ static function ( $matches ) {
return $content;
}
-/**
- * Ensure that the view script has the `wp-interactivity` dependency.
- *
- * @since 6.4.0
- *
- * @global WP_Scripts $wp_scripts
- */
-function block_core_file_ensure_interactivity_dependency() {
- global $wp_scripts;
- if (
- isset( $wp_scripts->registered['wp-block-file-view'] ) &&
- ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-file-view']->deps, true )
- ) {
- $wp_scripts->registered['wp-block-file-view']->deps[] = 'wp-interactivity';
- }
-}
-
-add_action( 'wp_print_scripts', 'block_core_file_ensure_interactivity_dependency' );
-
/**
* Registers the `core/file` block on server.
*/
@@ -96,5 +62,12 @@ function register_block_core_file() {
'render_callback' => 'render_block_core_file',
)
);
+
+ wp_register_script_module(
+ '@wordpress/block-library/file',
+ defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ? gutenberg_url( '/build/interactivity/file.min.js' ) : includes_url( 'blocks/file/view.min.js' ),
+ array( '@wordpress/interactivity' ),
+ defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
+ );
}
add_action( 'init', 'register_block_core_file' );
diff --git a/src/wp-includes/blocks/file/block.json b/src/wp-includes/blocks/file/block.json
index 0cc20b3f501e9..fd5da67d284f4 100644
--- a/src/wp-includes/blocks/file/block.json
+++ b/src/wp-includes/blocks/file/block.json
@@ -21,8 +21,8 @@
"attribute": "id"
},
"fileName": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "a:not([download])"
},
"textLinkHref": {
@@ -42,8 +42,8 @@
"default": true
},
"downloadButtonText": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "a[download]"
},
"displayPreview": {
@@ -72,7 +72,6 @@
},
"interactivity": true
},
- "viewScript": "file:./view.min.js",
"editorStyle": "wp-block-file-editor",
"style": "wp-block-file"
}
diff --git a/src/wp-includes/blocks/file/view.asset.php b/src/wp-includes/blocks/file/view.asset.php
index 31a7a74abccb2..ce536d2611595 100644
--- a/src/wp-includes/blocks/file/view.asset.php
+++ b/src/wp-includes/blocks/file/view.asset.php
@@ -1 +1 @@
- array(), 'version' => '6d205911bc72812dd293');
+ array(), 'version' => '498971a8a9512421f3b5');
diff --git a/src/wp-includes/blocks/file/view.min.asset.php b/src/wp-includes/blocks/file/view.min.asset.php
index 990e381b31921..76f2ca1fbc30c 100644
--- a/src/wp-includes/blocks/file/view.min.asset.php
+++ b/src/wp-includes/blocks/file/view.min.asset.php
@@ -1 +1 @@
- array(), 'version' => '8a0237493a27c0d781aa');
+ array(), 'version' => '9c04187f1796859989c3');
diff --git a/src/wp-includes/blocks/footnotes.php b/src/wp-includes/blocks/footnotes.php
index bc6291dd21c38..0cd2ad73ef3d4 100644
--- a/src/wp-includes/blocks/footnotes.php
+++ b/src/wp-includes/blocks/footnotes.php
@@ -68,17 +68,26 @@ function render_block_core_footnotes( $attributes, $content, $block ) {
* @since 6.3.0
*/
function register_block_core_footnotes() {
- foreach ( array( 'post', 'page' ) as $post_type ) {
- register_post_meta(
- $post_type,
- 'footnotes',
- array(
- 'show_in_rest' => true,
- 'single' => true,
- 'type' => 'string',
- 'revisions_enabled' => true,
- )
- );
+ $post_types = get_post_types(
+ array(
+ 'show_in_rest' => true,
+ 'public' => true,
+ )
+ );
+ foreach ( $post_types as $post_type ) {
+ // Only register the meta field if the post type supports the editor, custom fields, and revisions.
+ if ( post_type_supports( $post_type, 'editor' ) && post_type_supports( $post_type, 'custom-fields' ) && post_type_supports( $post_type, 'revisions' ) ) {
+ register_post_meta(
+ $post_type,
+ 'footnotes',
+ array(
+ 'show_in_rest' => true,
+ 'single' => true,
+ 'type' => 'string',
+ 'revisions_enabled' => true,
+ )
+ );
+ }
}
register_block_type_from_metadata(
__DIR__ . '/footnotes',
diff --git a/src/wp-includes/blocks/footnotes/block.json b/src/wp-includes/blocks/footnotes/block.json
index 28b094f24f916..3192df7796978 100644
--- a/src/wp-includes/blocks/footnotes/block.json
+++ b/src/wp-includes/blocks/footnotes/block.json
@@ -4,7 +4,7 @@
"name": "core/footnotes",
"title": "Footnotes",
"category": "text",
- "description": "",
+ "description": "Display footnotes added to the page.",
"keywords": [ "references" ],
"textdomain": "default",
"usesContext": [ "postId", "postType" ],
@@ -33,6 +33,7 @@
"html": false,
"multiple": false,
"reusable": false,
+ "inserter": false,
"spacing": {
"margin": true,
"padding": true,
diff --git a/src/wp-includes/blocks/gallery.php b/src/wp-includes/blocks/gallery.php
index edde9b4da101a..342264de6fce3 100644
--- a/src/wp-includes/blocks/gallery.php
+++ b/src/wp-includes/blocks/gallery.php
@@ -32,6 +32,21 @@ function block_core_gallery_data_id_backcompatibility( $parsed_block ) {
add_filter( 'render_block_data', 'block_core_gallery_data_id_backcompatibility' );
+/**
+ * Filter to randomize the order of image blocks.
+ *
+ * @param array $parsed_block The block being rendered.
+ * @return array The block object with randomized order of image blocks.
+ */
+function block_core_gallery_random_order( $parsed_block ) {
+ if ( 'core/gallery' === $parsed_block['blockName'] && ! empty( $parsed_block['attrs']['randomOrder'] ) ) {
+ shuffle( $parsed_block['innerBlocks'] );
+ }
+ return $parsed_block;
+}
+
+add_filter( 'render_block_data', 'block_core_gallery_random_order' );
+
/**
* Adds a style tag for the --wp--style--unstable-gallery-gap var.
*
diff --git a/src/wp-includes/blocks/gallery/block.json b/src/wp-includes/blocks/gallery/block.json
index 0867989af4ec7..a5425c55381f9 100644
--- a/src/wp-includes/blocks/gallery/block.json
+++ b/src/wp-includes/blocks/gallery/block.json
@@ -46,8 +46,8 @@
"attribute": "data-id"
},
"caption": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": ".blocks-gallery-item__caption"
}
}
@@ -72,14 +72,18 @@
"maximum": 8
},
"caption": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": ".blocks-gallery-caption"
},
"imageCrop": {
"type": "boolean",
"default": true
},
+ "randomOrder": {
+ "type": "boolean",
+ "default": false
+ },
"fixedHeight": {
"type": "boolean",
"default": true
diff --git a/src/wp-includes/blocks/group/block.json b/src/wp-includes/blocks/group/block.json
index 4b89d86539117..df59c25a7751f 100644
--- a/src/wp-includes/blocks/group/block.json
+++ b/src/wp-includes/blocks/group/block.json
@@ -24,13 +24,16 @@
"__experimentalOnEnter": true,
"__experimentalOnMerge": true,
"__experimentalSettings": true,
- "__experimentalMetadata": true,
"align": [ "wide", "full" ],
"anchor": true,
"ariaLabel": true,
"html": false,
"background": {
- "backgroundImage": true
+ "backgroundImage": true,
+ "backgroundSize": true,
+ "__experimentalDefaultControls": {
+ "backgroundImage": true
+ }
},
"color": {
"gradients": true,
diff --git a/src/wp-includes/blocks/heading/block.json b/src/wp-includes/blocks/heading/block.json
index 7c018f8472cb4..a1eb3fce32ef1 100644
--- a/src/wp-includes/blocks/heading/block.json
+++ b/src/wp-includes/blocks/heading/block.json
@@ -7,15 +7,15 @@
"description": "Introduce new sections and organize content to help visitors (and search engines) understand the structure of your content.",
"keywords": [ "title", "subtitle" ],
"textdomain": "default",
+ "usesContext": [ "pattern/overrides" ],
"attributes": {
"textAlign": {
"type": "string"
},
"content": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "h1,h2,h3,h4,h5,h6",
- "default": "",
"__experimentalRole": "content"
},
"level": {
@@ -57,9 +57,7 @@
"__experimentalTextDecoration": true,
"__experimentalWritingMode": true,
"__experimentalDefaultControls": {
- "fontSize": true,
- "fontAppearance": true,
- "textTransform": true
+ "fontSize": true
}
},
"__unstablePasteTextInline": true,
diff --git a/src/wp-includes/blocks/image.php b/src/wp-includes/blocks/image.php
index acefd5714bbd4..f926890c1a3fc 100644
--- a/src/wp-includes/blocks/image.php
+++ b/src/wp-includes/blocks/image.php
@@ -37,9 +37,6 @@ function render_block_core_image( $attributes, $content, $block ) {
$link_destination = isset( $attributes['linkDestination'] ) ? $attributes['linkDestination'] : 'none';
$lightbox_settings = block_core_image_get_lightbox_settings( $block->parsed_block );
- $view_js_file_handle = 'wp-block-image-view';
- $script_handles = $block->block_type->view_script_handles;
-
/*
* If the lightbox is enabled and the image is not linked, add the filter
* and the JavaScript view file.
@@ -50,31 +47,22 @@ function render_block_core_image( $attributes, $content, $block ) {
isset( $lightbox_settings['enabled'] ) &&
true === $lightbox_settings['enabled']
) {
- $block->block_type->supports['interactivity'] = true;
-
- if ( ! in_array( $view_js_file_handle, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file_handle ) );
- }
+ wp_enqueue_script_module( '@wordpress/block-library/image' );
/*
- * This render needs to happen in a filter with priority 15 to ensure
- * that it runs after the duotone filter and that duotone styles are
- * applied to the image in the lightbox. We also need to ensure that the
- * lightbox works with any plugins that might use filters as well. We
- * can consider removing this in the future if the way the blocks are
- * rendered changes, or if a new kind of filter is introduced.
+ * This render needs to happen in a filter with priority 15 to ensure that
+ * it runs after the duotone filter and that duotone styles are applied to
+ * the image in the lightbox. Lightbox has to work with any plugins that
+ * might use filters as well. Removing this can be considered in the
+ * future if the way the blocks are rendered changes, or if a
+ * new kind of filter is introduced.
*/
add_filter( 'render_block_core/image', 'block_core_image_render_lightbox', 15, 2 );
} else {
/*
- * Remove the filter and the JavaScript view file if previously added by
- * other Image blocks.
+ * Remove the filter if previously added by other Image blocks.
*/
remove_filter( 'render_block_core/image', 'block_core_image_render_lightbox', 15 );
- // If the script is not needed, and it is still in the `view_script_handles`, remove it.
- if ( in_array( $view_js_file_handle, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file_handle ) );
- }
}
return $processor->get_updated_html();
@@ -93,12 +81,6 @@ function block_core_image_get_lightbox_settings( $block ) {
// Get the lightbox setting from the block attributes.
if ( isset( $block['attrs']['lightbox'] ) ) {
$lightbox_settings = $block['attrs']['lightbox'];
- // If the lightbox setting is not set in the block attributes,
- // check the legacy lightbox settings that are set using the
- // `gutenberg_should_render_lightbox` filter.
- // We can remove this elseif statement when the legacy lightbox settings are removed.
- } elseif ( isset( $block['legacyLightboxSettings'] ) ) {
- $lightbox_settings = $block['legacyLightboxSettings'];
}
if ( ! isset( $lightbox_settings ) ) {
@@ -187,27 +169,23 @@ function block_core_image_render_lightbox( $block_content, $block ) {
$w = new WP_HTML_Tag_Processor( $block_content );
$w->next_tag( 'figure' );
$w->add_class( 'wp-lightbox-container' );
- $w->set_attribute( 'data-wp-interactive', true );
+ $w->set_attribute( 'data-wp-interactive', '{"namespace":"core/image"}' );
$w->set_attribute(
'data-wp-context',
sprintf(
- '{ "core":
- { "image":
- { "imageLoaded": false,
- "initialized": false,
- "lightboxEnabled": false,
- "hideAnimationEnabled": false,
- "preloadInitialized": false,
- "lightboxAnimation": "%s",
- "imageUploadedSrc": "%s",
- "imageCurrentSrc": "",
- "targetWidth": "%s",
- "targetHeight": "%s",
- "scaleAttr": "%s",
- "dialogLabel": "%s"
- }
- }
+ '{ "imageLoaded": false,
+ "initialized": false,
+ "lightboxEnabled": false,
+ "hideAnimationEnabled": false,
+ "preloadInitialized": false,
+ "lightboxAnimation": "%s",
+ "imageUploadedSrc": "%s",
+ "imageCurrentSrc": "",
+ "targetWidth": "%s",
+ "targetHeight": "%s",
+ "scaleAttr": "%s",
+ "dialogLabel": "%s"
}',
$lightbox_animation,
$img_uploaded_src,
@@ -218,14 +196,14 @@ function block_core_image_render_lightbox( $block_content, $block ) {
)
);
$w->next_tag( 'img' );
- $w->set_attribute( 'data-wp-init', 'effects.core.image.initOriginImage' );
- $w->set_attribute( 'data-wp-on--load', 'actions.core.image.handleLoad' );
- $w->set_attribute( 'data-wp-effect', 'effects.core.image.setButtonStyles' );
+ $w->set_attribute( 'data-wp-init', 'callbacks.initOriginImage' );
+ $w->set_attribute( 'data-wp-on--load', 'actions.handleLoad' );
+ $w->set_attribute( 'data-wp-watch', 'callbacks.setButtonStyles' );
// We need to set an event callback on the `img` specifically
// because the `figure` element can also contain a caption, and
// we don't want to trigger the lightbox when the caption is clicked.
- $w->set_attribute( 'data-wp-on--click', 'actions.core.image.showLightbox' );
- $w->set_attribute( 'data-wp-effect--setStylesOnResize', 'effects.core.image.setStylesOnResize' );
+ $w->set_attribute( 'data-wp-on--click', 'actions.showLightbox' );
+ $w->set_attribute( 'data-wp-watch--setStylesOnResize', 'callbacks.setStylesOnResize' );
$body_content = $w->get_updated_html();
// Add a button alongside image in the body content.
@@ -239,9 +217,10 @@ class="lightbox-trigger"
type="button"
aria-haspopup="dialog"
aria-label="' . esc_attr( $aria_label ) . '"
- data-wp-on--click="actions.core.image.showLightbox"
- data-wp-style--right="context.core.image.imageButtonRight"
- data-wp-style--top="context.core.image.imageButtonTop"
+ data-wp-init="callbacks.initTriggerButton"
+ data-wp-on--click="actions.showLightbox"
+ data-wp-style--right="context.imageButtonRight"
+ data-wp-style--top="context.imageButtonTop"
>
@@ -267,8 +246,8 @@ class="lightbox-trigger"
// use the exact same image as in the content when the lightbox is first opened while
// we wait for the larger image to load.
$m->set_attribute( 'src', '' );
- $m->set_attribute( 'data-wp-bind--src', 'context.core.image.imageCurrentSrc' );
- $m->set_attribute( 'data-wp-style--object-fit', 'selectors.core.image.lightboxObjectFit' );
+ $m->set_attribute( 'data-wp-bind--src', 'context.imageCurrentSrc' );
+ $m->set_attribute( 'data-wp-style--object-fit', 'state.lightboxObjectFit' );
$initial_image_content = $m->get_updated_html();
$q = new WP_HTML_Tag_Processor( $block_content );
@@ -283,8 +262,8 @@ class="lightbox-trigger"
// and Chrome (see https://github.com/WordPress/gutenberg/pull/52765#issuecomment-1674008151). Until that
// is resolved, manually setting the 'src' seems to be the best solution to load the large image on demand.
$q->set_attribute( 'src', '' );
- $q->set_attribute( 'data-wp-bind--src', 'selectors.core.image.enlargedImgSrc' );
- $q->set_attribute( 'data-wp-style--object-fit', 'selectors.core.image.lightboxObjectFit' );
+ $q->set_attribute( 'data-wp-bind--src', 'state.enlargedImgSrc' );
+ $q->set_attribute( 'data-wp-style--object-fit', 'state.lightboxObjectFit' );
$enlarged_image_content = $q->get_updated_html();
// If the current theme does NOT have a `theme.json`, or the colors are not defined,
@@ -307,21 +286,21 @@ class="lightbox-trigger"
$lightbox_html = <<
-
+
$close_button_icon
$initial_image_content
@@ -333,25 +312,6 @@ class="lightbox-trigger"
return str_replace( '', $lightbox_html . '', $body_content );
}
-/**
- * Ensures that the view script has the `wp-interactivity` dependency.
- *
- * @since 6.4.0
- *
- * @global WP_Scripts $wp_scripts
- */
-function block_core_image_ensure_interactivity_dependency() {
- global $wp_scripts;
- if (
- isset( $wp_scripts->registered['wp-block-image-view'] ) &&
- ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-image-view']->deps, true )
- ) {
- $wp_scripts->registered['wp-block-image-view']->deps[] = 'wp-interactivity';
- }
-}
-
-add_action( 'wp_print_scripts', 'block_core_image_ensure_interactivity_dependency' );
-
/**
* Registers the `core/image` block on server.
*/
@@ -362,5 +322,12 @@ function register_block_core_image() {
'render_callback' => 'render_block_core_image',
)
);
+
+ wp_register_script_module(
+ '@wordpress/block-library/image',
+ defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ? gutenberg_url( '/build/interactivity/image.min.js' ) : includes_url( 'blocks/image/view.min.js' ),
+ array( '@wordpress/interactivity' ),
+ defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
+ );
}
add_action( 'init', 'register_block_core_image' );
diff --git a/src/wp-includes/blocks/image/block.json b/src/wp-includes/blocks/image/block.json
index d665a8a8f7708..d60bcadf0eec7 100644
--- a/src/wp-includes/blocks/image/block.json
+++ b/src/wp-includes/blocks/image/block.json
@@ -4,14 +4,16 @@
"name": "core/image",
"title": "Image",
"category": "media",
- "usesContext": [ "allowResize", "imageCrop", "fixedHeight" ],
+ "usesContext": [
+ "allowResize",
+ "imageCrop",
+ "fixedHeight",
+ "pattern/overrides"
+ ],
"description": "Insert an image to make a visual statement.",
"keywords": [ "img", "photo", "picture" ],
"textdomain": "default",
"attributes": {
- "align": {
- "type": "string"
- },
"url": {
"type": "string",
"source": "attribute",
@@ -28,8 +30,8 @@
"__experimentalRole": "content"
},
"caption": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "figcaption",
"__experimentalRole": "content"
},
@@ -95,6 +97,8 @@
}
},
"supports": {
+ "interactivity": true,
+ "align": [ "left", "center", "right", "wide", "full" ],
"anchor": true,
"color": {
"text": false,
@@ -130,6 +134,5 @@
{ "name": "rounded", "label": "Rounded" }
],
"editorStyle": "wp-block-image-editor",
- "style": "wp-block-image",
- "viewScript": "file:./view.min.js"
+ "style": "wp-block-image"
}
diff --git a/src/wp-includes/blocks/image/view.asset.php b/src/wp-includes/blocks/image/view.asset.php
index 568cdb6f733d8..58058b1408c81 100644
--- a/src/wp-includes/blocks/image/view.asset.php
+++ b/src/wp-includes/blocks/image/view.asset.php
@@ -1 +1 @@
- array(), 'version' => '62ff3b968891a0e3ca3a');
+ array(), 'version' => '7500eb032759d407a71d');
diff --git a/src/wp-includes/blocks/image/view.min.asset.php b/src/wp-includes/blocks/image/view.min.asset.php
index d1b4a615a9aef..5b46fcb7d531e 100644
--- a/src/wp-includes/blocks/image/view.min.asset.php
+++ b/src/wp-includes/blocks/image/view.min.asset.php
@@ -1 +1 @@
- array(), 'version' => '32caaf5e7c6834efef4c');
+ array(), 'version' => 'ff354d5368d64857fef0');
diff --git a/src/wp-includes/blocks/legacy-widget/block.json b/src/wp-includes/blocks/legacy-widget/block.json
index 6b0c1e2a916fd..a03eb090633fc 100644
--- a/src/wp-includes/blocks/legacy-widget/block.json
+++ b/src/wp-includes/blocks/legacy-widget/block.json
@@ -1,4 +1,5 @@
{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "core/legacy-widget",
"title": "Legacy Widget",
diff --git a/src/wp-includes/blocks/list-item/block.json b/src/wp-includes/blocks/list-item/block.json
index 41221f1c31772..06997c2ac23f8 100644
--- a/src/wp-includes/blocks/list-item/block.json
+++ b/src/wp-includes/blocks/list-item/block.json
@@ -12,16 +12,23 @@
"type": "string"
},
"content": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "li",
- "default": "",
"__experimentalRole": "content"
}
},
"supports": {
"className": false,
"__experimentalSelector": "li",
+ "spacing": {
+ "margin": true,
+ "padding": true,
+ "__experimentalDefaultControls": {
+ "margin": false,
+ "padding": false
+ }
+ },
"typography": {
"fontSize": true,
"lineHeight": true,
diff --git a/src/wp-includes/blocks/loginout/block.json b/src/wp-includes/blocks/loginout/block.json
index 3593961c09cfd..59fceec596e37 100644
--- a/src/wp-includes/blocks/loginout/block.json
+++ b/src/wp-includes/blocks/loginout/block.json
@@ -19,6 +19,14 @@
},
"supports": {
"className": true,
+ "spacing": {
+ "margin": true,
+ "padding": true,
+ "__experimentalDefaultControls": {
+ "margin": false,
+ "padding": false
+ }
+ },
"typography": {
"fontSize": true,
"lineHeight": true,
diff --git a/src/wp-includes/blocks/missing/block.json b/src/wp-includes/blocks/missing/block.json
index 0bc512bbbf709..242a1d2c6b21a 100644
--- a/src/wp-includes/blocks/missing/block.json
+++ b/src/wp-includes/blocks/missing/block.json
@@ -15,7 +15,7 @@
},
"originalContent": {
"type": "string",
- "source": "html"
+ "source": "raw"
}
},
"supports": {
diff --git a/src/wp-includes/blocks/navigation-link.php b/src/wp-includes/blocks/navigation-link.php
index 5333ab6ea3dc9..71ef26b630d51 100644
--- a/src/wp-includes/blocks/navigation-link.php
+++ b/src/wp-includes/blocks/navigation-link.php
@@ -1,6 +1,6 @@
get_registered( 'core/navigation-link' );
+ // If the block is not registered yet, bail early.
+ // Variation will be registered in register_block_core_navigation_link then.
+ if ( ! $navigation_block_type ) {
+ return;
+ }
+
+ $navigation_block_type->variations = array_merge(
+ $navigation_block_type->variations,
+ array( $variation )
+ );
+}
+
+/**
+ * Unregister a variation for a post type / taxonomy for the navigation link block.
+ *
+ * @param string $name Name of the post type / taxonomy (which was used as variation name).
+ * @return void
+ */
+function block_core_navigation_link_unregister_variation( $name ) {
+ // Directly get the variations from the registered block type
+ // because there's no server side (un)registration for variations (see #47170).
+ $navigation_block_type = WP_Block_Type_Registry::get_instance()->get_registered( 'core/navigation-link' );
+ // If the block is not registered (yet), there's no need to remove a variation.
+ if ( ! $navigation_block_type || empty( $navigation_block_type->variations ) ) {
+ return;
+ }
+ $variations = $navigation_block_type->variations;
+ // Search for the variation and remove it from the array.
+ foreach ( $variations as $i => $variation ) {
+ if ( $variation['name'] === $name ) {
+ unset( $variations[ $i ] );
+ break;
+ }
+ }
+ // Reindex array after removing one variation.
+ $navigation_block_type->variations = array_values( $variations );
+}
+
/**
* Register the navigation link block.
+ * Returns an array of variations for the navigation link block.
*
- * @uses render_block_core_navigation()
- * @throws WP_Error An WP_Error exception parsing the block definition.
+ * @return array
*/
-function register_block_core_navigation_link() {
+function build_navigation_link_block_variations() {
+ // This will only handle post types and taxonomies registered until this point (init on priority 9).
+ // See action hooks below for other post types and taxonomies.
+ // See https://github.com/WordPress/gutenberg/issues/53826 for details.
$post_types = get_post_types( array( 'show_in_nav_menus' => true ), 'objects' );
$taxonomies = get_taxonomies( array( 'show_in_nav_menus' => true ), 'objects' );
@@ -360,12 +411,80 @@ function register_block_core_navigation_link() {
}
}
+ return array_merge( $built_ins, $variations );
+}
+
+/**
+ * Register the navigation link block.
+ *
+ * @uses render_block_core_navigation()
+ * @throws WP_Error An WP_Error exception parsing the block definition.
+ */
+function register_block_core_navigation_link() {
register_block_type_from_metadata(
__DIR__ . '/navigation-link',
array(
- 'render_callback' => 'render_block_core_navigation_link',
- 'variations' => array_merge( $built_ins, $variations ),
+ 'render_callback' => 'render_block_core_navigation_link',
+ 'variation_callback' => 'build_navigation_link_block_variations',
)
);
}
add_action( 'init', 'register_block_core_navigation_link' );
+// Register actions for all post types and taxonomies, to add variations when they are registered.
+// All post types/taxonomies registered before register_block_core_navigation_link, will be handled by that function.
+add_action( 'registered_post_type', 'block_core_navigation_link_register_post_type_variation', 10, 2 );
+add_action( 'registered_taxonomy', 'block_core_navigation_link_register_taxonomy_variation', 10, 3 );
+// Handle unregistering of post types and taxonomies and remove the variations.
+add_action( 'unregistered_post_type', 'block_core_navigation_link_unregister_post_type_variation' );
+add_action( 'unregistered_taxonomy', 'block_core_navigation_link_unregister_taxonomy_variation' );
+
+/**
+ * Register custom post type variations for navigation link on post type registration
+ * Handles all post types registered after the block is registered in register_navigation_link_post_type_variations
+ *
+ * @param string $post_type The post type name passed from registered_post_type action hook.
+ * @param WP_Post_Type $post_type_object The post type object passed from registered_post_type.
+ * @return void
+ */
+function block_core_navigation_link_register_post_type_variation( $post_type, $post_type_object ) {
+ if ( $post_type_object->show_in_nav_menus ) {
+ $variation = build_variation_for_navigation_link( $post_type_object, 'post-type' );
+ block_core_navigation_link_register_variation( $variation );
+ }
+}
+
+/**
+ * Register a custom taxonomy variation for navigation link on taxonomy registration
+ * Handles all taxonomies registered after the block is registered in register_navigation_link_post_type_variations
+ *
+ * @param string $taxonomy Taxonomy slug.
+ * @param array|string $object_type Object type or array of object types.
+ * @param array $args Array of taxonomy registration arguments.
+ * @return void
+ */
+function block_core_navigation_link_register_taxonomy_variation( $taxonomy, $object_type, $args ) {
+ if ( isset( $args['show_in_nav_menus'] ) && $args['show_in_nav_menus'] ) {
+ $variation = build_variation_for_navigation_link( (object) $args, 'post-type' );
+ block_core_navigation_link_register_variation( $variation );
+ }
+}
+
+/**
+ * Unregisters a custom post type variation for navigation link on post type unregistration.
+ *
+ * @param string $post_type The post type name passed from unregistered_post_type action hook.
+ * @return void
+ */
+function block_core_navigation_link_unregister_post_type_variation( $post_type ) {
+ block_core_navigation_link_unregister_variation( $post_type );
+}
+
+/**
+ * Unregisters a custom taxonomy variation for navigation link on taxonomy unregistration.
+ *
+ * @param string $taxonomy The taxonomy name passed from unregistered_taxonomy action hook.
+ * @return void
+ */
+function block_core_navigation_link_unregister_taxonomy_variation( $taxonomy ) {
+ block_core_navigation_link_unregister_variation( $taxonomy );
+}
diff --git a/src/wp-includes/blocks/navigation-link/block.json b/src/wp-includes/blocks/navigation-link/block.json
index b2cbeaed63d3e..d8f2fe31aef9d 100644
--- a/src/wp-includes/blocks/navigation-link/block.json
+++ b/src/wp-includes/blocks/navigation-link/block.json
@@ -71,7 +71,8 @@
"__experimentalDefaultControls": {
"fontSize": true
}
- }
+ },
+ "renaming": false
},
"editorStyle": "wp-block-navigation-link-editor",
"style": "wp-block-navigation-link"
diff --git a/src/wp-includes/blocks/navigation.php b/src/wp-includes/blocks/navigation.php
index 4d9fe4a08c6bf..40ae2f045d7bf 100644
--- a/src/wp-includes/blocks/navigation.php
+++ b/src/wp-includes/blocks/navigation.php
@@ -5,6 +5,648 @@
* @package WordPress
*/
+/**
+ * Helper functions used to render the navigation block.
+ */
+class WP_Navigation_Block_Renderer {
+ /**
+ * Used to determine which blocks are wrapped in an .
+ *
+ * @var array
+ */
+ private static $nav_blocks_wrapped_in_list_item = array(
+ 'core/navigation-link',
+ 'core/home-link',
+ 'core/site-title',
+ 'core/site-logo',
+ 'core/navigation-submenu',
+ );
+
+ /**
+ * Used to determine which blocks need an wrapper.
+ *
+ * @var array
+ */
+ private static $needs_list_item_wrapper = array(
+ 'core/site-title',
+ 'core/site-logo',
+ );
+
+ /**
+ * Keeps track of all the navigation names that have been seen.
+ *
+ * @var array
+ */
+ private static $seen_menu_names = array();
+
+ /**
+ * Returns whether or not this is responsive navigation.
+ *
+ * @param array $attributes The block attributes.
+ * @return bool Returns whether or not this is responsive navigation.
+ */
+ private static function is_responsive( $attributes ) {
+ /**
+ * This is for backwards compatibility after the `isResponsive` attribute was been removed.
+ */
+
+ $has_old_responsive_attribute = ! empty( $attributes['isResponsive'] ) && $attributes['isResponsive'];
+ return isset( $attributes['overlayMenu'] ) && 'never' !== $attributes['overlayMenu'] || $has_old_responsive_attribute;
+ }
+
+ /**
+ * Returns whether or not a navigation has a submenu.
+ *
+ * @param WP_Block_List $inner_blocks The list of inner blocks.
+ * @return bool Returns whether or not a navigation has a submenu.
+ */
+ private static function has_submenus( $inner_blocks ) {
+ foreach ( $inner_blocks as $inner_block ) {
+ $inner_block_content = $inner_block->render();
+ $p = new WP_HTML_Tag_Processor( $inner_block_content );
+ if ( $p->next_tag(
+ array(
+ 'name' => 'LI',
+ 'class_name' => 'has-child',
+ )
+ ) ) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine whether the navigation blocks is interactive.
+ *
+ * @param array $attributes The block attributes.
+ * @param WP_Block_List $inner_blocks The list of inner blocks.
+ * @return bool Returns whether or not to load the view script.
+ */
+ private static function is_interactive( $attributes, $inner_blocks ) {
+ $has_submenus = static::has_submenus( $inner_blocks );
+ $is_responsive_menu = static::is_responsive( $attributes );
+ return ( $has_submenus && ( $attributes['openSubmenusOnClick'] || $attributes['showSubmenuIcon'] ) ) || $is_responsive_menu;
+ }
+
+ /**
+ * Returns whether or not a block needs a list item wrapper.
+ *
+ * @param WP_Block $block The block.
+ * @return bool Returns whether or not a block needs a list item wrapper.
+ */
+ private static function does_block_need_a_list_item_wrapper( $block ) {
+ return in_array( $block->name, static::$needs_list_item_wrapper, true );
+ }
+
+ /**
+ * Returns the markup for a single inner block.
+ *
+ * @param WP_Block $inner_block The inner block.
+ * @return string Returns the markup for a single inner block.
+ */
+ private static function get_markup_for_inner_block( $inner_block ) {
+ $inner_block_content = $inner_block->render();
+ if ( ! empty( $inner_block_content ) ) {
+ if ( static::does_block_need_a_list_item_wrapper( $inner_block ) ) {
+ return ' ' . $inner_block_content . ' ';
+ }
+
+ return $inner_block_content;
+ }
+ }
+
+ /**
+ * Returns the html for the inner blocks of the navigation block.
+ *
+ * @param array $attributes The block attributes.
+ * @param WP_Block_List $inner_blocks The list of inner blocks.
+ * @return string Returns the html for the inner blocks of the navigation block.
+ */
+ private static function get_inner_blocks_html( $attributes, $inner_blocks ) {
+ $has_submenus = static::has_submenus( $inner_blocks );
+ $is_interactive = static::is_interactive( $attributes, $inner_blocks );
+
+ $style = static::get_styles( $attributes );
+ $class = static::get_classes( $attributes );
+ $container_attributes = get_block_wrapper_attributes(
+ array(
+ 'class' => 'wp-block-navigation__container ' . $class,
+ 'style' => $style,
+ )
+ );
+
+ $inner_blocks_html = '';
+ $is_list_open = false;
+
+ foreach ( $inner_blocks as $inner_block ) {
+ $is_list_item = in_array( $inner_block->name, static::$nav_blocks_wrapped_in_list_item, true );
+
+ if ( $is_list_item && ! $is_list_open ) {
+ $is_list_open = true;
+ $inner_blocks_html .= sprintf(
+ '',
+ $container_attributes
+ );
+ }
+
+ if ( ! $is_list_item && $is_list_open ) {
+ $is_list_open = false;
+ $inner_blocks_html .= ' ';
+ }
+
+ $inner_blocks_html .= static::get_markup_for_inner_block( $inner_block );
+ }
+
+ if ( $is_list_open ) {
+ $inner_blocks_html .= '';
+ }
+
+ // Add directives to the submenu if needed.
+ if ( $has_submenus && $is_interactive ) {
+ $tags = new WP_HTML_Tag_Processor( $inner_blocks_html );
+ $inner_blocks_html = block_core_navigation_add_directives_to_submenu( $tags, $attributes );
+ }
+
+ return $inner_blocks_html;
+ }
+
+ /**
+ * Gets the inner blocks for the navigation block from the navigation post.
+ *
+ * @param array $attributes The block attributes.
+ * @return WP_Block_List Returns the inner blocks for the navigation block.
+ */
+ private static function get_inner_blocks_from_navigation_post( $attributes ) {
+ $navigation_post = get_post( $attributes['ref'] );
+ if ( ! isset( $navigation_post ) ) {
+ return new WP_Block_List( array(), $attributes );
+ }
+
+ // Only published posts are valid. If this is changed then a corresponding change
+ // must also be implemented in `use-navigation-menu.js`.
+ if ( 'publish' === $navigation_post->post_status ) {
+ $parsed_blocks = parse_blocks( $navigation_post->post_content );
+
+ // 'parse_blocks' includes a null block with '\n\n' as the content when
+ // it encounters whitespace. This code strips it.
+ $blocks = block_core_navigation_filter_out_empty_blocks( $parsed_blocks );
+
+ if ( function_exists( 'get_hooked_block_markup' ) ) {
+ // Run Block Hooks algorithm to inject hooked blocks.
+ $markup = block_core_navigation_insert_hooked_blocks( $blocks, $navigation_post );
+ $root_nav_block = parse_blocks( $markup )[0];
+
+ $blocks = isset( $root_nav_block['innerBlocks'] ) ? $root_nav_block['innerBlocks'] : $blocks;
+ }
+
+ // TODO - this uses the full navigation block attributes for the
+ // context which could be refined.
+ return new WP_Block_List( $blocks, $attributes );
+ }
+ }
+
+ /**
+ * Gets the inner blocks for the navigation block from the fallback.
+ *
+ * @param array $attributes The block attributes.
+ * @return WP_Block_List Returns the inner blocks for the navigation block.
+ */
+ private static function get_inner_blocks_from_fallback( $attributes ) {
+ $fallback_blocks = block_core_navigation_get_fallback_blocks();
+
+ // Fallback my have been filtered so do basic test for validity.
+ if ( empty( $fallback_blocks ) || ! is_array( $fallback_blocks ) ) {
+ return new WP_Block_List( array(), $attributes );
+ }
+
+ return new WP_Block_List( $fallback_blocks, $attributes );
+ }
+
+ /**
+ * Gets the inner blocks for the navigation block.
+ *
+ * @param array $attributes The block attributes.
+ * @param WP_Block $block The parsed block.
+ * @return WP_Block_List Returns the inner blocks for the navigation block.
+ */
+ private static function get_inner_blocks( $attributes, $block ) {
+ $inner_blocks = $block->inner_blocks;
+
+ // Ensure that blocks saved with the legacy ref attribute name (navigationMenuId) continue to render.
+ if ( array_key_exists( 'navigationMenuId', $attributes ) ) {
+ $attributes['ref'] = $attributes['navigationMenuId'];
+ }
+
+ // If:
+ // - the gutenberg plugin is active
+ // - `__unstableLocation` is defined
+ // - we have menu items at the defined location
+ // - we don't have a relationship to a `wp_navigation` Post (via `ref`).
+ // ...then create inner blocks from the classic menu assigned to that location.
+ if (
+ defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN &&
+ array_key_exists( '__unstableLocation', $attributes ) &&
+ ! array_key_exists( 'ref', $attributes ) &&
+ ! empty( block_core_navigation_get_menu_items_at_location( $attributes['__unstableLocation'] ) )
+ ) {
+ $inner_blocks = block_core_navigation_get_inner_blocks_from_unstable_location( $attributes );
+ }
+
+ // Load inner blocks from the navigation post.
+ if ( array_key_exists( 'ref', $attributes ) ) {
+ $inner_blocks = static::get_inner_blocks_from_navigation_post( $attributes );
+ }
+
+ // If there are no inner blocks then fallback to rendering an appropriate fallback.
+ if ( empty( $inner_blocks ) ) {
+ $inner_blocks = static::get_inner_blocks_from_fallback( $attributes );
+ }
+
+ /**
+ * Filter navigation block $inner_blocks.
+ * Allows modification of a navigation block menu items.
+ *
+ * @since 6.1.0
+ *
+ * @param \WP_Block_List $inner_blocks
+ */
+ $inner_blocks = apply_filters( 'block_core_navigation_render_inner_blocks', $inner_blocks );
+
+ $post_ids = block_core_navigation_get_post_ids( $inner_blocks );
+ if ( $post_ids ) {
+ _prime_post_caches( $post_ids, false, false );
+ }
+
+ return $inner_blocks;
+ }
+
+ /**
+ * Gets the name of the current navigation, if it has one.
+ *
+ * @param array $attributes The block attributes.
+ * @return string Returns the name of the navigation.
+ */
+ private static function get_navigation_name( $attributes ) {
+
+ $navigation_name = $attributes['ariaLabel'] ?? '';
+
+ // Load the navigation post.
+ if ( array_key_exists( 'ref', $attributes ) ) {
+ $navigation_post = get_post( $attributes['ref'] );
+ if ( ! isset( $navigation_post ) ) {
+ return $navigation_name;
+ }
+
+ // Only published posts are valid. If this is changed then a corresponding change
+ // must also be implemented in `use-navigation-menu.js`.
+ if ( 'publish' === $navigation_post->post_status ) {
+ $navigation_name = $navigation_post->post_title;
+
+ // This is used to count the number of times a navigation name has been seen,
+ // so that we can ensure every navigation has a unique id.
+ if ( isset( static::$seen_menu_names[ $navigation_name ] ) ) {
+ ++static::$seen_menu_names[ $navigation_name ];
+ } else {
+ static::$seen_menu_names[ $navigation_name ] = 1;
+ }
+ }
+ }
+
+ return $navigation_name;
+ }
+
+ /**
+ * Returns the layout class for the navigation block.
+ *
+ * @param array $attributes The block attributes.
+ * @return string Returns the layout class for the navigation block.
+ */
+ private static function get_layout_class( $attributes ) {
+ $layout_justification = array(
+ 'left' => 'items-justified-left',
+ 'right' => 'items-justified-right',
+ 'center' => 'items-justified-center',
+ 'space-between' => 'items-justified-space-between',
+ );
+
+ $layout_class = '';
+ if (
+ isset( $attributes['layout']['justifyContent'] ) &&
+ isset( $layout_justification[ $attributes['layout']['justifyContent'] ] )
+ ) {
+ $layout_class .= $layout_justification[ $attributes['layout']['justifyContent'] ];
+ }
+ if ( isset( $attributes['layout']['orientation'] ) && 'vertical' === $attributes['layout']['orientation'] ) {
+ $layout_class .= ' is-vertical';
+ }
+
+ if ( isset( $attributes['layout']['flexWrap'] ) && 'nowrap' === $attributes['layout']['flexWrap'] ) {
+ $layout_class .= ' no-wrap';
+ }
+ return $layout_class;
+ }
+
+ /**
+ * Return classes for the navigation block.
+ *
+ * @param array $attributes The block attributes.
+ * @return string Returns the classes for the navigation block.
+ */
+ private static function get_classes( $attributes ) {
+ // Restore legacy classnames for submenu positioning.
+ $layout_class = static::get_layout_class( $attributes );
+ $colors = block_core_navigation_build_css_colors( $attributes );
+ $font_sizes = block_core_navigation_build_css_font_sizes( $attributes );
+ $is_responsive_menu = static::is_responsive( $attributes );
+
+ // Manually add block support text decoration as CSS class.
+ $text_decoration = $attributes['style']['typography']['textDecoration'] ?? null;
+ $text_decoration_class = sprintf( 'has-text-decoration-%s', $text_decoration );
+
+ // Sets the is-collapsed class when the navigation is set to always use the overlay.
+ // This saves us from needing to do this check in the view.js file (see the collapseNav function).
+ $is_collapsed_class = static::is_always_overlay( $attributes ) ? array( 'is-collapsed' ) : array();
+
+ $classes = array_merge(
+ $colors['css_classes'],
+ $font_sizes['css_classes'],
+ $is_responsive_menu ? array( 'is-responsive' ) : array(),
+ $layout_class ? array( $layout_class ) : array(),
+ $text_decoration ? array( $text_decoration_class ) : array(),
+ $is_collapsed_class
+ );
+ return implode( ' ', $classes );
+ }
+
+ private static function is_always_overlay( $attributes ) {
+ return isset( $attributes['overlayMenu'] ) && 'always' === $attributes['overlayMenu'];
+ }
+
+ /**
+ * Get styles for the navigation block.
+ *
+ * @param array $attributes The block attributes.
+ * @return string Returns the styles for the navigation block.
+ */
+ private static function get_styles( $attributes ) {
+ $colors = block_core_navigation_build_css_colors( $attributes );
+ $font_sizes = block_core_navigation_build_css_font_sizes( $attributes );
+ $block_styles = isset( $attributes['styles'] ) ? $attributes['styles'] : '';
+ return $block_styles . $colors['inline_styles'] . $font_sizes['inline_styles'];
+ }
+
+ /**
+ * Get the responsive container markup
+ *
+ * @param array $attributes The block attributes.
+ * @param WP_Block_List $inner_blocks The list of inner blocks.
+ * @param string $inner_blocks_html The markup for the inner blocks.
+ * @return string Returns the container markup.
+ */
+ private static function get_responsive_container_markup( $attributes, $inner_blocks, $inner_blocks_html ) {
+ $is_interactive = static::is_interactive( $attributes, $inner_blocks );
+ $colors = block_core_navigation_build_css_colors( $attributes );
+ $modal_unique_id = wp_unique_id( 'modal-' );
+
+ $responsive_container_classes = array(
+ 'wp-block-navigation__responsive-container',
+ implode( ' ', $colors['overlay_css_classes'] ),
+ );
+ $open_button_classes = array(
+ 'wp-block-navigation__responsive-container-open',
+ );
+
+ $should_display_icon_label = isset( $attributes['hasIcon'] ) && true === $attributes['hasIcon'];
+ $toggle_button_icon = ' ';
+ if ( isset( $attributes['icon'] ) ) {
+ if ( 'menu' === $attributes['icon'] ) {
+ $toggle_button_icon = ' ';
+ }
+ }
+ $toggle_button_content = $should_display_icon_label ? $toggle_button_icon : __( 'Menu' );
+ $toggle_close_button_icon = ' ';
+ $toggle_close_button_content = $should_display_icon_label ? $toggle_close_button_icon : __( 'Close' );
+ $toggle_aria_label_open = $should_display_icon_label ? 'aria-label="' . __( 'Open menu' ) . '"' : ''; // Open button label.
+ $toggle_aria_label_close = $should_display_icon_label ? 'aria-label="' . __( 'Close menu' ) . '"' : ''; // Close button label.
+
+ // Add Interactivity API directives to the markup if needed.
+ $open_button_directives = '';
+ $responsive_container_directives = '';
+ $responsive_dialog_directives = '';
+ $close_button_directives = '';
+ if ( $is_interactive ) {
+ $open_button_directives = '
+ data-wp-on--click="actions.openMenuOnClick"
+ data-wp-on--keydown="actions.handleMenuKeydown"
+ ';
+ $responsive_container_directives = '
+ data-wp-class--has-modal-open="state.isMenuOpen"
+ data-wp-class--is-menu-open="state.isMenuOpen"
+ data-wp-watch="callbacks.initMenu"
+ data-wp-on--keydown="actions.handleMenuKeydown"
+ data-wp-on--focusout="actions.handleMenuFocusout"
+ tabindex="-1"
+ ';
+ $responsive_dialog_directives = '
+ data-wp-bind--aria-modal="state.ariaModal"
+ data-wp-bind--aria-label="state.ariaLabel"
+ data-wp-bind--role="state.roleAttribute"
+ ';
+ $close_button_directives = '
+ data-wp-on--click="actions.closeMenuOnClick"
+ ';
+ $responsive_container_content_directives = '
+ data-wp-watch="callbacks.focusFirstElement"
+ ';
+ }
+
+ return sprintf(
+ '%8$s
+ ',
+ esc_attr( $modal_unique_id ),
+ $inner_blocks_html,
+ $toggle_aria_label_open,
+ $toggle_aria_label_close,
+ esc_attr( implode( ' ', $responsive_container_classes ) ),
+ esc_attr( implode( ' ', $open_button_classes ) ),
+ esc_attr( safecss_filter_attr( $colors['overlay_inline_styles'] ) ),
+ $toggle_button_content,
+ $toggle_close_button_content,
+ $open_button_directives,
+ $responsive_container_directives,
+ $responsive_dialog_directives,
+ $close_button_directives,
+ $responsive_container_content_directives
+ );
+ }
+
+ /**
+ * Get the wrapper attributes
+ *
+ * @param array $attributes The block attributes.
+ * @param WP_Block_List $inner_blocks A list of inner blocks.
+ * @return string Returns the navigation block markup.
+ */
+ private static function get_nav_wrapper_attributes( $attributes, $inner_blocks ) {
+ $nav_menu_name = static::get_unique_navigation_name( $attributes );
+ $is_interactive = static::is_interactive( $attributes, $inner_blocks );
+ $is_responsive_menu = static::is_responsive( $attributes );
+ $style = static::get_styles( $attributes );
+ $class = static::get_classes( $attributes );
+ $wrapper_attributes = get_block_wrapper_attributes(
+ array(
+ 'class' => $class,
+ 'style' => $style,
+ 'aria-label' => $nav_menu_name,
+ )
+ );
+
+ if ( $is_responsive_menu ) {
+ $nav_element_directives = static::get_nav_element_directives( $is_interactive, $attributes );
+ $wrapper_attributes .= ' ' . $nav_element_directives;
+ }
+
+ return $wrapper_attributes;
+ }
+
+ /**
+ * Gets the nav element directives.
+ *
+ * @param bool $is_interactive Whether the block is interactive.
+ * @param array $attributes The block attributes.
+ * @return string the directives for the navigation element.
+ */
+ private static function get_nav_element_directives( $is_interactive, $attributes ) {
+ if ( ! $is_interactive ) {
+ return '';
+ }
+ // When adding to this array be mindful of security concerns.
+ $nav_element_context = wp_json_encode(
+ array(
+ 'overlayOpenedBy' => array(),
+ 'type' => 'overlay',
+ 'roleAttribute' => '',
+ 'ariaLabel' => __( 'Menu' ),
+ ),
+ JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP
+ );
+ $nav_element_directives = '
+ data-wp-interactive=\'{"namespace":"core/navigation"}\'
+ data-wp-context=\'' . $nav_element_context . '\'
+ ';
+
+ /*
+ * When the navigation's 'overlayMenu' attribute is set to 'always', JavaScript
+ * is not needed for collapsing the menu because the class is set manually.
+ */
+ if ( ! static::is_always_overlay( $attributes ) ) {
+ $nav_element_directives .= 'data-wp-init="callbacks.initNav"';
+ $nav_element_directives .= ' '; // space separator
+ $nav_element_directives .= 'data-wp-class--is-collapsed="context.isCollapsed"';
+ }
+
+ return $nav_element_directives;
+ }
+
+ /**
+ * Handle view script module loading.
+ *
+ * @param array $attributes The block attributes.
+ * @param WP_Block $block The parsed block.
+ * @param WP_Block_List $inner_blocks The list of inner blocks.
+ */
+ private static function handle_view_script_module_loading( $attributes, $block, $inner_blocks ) {
+ if ( static::is_interactive( $attributes, $inner_blocks ) ) {
+ wp_enqueue_script_module( '@wordpress/block-library/navigation' );
+ }
+ }
+
+ /**
+ * Returns the markup for the navigation block.
+ *
+ * @param array $attributes The block attributes.
+ * @param WP_Block_List $inner_blocks The list of inner blocks.
+ * @return string Returns the navigation wrapper markup.
+ */
+ private static function get_wrapper_markup( $attributes, $inner_blocks ) {
+ $inner_blocks_html = static::get_inner_blocks_html( $attributes, $inner_blocks );
+ if ( static::is_responsive( $attributes ) ) {
+ return static::get_responsive_container_markup( $attributes, $inner_blocks, $inner_blocks_html );
+ }
+ return $inner_blocks_html;
+ }
+
+ /**
+ * Returns a unique name for the navigation.
+ *
+ * @param array $attributes The block attributes.
+ * @return string Returns a unique name for the navigation.
+ */
+ private static function get_unique_navigation_name( $attributes ) {
+ $nav_menu_name = static::get_navigation_name( $attributes );
+
+ // If the menu name has been used previously then append an ID
+ // to the name to ensure uniqueness across a given post.
+ if ( isset( static::$seen_menu_names[ $nav_menu_name ] ) && static::$seen_menu_names[ $nav_menu_name ] > 1 ) {
+ $count = static::$seen_menu_names[ $nav_menu_name ];
+ $nav_menu_name = $nav_menu_name . ' ' . ( $count );
+ }
+
+ return $nav_menu_name;
+ }
+
+ /**
+ * Renders the navigation block.
+ *
+ * @param array $attributes The block attributes.
+ * @param string $content The saved content.
+ * @param WP_Block $block The parsed block.
+ * @return string Returns the navigation block markup.
+ */
+ public static function render( $attributes, $content, $block ) {
+ /**
+ * Deprecated:
+ * The rgbTextColor and rgbBackgroundColor attributes
+ * have been deprecated in favor of
+ * customTextColor and customBackgroundColor ones.
+ * Move the values from old attrs to the new ones.
+ */
+ if ( isset( $attributes['rgbTextColor'] ) && empty( $attributes['textColor'] ) ) {
+ $attributes['customTextColor'] = $attributes['rgbTextColor'];
+ }
+
+ if ( isset( $attributes['rgbBackgroundColor'] ) && empty( $attributes['backgroundColor'] ) ) {
+ $attributes['customBackgroundColor'] = $attributes['rgbBackgroundColor'];
+ }
+
+ unset( $attributes['rgbTextColor'], $attributes['rgbBackgroundColor'] );
+
+ $inner_blocks = static::get_inner_blocks( $attributes, $block );
+ // Prevent navigation blocks referencing themselves from rendering.
+ if ( block_core_navigation_block_contains_core_navigation( $inner_blocks ) ) {
+ return '';
+ }
+
+ static::handle_view_script_module_loading( $attributes, $block, $inner_blocks );
+
+ return sprintf(
+ '%2$s ',
+ static::get_nav_wrapper_attributes( $attributes, $inner_blocks ),
+ static::get_wrapper_markup( $attributes, $inner_blocks )
+ );
+ }
+}
+
// These functions are used for the __unstableLocation feature and only active
// when the gutenberg plugin is active.
if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ) {
@@ -65,68 +707,84 @@ function block_core_navigation_sort_menu_items_by_parent_id( $menu_items ) {
return $menu_items_by_parent_id;
}
-}
+ /**
+ * Gets the inner blocks for the navigation block from the unstable location attribute.
+ *
+ * @param array $attributes The block attributes.
+ * @return WP_Block_List Returns the inner blocks for the navigation block.
+ */
+ function block_core_navigation_get_inner_blocks_from_unstable_location( $attributes ) {
+ $menu_items = block_core_navigation_get_menu_items_at_location( $attributes['__unstableLocation'] );
+ if ( empty( $menu_items ) ) {
+ return new WP_Block_List( array(), $attributes );
+ }
+
+ $menu_items_by_parent_id = block_core_navigation_sort_menu_items_by_parent_id( $menu_items );
+ $parsed_blocks = block_core_navigation_parse_blocks_from_menu_items( $menu_items_by_parent_id[0], $menu_items_by_parent_id );
+ return new WP_Block_List( $parsed_blocks, $attributes );
+ }
+}
/**
* Add Interactivity API directives to the navigation-submenu and page-list
* blocks markup using the Tag Processor.
*
- * @param string $w Markup of the navigation block.
- * @param array $block_attributes Block attributes.
+ * @param WP_HTML_Tag_Processor $tags Markup of the navigation block.
+ * @param array $block_attributes Block attributes.
*
* @return string Submenu markup with the directives injected.
*/
-function block_core_navigation_add_directives_to_submenu( $w, $block_attributes ) {
- while ( $w->next_tag(
+function block_core_navigation_add_directives_to_submenu( $tags, $block_attributes ) {
+ while ( $tags->next_tag(
array(
'tag_name' => 'LI',
'class_name' => 'has-child',
)
) ) {
// Add directives to the parent ``.
- $w->set_attribute( 'data-wp-interactive', true );
- $w->set_attribute( 'data-wp-context', '{ "core": { "navigation": { "submenuOpenedBy": {}, "type": "submenu" } } }' );
- $w->set_attribute( 'data-wp-effect', 'effects.core.navigation.initMenu' );
- $w->set_attribute( 'data-wp-on--focusout', 'actions.core.navigation.handleMenuFocusout' );
- $w->set_attribute( 'data-wp-on--keydown', 'actions.core.navigation.handleMenuKeydown' );
+ $tags->set_attribute( 'data-wp-interactive', '{ "namespace": "core/navigation" }' );
+ $tags->set_attribute( 'data-wp-context', '{ "submenuOpenedBy": {}, "type": "submenu" }' );
+ $tags->set_attribute( 'data-wp-watch', 'callbacks.initMenu' );
+ $tags->set_attribute( 'data-wp-on--focusout', 'actions.handleMenuFocusout' );
+ $tags->set_attribute( 'data-wp-on--keydown', 'actions.handleMenuKeydown' );
// This is a fix for Safari. Without it, Safari doesn't change the active
// element when the user clicks on a button. It can be removed once we add
// an overlay to capture the clicks, instead of relying on the focusout
// event.
- $w->set_attribute( 'tabindex', '-1' );
+ $tags->set_attribute( 'tabindex', '-1' );
if ( ! isset( $block_attributes['openSubmenusOnClick'] ) || false === $block_attributes['openSubmenusOnClick'] ) {
- $w->set_attribute( 'data-wp-on--mouseenter', 'actions.core.navigation.openMenuOnHover' );
- $w->set_attribute( 'data-wp-on--mouseleave', 'actions.core.navigation.closeMenuOnHover' );
+ $tags->set_attribute( 'data-wp-on--mouseenter', 'actions.openMenuOnHover' );
+ $tags->set_attribute( 'data-wp-on--mouseleave', 'actions.closeMenuOnHover' );
}
// Add directives to the toggle submenu button.
- if ( $w->next_tag(
+ if ( $tags->next_tag(
array(
'tag_name' => 'BUTTON',
'class_name' => 'wp-block-navigation-submenu__toggle',
)
) ) {
- $w->set_attribute( 'data-wp-on--click', 'actions.core.navigation.toggleMenuOnClick' );
- $w->set_attribute( 'data-wp-bind--aria-expanded', 'selectors.core.navigation.isMenuOpen' );
+ $tags->set_attribute( 'data-wp-on--click', 'actions.toggleMenuOnClick' );
+ $tags->set_attribute( 'data-wp-bind--aria-expanded', 'state.isMenuOpen' );
// The `aria-expanded` attribute for SSR is already added in the submenu block.
}
// Add directives to the submenu.
- if ( $w->next_tag(
+ if ( $tags->next_tag(
array(
'tag_name' => 'UL',
'class_name' => 'wp-block-navigation__submenu-container',
)
) ) {
- $w->set_attribute( 'data-wp-on--focus', 'actions.core.navigation.openMenuOnFocus' );
+ $tags->set_attribute( 'data-wp-on--focus', 'actions.openMenuOnFocus' );
}
// Iterate through subitems if exist.
- block_core_navigation_add_directives_to_submenu( $w, $block_attributes );
+ block_core_navigation_add_directives_to_submenu( $tags, $block_attributes );
}
- return $w->get_updated_html();
+ return $tags->get_updated_html();
}
/**
@@ -333,6 +991,17 @@ function block_core_navigation_get_fallback_blocks() {
// Normalizing blocks may result in an empty array of blocks if they were all `null` blocks.
// In this case default to the (Page List) fallback.
$fallback_blocks = ! empty( $maybe_fallback ) ? $maybe_fallback : $fallback_blocks;
+
+ if ( function_exists( 'get_hooked_block_markup' ) ) {
+ // Run Block Hooks algorithm to inject hooked blocks.
+ // We have to run it here because we need the post ID of the Navigation block to track ignored hooked blocks.
+ $markup = block_core_navigation_insert_hooked_blocks( $fallback_blocks, $navigation_post );
+ $blocks = parse_blocks( $markup );
+
+ if ( isset( $blocks[0]['innerBlocks'] ) ) {
+ $fallback_blocks = $blocks[0]['innerBlocks'];
+ }
+ }
}
/**
@@ -344,7 +1013,7 @@ function block_core_navigation_get_fallback_blocks() {
*
* @since 5.9.0
*
- * @param array[] default fallback blocks provided by the default block mechanic.
+ * @param array[] $fallback_blocks default fallback blocks provided by the default block mechanic.
*/
return apply_filters( 'block_core_navigation_render_fallback', $fallback_blocks );
}
@@ -391,391 +1060,10 @@ function block_core_navigation_from_block_get_post_ids( $block ) {
* @param string $content The saved content.
* @param WP_Block $block The parsed block.
*
- * @return string Returns the post content with the legacy widget added.
+ * @return string Returns the navigation block markup.
*/
function render_block_core_navigation( $attributes, $content, $block ) {
- static $seen_menu_names = array();
-
- // Flag used to indicate whether the rendered output is considered to be
- // a fallback (i.e. the block has no menu associated with it).
- $is_fallback = false;
-
- $nav_menu_name = $attributes['ariaLabel'] ?? '';
-
- /**
- * Deprecated:
- * The rgbTextColor and rgbBackgroundColor attributes
- * have been deprecated in favor of
- * customTextColor and customBackgroundColor ones.
- * Move the values from old attrs to the new ones.
- */
- if ( isset( $attributes['rgbTextColor'] ) && empty( $attributes['textColor'] ) ) {
- $attributes['customTextColor'] = $attributes['rgbTextColor'];
- }
-
- if ( isset( $attributes['rgbBackgroundColor'] ) && empty( $attributes['backgroundColor'] ) ) {
- $attributes['customBackgroundColor'] = $attributes['rgbBackgroundColor'];
- }
-
- unset( $attributes['rgbTextColor'], $attributes['rgbBackgroundColor'] );
-
- /**
- * This is for backwards compatibility after `isResponsive` attribute has been removed.
- */
- $has_old_responsive_attribute = ! empty( $attributes['isResponsive'] ) && $attributes['isResponsive'];
- $is_responsive_menu = isset( $attributes['overlayMenu'] ) && 'never' !== $attributes['overlayMenu'] || $has_old_responsive_attribute;
-
- $inner_blocks = $block->inner_blocks;
-
- // Ensure that blocks saved with the legacy ref attribute name (navigationMenuId) continue to render.
- if ( array_key_exists( 'navigationMenuId', $attributes ) ) {
- $attributes['ref'] = $attributes['navigationMenuId'];
- }
-
- // If:
- // - the gutenberg plugin is active
- // - `__unstableLocation` is defined
- // - we have menu items at the defined location
- // - we don't have a relationship to a `wp_navigation` Post (via `ref`).
- // ...then create inner blocks from the classic menu assigned to that location.
- if (
- defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN &&
- array_key_exists( '__unstableLocation', $attributes ) &&
- ! array_key_exists( 'ref', $attributes ) &&
- ! empty( block_core_navigation_get_menu_items_at_location( $attributes['__unstableLocation'] ) )
- ) {
- $menu_items = block_core_navigation_get_menu_items_at_location( $attributes['__unstableLocation'] );
- if ( empty( $menu_items ) ) {
- return '';
- }
-
- $menu_items_by_parent_id = block_core_navigation_sort_menu_items_by_parent_id( $menu_items );
- $parsed_blocks = block_core_navigation_parse_blocks_from_menu_items( $menu_items_by_parent_id[0], $menu_items_by_parent_id );
- $inner_blocks = new WP_Block_List( $parsed_blocks, $attributes );
- }
-
- // Load inner blocks from the navigation post.
- if ( array_key_exists( 'ref', $attributes ) ) {
- $navigation_post = get_post( $attributes['ref'] );
- if ( ! isset( $navigation_post ) ) {
- return '';
- }
-
- // Only published posts are valid. If this is changed then a corresponding change
- // must also be implemented in `use-navigation-menu.js`.
- if ( 'publish' === $navigation_post->post_status ) {
- $nav_menu_name = $navigation_post->post_title;
-
- if ( isset( $seen_menu_names[ $nav_menu_name ] ) ) {
- ++$seen_menu_names[ $nav_menu_name ];
- } else {
- $seen_menu_names[ $nav_menu_name ] = 1;
- }
-
- $parsed_blocks = parse_blocks( $navigation_post->post_content );
-
- // 'parse_blocks' includes a null block with '\n\n' as the content when
- // it encounters whitespace. This code strips it.
- $compacted_blocks = block_core_navigation_filter_out_empty_blocks( $parsed_blocks );
-
- // TODO - this uses the full navigation block attributes for the
- // context which could be refined.
- $inner_blocks = new WP_Block_List( $compacted_blocks, $attributes );
- }
- }
-
- // If there are no inner blocks then fallback to rendering an appropriate fallback.
- if ( empty( $inner_blocks ) ) {
- $is_fallback = true; // indicate we are rendering the fallback.
-
- $fallback_blocks = block_core_navigation_get_fallback_blocks();
-
- // Fallback my have been filtered so do basic test for validity.
- if ( empty( $fallback_blocks ) || ! is_array( $fallback_blocks ) ) {
- return '';
- }
-
- $inner_blocks = new WP_Block_List( $fallback_blocks, $attributes );
- }
-
- if ( block_core_navigation_block_contains_core_navigation( $inner_blocks ) ) {
- return '';
- }
-
- /**
- * Filter navigation block $inner_blocks.
- * Allows modification of a navigation block menu items.
- *
- * @since 6.1.0
- *
- * @param \WP_Block_List $inner_blocks
- */
- $inner_blocks = apply_filters( 'block_core_navigation_render_inner_blocks', $inner_blocks );
-
- $layout_justification = array(
- 'left' => 'items-justified-left',
- 'right' => 'items-justified-right',
- 'center' => 'items-justified-center',
- 'space-between' => 'items-justified-space-between',
- );
-
- // Restore legacy classnames for submenu positioning.
- $layout_class = '';
- if (
- isset( $attributes['layout']['justifyContent'] ) &&
- isset( $layout_justification[ $attributes['layout']['justifyContent'] ] )
- ) {
- $layout_class .= $layout_justification[ $attributes['layout']['justifyContent'] ];
- }
- if ( isset( $attributes['layout']['orientation'] ) && 'vertical' === $attributes['layout']['orientation'] ) {
- $layout_class .= ' is-vertical';
- }
-
- if ( isset( $attributes['layout']['flexWrap'] ) && 'nowrap' === $attributes['layout']['flexWrap'] ) {
- $layout_class .= ' no-wrap';
- }
-
- // Manually add block support text decoration as CSS class.
- $text_decoration = $attributes['style']['typography']['textDecoration'] ?? null;
- $text_decoration_class = sprintf( 'has-text-decoration-%s', $text_decoration );
-
- $colors = block_core_navigation_build_css_colors( $attributes );
- $font_sizes = block_core_navigation_build_css_font_sizes( $attributes );
- $classes = array_merge(
- $colors['css_classes'],
- $font_sizes['css_classes'],
- $is_responsive_menu ? array( 'is-responsive' ) : array(),
- $layout_class ? array( $layout_class ) : array(),
- $is_fallback ? array( 'is-fallback' ) : array(),
- $text_decoration ? array( $text_decoration_class ) : array()
- );
-
- $post_ids = block_core_navigation_get_post_ids( $inner_blocks );
- if ( $post_ids ) {
- _prime_post_caches( $post_ids, false, false );
- }
-
- $list_item_nav_blocks = array(
- 'core/navigation-link',
- 'core/home-link',
- 'core/site-title',
- 'core/site-logo',
- 'core/navigation-submenu',
- );
-
- $needs_list_item_wrapper = array(
- 'core/site-title',
- 'core/site-logo',
- );
-
- $block_styles = isset( $attributes['styles'] ) ? $attributes['styles'] : '';
- $style = $block_styles . $colors['inline_styles'] . $font_sizes['inline_styles'];
- $class = implode( ' ', $classes );
-
- // If the menu name has been used previously then append an ID
- // to the name to ensure uniqueness across a given post.
- if ( isset( $seen_menu_names[ $nav_menu_name ] ) && $seen_menu_names[ $nav_menu_name ] > 1 ) {
- $count = $seen_menu_names[ $nav_menu_name ];
- $nav_menu_name = $nav_menu_name . ' ' . ( $count );
- }
-
- $wrapper_attributes = get_block_wrapper_attributes(
- array(
- 'class' => $class,
- 'style' => $style,
- 'aria-label' => $nav_menu_name,
- )
- );
-
- $container_attributes = get_block_wrapper_attributes(
- array(
- 'class' => 'wp-block-navigation__container ' . $class,
- 'style' => $style,
- )
- );
-
- $inner_blocks_html = '';
- $is_list_open = false;
- $has_submenus = false;
- foreach ( $inner_blocks as $inner_block ) {
- $is_list_item = in_array( $inner_block->name, $list_item_nav_blocks, true );
-
- if ( $is_list_item && ! $is_list_open ) {
- $is_list_open = true;
- $inner_blocks_html .= sprintf(
- '',
- $container_attributes
- );
- }
-
- if ( ! $is_list_item && $is_list_open ) {
- $is_list_open = false;
- $inner_blocks_html .= ' ';
- }
-
- $inner_block_content = $inner_block->render();
- $p = new WP_HTML_Tag_Processor( $inner_block_content );
- if ( $p->next_tag(
- array(
- 'name' => 'LI',
- 'class_name' => 'has-child',
- )
- ) ) {
- $has_submenus = true;
- }
- if ( ! empty( $inner_block_content ) ) {
- if ( in_array( $inner_block->name, $needs_list_item_wrapper, true ) ) {
- $inner_blocks_html .= ' ' . $inner_block_content . ' ';
- } else {
- $inner_blocks_html .= $inner_block_content;
- }
- }
- }
-
- if ( $is_list_open ) {
- $inner_blocks_html .= '';
- }
-
- $should_load_view_script = ( $has_submenus && ( $attributes['openSubmenusOnClick'] || $attributes['showSubmenuIcon'] ) ) || $is_responsive_menu;
- $view_js_file = 'wp-block-navigation-view';
-
- // If the script already exists, there is no point in removing it from viewScript.
- if ( ! wp_script_is( $view_js_file ) ) {
- $script_handles = $block->block_type->view_script_handles;
-
- // If the script is not needed, and it is still in the `view_script_handles`, remove it.
- if ( ! $should_load_view_script && in_array( $view_js_file, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) );
- }
- // If the script is needed, but it was previously removed, add it again.
- if ( $should_load_view_script && ! in_array( $view_js_file, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) );
- }
- }
-
- // Add directives to the submenu if needed.
- if ( $has_submenus && $should_load_view_script ) {
- $w = new WP_HTML_Tag_Processor( $inner_blocks_html );
- $inner_blocks_html = block_core_navigation_add_directives_to_submenu( $w, $attributes );
- }
-
- $modal_unique_id = wp_unique_id( 'modal-' );
-
- // Determine whether or not navigation elements should be wrapped in the markup required to make it responsive,
- // return early if they don't.
- if ( ! $is_responsive_menu ) {
- return sprintf(
- '%2$s ',
- $wrapper_attributes,
- $inner_blocks_html
- );
- }
-
- $is_hidden_by_default = isset( $attributes['overlayMenu'] ) && 'always' === $attributes['overlayMenu'];
-
- $responsive_container_classes = array(
- 'wp-block-navigation__responsive-container',
- $is_hidden_by_default ? 'hidden-by-default' : '',
- implode( ' ', $colors['overlay_css_classes'] ),
- );
- $open_button_classes = array(
- 'wp-block-navigation__responsive-container-open',
- $is_hidden_by_default ? 'always-shown' : '',
- );
-
- $should_display_icon_label = isset( $attributes['hasIcon'] ) && true === $attributes['hasIcon'];
- $toggle_button_icon = ' ';
- if ( isset( $attributes['icon'] ) ) {
- if ( 'menu' === $attributes['icon'] ) {
- $toggle_button_icon = ' ';
- }
- }
- $toggle_button_content = $should_display_icon_label ? $toggle_button_icon : __( 'Menu' );
- $toggle_close_button_icon = ' ';
- $toggle_close_button_content = $should_display_icon_label ? $toggle_close_button_icon : __( 'Close' );
- $toggle_aria_label_open = $should_display_icon_label ? 'aria-label="' . __( 'Open menu' ) . '"' : ''; // Open button label.
- $toggle_aria_label_close = $should_display_icon_label ? 'aria-label="' . __( 'Close menu' ) . '"' : ''; // Close button label.
-
- // Add Interactivity API directives to the markup if needed.
- $nav_element_directives = '';
- $open_button_directives = '';
- $responsive_container_directives = '';
- $responsive_dialog_directives = '';
- $close_button_directives = '';
- if ( $should_load_view_script ) {
- $nav_element_context = wp_json_encode(
- array(
- 'core' => array(
- 'navigation' => array(
- 'overlayOpenedBy' => array(),
- 'type' => 'overlay',
- 'roleAttribute' => '',
- 'ariaLabel' => __( 'Menu' ),
- ),
- ),
- ),
- JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP
- );
- $nav_element_directives = '
- data-wp-interactive
- data-wp-context=\'' . $nav_element_context . '\'
- ';
- $open_button_directives = '
- data-wp-on--click="actions.core.navigation.openMenuOnClick"
- data-wp-on--keydown="actions.core.navigation.handleMenuKeydown"
- ';
- $responsive_container_directives = '
- data-wp-class--has-modal-open="selectors.core.navigation.isMenuOpen"
- data-wp-class--is-menu-open="selectors.core.navigation.isMenuOpen"
- data-wp-effect="effects.core.navigation.initMenu"
- data-wp-on--keydown="actions.core.navigation.handleMenuKeydown"
- data-wp-on--focusout="actions.core.navigation.handleMenuFocusout"
- tabindex="-1"
- ';
- $responsive_dialog_directives = '
- data-wp-bind--aria-modal="selectors.core.navigation.ariaModal"
- data-wp-bind--aria-label="selectors.core.navigation.ariaLabel"
- data-wp-bind--role="selectors.core.navigation.roleAttribute"
- data-wp-effect="effects.core.navigation.focusFirstElement"
- ';
- $close_button_directives = '
- data-wp-on--click="actions.core.navigation.closeMenuOnClick"
- ';
- }
-
- $responsive_container_markup = sprintf(
- '%8$s
- ',
- esc_attr( $modal_unique_id ),
- $inner_blocks_html,
- $toggle_aria_label_open,
- $toggle_aria_label_close,
- esc_attr( implode( ' ', $responsive_container_classes ) ),
- esc_attr( implode( ' ', $open_button_classes ) ),
- esc_attr( safecss_filter_attr( $colors['overlay_inline_styles'] ) ),
- $toggle_button_content,
- $toggle_close_button_content,
- $open_button_directives,
- $responsive_container_directives,
- $responsive_dialog_directives,
- $close_button_directives
- );
-
- return sprintf(
- '%2$s ',
- $wrapper_attributes,
- $responsive_container_markup,
- $nav_element_directives
- );
+ return WP_Navigation_Block_Renderer::render( $attributes, $content, $block );
}
/**
@@ -791,6 +1079,13 @@ function register_block_core_navigation() {
'render_callback' => 'render_block_core_navigation',
)
);
+
+ wp_register_script_module(
+ '@wordpress/block-library/navigation',
+ defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ? gutenberg_url( '/build/interactivity/navigation.min.js' ) : includes_url( 'blocks/navigation/view.min.js' ),
+ array( '@wordpress/interactivity' ),
+ defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
+ );
}
add_action( 'init', 'register_block_core_navigation' );
@@ -829,25 +1124,6 @@ function block_core_navigation_typographic_presets_backcompatibility( $parsed_bl
add_filter( 'render_block_data', 'block_core_navigation_typographic_presets_backcompatibility' );
-/**
- * Ensure that the view script has the `wp-interactivity` dependency.
- *
- * @since 6.4.0
- *
- * @global WP_Scripts $wp_scripts
- */
-function block_core_navigation_ensure_interactivity_dependency() {
- global $wp_scripts;
- if (
- isset( $wp_scripts->registered['wp-block-navigation-view'] ) &&
- ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-navigation-view']->deps, true )
- ) {
- $wp_scripts->registered['wp-block-navigation-view']->deps[] = 'wp-interactivity';
- }
-}
-
-add_action( 'wp_print_scripts', 'block_core_navigation_ensure_interactivity_dependency' );
-
/**
* Turns menu item data into a nested array of parsed blocks
*
@@ -1066,3 +1342,116 @@ function block_core_navigation_get_most_recently_published_navigation() {
return null;
}
+
+/**
+ * Insert hooked blocks into a Navigation block.
+ *
+ * Given a Navigation block's inner blocks and its corresponding `wp_navigation` post object,
+ * this function inserts hooked blocks into it, and returns the serialized inner blocks in a
+ * mock Navigation block wrapper.
+ *
+ * If there are any hooked blocks that need to be inserted as the Navigation block's first or last
+ * children, the `wp_navigation` post's `_wp_ignored_hooked_blocks` meta is checked to see if any
+ * of those hooked blocks should be exempted from insertion.
+ *
+ * @param array $inner_blocks Parsed inner blocks of a Navigation block.
+ * @param WP_Post $post `wp_navigation` post object corresponding to the block.
+ * @return string Serialized inner blocks in mock Navigation block wrapper, with hooked blocks inserted, if any.
+ */
+function block_core_navigation_insert_hooked_blocks( $inner_blocks, $post ) {
+ $before_block_visitor = null;
+ $after_block_visitor = null;
+ $hooked_blocks = get_hooked_blocks();
+ $attributes = array();
+
+ if ( isset( $post->ID ) ) {
+ $ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
+ if ( ! empty( $ignored_hooked_blocks ) ) {
+ $ignored_hooked_blocks = json_decode( $ignored_hooked_blocks, true );
+ $attributes['metadata'] = array(
+ 'ignoredHookedBlocks' => $ignored_hooked_blocks,
+ );
+ }
+ }
+
+ $mock_anchor_parent_block = array(
+ 'blockName' => 'core/navigation',
+ 'attrs' => $attributes,
+ 'innerBlocks' => $inner_blocks,
+ 'innerContent' => array_fill( 0, count( $inner_blocks ), null ),
+ );
+ $before_block_visitor = null;
+ $after_block_visitor = null;
+
+ if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
+ $before_block_visitor = make_before_block_visitor( $hooked_blocks, $post );
+ $after_block_visitor = make_after_block_visitor( $hooked_blocks, $post );
+ }
+
+ return traverse_and_serialize_block( $mock_anchor_parent_block, $before_block_visitor, $after_block_visitor );
+}
+
+/**
+ * Updates the post meta with the list of ignored hooked blocks when the navigation is created or updated via the REST API.
+ *
+ * @param WP_Post $post Post object.
+ */
+function block_core_navigation_update_ignore_hooked_blocks_meta( $post ) {
+ // We run the Block Hooks mechanism so it will return the list of ignored hooked blocks
+ // in the mock root Navigation block's metadata attribute.
+ // We ignore the rest of the returned `$markup`; `$post->post_content` already has the hooked
+ // blocks inserted, whereas `$markup` will have them inserted twice.
+ $blocks = parse_blocks( $post->post_content );
+ $markup = block_core_navigation_insert_hooked_blocks( $blocks, $post );
+ $root_nav_block = parse_blocks( $markup )[0];
+ $ignored_hooked_blocks = isset( $root_nav_block['attrs']['metadata']['ignoredHookedBlocks'] )
+ ? $root_nav_block['attrs']['metadata']['ignoredHookedBlocks']
+ : array();
+
+ if ( ! empty( $ignored_hooked_blocks ) ) {
+ $existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
+ if ( ! empty( $existing_ignored_hooked_blocks ) ) {
+ $existing_ignored_hooked_blocks = json_decode( $existing_ignored_hooked_blocks, true );
+ $ignored_hooked_blocks = array_unique( array_merge( $ignored_hooked_blocks, $existing_ignored_hooked_blocks ) );
+ }
+ update_post_meta( $post->ID, '_wp_ignored_hooked_blocks', json_encode( $ignored_hooked_blocks ) );
+ }
+}
+
+// Injection of hooked blocks into the Navigation block relies on some functions present in WP >= 6.5
+// that are not present in Gutenberg's WP 6.5 compatibility layer.
+if ( function_exists( 'get_hooked_block_markup' ) ) {
+ add_action( 'rest_insert_wp_navigation', 'block_core_navigation_update_ignore_hooked_blocks_meta', 10, 3 );
+}
+
+/**
+ * Hooks into the REST API response for the core/navigation block and adds the first and last inner blocks.
+ *
+ * @param WP_REST_Response $response The response object.
+ * @param WP_Post $post Post object.
+ * @param WP_REST_Request $request Request object.
+ * @return WP_REST_Response The response object.
+ */
+function block_core_navigation_insert_hooked_blocks_into_rest_response( $response, $post ) {
+ if ( ! isset( $response->data['content']['raw'] ) || ! isset( $response->data['content']['rendered'] ) ) {
+ return $response;
+ }
+ $parsed_blocks = parse_blocks( $response->data['content']['raw'] );
+ $content = block_core_navigation_insert_hooked_blocks( $parsed_blocks, $post );
+
+ // Remove mock Navigation block wrapper.
+ $start = strpos( $content, '-->' ) + strlen( '-->' );
+ $end = strrpos( $content, '`. Support these by defaulting an undefined label and
@@ -36,7 +36,6 @@ function render_block_core_search( $attributes, $content, $block ) {
$show_button = ( ! empty( $attributes['buttonPosition'] ) && 'no-button' === $attributes['buttonPosition'] ) ? false : true;
$button_position = $show_button ? $attributes['buttonPosition'] : null;
$query_params = ( ! empty( $attributes['query'] ) ) ? $attributes['query'] : array();
- $button_behavior = ( ! empty( $attributes['buttonBehavior'] ) ) ? $attributes['buttonBehavior'] : 'default';
$button = '';
$query_params_markup = '';
$inline_styles = styles_for_block_core_search( $attributes );
@@ -78,28 +77,18 @@ function render_block_core_search( $attributes, $content, $block ) {
$input->set_attribute( 'value', get_search_query() );
$input->set_attribute( 'placeholder', $attributes['placeholder'] );
- $is_expandable_searchfield = 'button-only' === $button_position && 'expand-searchfield' === $button_behavior;
+ // If it's interactive, enqueue the script module and add the directives.
+ $is_expandable_searchfield = 'button-only' === $button_position;
if ( $is_expandable_searchfield ) {
- $input->set_attribute( 'data-wp-bind--aria-hidden', '!context.core.search.isSearchInputVisible' );
- $input->set_attribute( 'data-wp-bind--tabindex', 'selectors.core.search.tabindex' );
- // Adding these attributes manually is needed until the Interactivity API SSR logic is added to core.
- $input->set_attribute( 'aria-hidden', 'true' );
- $input->set_attribute( 'tabindex', '-1' );
- }
+ wp_enqueue_script_module( '@wordpress/block-library/search' );
- // If the script already exists, there is no point in removing it from viewScript.
- $view_js_file = 'wp-block-search-view';
- if ( ! wp_script_is( $view_js_file ) ) {
- $script_handles = $block->block_type->view_script_handles;
+ $input->set_attribute( 'data-wp-bind--aria-hidden', '!context.isSearchInputVisible' );
+ $input->set_attribute( 'data-wp-bind--tabindex', 'state.tabindex' );
- // If the script is not needed, and it is still in the `view_script_handles`, remove it.
- if ( ! $is_expandable_searchfield && in_array( $view_js_file, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_diff( $script_handles, array( $view_js_file ) );
- }
- // If the script is needed, but it was previously removed, add it again.
- if ( $is_expandable_searchfield && ! in_array( $view_js_file, $script_handles, true ) ) {
- $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) );
- }
+ // Adding these attributes manually is needed until the Interactivity API
+ // SSR logic is added to core.
+ $input->set_attribute( 'aria-hidden', 'true' );
+ $input->set_attribute( 'tabindex', '-1' );
}
}
@@ -144,13 +133,15 @@ function render_block_core_search( $attributes, $content, $block ) {
if ( $button->next_tag() ) {
$button->add_class( implode( ' ', $button_classes ) );
- if ( 'expand-searchfield' === $attributes['buttonBehavior'] && 'button-only' === $attributes['buttonPosition'] ) {
- $button->set_attribute( 'data-wp-bind--aria-label', 'selectors.core.search.ariaLabel' );
- $button->set_attribute( 'data-wp-bind--aria-controls', 'selectors.core.search.ariaControls' );
- $button->set_attribute( 'data-wp-bind--aria-expanded', 'context.core.search.isSearchInputVisible' );
- $button->set_attribute( 'data-wp-bind--type', 'selectors.core.search.type' );
- $button->set_attribute( 'data-wp-on--click', 'actions.core.search.openSearchInput' );
- // Adding these attributes manually is needed until the Interactivity API SSR logic is added to core.
+ if ( 'button-only' === $attributes['buttonPosition'] ) {
+ $button->set_attribute( 'data-wp-bind--aria-label', 'state.ariaLabel' );
+ $button->set_attribute( 'data-wp-bind--aria-controls', 'state.ariaControls' );
+ $button->set_attribute( 'data-wp-bind--aria-expanded', 'context.isSearchInputVisible' );
+ $button->set_attribute( 'data-wp-bind--type', 'state.type' );
+ $button->set_attribute( 'data-wp-on--click', 'actions.openSearchInput' );
+
+ // Adding these attributes manually is needed until the Interactivity
+ // API SSR logic is added to core.
$button->set_attribute( 'aria-label', __( 'Expand search field' ) );
$button->set_attribute( 'aria-controls', 'wp-block-search__input-' . $input_id );
$button->set_attribute( 'aria-expanded', 'false' );
@@ -172,15 +163,17 @@ function render_block_core_search( $attributes, $content, $block ) {
array( 'class' => $classnames )
);
$form_directives = '';
+
+ // If it's interactive, add the directives.
if ( $is_expandable_searchfield ) {
$aria_label_expanded = __( 'Submit Search' );
$aria_label_collapsed = __( 'Expand search field' );
$form_directives = '
- data-wp-interactive
- data-wp-context=\'{ "core": { "search": { "isSearchInputVisible": ' . $open_by_default . ', "inputId": "' . $input_id . '", "ariaLabelExpanded": "' . $aria_label_expanded . '", "ariaLabelCollapsed": "' . $aria_label_collapsed . '" } } }\'
- data-wp-class--wp-block-search__searchfield-hidden="!context.core.search.isSearchInputVisible"
- data-wp-on--keydown="actions.core.search.handleSearchKeydown"
- data-wp-on--focusout="actions.core.search.handleSearchFocusout"
+ data-wp-interactive=\'{ "namespace": "core/search" }\'
+ data-wp-context=\'{ "isSearchInputVisible": ' . $open_by_default . ', "inputId": "' . $input_id . '", "ariaLabelExpanded": "' . $aria_label_expanded . '", "ariaLabelCollapsed": "' . $aria_label_collapsed . '" }\'
+ data-wp-class--wp-block-search__searchfield-hidden="!context.isSearchInputVisible"
+ data-wp-on--keydown="actions.handleSearchKeydown"
+ data-wp-on--focusout="actions.handleSearchFocusout"
';
}
@@ -203,27 +196,15 @@ function register_block_core_search() {
'render_callback' => 'render_block_core_search',
)
);
-}
-add_action( 'init', 'register_block_core_search' );
-/**
- * Ensure that the view script has the `wp-interactivity` dependency.
- *
- * @since 6.4.0
- *
- * @global WP_Scripts $wp_scripts
- */
-function block_core_search_ensure_interactivity_dependency() {
- global $wp_scripts;
- if (
- isset( $wp_scripts->registered['wp-block-search-view'] ) &&
- ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-search-view']->deps, true )
- ) {
- $wp_scripts->registered['wp-block-search-view']->deps[] = 'wp-interactivity';
- }
+ wp_register_script_module(
+ '@wordpress/block-library/search',
+ defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN ? gutenberg_url( '/build/interactivity/search.min.js' ) : includes_url( 'blocks/search/view.min.js' ),
+ array( '@wordpress/interactivity' ),
+ defined( 'GUTENBERG_VERSION' ) ? GUTENBERG_VERSION : get_bloginfo( 'version' )
+ );
}
-
-add_action( 'wp_print_scripts', 'block_core_search_ensure_interactivity_dependency' );
+add_action( 'init', 'register_block_core_search' );
/**
* Builds the correct top level classnames for the 'core/search' block.
@@ -249,10 +230,7 @@ function classnames_for_block_core_search( $attributes ) {
}
if ( 'button-only' === $attributes['buttonPosition'] ) {
- $classnames[] = 'wp-block-search__button-only';
- if ( ! empty( $attributes['buttonBehavior'] ) && 'expand-searchfield' === $attributes['buttonBehavior'] ) {
- $classnames[] = 'wp-block-search__button-behavior-expand wp-block-search__searchfield-hidden';
- }
+ $classnames[] = 'wp-block-search__button-only wp-block-search__searchfield-hidden';
}
}
diff --git a/src/wp-includes/blocks/search/block.json b/src/wp-includes/blocks/search/block.json
index 5669a9089d0e0..8d5e208045068 100644
--- a/src/wp-includes/blocks/search/block.json
+++ b/src/wp-includes/blocks/search/block.json
@@ -43,10 +43,6 @@
"type": "object",
"default": {}
},
- "buttonBehavior": {
- "type": "string",
- "default": "expand-searchfield"
- },
"isSearchFieldHidden": {
"type": "boolean",
"default": false
@@ -91,7 +87,6 @@
},
"html": false
},
- "viewScript": "file:./view.min.js",
"editorStyle": "wp-block-search-editor",
"style": "wp-block-search"
}
diff --git a/src/wp-includes/blocks/search/view.asset.php b/src/wp-includes/blocks/search/view.asset.php
index e2b70b1990bb1..e9b5021ae35c5 100644
--- a/src/wp-includes/blocks/search/view.asset.php
+++ b/src/wp-includes/blocks/search/view.asset.php
@@ -1 +1 @@
- array(), 'version' => 'e81408b3448113f37705');
+ array(), 'version' => '2a0784014283afdd3c25');
diff --git a/src/wp-includes/blocks/search/view.min.asset.php b/src/wp-includes/blocks/search/view.min.asset.php
index dc204c9390558..f9f2fddc7dd06 100644
--- a/src/wp-includes/blocks/search/view.min.asset.php
+++ b/src/wp-includes/blocks/search/view.min.asset.php
@@ -1 +1 @@
- array(), 'version' => 'ff76b5016de2df424c55');
+ array(), 'version' => '765a40956d200c79d99e');
diff --git a/src/wp-includes/blocks/site-title/block.json b/src/wp-includes/blocks/site-title/block.json
index e936bad0e4515..4a2685e6941fc 100644
--- a/src/wp-includes/blocks/site-title/block.json
+++ b/src/wp-includes/blocks/site-title/block.json
@@ -56,11 +56,7 @@
"__experimentalFontWeight": true,
"__experimentalLetterSpacing": true,
"__experimentalDefaultControls": {
- "fontSize": true,
- "lineHeight": true,
- "fontAppearance": true,
- "letterSpacing": true,
- "textTransform": true
+ "fontSize": true
}
}
},
diff --git a/src/wp-includes/blocks/social-link.php b/src/wp-includes/blocks/social-link.php
index cda8e125097a5..fe256879fa4ff 100644
--- a/src/wp-includes/blocks/social-link.php
+++ b/src/wp-includes/blocks/social-link.php
@@ -33,7 +33,7 @@ function render_block_core_social_link( $attributes, $content, $block ) {
* The `is_email` returns false for emails with schema.
*/
if ( is_email( $url ) ) {
- $url = 'mailto:' . $url;
+ $url = 'mailto:' . antispambot( $url );
}
/**
@@ -62,10 +62,10 @@ function render_block_core_social_link( $attributes, $content, $block ) {
$processor = new WP_HTML_Tag_Processor( $link );
$processor->next_tag( 'a' );
if ( $open_in_new_tab ) {
- $processor->set_attribute( 'rel', esc_attr( $rel ) . ' noopener nofollow' );
+ $processor->set_attribute( 'rel', trim( $rel . ' noopener nofollow' ) );
$processor->set_attribute( 'target', '_blank' );
} elseif ( '' !== $rel ) {
- $processor->set_attribute( 'rel', esc_attr( $rel ) );
+ $processor->set_attribute( 'rel', trim( $rel ) );
}
return $processor->get_updated_html();
}
@@ -194,6 +194,10 @@ function block_core_social_link_services( $service = '', $field = '' ) {
'name' => 'GitHub',
'icon' => ' ',
),
+ 'gravatar' => array(
+ 'name' => 'Gravatar',
+ 'icon' => ' ',
+ ),
'instagram' => array(
'name' => 'Instagram',
'icon' => ' ',
diff --git a/src/wp-includes/blocks/table/block.json b/src/wp-includes/blocks/table/block.json
index d1139d6c55add..470886a1247fe 100644
--- a/src/wp-includes/blocks/table/block.json
+++ b/src/wp-includes/blocks/table/block.json
@@ -12,10 +12,9 @@
"default": false
},
"caption": {
- "type": "string",
- "source": "html",
- "selector": "figcaption",
- "default": ""
+ "type": "rich-text",
+ "source": "rich-text",
+ "selector": "figcaption"
},
"head": {
"type": "array",
@@ -30,8 +29,8 @@
"selector": "td,th",
"query": {
"content": {
- "type": "string",
- "source": "html"
+ "type": "rich-text",
+ "source": "rich-text"
},
"tag": {
"type": "string",
@@ -75,8 +74,8 @@
"selector": "td,th",
"query": {
"content": {
- "type": "string",
- "source": "html"
+ "type": "rich-text",
+ "source": "rich-text"
},
"tag": {
"type": "string",
@@ -120,8 +119,8 @@
"selector": "td,th",
"query": {
"content": {
- "type": "string",
- "source": "html"
+ "type": "rich-text",
+ "source": "rich-text"
},
"tag": {
"type": "string",
diff --git a/src/wp-includes/blocks/template-part.php b/src/wp-includes/blocks/template-part.php
index 3ad400906945b..86a17f33c92f3 100644
--- a/src/wp-includes/blocks/template-part.php
+++ b/src/wp-includes/blocks/template-part.php
@@ -43,10 +43,10 @@ function render_block_core_template_part( $attributes ) {
if ( $template_part_post ) {
// A published post might already exist if this template part was customized elsewhere
// or if it's part of a customized template.
- $content = $template_part_post->post_content;
- $area_terms = get_the_terms( $template_part_post, 'wp_template_part_area' );
- if ( ! is_wp_error( $area_terms ) && false !== $area_terms ) {
- $area = $area_terms[0]->name;
+ $block_template = _build_block_template_result_from_post( $template_part_post );
+ $content = $block_template->content;
+ if ( isset( $block_template->area ) ) {
+ $area = $block_template->area;
}
/**
* Fires when a block template part is loaded from a template post stored in the database.
@@ -70,6 +70,12 @@ function render_block_core_template_part( $attributes ) {
if ( isset( $block_template->area ) ) {
$area = $block_template->area;
}
+
+ // Needed for the `render_block_core_template_part_file` and `render_block_core_template_part_none` actions below.
+ $block_template_file = _get_block_template_file( 'wp_template_part', $attributes['slug'] );
+ if ( $block_template_file ) {
+ $template_part_file_path = $block_template_file['path'];
+ }
}
if ( '' !== $content && null !== $content ) {
@@ -275,8 +281,8 @@ function register_block_core_template_part() {
register_block_type_from_metadata(
__DIR__ . '/template-part',
array(
- 'render_callback' => 'render_block_core_template_part',
- 'variations' => build_template_part_block_variations(),
+ 'render_callback' => 'render_block_core_template_part',
+ 'variation_callback' => 'build_template_part_block_variations',
)
);
}
diff --git a/src/wp-includes/blocks/template-part/block.json b/src/wp-includes/blocks/template-part/block.json
index 9fe431150ae39..3b0946718bcb9 100644
--- a/src/wp-includes/blocks/template-part/block.json
+++ b/src/wp-includes/blocks/template-part/block.json
@@ -23,7 +23,8 @@
"supports": {
"align": true,
"html": false,
- "reusable": false
+ "reusable": false,
+ "renaming": false
},
"editorStyle": "wp-block-template-part-editor"
}
diff --git a/src/wp-includes/blocks/verse/block.json b/src/wp-includes/blocks/verse/block.json
index d0fffc8ae5076..846a1dc99caaf 100644
--- a/src/wp-includes/blocks/verse/block.json
+++ b/src/wp-includes/blocks/verse/block.json
@@ -9,10 +9,9 @@
"textdomain": "default",
"attributes": {
"content": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "pre",
- "default": "",
"__unstablePreserveWhiteSpace": true,
"__experimentalRole": "content"
},
@@ -40,8 +39,7 @@
"__experimentalTextTransform": true,
"__experimentalTextDecoration": true,
"__experimentalDefaultControls": {
- "fontSize": true,
- "fontAppearance": true
+ "fontSize": true
}
},
"spacing": {
diff --git a/src/wp-includes/blocks/video/block.json b/src/wp-includes/blocks/video/block.json
index debe6f20fe53f..5d4680f39e79a 100644
--- a/src/wp-includes/blocks/video/block.json
+++ b/src/wp-includes/blocks/video/block.json
@@ -15,8 +15,8 @@
"attribute": "autoplay"
},
"caption": {
- "type": "string",
- "source": "html",
+ "type": "rich-text",
+ "source": "rich-text",
"selector": "figcaption",
"__experimentalRole": "content"
},
diff --git a/src/wp-includes/blocks/widget-group/block.json b/src/wp-includes/blocks/widget-group/block.json
index c29e811554ac1..0e59e58aca224 100644
--- a/src/wp-includes/blocks/widget-group/block.json
+++ b/src/wp-includes/blocks/widget-group/block.json
@@ -1,4 +1,5 @@
{
+ "$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "core/widget-group",
"category": "widgets",
diff --git a/src/wp-includes/canonical.php b/src/wp-includes/canonical.php
index 0b94791fd9b45..093493731f91a 100644
--- a/src/wp-includes/canonical.php
+++ b/src/wp-includes/canonical.php
@@ -550,13 +550,23 @@ function redirect_canonical( $requested_url = null, $do_redirect = true ) {
$is_attachment_redirect = false;
if ( is_attachment() && ! get_option( 'wp_attachment_pages_enabled' ) ) {
- $attachment_id = get_query_var( 'attachment_id' );
-
- if ( current_user_can( 'read_post', $attachment_id ) ) {
- $redirect_url = wp_get_attachment_url( $attachment_id );
-
- $is_attachment_redirect = true;
+ $attachment_id = get_query_var( 'attachment_id' );
+ $attachment_post = get_post( $attachment_id );
+ $attachment_parent_id = $attachment_post ? $attachment_post->post_parent : 0;
+
+ $attachment_url = wp_get_attachment_url( $attachment_id );
+ if ( $attachment_url !== $redirect_url ) {
+ /*
+ * If an attachment is attached to a post, it inherits the parent post's status. Fetch the
+ * parent post to check its status later.
+ */
+ if ( $attachment_parent_id ) {
+ $redirect_obj = get_post( $attachment_parent_id );
+ }
+ $redirect_url = $attachment_url;
}
+
+ $is_attachment_redirect = true;
}
$redirect['query'] = preg_replace( '#^\??&*?#', '', $redirect['query'] );
diff --git a/src/wp-includes/class-avif-info.php b/src/wp-includes/class-avif-info.php
new file mode 100644
index 0000000000000..93280b3806dad
--- /dev/null
+++ b/src/wp-includes/class-avif-info.php
@@ -0,0 +1,781 @@
+= 2^31 on 32-bit systems.
+ // See https://www.php.net/manual/en/function.unpack.php#106041
+ return unpack( 'N', $input ) [1];
+ }
+}
+
+/**
+ * Reads bytes and advances the stream position by the same count.
+ *
+ * @param stream $handle Bytes will be read from this resource.
+ * @param int $num_bytes Number of bytes read. Must be greater than 0.
+ * @return binary string|false The raw bytes or false on failure.
+ */
+function read( $handle, $num_bytes ) {
+ $data = fread( $handle, $num_bytes );
+ return ( $data !== false && strlen( $data ) >= $num_bytes ) ? $data : false;
+}
+
+/**
+ * Advances the stream position by the given offset.
+ *
+ * @param stream $handle Bytes will be skipped from this resource.
+ * @param int $num_bytes Number of skipped bytes. Can be 0.
+ * @return bool True on success or false on failure.
+ */
+// Skips 'num_bytes' from the 'stream'. 'num_bytes' can be zero.
+function skip( $handle, $num_bytes ) {
+ return ( fseek( $handle, $num_bytes, SEEK_CUR ) == 0 );
+}
+
+//------------------------------------------------------------------------------
+// Features are parsed into temporary property associations.
+
+class Tile { // Tile item id <-> parent item id associations.
+ public $tile_item_id;
+ public $parent_item_id;
+}
+
+class Prop { // Property index <-> item id associations.
+ public $property_index;
+ public $item_id;
+}
+
+class Dim_Prop { // Property <-> features associations.
+ public $property_index;
+ public $width;
+ public $height;
+}
+
+class Chan_Prop { // Property <-> features associations.
+ public $property_index;
+ public $bit_depth;
+ public $num_channels;
+}
+
+class Features {
+ public $has_primary_item = false; // True if "pitm" was parsed.
+ public $has_alpha = false; // True if an alpha "auxC" was parsed.
+ public $primary_item_id;
+ public $primary_item_features = array( // Deduced from the data below.
+ 'width' => UNDEFINED, // In number of pixels.
+ 'height' => UNDEFINED, // Ignores mirror and rotation.
+ 'bit_depth' => UNDEFINED, // Likely 8, 10 or 12 bits per channel per pixel.
+ 'num_channels' => UNDEFINED // Likely 1, 2, 3 or 4 channels:
+ // (1 monochrome or 3 colors) + (0 or 1 alpha)
+ );
+
+ public $tiles = array(); // Tile[]
+ public $props = array(); // Prop[]
+ public $dim_props = array(); // Dim_Prop[]
+ public $chan_props = array(); // Chan_Prop[]
+
+ /**
+ * Binds the width, height, bit depth and number of channels from stored internal features.
+ *
+ * @param int $target_item_id Id of the item whose features will be bound.
+ * @param int $tile_depth Maximum recursion to search within tile-parent relations.
+ * @return Status FOUND on success or NOT_FOUND on failure.
+ */
+ private function get_item_features( $target_item_id, $tile_depth ) {
+ foreach ( $this->props as $prop ) {
+ if ( $prop->item_id != $target_item_id ) {
+ continue;
+ }
+
+ // Retrieve the width and height of the primary item if not already done.
+ if ( $target_item_id == $this->primary_item_id &&
+ ( $this->primary_item_features['width'] == UNDEFINED ||
+ $this->primary_item_features['height'] == UNDEFINED ) ) {
+ foreach ( $this->dim_props as $dim_prop ) {
+ if ( $dim_prop->property_index != $prop->property_index ) {
+ continue;
+ }
+ $this->primary_item_features['width'] = $dim_prop->width;
+ $this->primary_item_features['height'] = $dim_prop->height;
+ if ( $this->primary_item_features['bit_depth'] != UNDEFINED &&
+ $this->primary_item_features['num_channels'] != UNDEFINED ) {
+ return FOUND;
+ }
+ break;
+ }
+ }
+ // Retrieve the bit depth and number of channels of the target item if not
+ // already done.
+ if ( $this->primary_item_features['bit_depth'] == UNDEFINED ||
+ $this->primary_item_features['num_channels'] == UNDEFINED ) {
+ foreach ( $this->chan_props as $chan_prop ) {
+ if ( $chan_prop->property_index != $prop->property_index ) {
+ continue;
+ }
+ $this->primary_item_features['bit_depth'] = $chan_prop->bit_depth;
+ $this->primary_item_features['num_channels'] = $chan_prop->num_channels;
+ if ( $this->primary_item_features['width'] != UNDEFINED &&
+ $this->primary_item_features['height'] != UNDEFINED ) {
+ return FOUND;
+ }
+ break;
+ }
+ }
+ }
+
+ // Check for the bit_depth and num_channels in a tile if not yet found.
+ if ( $tile_depth < 3 ) {
+ foreach ( $this->tiles as $tile ) {
+ if ( $tile->parent_item_id != $target_item_id ) {
+ continue;
+ }
+ $status = get_item_features( $tile->tile_item_id, $tile_depth + 1 );
+ if ( $status != NOT_FOUND ) {
+ return $status;
+ }
+ }
+ }
+ return NOT_FOUND;
+ }
+
+ /**
+ * Finds the width, height, bit depth and number of channels of the primary item.
+ *
+ * @return Status FOUND on success or NOT_FOUND on failure.
+ */
+ public function get_primary_item_features() {
+ // Nothing to do without the primary item ID.
+ if ( !$this->has_primary_item ) {
+ return NOT_FOUND;
+ }
+ // Early exit.
+ if ( empty( $this->dim_props ) || empty( $this->chan_props ) ) {
+ return NOT_FOUND;
+ }
+ $status = $this->get_item_features( $this->primary_item_id, /*tile_depth=*/ 0 );
+ if ( $status != FOUND ) {
+ return $status;
+ }
+
+ // "auxC" is parsed before the "ipma" properties so it is known now, if any.
+ if ( $this->has_alpha ) {
+ ++$this->primary_item_features['num_channels'];
+ }
+ return FOUND;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+class Box {
+ public $size; // In bytes.
+ public $type; // Four characters.
+ public $version; // 0 or actual version if this is a full box.
+ public $flags; // 0 or actual value if this is a full box.
+ public $content_size; // 'size' minus the header size.
+
+ /**
+ * Reads the box header.
+ *
+ * @param stream $handle The resource the header will be parsed from.
+ * @param int $num_parsed_boxes The total number of parsed boxes. Prevents timeouts.
+ * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
+ * @return Status FOUND on success or an error on failure.
+ */
+ public function parse( $handle, &$num_parsed_boxes, $num_remaining_bytes = MAX_SIZE ) {
+ // See ISO/IEC 14496-12:2012(E) 4.2
+ $header_size = 8; // box 32b size + 32b type (at least)
+ if ( $header_size > $num_remaining_bytes ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $handle, 8 ) ) ) {
+ return TRUNCATED;
+ }
+ $this->size = read_big_endian( $data, 4 );
+ $this->type = substr( $data, 4, 4 );
+ // 'box->size==1' means 64-bit size should be read after the box type.
+ // 'box->size==0' means this box extends to all remaining bytes.
+ if ( $this->size == 1 ) {
+ $header_size += 8;
+ if ( $header_size > $num_remaining_bytes ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $handle, 8 ) ) ) {
+ return TRUNCATED;
+ }
+ // Stop the parsing if any box has a size greater than 4GB.
+ if ( read_big_endian( $data, 4 ) != 0 ) {
+ return ABORTED;
+ }
+ // Read the 32 least-significant bits.
+ $this->size = read_big_endian( substr( $data, 4, 4 ), 4 );
+ } else if ( $this->size == 0 ) {
+ $this->size = $num_remaining_bytes;
+ }
+ if ( $this->size < $header_size ) {
+ return INVALID;
+ }
+ if ( $this->size > $num_remaining_bytes ) {
+ return INVALID;
+ }
+
+ $has_fullbox_header = $this->type == 'meta' || $this->type == 'pitm' ||
+ $this->type == 'ipma' || $this->type == 'ispe' ||
+ $this->type == 'pixi' || $this->type == 'iref' ||
+ $this->type == 'auxC';
+ if ( $has_fullbox_header ) {
+ $header_size += 4;
+ }
+ if ( $this->size < $header_size ) {
+ return INVALID;
+ }
+ $this->content_size = $this->size - $header_size;
+ // Avoid timeouts. The maximum number of parsed boxes is arbitrary.
+ ++$num_parsed_boxes;
+ if ( $num_parsed_boxes >= MAX_NUM_BOXES ) {
+ return ABORTED;
+ }
+
+ $this->version = 0;
+ $this->flags = 0;
+ if ( $has_fullbox_header ) {
+ if ( !( $data = read( $handle, 4 ) ) ) {
+ return TRUNCATED;
+ }
+ $this->version = read_big_endian( $data, 1 );
+ $this->flags = read_big_endian( substr( $data, 1, 3 ), 3 );
+ // See AV1 Image File Format (AVIF) 8.1
+ // at https://aomediacodec.github.io/av1-avif/#avif-boxes (available when
+ // https://github.com/AOMediaCodec/av1-avif/pull/170 is merged).
+ $is_parsable = ( $this->type == 'meta' && $this->version <= 0 ) ||
+ ( $this->type == 'pitm' && $this->version <= 1 ) ||
+ ( $this->type == 'ipma' && $this->version <= 1 ) ||
+ ( $this->type == 'ispe' && $this->version <= 0 ) ||
+ ( $this->type == 'pixi' && $this->version <= 0 ) ||
+ ( $this->type == 'iref' && $this->version <= 1 ) ||
+ ( $this->type == 'auxC' && $this->version <= 0 );
+ // Instead of considering this file as invalid, skip unparsable boxes.
+ if ( !$is_parsable ) {
+ $this->type = 'unknownversion';
+ }
+ }
+ // print_r( $this ); // Uncomment to print all boxes.
+ return FOUND;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+class Parser {
+ private $handle; // Input stream.
+ private $num_parsed_boxes = 0;
+ private $data_was_skipped = false;
+ public $features;
+
+ function __construct( $handle ) {
+ $this->handle = $handle;
+ $this->features = new Features();
+ }
+
+ /**
+ * Parses an "ipco" box.
+ *
+ * "ispe" is used for width and height, "pixi" and "av1C" are used for bit depth
+ * and number of channels, and "auxC" is used for alpha.
+ *
+ * @param stream $handle The resource the box will be parsed from.
+ * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
+ * @return Status FOUND on success or an error on failure.
+ */
+ private function parse_ipco( $num_remaining_bytes ) {
+ $box_index = 1; // 1-based index. Used for iterating over properties.
+ do {
+ $box = new Box();
+ $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
+ if ( $status != FOUND ) {
+ return $status;
+ }
+
+ if ( $box->type == 'ispe' ) {
+ // See ISO/IEC 23008-12:2017(E) 6.5.3.2
+ if ( $box->content_size < 8 ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, 8 ) ) ) {
+ return TRUNCATED;
+ }
+ $width = read_big_endian( substr( $data, 0, 4 ), 4 );
+ $height = read_big_endian( substr( $data, 4, 4 ), 4 );
+ if ( $width == 0 || $height == 0 ) {
+ return INVALID;
+ }
+ if ( count( $this->features->dim_props ) <= MAX_FEATURES &&
+ $box_index <= MAX_VALUE ) {
+ $dim_prop_count = count( $this->features->dim_props );
+ $this->features->dim_props[$dim_prop_count] = new Dim_Prop();
+ $this->features->dim_props[$dim_prop_count]->property_index = $box_index;
+ $this->features->dim_props[$dim_prop_count]->width = $width;
+ $this->features->dim_props[$dim_prop_count]->height = $height;
+ } else {
+ $this->data_was_skipped = true;
+ }
+ if ( !skip( $this->handle, $box->content_size - 8 ) ) {
+ return TRUNCATED;
+ }
+ } else if ( $box->type == 'pixi' ) {
+ // See ISO/IEC 23008-12:2017(E) 6.5.6.2
+ if ( $box->content_size < 1 ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, 1 ) ) ) {
+ return TRUNCATED;
+ }
+ $num_channels = read_big_endian( $data, 1 );
+ if ( $num_channels < 1 ) {
+ return INVALID;
+ }
+ if ( $box->content_size < 1 + $num_channels ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, 1 ) ) ) {
+ return TRUNCATED;
+ }
+ $bit_depth = read_big_endian( $data, 1 );
+ if ( $bit_depth < 1 ) {
+ return INVALID;
+ }
+ for ( $i = 1; $i < $num_channels; ++$i ) {
+ if ( !( $data = read( $this->handle, 1 ) ) ) {
+ return TRUNCATED;
+ }
+ // Bit depth should be the same for all channels.
+ if ( read_big_endian( $data, 1 ) != $bit_depth ) {
+ return INVALID;
+ }
+ if ( $i > 32 ) {
+ return ABORTED; // Be reasonable.
+ }
+ }
+ if ( count( $this->features->chan_props ) <= MAX_FEATURES &&
+ $box_index <= MAX_VALUE && $bit_depth <= MAX_VALUE &&
+ $num_channels <= MAX_VALUE ) {
+ $chan_prop_count = count( $this->features->chan_props );
+ $this->features->chan_props[$chan_prop_count] = new Chan_Prop();
+ $this->features->chan_props[$chan_prop_count]->property_index = $box_index;
+ $this->features->chan_props[$chan_prop_count]->bit_depth = $bit_depth;
+ $this->features->chan_props[$chan_prop_count]->num_channels = $num_channels;
+ } else {
+ $this->data_was_skipped = true;
+ }
+ if ( !skip( $this->handle, $box->content_size - ( 1 + $num_channels ) ) ) {
+ return TRUNCATED;
+ }
+ } else if ( $box->type == 'av1C' ) {
+ // See AV1 Codec ISO Media File Format Binding 2.3.1
+ // at https://aomediacodec.github.io/av1-isobmff/#av1c
+ // Only parse the necessary third byte. Assume that the others are valid.
+ if ( $box->content_size < 3 ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, 3 ) ) ) {
+ return TRUNCATED;
+ }
+ $byte = read_big_endian( substr( $data, 2, 1 ), 1 );
+ $high_bitdepth = ( $byte & 0x40 ) != 0;
+ $twelve_bit = ( $byte & 0x20 ) != 0;
+ $monochrome = ( $byte & 0x10 ) != 0;
+ if ( $twelve_bit && !$high_bitdepth ) {
+ return INVALID;
+ }
+ if ( count( $this->features->chan_props ) <= MAX_FEATURES &&
+ $box_index <= MAX_VALUE ) {
+ $chan_prop_count = count( $this->features->chan_props );
+ $this->features->chan_props[$chan_prop_count] = new Chan_Prop();
+ $this->features->chan_props[$chan_prop_count]->property_index = $box_index;
+ $this->features->chan_props[$chan_prop_count]->bit_depth =
+ $high_bitdepth ? $twelve_bit ? 12 : 10 : 8;
+ $this->features->chan_props[$chan_prop_count]->num_channels = $monochrome ? 1 : 3;
+ } else {
+ $this->data_was_skipped = true;
+ }
+ if ( !skip( $this->handle, $box->content_size - 3 ) ) {
+ return TRUNCATED;
+ }
+ } else if ( $box->type == 'auxC' ) {
+ // See AV1 Image File Format (AVIF) 4
+ // at https://aomediacodec.github.io/av1-avif/#auxiliary-images
+ $kAlphaStr = "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0";
+ $kAlphaStrLength = 44; // Includes terminating character.
+ if ( $box->content_size >= $kAlphaStrLength ) {
+ if ( !( $data = read( $this->handle, $kAlphaStrLength ) ) ) {
+ return TRUNCATED;
+ }
+ if ( substr( $data, 0, $kAlphaStrLength ) == $kAlphaStr ) {
+ // Note: It is unlikely but it is possible that this alpha plane does
+ // not belong to the primary item or a tile. Ignore this issue.
+ $this->features->has_alpha = true;
+ }
+ if ( !skip( $this->handle, $box->content_size - $kAlphaStrLength ) ) {
+ return TRUNCATED;
+ }
+ } else {
+ if ( !skip( $this->handle, $box->content_size ) ) {
+ return TRUNCATED;
+ }
+ }
+ } else {
+ if ( !skip( $this->handle, $box->content_size ) ) {
+ return TRUNCATED;
+ }
+ }
+ ++$box_index;
+ $num_remaining_bytes -= $box->size;
+ } while ( $num_remaining_bytes > 0 );
+ return NOT_FOUND;
+ }
+
+ /**
+ * Parses an "iprp" box.
+ *
+ * The "ipco" box contain the properties which are linked to items by the "ipma" box.
+ *
+ * @param stream $handle The resource the box will be parsed from.
+ * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
+ * @return Status FOUND on success or an error on failure.
+ */
+ private function parse_iprp( $num_remaining_bytes ) {
+ do {
+ $box = new Box();
+ $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
+ if ( $status != FOUND ) {
+ return $status;
+ }
+
+ if ( $box->type == 'ipco' ) {
+ $status = $this->parse_ipco( $box->content_size );
+ if ( $status != NOT_FOUND ) {
+ return $status;
+ }
+ } else if ( $box->type == 'ipma' ) {
+ // See ISO/IEC 23008-12:2017(E) 9.3.2
+ $num_read_bytes = 4;
+ if ( $box->content_size < $num_read_bytes ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, $num_read_bytes ) ) ) {
+ return TRUNCATED;
+ }
+ $entry_count = read_big_endian( $data, 4 );
+ $id_num_bytes = ( $box->version < 1 ) ? 2 : 4;
+ $index_num_bytes = ( $box->flags & 1 ) ? 2 : 1;
+ $essential_bit_mask = ( $box->flags & 1 ) ? 0x8000 : 0x80;
+
+ for ( $entry = 0; $entry < $entry_count; ++$entry ) {
+ if ( $entry >= MAX_PROPS ||
+ count( $this->features->props ) >= MAX_PROPS ) {
+ $this->data_was_skipped = true;
+ break;
+ }
+ $num_read_bytes += $id_num_bytes + 1;
+ if ( $box->content_size < $num_read_bytes ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, $id_num_bytes + 1 ) ) ) {
+ return TRUNCATED;
+ }
+ $item_id = read_big_endian(
+ substr( $data, 0, $id_num_bytes ), $id_num_bytes );
+ $association_count = read_big_endian(
+ substr( $data, $id_num_bytes, 1 ), 1 );
+
+ for ( $property = 0; $property < $association_count; ++$property ) {
+ if ( $property >= MAX_PROPS ||
+ count( $this->features->props ) >= MAX_PROPS ) {
+ $this->data_was_skipped = true;
+ break;
+ }
+ $num_read_bytes += $index_num_bytes;
+ if ( $box->content_size < $num_read_bytes ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, $index_num_bytes ) ) ) {
+ return TRUNCATED;
+ }
+ $value = read_big_endian( $data, $index_num_bytes );
+ // $essential = ($value & $essential_bit_mask); // Unused.
+ $property_index = ( $value & ~$essential_bit_mask );
+ if ( $property_index <= MAX_VALUE && $item_id <= MAX_VALUE ) {
+ $prop_count = count( $this->features->props );
+ $this->features->props[$prop_count] = new Prop();
+ $this->features->props[$prop_count]->property_index = $property_index;
+ $this->features->props[$prop_count]->item_id = $item_id;
+ } else {
+ $this->data_was_skipped = true;
+ }
+ }
+ if ( $property < $association_count ) {
+ break; // Do not read garbage.
+ }
+ }
+
+ // If all features are available now, do not look further.
+ $status = $this->features->get_primary_item_features();
+ if ( $status != NOT_FOUND ) {
+ return $status;
+ }
+
+ // Mostly if 'data_was_skipped'.
+ if ( !skip( $this->handle, $box->content_size - $num_read_bytes ) ) {
+ return TRUNCATED;
+ }
+ } else {
+ if ( !skip( $this->handle, $box->content_size ) ) {
+ return TRUNCATED;
+ }
+ }
+ $num_remaining_bytes -= $box->size;
+ } while ( $num_remaining_bytes > 0 );
+ return NOT_FOUND;
+ }
+
+ /**
+ * Parses an "iref" box.
+ *
+ * The "dimg" boxes contain links between tiles and their parent items, which
+ * can be used to infer bit depth and number of channels for the primary item
+ * when the latter does not have these properties.
+ *
+ * @param stream $handle The resource the box will be parsed from.
+ * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
+ * @return Status FOUND on success or an error on failure.
+ */
+ private function parse_iref( $num_remaining_bytes ) {
+ do {
+ $box = new Box();
+ $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
+ if ( $status != FOUND ) {
+ return $status;
+ }
+
+ if ( $box->type == 'dimg' ) {
+ // See ISO/IEC 14496-12:2015(E) 8.11.12.2
+ $num_bytes_per_id = ( $box->version == 0 ) ? 2 : 4;
+ $num_read_bytes = $num_bytes_per_id + 2;
+ if ( $box->content_size < $num_read_bytes ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, $num_read_bytes ) ) ) {
+ return TRUNCATED;
+ }
+ $from_item_id = read_big_endian( $data, $num_bytes_per_id );
+ $reference_count = read_big_endian( substr( $data, $num_bytes_per_id, 2 ), 2 );
+
+ for ( $i = 0; $i < $reference_count; ++$i ) {
+ if ( $i >= MAX_TILES ) {
+ $this->data_was_skipped = true;
+ break;
+ }
+ $num_read_bytes += $num_bytes_per_id;
+ if ( $box->content_size < $num_read_bytes ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, $num_bytes_per_id ) ) ) {
+ return TRUNCATED;
+ }
+ $to_item_id = read_big_endian( $data, $num_bytes_per_id );
+ $tile_count = count( $this->features->tiles );
+ if ( $from_item_id <= MAX_VALUE && $to_item_id <= MAX_VALUE &&
+ $tile_count < MAX_TILES ) {
+ $this->features->tiles[$tile_count] = new Tile();
+ $this->features->tiles[$tile_count]->tile_item_id = $to_item_id;
+ $this->features->tiles[$tile_count]->parent_item_id = $from_item_id;
+ } else {
+ $this->data_was_skipped = true;
+ }
+ }
+
+ // If all features are available now, do not look further.
+ $status = $this->features->get_primary_item_features();
+ if ( $status != NOT_FOUND ) {
+ return $status;
+ }
+
+ // Mostly if 'data_was_skipped'.
+ if ( !skip( $this->handle, $box->content_size - $num_read_bytes ) ) {
+ return TRUNCATED;
+ }
+ } else {
+ if ( !skip( $this->handle, $box->content_size ) ) {
+ return TRUNCATED;
+ }
+ }
+ $num_remaining_bytes -= $box->size;
+ } while ( $num_remaining_bytes > 0 );
+ return NOT_FOUND;
+ }
+
+ /**
+ * Parses a "meta" box.
+ *
+ * It looks for the primary item ID in the "pitm" box and recurses into other boxes
+ * to find its features.
+ *
+ * @param stream $handle The resource the box will be parsed from.
+ * @param int $num_remaining_bytes The number of bytes that should be available from the resource.
+ * @return Status FOUND on success or an error on failure.
+ */
+ private function parse_meta( $num_remaining_bytes ) {
+ do {
+ $box = new Box();
+ $status = $box->parse( $this->handle, $this->num_parsed_boxes, $num_remaining_bytes );
+ if ( $status != FOUND ) {
+ return $status;
+ }
+
+ if ( $box->type == 'pitm' ) {
+ // See ISO/IEC 14496-12:2015(E) 8.11.4.2
+ $num_bytes_per_id = ( $box->version == 0 ) ? 2 : 4;
+ if ( $num_bytes_per_id > $num_remaining_bytes ) {
+ return INVALID;
+ }
+ if ( !( $data = read( $this->handle, $num_bytes_per_id ) ) ) {
+ return TRUNCATED;
+ }
+ $primary_item_id = read_big_endian( $data, $num_bytes_per_id );
+ if ( $primary_item_id > MAX_VALUE ) {
+ return ABORTED;
+ }
+ $this->features->has_primary_item = true;
+ $this->features->primary_item_id = $primary_item_id;
+ if ( !skip( $this->handle, $box->content_size - $num_bytes_per_id ) ) {
+ return TRUNCATED;
+ }
+ } else if ( $box->type == 'iprp' ) {
+ $status = $this->parse_iprp( $box->content_size );
+ if ( $status != NOT_FOUND ) {
+ return $status;
+ }
+ } else if ( $box->type == 'iref' ) {
+ $status = $this->parse_iref( $box->content_size );
+ if ( $status != NOT_FOUND ) {
+ return $status;
+ }
+ } else {
+ if ( !skip( $this->handle, $box->content_size ) ) {
+ return TRUNCATED;
+ }
+ }
+ $num_remaining_bytes -= $box->size;
+ } while ( $num_remaining_bytes != 0 );
+ // According to ISO/IEC 14496-12:2012(E) 8.11.1.1 there is at most one "meta".
+ return INVALID;
+ }
+
+ /**
+ * Parses a file stream.
+ *
+ * The file type is checked through the "ftyp" box.
+ *
+ * @return bool True if the input stream is an AVIF bitstream or false.
+ */
+ public function parse_ftyp() {
+ $box = new Box();
+ $status = $box->parse( $this->handle, $this->num_parsed_boxes );
+ if ( $status != FOUND ) {
+ return false;
+ }
+
+ if ( $box->type != 'ftyp' ) {
+ return false;
+ }
+ // Iterate over brands. See ISO/IEC 14496-12:2012(E) 4.3.1
+ if ( $box->content_size < 8 ) {
+ return false;
+ }
+ for ( $i = 0; $i + 4 <= $box->content_size; $i += 4 ) {
+ if ( !( $data = read( $this->handle, 4 ) ) ) {
+ return false;
+ }
+ if ( $i == 4 ) {
+ continue; // Skip minor_version.
+ }
+ if ( substr( $data, 0, 4 ) == 'avif' || substr( $data, 0, 4 ) == 'avis' ) {
+ return skip( $this->handle, $box->content_size - ( $i + 4 ) );
+ }
+ if ( $i > 32 * 4 ) {
+ return false; // Be reasonable.
+ }
+
+ }
+ return false; // No AVIF brand no good.
+ }
+
+ /**
+ * Parses a file stream.
+ *
+ * Features are extracted from the "meta" box.
+ *
+ * @return bool True if the main features of the primary item were parsed or false.
+ */
+ public function parse_file() {
+ $box = new Box();
+ while ( $box->parse( $this->handle, $this->num_parsed_boxes ) == FOUND ) {
+ if ( $box->type === 'meta' ) {
+ if ( $this->parse_meta( $box->content_size ) != FOUND ) {
+ return false;
+ }
+ return true;
+ }
+ if ( !skip( $this->handle, $box->content_size ) ) {
+ return false;
+ }
+ }
+ return false; // No "meta" no good.
+ }
+}
diff --git a/src/wp-includes/class-wp-block-bindings-registry.php b/src/wp-includes/class-wp-block-bindings-registry.php
new file mode 100644
index 0000000000000..65f5f13c36eec
--- /dev/null
+++ b/src/wp-includes/class-wp-block-bindings-registry.php
@@ -0,0 +1,230 @@
+is_registered( $source_name ) ) {
+ _doing_it_wrong(
+ __METHOD__,
+ /* translators: %s: Block bindings source name. */
+ sprintf( __( 'Block bindings source "%s" already registered.' ), $source_name ),
+ '6.5.0'
+ );
+ return false;
+ }
+
+ /* Validate that the source properties contain the label */
+ if ( ! isset( $source_properties['label'] ) ) {
+ _doing_it_wrong(
+ __METHOD__,
+ __( 'The $source_properties must contain a "label".' ),
+ '6.5.0'
+ );
+ return false;
+ }
+
+ /* Validate that the source properties contain the get_value_callback */
+ if ( ! isset( $source_properties['get_value_callback'] ) ) {
+ _doing_it_wrong(
+ __METHOD__,
+ __( 'The $source_properties must contain a "get_value_callback".' ),
+ '6.5.0'
+ );
+ return false;
+ }
+
+ /* Validate that the get_value_callback is a valid callback */
+ if ( ! is_callable( $source_properties['get_value_callback'] ) ) {
+ _doing_it_wrong(
+ __METHOD__,
+ __( 'The "get_value_callback" parameter must be a valid callback.' ),
+ '6.5.0'
+ );
+ return false;
+ }
+
+ $source = new WP_Block_Bindings_Source(
+ $source_name,
+ $source_properties
+ );
+
+ $this->sources[ $source_name ] = $source;
+
+ return $source;
+ }
+
+ /**
+ * Unregisters a block bindings source.
+ *
+ * @since 6.5.0
+ *
+ * @param string $source_name Block bindings source name including namespace.
+ * @return WP_Block_Bindings_Source|false The unregistered block bindings source on success and `false` otherwise.
+ */
+ public function unregister( string $source_name ) {
+ if ( ! $this->is_registered( $source_name ) ) {
+ _doing_it_wrong(
+ __METHOD__,
+ /* translators: %s: Block bindings source name. */
+ sprintf( __( 'Block binding "%s" not found.' ), $source_name ),
+ '6.5.0'
+ );
+ return false;
+ }
+
+ $unregistered_source = $this->sources[ $source_name ];
+ unset( $this->sources[ $source_name ] );
+
+ return $unregistered_source;
+ }
+
+ /**
+ * Retrieves the list of all registered block bindings sources.
+ *
+ * @since 6.5.0
+ *
+ * @return WP_Block_Bindings_Source[] The array of registered sources.
+ */
+ public function get_all_registered() {
+ return $this->sources;
+ }
+
+ /**
+ * Retrieves a registered block bindings source.
+ *
+ * @since 6.5.0
+ *
+ * @param string $source_name The name of the source.
+ * @return WP_Block_Bindings_Source|null The registered block bindings source, or `null` if it is not registered.
+ */
+ public function get_registered( string $source_name ) {
+ if ( ! $this->is_registered( $source_name ) ) {
+ return null;
+ }
+
+ return $this->sources[ $source_name ];
+ }
+
+ /**
+ * Checks if a block bindings source is registered.
+ *
+ * @since 6.5.0
+ *
+ * @param string $source_name The name of the source.
+ * @return bool `true` if the block bindings source is registered, `false` otherwise.
+ */
+ public function is_registered( $source_name ) {
+ return isset( $this->sources[ $source_name ] );
+ }
+
+ /**
+ * Utility method to retrieve the main instance of the class.
+ *
+ * The instance will be created if it does not exist yet.
+ *
+ * @since 6.5.0
+ *
+ * @return WP_Block_Bindings_Registry The main instance.
+ */
+ public static function get_instance() {
+ if ( null === self::$instance ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+}
diff --git a/src/wp-includes/class-wp-block-bindings-source.php b/src/wp-includes/class-wp-block-bindings-source.php
new file mode 100644
index 0000000000000..c2a3d4f8ae2b8
--- /dev/null
+++ b/src/wp-includes/class-wp-block-bindings-source.php
@@ -0,0 +1,88 @@
+name = $name;
+ $this->label = $source_properties['label'];
+ $this->get_value_callback = $source_properties['get_value_callback'];
+ }
+
+ /**
+ * Retrieves the value from the source.
+ *
+ * @since 6.5.0
+ *
+ * @param array $source_args Array containing source arguments used to look up the override value, i.e. {"key": "foo"}.
+ * @param WP_Block $block_instance The block instance.
+ * @param string $attribute_name The name of the target attribute.
+ *
+ * @return mixed The value of the source.
+ */
+ public function get_value( array $source_args, $block_instance, string $attribute_name ) {
+ return call_user_func_array( $this->get_value_callback, array( $source_args, $block_instance, $attribute_name ) );
+ }
+
+ /**
+ * Wakeup magic method.
+ *
+ * @since 6.5.0
+ */
+ public function __wakeup() {
+ throw new \LogicException( __CLASS__ . ' should never be unserialized' );
+ }
+}
diff --git a/src/wp-includes/class-wp-block-type.php b/src/wp-includes/class-wp-block-type.php
index 9caa366032a75..33825a7888320 100644
--- a/src/wp-includes/class-wp-block-type.php
+++ b/src/wp-includes/class-wp-block-type.php
@@ -68,6 +68,14 @@ class WP_Block_Type {
*/
public $ancestor = null;
+ /**
+ * Limits which block types can be inserted as children of this block type.
+ *
+ * @since 6.5.0
+ * @var string[]|null
+ */
+ public $allowed_blocks = null;
+
/**
* Block type icon.
*
@@ -113,9 +121,18 @@ class WP_Block_Type {
* Block variations.
*
* @since 5.8.0
- * @var array[]
+ * @since 6.5.0 Only accessible through magic getter. null by default.
+ * @var array[]|null
+ */
+ private $variations = null;
+
+ /**
+ * Block variations callback.
+ *
+ * @since 6.5.0
+ * @var callable|null
*/
- public $variations = array();
+ public $variation_callback = null;
/**
* Custom CSS selectors for theme.json style generation.
@@ -225,6 +242,14 @@ class WP_Block_Type {
*/
public $style_handles = array();
+ /**
+ * Block type front end only style handles.
+ *
+ * @since 6.5.0
+ * @var string[]
+ */
+ public $view_style_handles = array();
+
/**
* Deprecated block type properties for script and style handles.
*
@@ -269,6 +294,7 @@ class WP_Block_Type {
* Deprecated the `editor_script`, `script`, `view_script`, `editor_style`, and `style` properties.
* @since 6.3.0 Added the `selectors` property.
* @since 6.4.0 Added the `block_hooks` property.
+ * @since 6.5.0 Added the `view_style_handles` property.
*
* @see register_block_type()
*
@@ -285,6 +311,7 @@ class WP_Block_Type {
* available when nested within the specified blocks.
* @type string[]|null $ancestor Setting ancestor makes a block available only inside the specified
* block types at any position of the ancestor's block subtree.
+ * @type string[]|null $allowed_blocks Limits which block types can be inserted as children of this block type.
* @type string|null $icon Block type icon.
* @type string $description A detailed block type description.
* @type string[] $keywords Additional keywords to produce block type as
@@ -296,6 +323,7 @@ class WP_Block_Type {
* @type array|null $supports Supported features.
* @type array|null $example Structured data for the block preview.
* @type callable|null $render_callback Block type render callback.
+ * @type callable|null $variation_callback Block type variations callback.
* @type array|null $attributes Block type attributes property schemas.
* @type string[] $uses_context Context values inherited by blocks of this type.
* @type string[]|null $provides_context Context provided by blocks of this type.
@@ -305,6 +333,7 @@ class WP_Block_Type {
* @type string[] $view_script_handles Block type front end only script handles.
* @type string[] $editor_style_handles Block type editor only style handles.
* @type string[] $style_handles Block type front end and editor style handles.
+ * @type string[] $view_style_handles Block type front end only style handles.
* }
*/
public function __construct( $block_type, $args = array() ) {
@@ -325,6 +354,10 @@ public function __construct( $block_type, $args = array() ) {
* null when value not found, or void when unknown property name provided.
*/
public function __get( $name ) {
+ if ( 'variations' === $name ) {
+ return $this->get_variations();
+ }
+
if ( ! in_array( $name, $this->deprecated_properties, true ) ) {
return;
}
@@ -353,6 +386,10 @@ public function __get( $name ) {
* or false otherwise.
*/
public function __isset( $name ) {
+ if ( 'variations' === $name ) {
+ return true;
+ }
+
if ( ! in_array( $name, $this->deprecated_properties, true ) ) {
return false;
}
@@ -372,6 +409,11 @@ public function __isset( $name ) {
* @param mixed $value Property value.
*/
public function __set( $name, $value ) {
+ if ( 'variations' === $name ) {
+ $this->variations = $value;
+ return;
+ }
+
if ( ! in_array( $name, $this->deprecated_properties, true ) ) {
$this->{$name} = $value;
return;
@@ -540,4 +582,30 @@ public function get_attributes() {
$this->attributes :
array();
}
+
+ /**
+ * Get block variations.
+ *
+ * @since 6.5.0
+ *
+ * @return array[]
+ */
+ public function get_variations() {
+ if ( ! isset( $this->variations ) ) {
+ $this->variations = array();
+ if ( is_callable( $this->variation_callback ) ) {
+ $this->variations = call_user_func( $this->variation_callback );
+ }
+ }
+
+ /**
+ * Filters the registered variations for a block type.
+ *
+ * @since 6.5.0
+ *
+ * @param array $variations Array of registered variations for a block type.
+ * @param WP_Block_Type $block_type The full block type object.
+ */
+ return apply_filters( 'get_block_type_variations', $this->variations, $this );
+ }
}
diff --git a/src/wp-includes/class-wp-block.php b/src/wp-includes/class-wp-block.php
index 65d3af6a12f1a..a965ef13727e1 100644
--- a/src/wp-includes/class-wp-block.php
+++ b/src/wp-includes/class-wp-block.php
@@ -191,6 +191,202 @@ public function __get( $name ) {
return null;
}
+ /**
+ * Processes the block bindings in block's attributes.
+ *
+ * A block might contain bindings in its attributes. Bindings are mappings
+ * between an attribute of the block and a source. A "source" is a function
+ * registered with `register_block_bindings_source()` that defines how to
+ * retrieve a value from outside the block, e.g. from post meta.
+ *
+ * This function will process those bindings and replace the HTML with the value of the binding.
+ * The value is retrieved from the source of the binding.
+ *
+ * ### Example
+ *
+ * The "bindings" property for an Image block might look like this:
+ *
+ * ```json
+ * {
+ * "metadata": {
+ * "bindings": {
+ * "title": {
+ * "source": "core/post-meta",
+ * "args": { "key": "text_custom_field" }
+ * },
+ * "url": {
+ * "source": "core/post-meta",
+ * "args": { "key": "url_custom_field" }
+ * }
+ * }
+ * }
+ * }
+ * ```
+ *
+ * The above example will replace the `title` and `url` attributes of the Image
+ * block with the values of the `text_custom_field` and `url_custom_field` post meta.
+ *
+ * @since 6.5.0
+ *
+ * @param string $block_content Block content.
+ * @param array $block The full block, including name and attributes.
+ * @return string The modified block content.
+ */
+ private function process_block_bindings( $block_content ) {
+ $parsed_block = $this->parsed_block;
+
+ // Allowed blocks that support block bindings.
+ // TODO: Look for a mechanism to opt-in for this. Maybe adding a property to block attributes?
+ $allowed_blocks = array(
+ 'core/paragraph' => array( 'content' ),
+ 'core/heading' => array( 'content' ),
+ 'core/image' => array( 'url', 'title', 'alt' ),
+ 'core/button' => array( 'url', 'text' ),
+ );
+
+ // If the block doesn't have the bindings property, isn't one of the allowed
+ // block types, or the bindings property is not an array, return the block content.
+ if (
+ ! isset( $allowed_blocks[ $this->name ] ) ||
+ empty( $parsed_block['attrs']['metadata']['bindings'] ) ||
+ ! is_array( $parsed_block['attrs']['metadata']['bindings'] )
+ ) {
+ return $block_content;
+ }
+
+ $modified_block_content = $block_content;
+ foreach ( $parsed_block['attrs']['metadata']['bindings'] as $attribute_name => $block_binding ) {
+ // If the attribute is not in the allowed list, process next attribute.
+ if ( ! in_array( $attribute_name, $allowed_blocks[ $this->name ], true ) ) {
+ continue;
+ }
+ // If no source is provided, or that source is not registered, process next attribute.
+ if ( ! isset( $block_binding['source'] ) || ! is_string( $block_binding['source'] ) ) {
+ continue;
+ }
+
+ $block_binding_source = get_block_bindings_source( $block_binding['source'] );
+ if ( null === $block_binding_source ) {
+ continue;
+ }
+
+ $source_args = ! empty( $block_binding['args'] ) && is_array( $block_binding['args'] ) ? $block_binding['args'] : array();
+ $source_value = $block_binding_source->get_value( $source_args, $this, $attribute_name );
+
+ // If the value is not null, process the HTML based on the block and the attribute.
+ if ( ! is_null( $source_value ) ) {
+ $modified_block_content = $this->replace_html( $modified_block_content, $attribute_name, $source_value );
+ }
+ }
+
+ return $modified_block_content;
+ }
+
+ /**
+ * Depending on the block attribute name, replace its value in the HTML based on the value provided.
+ *
+ * @since 6.5.0
+ *
+ * @param string $block_content Block content.
+ * @param string $attribute_name The attribute name to replace.
+ * @param mixed $source_value The value used to replace in the HTML.
+ * @return string The modified block content.
+ */
+ private function replace_html( string $block_content, string $attribute_name, $source_value ) {
+ $block_type = $this->block_type;
+ if ( ! isset( $block_type->attributes[ $attribute_name ] ) ) {
+ return $block_content;
+ }
+
+ // Depending on the attribute source, the processing will be different.
+ switch ( $block_type->attributes[ $attribute_name ]['source'] ) {
+ case 'html':
+ case 'rich-text':
+ $block_reader = new WP_HTML_Tag_Processor( $block_content );
+
+ // TODO: Support for CSS selectors whenever they are ready in the HTML API.
+ // In the meantime, support comma-separated selectors by exploding them into an array.
+ $selectors = explode( ',', $block_type->attributes[ $attribute_name ]['selector'] );
+ // Add a bookmark to the first tag to be able to iterate over the selectors.
+ $block_reader->next_tag();
+ $block_reader->set_bookmark( 'iterate-selectors' );
+
+ // TODO: This shouldn't be needed when the `set_inner_html` function is ready.
+ // Store the parent tag and its attributes to be able to restore them later in the button.
+ // The button block has a wrapper while the paragraph and heading blocks don't.
+ if ( 'core/button' === $this->name ) {
+ $button_wrapper = $block_reader->get_tag();
+ $button_wrapper_attribute_names = $block_reader->get_attribute_names_with_prefix( '' );
+ $button_wrapper_attrs = array();
+ foreach ( $button_wrapper_attribute_names as $name ) {
+ $button_wrapper_attrs[ $name ] = $block_reader->get_attribute( $name );
+ }
+ }
+
+ foreach ( $selectors as $selector ) {
+ // If the parent tag, or any of its children, matches the selector, replace the HTML.
+ if ( strcasecmp( $block_reader->get_tag( $selector ), $selector ) === 0 || $block_reader->next_tag(
+ array(
+ 'tag_name' => $selector,
+ )
+ ) ) {
+ $block_reader->release_bookmark( 'iterate-selectors' );
+
+ // TODO: Use `set_inner_html` method whenever it's ready in the HTML API.
+ // Until then, it is hardcoded for the paragraph, heading, and button blocks.
+ // Store the tag and its attributes to be able to restore them later.
+ $selector_attribute_names = $block_reader->get_attribute_names_with_prefix( '' );
+ $selector_attrs = array();
+ foreach ( $selector_attribute_names as $name ) {
+ $selector_attrs[ $name ] = $block_reader->get_attribute( $name );
+ }
+ $selector_markup = "<$selector>" . wp_kses_post( $source_value ) . "$selector>";
+ $amended_content = new WP_HTML_Tag_Processor( $selector_markup );
+ $amended_content->next_tag();
+ foreach ( $selector_attrs as $attribute_key => $attribute_value ) {
+ $amended_content->set_attribute( $attribute_key, $attribute_value );
+ }
+ if ( 'core/paragraph' === $this->name || 'core/heading' === $this->name ) {
+ return $amended_content->get_updated_html();
+ }
+ if ( 'core/button' === $this->name ) {
+ $button_markup = "<$button_wrapper>{$amended_content->get_updated_html()}$button_wrapper>";
+ $amended_button = new WP_HTML_Tag_Processor( $button_markup );
+ $amended_button->next_tag();
+ foreach ( $button_wrapper_attrs as $attribute_key => $attribute_value ) {
+ $amended_button->set_attribute( $attribute_key, $attribute_value );
+ }
+ return $amended_button->get_updated_html();
+ }
+ } else {
+ $block_reader->seek( 'iterate-selectors' );
+ }
+ }
+ $block_reader->release_bookmark( 'iterate-selectors' );
+ return $block_content;
+
+ case 'attribute':
+ $amended_content = new WP_HTML_Tag_Processor( $block_content );
+ if ( ! $amended_content->next_tag(
+ array(
+ // TODO: build the query from CSS selector.
+ 'tag_name' => $block_type->attributes[ $attribute_name ]['selector'],
+ )
+ ) ) {
+ return $block_content;
+ }
+ $amended_content->set_attribute( $block_type->attributes[ $attribute_name ]['attribute'], $source_value );
+ return $amended_content->get_updated_html();
+ break;
+
+ default:
+ return $block_content;
+ break;
+ }
+ return;
+ }
+
+
/**
* Generates the render output for the block.
*
@@ -280,6 +476,16 @@ public function render( $options = array() ) {
}
}
+ if ( ( ! empty( $this->block_type->view_style_handles ) ) ) {
+ foreach ( $this->block_type->view_style_handles as $view_style_handle ) {
+ wp_enqueue_style( $view_style_handle );
+ }
+ }
+
+ // Process the block bindings for this block, if any are registered. This
+ // will replace the block content with the value from a registered binding source.
+ $block_content = $this->process_block_bindings( $block_content );
+
/**
* Filters the content of a single block.
*
diff --git a/src/wp-includes/class-wp-comment-query.php b/src/wp-includes/class-wp-comment-query.php
index 9ebddd1c74e15..e2ea55a22c2c6 100644
--- a/src/wp-includes/class-wp-comment-query.php
+++ b/src/wp-includes/class-wp-comment-query.php
@@ -329,7 +329,7 @@ public function __construct( $query = '' ) {
*
* @since 4.2.0 Extracted from WP_Comment_Query::query().
*
- * @param string|array $query WP_Comment_Query arguments. See WP_Comment_Query::__construct()
+ * @param string|array $query WP_Comment_Query arguments. See WP_Comment_Query::__construct().
*/
public function parse_query( $query = '' ) {
if ( empty( $query ) ) {
diff --git a/src/wp-includes/class-wp-customize-control.php b/src/wp-includes/class-wp-customize-control.php
index 30e8c2c63914b..055f6cf670fb7 100644
--- a/src/wp-includes/class-wp-customize-control.php
+++ b/src/wp-includes/class-wp-customize-control.php
@@ -553,7 +553,7 @@ protected function render_content() {
link(); ?>>
choices as $value => $label ) {
- echo 'value(), $value, false ) . '>' . $label . ' ';
+ echo 'value(), $value, false ) . '>' . esc_html( $label ) . ' ';
}
?>
diff --git a/src/wp-includes/class-wp-customize-widgets.php b/src/wp-includes/class-wp-customize-widgets.php
index c8a00c741ff8a..8c822ea28f1f5 100644
--- a/src/wp-includes/class-wp-customize-widgets.php
+++ b/src/wp-includes/class-wp-customize-widgets.php
@@ -823,7 +823,7 @@ public function enqueue_scripts() {
);
foreach ( $settings['registeredWidgets'] as &$registered_widget ) {
- unset( $registered_widget['callback'] ); // May not be JSON-serializeable.
+ unset( $registered_widget['callback'] ); // May not be JSON-serializable.
}
$wp_scripts->add_data(
@@ -1308,7 +1308,7 @@ public function export_preview_data() {
);
foreach ( $settings['registeredWidgets'] as &$registered_widget ) {
- unset( $registered_widget['callback'] ); // May not be JSON-serializeable.
+ unset( $registered_widget['callback'] ); // May not be JSON-serializable.
}
wp_print_inline_script_tag(
sprintf( 'var _wpWidgetCustomizerPreviewSettings = %s;', wp_json_encode( $settings ) )
diff --git a/src/wp-includes/class-wp-http.php b/src/wp-includes/class-wp-http.php
index a30f9f7931a5d..bbb6dd41ae0ec 100644
--- a/src/wp-includes/class-wp-http.php
+++ b/src/wp-includes/class-wp-http.php
@@ -467,9 +467,9 @@ static function ( $attr ) {
return null !== $attr;
}
);
- $cookie_jar[ $value->name ] = new WpOrg\Requests\Cookie( $value->name, $value->value, $attributes, array( 'host-only' => $value->host_only ) );
+ $cookie_jar[ $value->name ] = new WpOrg\Requests\Cookie( (string) $value->name, $value->value, $attributes, array( 'host-only' => $value->host_only ) );
} elseif ( is_scalar( $value ) ) {
- $cookie_jar[ $name ] = new WpOrg\Requests\Cookie( $name, (string) $value );
+ $cookie_jar[ $name ] = new WpOrg\Requests\Cookie( (string) $name, (string) $value );
}
}
diff --git a/src/wp-includes/class-wp-image-editor-gd.php b/src/wp-includes/class-wp-image-editor-gd.php
index de079357fb860..23331c7f196cc 100644
--- a/src/wp-includes/class-wp-image-editor-gd.php
+++ b/src/wp-includes/class-wp-image-editor-gd.php
@@ -71,6 +71,8 @@ public static function supports_mime_type( $mime_type ) {
return ( $image_types & IMG_GIF ) != 0;
case 'image/webp':
return ( $image_types & IMG_WEBP ) != 0;
+ case 'image/avif':
+ return ( $image_types & IMG_AVIF ) != 0;
}
return false;
@@ -111,6 +113,16 @@ function_exists( 'imagecreatefromwebp' ) &&
$this->image = @imagecreatefromstring( $file_contents );
}
+ // AVIF may not work with imagecreatefromstring().
+ if (
+ function_exists( 'imagecreatefromavif' ) &&
+ ( 'image/avif' === wp_get_image_mime( $this->file ) )
+ ) {
+ $this->image = @imagecreatefromavif( $this->file );
+ } else {
+ $this->image = @imagecreatefromstring( $file_contents );
+ }
+
if ( ! is_gd_image( $this->image ) ) {
return new WP_Error( 'invalid_image', __( 'File is not an image.' ), $this->file );
}
@@ -513,6 +525,10 @@ protected function _save( $image, $filename = null, $mime_type = null ) {
if ( ! function_exists( 'imagewebp' ) || ! $this->make_image( $filename, 'imagewebp', array( $image, $filename, $this->get_quality() ) ) ) {
return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
}
+ } elseif ( 'image/avif' == $mime_type ) {
+ if ( ! function_exists( 'imageavif' ) || ! $this->make_image( $filename, 'imageavif', array( $image, $filename, $this->get_quality() ) ) ) {
+ return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
+ }
} else {
return new WP_Error( 'image_save_error', __( 'Image Editor Save Failed' ) );
}
@@ -561,8 +577,17 @@ public function stream( $mime_type = null ) {
if ( function_exists( 'imagewebp' ) ) {
header( 'Content-Type: image/webp' );
return imagewebp( $this->image, null, $this->get_quality() );
+ } else {
+ // Fall back to JPEG.
+ header( 'Content-Type: image/jpeg' );
+ return imagejpeg( $this->image, null, $this->get_quality() );
+ }
+ case 'image/avif':
+ if ( function_exists( 'imageavif' ) ) {
+ header( 'Content-Type: image/avif' );
+ return imageavif( $this->image, null, $this->get_quality() );
}
- // Fall back to the default if webp isn't supported.
+ // Fall back to JPEG.
default:
header( 'Content-Type: image/jpeg' );
return imagejpeg( $this->image, null, $this->get_quality() );
diff --git a/src/wp-includes/class-wp-image-editor-imagick.php b/src/wp-includes/class-wp-image-editor-imagick.php
index 03fe0bca6975f..546ad3e7991bf 100644
--- a/src/wp-includes/class-wp-image-editor-imagick.php
+++ b/src/wp-includes/class-wp-image-editor-imagick.php
@@ -219,6 +219,7 @@ public function set_quality( $quality = null ) {
$this->image->setImageCompressionQuality( $quality );
}
break;
+ case 'image/avif':
default:
$this->image->setImageCompressionQuality( $quality );
}
@@ -256,6 +257,16 @@ protected function update_size( $width = null, $height = null ) {
$height = $size['height'];
}
+ /*
+ * If we still don't have the image size, fall back to `wp_getimagesize`. This ensures AVIF images
+ * are properly sized without affecting previous `getImageGeometry` behavior.
+ */
+ if ( ( ! $width || ! $height ) && 'image/avif' === $this->mime_type ) {
+ $size = wp_getimagesize( $this->file );
+ $width = $size[0];
+ $height = $size[1];
+ }
+
return parent::update_size( $width, $height );
}
diff --git a/src/wp-includes/class-wp-image-editor.php b/src/wp-includes/class-wp-image-editor.php
index 3c636dc6ba5a7..6604685a024f0 100644
--- a/src/wp-includes/class-wp-image-editor.php
+++ b/src/wp-includes/class-wp-image-editor.php
@@ -318,6 +318,7 @@ protected function get_default_quality( $mime_type ) {
$quality = 86;
break;
case 'image/jpeg':
+ case 'image/avif':
default:
$quality = $this->default_quality;
}
diff --git a/src/wp-includes/class-wp-locale-switcher.php b/src/wp-includes/class-wp-locale-switcher.php
index d07490f107d1d..9f1c4831ed446 100644
--- a/src/wp-includes/class-wp-locale-switcher.php
+++ b/src/wp-includes/class-wp-locale-switcher.php
@@ -283,6 +283,8 @@ private function change_locale( $locale ) {
$wp_locale = new WP_Locale();
+ WP_Translation_Controller::get_instance()->set_locale( $locale );
+
/**
* Fires when the locale is switched to or restored.
*
diff --git a/src/wp-includes/class-wp-matchesmapregex.php b/src/wp-includes/class-wp-matchesmapregex.php
index 558bd9866781c..ddca4f2cb2e02 100644
--- a/src/wp-includes/class-wp-matchesmapregex.php
+++ b/src/wp-includes/class-wp-matchesmapregex.php
@@ -63,8 +63,8 @@ public function __construct( $subject, $matches ) {
* @return string
*/
public static function apply( $subject, $matches ) {
- $oSelf = new WP_MatchesMapRegex( $subject, $matches );
- return $oSelf->output;
+ $result = new WP_MatchesMapRegex( $subject, $matches );
+ return $result->output;
}
/**
diff --git a/src/wp-includes/class-wp-plugin-dependencies.php b/src/wp-includes/class-wp-plugin-dependencies.php
new file mode 100644
index 0000000000000..c8b9bebb5245f
--- /dev/null
+++ b/src/wp-includes/class-wp-plugin-dependencies.php
@@ -0,0 +1,949 @@
+ $dependencies ) {
+ if ( in_array( $slug, $dependencies, true ) ) {
+ $dependents[] = $dependent;
+ }
+ }
+
+ return $dependents;
+ }
+
+ /**
+ * Gets the slugs of plugins that the dependent requires.
+ *
+ * @since 6.5.0
+ *
+ * @param string $plugin_file The dependent plugin's filepath, relative to the plugins directory.
+ * @return array An array of dependency plugin slugs.
+ */
+ public static function get_dependencies( $plugin_file ) {
+ if ( isset( self::$dependencies[ $plugin_file ] ) ) {
+ return self::$dependencies[ $plugin_file ];
+ }
+
+ return array();
+ }
+
+ /**
+ * Gets a dependent plugin's filepath.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slug The dependent plugin's slug.
+ * @return string|false The dependent plugin's filepath, relative to the plugins directory,
+ * or false if the plugin has no dependencies.
+ */
+ public static function get_dependent_filepath( $slug ) {
+ $filepath = array_search( $slug, self::$dependent_slugs, true );
+
+ return $filepath ? $filepath : false;
+ }
+
+ /**
+ * Determines whether the plugin has unmet dependencies.
+ *
+ * @since 6.5.0
+ *
+ * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
+ * @return bool Whether the plugin has unmet dependencies.
+ */
+ public static function has_unmet_dependencies( $plugin_file ) {
+ if ( ! isset( self::$dependencies[ $plugin_file ] ) ) {
+ return false;
+ }
+
+ require_once ABSPATH . '/wp-admin/includes/plugin.php';
+
+ foreach ( self::$dependencies[ $plugin_file ] as $dependency ) {
+ $dependency_filepath = self::get_dependency_filepath( $dependency );
+
+ if ( false === $dependency_filepath || is_plugin_inactive( $dependency_filepath ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines whether the plugin has a circular dependency.
+ *
+ * @since 6.5.0
+ *
+ * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
+ * @return bool Whether the plugin has a circular dependency.
+ */
+ public static function has_circular_dependency( $plugin_file ) {
+ if ( ! is_array( self::$circular_dependencies_slugs ) ) {
+ self::get_circular_dependencies();
+ }
+
+ if ( ! empty( self::$circular_dependencies_slugs ) ) {
+ $slug = self::convert_to_slug( $plugin_file );
+
+ if ( in_array( $slug, self::$circular_dependencies_slugs, true ) ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Gets the names of plugins that require the plugin.
+ *
+ * @since 6.5.0
+ *
+ * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
+ * @return array An array of dependent names.
+ */
+ public static function get_dependent_names( $plugin_file ) {
+ $dependent_names = array();
+ $plugins = self::get_plugins();
+ $slug = self::convert_to_slug( $plugin_file );
+
+ foreach ( self::get_dependents( $slug ) as $dependent ) {
+ $dependent_names[ $dependent ] = $plugins[ $dependent ]['Name'];
+ }
+ sort( $dependent_names );
+
+ return $dependent_names;
+ }
+
+ /**
+ * Gets the names of plugins required by the plugin.
+ *
+ * @since 6.5.0
+ *
+ * @param string $plugin_file The dependent plugin's filepath, relative to the plugins directory.
+ * @return array An array of dependency names.
+ */
+ public static function get_dependency_names( $plugin_file ) {
+ $dependency_api_data = self::get_dependency_api_data();
+ $dependencies = self::get_dependencies( $plugin_file );
+ $plugins = self::get_plugins();
+
+ $dependency_names = array();
+ foreach ( $dependencies as $dependency ) {
+ // Use the name if it's available, otherwise fall back to the slug.
+ if ( isset( $dependency_api_data[ $dependency ]['name'] ) ) {
+ $name = $dependency_api_data[ $dependency ]['name'];
+ } else {
+ $dependency_filepath = self::get_dependency_filepath( $dependency );
+ if ( false !== $dependency_filepath ) {
+ $name = $plugins[ $dependency_filepath ]['Name'];
+ } else {
+ $name = $dependency;
+ }
+ }
+
+ $dependency_names[ $dependency ] = $name;
+ }
+
+ return $dependency_names;
+ }
+
+ /**
+ * Gets the filepath for a dependency, relative to the plugin's directory.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slug The dependency's slug.
+ * @return string|false If installed, the dependency's filepath relative to the plugins directory, otherwise false.
+ */
+ public static function get_dependency_filepath( $slug ) {
+ $dependency_filepaths = self::get_dependency_filepaths();
+
+ if ( ! isset( $dependency_filepaths[ $slug ] ) ) {
+ return false;
+ }
+
+ return $dependency_filepaths[ $slug ];
+ }
+
+ /**
+ * Returns API data for the dependency.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slug The dependency's slug.
+ * @return array|false The dependency's API data on success, otherwise false.
+ */
+ public static function get_dependency_data( $slug ) {
+ $dependency_api_data = self::get_dependency_api_data();
+
+ if ( isset( $dependency_api_data[ $slug ] ) ) {
+ return $dependency_api_data[ $slug ];
+ }
+
+ return false;
+ }
+
+ /**
+ * Displays an admin notice if dependencies are not installed.
+ *
+ * @since 6.5.0
+ */
+ public static function display_admin_notice_for_unmet_dependencies() {
+ if ( in_array( false, self::get_dependency_filepaths(), true ) ) {
+ wp_admin_notice(
+ __( 'There are additional plugin dependencies that must be installed.' ),
+ array(
+ 'type' => 'info',
+ )
+ );
+ }
+ }
+
+ /**
+ * Displays an admin notice if dependencies have been deactivated.
+ *
+ * @since 6.5.0
+ */
+ public static function display_admin_notice_for_deactivated_dependents() {
+ /*
+ * Plugin deactivated if dependencies not met.
+ * Transient on a 10 second timeout.
+ */
+ $deactivate_requires = get_site_transient( 'wp_plugin_dependencies_deactivated_plugins' );
+ if ( ! empty( $deactivate_requires ) ) {
+ $deactivated_plugins = '';
+ foreach ( $deactivate_requires as $deactivated ) {
+ $deactivated_plugins .= '' . esc_html( self::$plugins[ $deactivated ]['Name'] ) . ' ';
+ }
+ wp_admin_notice(
+ sprintf(
+ /* translators: 1: plugin names */
+ __( 'The following plugin(s) have been deactivated due to uninstalled or inactive dependencies: %s' ),
+ ""
+ ),
+ array(
+ 'type' => 'error',
+ 'dismissible' => true,
+ )
+ );
+ }
+ }
+
+ /**
+ * Displays an admin notice if circular dependencies are installed.
+ *
+ * @since 6.5.0
+ */
+ public static function display_admin_notice_for_circular_dependencies() {
+ $circular_dependencies = self::get_circular_dependencies();
+ if ( ! empty( $circular_dependencies ) && count( $circular_dependencies ) > 1 ) {
+ $circular_dependencies = array_unique( $circular_dependencies, SORT_REGULAR );
+ $plugins = self::get_plugins();
+ $plugin_dirnames = self::get_plugin_dirnames();
+
+ // Build output lines.
+ $circular_dependency_lines = '';
+ foreach ( $circular_dependencies as $circular_dependency ) {
+ $first_filepath = $plugin_dirnames[ $circular_dependency[0] ];
+ $second_filepath = $plugin_dirnames[ $circular_dependency[1] ];
+ $circular_dependency_lines .= sprintf(
+ /* translators: 1: First plugin name, 2: Second plugin name. */
+ '' . _x( '%1$s requires %2$s', 'The first plugin requires the second plugin.' ) . ' ',
+ '' . esc_html( $plugins[ $first_filepath ]['Name'] ) . ' ',
+ '' . esc_html( $plugins[ $second_filepath ]['Name'] ) . ' '
+ );
+ }
+
+ wp_admin_notice(
+ sprintf(
+ '%1$s
%3$s
',
+ __( 'These plugins cannot be activated because their requirements are invalid. ' ),
+ $circular_dependency_lines,
+ __( 'Please contact the plugin authors for more information.' )
+ ),
+ array(
+ 'type' => 'warning',
+ 'paragraph_wrap' => false,
+ )
+ );
+ }
+ }
+
+ /**
+ * Checks plugin dependencies after a plugin is installed via AJAX.
+ *
+ * @since 6.5.0
+ */
+ public static function check_plugin_dependencies_during_ajax() {
+ check_ajax_referer( 'updates' );
+
+ if ( empty( $_POST['slug'] ) ) {
+ wp_send_json_error(
+ array(
+ 'slug' => '',
+ 'pluginName' => '',
+ 'errorCode' => 'no_plugin_specified',
+ 'errorMessage' => __( 'No plugin specified.' ),
+ )
+ );
+ }
+
+ $slug = sanitize_key( wp_unslash( $_POST['slug'] ) );
+ $status = array( 'slug' => $slug );
+
+ self::get_plugins();
+ self::get_plugin_dirnames();
+
+ if ( ! isset( self::$plugin_dirnames[ $slug ] ) ) {
+ $status['errorCode'] = 'plugin_not_installed';
+ $status['errorMessage'] = __( 'The plugin is not installed.' );
+ wp_send_json_error( $status );
+ }
+
+ $plugin_file = self::$plugin_dirnames[ $slug ];
+ $status['pluginName'] = self::$plugins[ $plugin_file ]['Name'];
+ $status['plugin'] = $plugin_file;
+
+ if ( current_user_can( 'activate_plugin', $plugin_file ) && is_plugin_inactive( $plugin_file ) ) {
+ $status['activateUrl'] = add_query_arg(
+ array(
+ '_wpnonce' => wp_create_nonce( 'activate-plugin_' . $plugin_file ),
+ 'action' => 'activate',
+ 'plugin' => $plugin_file,
+ ),
+ is_multisite() ? network_admin_url( 'plugins.php' ) : admin_url( 'plugins.php' )
+ );
+ }
+
+ if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) {
+ $status['activateUrl'] = add_query_arg( array( 'networkwide' => 1 ), $status['activateUrl'] );
+ }
+
+ $dependencies = self::get_dependencies( $plugin_file );
+ if ( empty( $dependencies ) ) {
+ $status['message'] = __( 'The plugin has no required plugins.' );
+ wp_send_json_success( $status );
+ }
+
+ require_once ABSPATH . '/wp-admin/includes/plugin.php';
+
+ $inactive_dependencies = array();
+ foreach ( $dependencies as $dependency ) {
+ if ( false === self::$plugin_dirnames[ $dependency ] || is_plugin_inactive( self::$plugin_dirnames[ $dependency ] ) ) {
+ $inactive_dependencies[] = $dependency;
+ }
+ }
+
+ if ( ! empty( $inactive_dependencies ) ) {
+ $inactive_dependency_names = array_map(
+ function ( $dependency ) {
+ if ( isset( self::$dependency_api_data[ $dependency ]['Name'] ) ) {
+ $inactive_dependency_name = self::$dependency_api_data[ $dependency ]['Name'];
+ } else {
+ $inactive_dependency_name = $dependency;
+ }
+ return $inactive_dependency_name;
+ },
+ $inactive_dependencies
+ );
+
+ $status['errorCode'] = 'inactive_dependencies';
+ $status['errorMessage'] = sprintf(
+ /* translators: %s: A list of inactive dependency plugin names. */
+ __( 'The following plugins must be activated first: %s.' ),
+ implode( ', ', $inactive_dependency_names )
+ );
+ $status['errorData'] = array_combine( $inactive_dependencies, $inactive_dependency_names );
+
+ wp_send_json_error( $status );
+ }
+
+ $status['message'] = __( 'All required plugins are installed and activated.' );
+ wp_send_json_success( $status );
+ }
+
+ /**
+ * Gets data for installed plugins.
+ *
+ * @since 6.5.0
+ *
+ * @return array An array of plugin data.
+ */
+ protected static function get_plugins() {
+ if ( is_array( self::$plugins ) ) {
+ return self::$plugins;
+ }
+
+ $all_plugin_data = get_option( 'plugin_data', array() );
+
+ if ( empty( $all_plugin_data ) ) {
+ require_once ABSPATH . '/wp-admin/includes/plugin.php';
+ $all_plugin_data = get_plugins();
+ }
+
+ self::$plugins = $all_plugin_data;
+
+ return self::$plugins;
+ }
+
+ /**
+ * Reads and stores dependency slugs from a plugin's 'Requires Plugins' header.
+ *
+ * @since 6.5.0
+ *
+ * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
+ */
+ protected static function read_dependencies_from_plugin_headers() {
+ self::$dependencies = array();
+ self::$dependency_slugs = array();
+ self::$dependent_slugs = array();
+ $plugins = self::get_plugins();
+ foreach ( $plugins as $plugin => $header ) {
+ if ( '' === $header['RequiresPlugins'] ) {
+ continue;
+ }
+
+ $dependency_slugs = self::sanitize_dependency_slugs( $header['RequiresPlugins'] );
+ self::$dependencies[ $plugin ] = $dependency_slugs;
+ self::$dependency_slugs = array_merge( self::$dependency_slugs, $dependency_slugs );
+
+ $dependent_slug = self::convert_to_slug( $plugin );
+ self::$dependent_slugs[ $plugin ] = $dependent_slug;
+ }
+ self::$dependency_slugs = array_unique( self::$dependency_slugs );
+ }
+
+ /**
+ * Sanitizes slugs.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slugs A comma-separated string of plugin dependency slugs.
+ * @return array An array of sanitized plugin dependency slugs.
+ */
+ protected static function sanitize_dependency_slugs( $slugs ) {
+ $sanitized_slugs = array();
+ $slugs = explode( ',', $slugs );
+
+ foreach ( $slugs as $slug ) {
+ $slug = trim( $slug );
+
+ /**
+ * Filters a plugin dependency's slug before matching to
+ * the WordPress.org slug format.
+ *
+ * Can be used to switch between free and premium plugin slugs, for example.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slug The slug.
+ */
+ $slug = apply_filters( 'wp_plugin_dependencies_slug', $slug );
+
+ // Match to WordPress.org slug format.
+ if ( preg_match( '/^[a-z0-9]+(-[a-z0-9]+)*$/mu', $slug ) ) {
+ $sanitized_slugs[] = $slug;
+ }
+ }
+ $sanitized_slugs = array_unique( $sanitized_slugs );
+ sort( $sanitized_slugs );
+
+ return $sanitized_slugs;
+ }
+
+ /**
+ * Gets plugin filepaths for active plugins that depend on the dependency.
+ *
+ * Recurses for each dependent that is also a dependency.
+ *
+ * @param string $plugin_file The dependency's filepath, relative to the plugin directory.
+ * @return string[] An array of active dependent plugin filepaths, relative to the plugin directory.
+ */
+ protected static function get_active_dependents_in_dependency_tree( $plugin_file ) {
+ $all_dependents = array();
+ $dependents = self::get_dependents( self::convert_to_slug( $plugin_file ) );
+
+ if ( empty( $dependents ) ) {
+ return $all_dependents;
+ }
+
+ require_once ABSPATH . '/wp-admin/includes/plugin.php';
+ foreach ( $dependents as $dependent ) {
+ if ( is_plugin_active( $dependent ) ) {
+ $all_dependents[] = $dependent;
+ $all_dependents = array_merge(
+ $all_dependents,
+ self::get_active_dependents_in_dependency_tree( $dependent )
+ );
+ }
+ }
+
+ return $all_dependents;
+ }
+
+ /**
+ * Deactivates dependent plugins with unmet dependencies.
+ *
+ * @since 6.5.0
+ */
+ protected static function deactivate_dependents_with_unmet_dependencies() {
+ $dependents_to_deactivate = array();
+ $circular_dependencies = array_reduce(
+ self::get_circular_dependencies(),
+ function ( $all_circular, $circular_pair ) {
+ return array_merge( $all_circular, $circular_pair );
+ },
+ array()
+ );
+
+ require_once ABSPATH . '/wp-admin/includes/plugin.php';
+ foreach ( self::$dependencies as $dependent => $dependencies ) {
+ // Skip dependents that are no longer installed or aren't active.
+ if ( ! array_key_exists( $dependent, self::$plugins ) || is_plugin_inactive( $dependent ) ) {
+ continue;
+ }
+
+ // Skip plugins within a circular dependency tree or plugins that have no unmet dependencies.
+ if ( in_array( $dependent, $circular_dependencies, true ) || ! self::has_unmet_dependencies( $dependent ) ) {
+ continue;
+ }
+
+ $dependents_to_deactivate[] = $dependent;
+
+ // Also add any plugins that rely on any of this plugin's dependents.
+ $dependents_to_deactivate = array_merge(
+ $dependents_to_deactivate,
+ self::get_active_dependents_in_dependency_tree( $dependent )
+ );
+ }
+
+ $dependents_to_deactivate = array_unique( $dependents_to_deactivate );
+
+ deactivate_plugins( $dependents_to_deactivate );
+ set_site_transient( 'wp_plugin_dependencies_deactivated_plugins', $dependents_to_deactivate, 10 );
+ }
+
+ /**
+ * Gets the filepath of installed dependencies.
+ * If a dependency is not installed, the filepath defaults to false.
+ *
+ * @since 6.5.0
+ *
+ * @return array An array of install dependencies filepaths, relative to the plugins directory.
+ */
+ protected static function get_dependency_filepaths() {
+ if ( is_array( self::$dependency_filepaths ) ) {
+ return self::$dependency_filepaths;
+ }
+
+ self::$dependency_filepaths = array();
+
+ $plugin_dirnames = self::get_plugin_dirnames();
+ foreach ( self::$dependency_slugs as $slug ) {
+ if ( isset( $plugin_dirnames[ $slug ] ) ) {
+ self::$dependency_filepaths[ $slug ] = $plugin_dirnames[ $slug ];
+ continue;
+ }
+
+ self::$dependency_filepaths[ $slug ] = false;
+ }
+
+ return self::$dependency_filepaths;
+ }
+
+ /**
+ * Retrieves and stores dependency plugin data from the WordPress.org Plugin API.
+ *
+ * @since 6.5.0
+ *
+ * @global string $pagenow The filename of the current screen.
+ *
+ * @return array|void An array of dependency API data, or void on early exit.
+ */
+ protected static function get_dependency_api_data() {
+ global $pagenow;
+
+ if ( ! is_admin() || ( 'plugins.php' !== $pagenow && 'plugin-install.php' !== $pagenow ) ) {
+ return;
+ }
+
+ if ( is_array( self::$dependency_api_data ) ) {
+ return self::$dependency_api_data;
+ }
+
+ $plugins = self::get_plugins();
+ self::$dependency_api_data = (array) get_site_transient( 'wp_plugin_dependencies_plugin_data' );
+ foreach ( self::$dependency_slugs as $slug ) {
+ // Set transient for individual data, remove from self::$dependency_api_data if transient expired.
+ if ( ! get_site_transient( "wp_plugin_dependencies_plugin_timeout_{$slug}" ) ) {
+ unset( self::$dependency_api_data[ $slug ] );
+ set_site_transient( "wp_plugin_dependencies_plugin_timeout_{$slug}", true, 12 * HOUR_IN_SECONDS );
+ }
+
+ if ( isset( self::$dependency_api_data[ $slug ] ) ) {
+ if ( false === self::$dependency_api_data[ $slug ] ) {
+ $dependency_file = self::get_dependency_filepath( $slug );
+
+ if ( false === $dependency_file ) {
+ self::$dependency_api_data[ $slug ] = array( 'Name' => $slug );
+ } else {
+ self::$dependency_api_data[ $slug ] = array( 'Name' => $plugins[ $dependency_file ]['Name'] );
+ }
+ continue;
+ }
+
+ // Don't hit the Plugin API if data exists.
+ if ( ! empty( self::$dependency_api_data[ $slug ]['last_updated'] ) ) {
+ continue;
+ }
+ }
+
+ if ( ! function_exists( 'plugins_api' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
+ }
+
+ $information = plugins_api(
+ 'plugin_information',
+ array(
+ 'slug' => $slug,
+ 'fields' => array(
+ 'short_description' => true,
+ 'icons' => true,
+ ),
+ )
+ );
+
+ if ( is_wp_error( $information ) ) {
+ continue;
+ }
+
+ self::$dependency_api_data[ $slug ] = (array) $information;
+ // plugins_api() returns 'name' not 'Name'.
+ self::$dependency_api_data[ $information->slug ]['Name'] = self::$dependency_api_data[ $information->slug ]['name'];
+ set_site_transient( 'wp_plugin_dependencies_plugin_data', self::$dependency_api_data, 0 );
+ }
+
+ // Remove from self::$dependency_api_data if slug no longer a dependency.
+ $differences = array_diff( array_keys( self::$dependency_api_data ), self::$dependency_slugs );
+ foreach ( $differences as $difference ) {
+ unset( self::$dependency_api_data[ $difference ] );
+ }
+
+ ksort( self::$dependency_api_data );
+ // Remove empty elements.
+ self::$dependency_api_data = array_filter( self::$dependency_api_data );
+ set_site_transient( 'wp_plugin_dependencies_plugin_data', self::$dependency_api_data, 0 );
+
+ return self::$dependency_api_data;
+ }
+
+ /**
+ * Gets plugin directory names.
+ *
+ * @since 6.5.0
+ *
+ * @return array An array of plugin directory names.
+ */
+ protected static function get_plugin_dirnames() {
+ if ( is_array( self::$plugin_dirnames ) ) {
+ return self::$plugin_dirnames;
+ }
+
+ self::$plugin_dirnames = array();
+
+ $plugin_files = array_keys( self::get_plugins() );
+ foreach ( $plugin_files as $plugin_file ) {
+ $slug = self::convert_to_slug( $plugin_file );
+ self::$plugin_dirnames[ $slug ] = $plugin_file;
+ }
+
+ return self::$plugin_dirnames;
+ }
+
+ /**
+ * Gets circular dependency data.
+ *
+ * @since 6.5.0
+ *
+ * @return array[] An array of circular dependency pairings.
+ */
+ protected static function get_circular_dependencies() {
+ if ( is_array( self::$circular_dependencies_pairs ) ) {
+ return self::$circular_dependencies_pairs;
+ }
+
+ self::$circular_dependencies_slugs = array();
+
+ self::$circular_dependencies_pairs = array();
+ foreach ( self::$dependencies as $dependent => $dependencies ) {
+ /*
+ * $dependent is in 'a/a.php' format. Dependencies are stored as slugs, i.e. 'a'.
+ *
+ * Convert $dependent to slug format for checking.
+ */
+ $dependent_slug = self::convert_to_slug( $dependent );
+
+ self::$circular_dependencies_pairs = array_merge(
+ self::$circular_dependencies_pairs,
+ self::check_for_circular_dependencies( array( $dependent_slug ), $dependencies )
+ );
+ }
+
+ return self::$circular_dependencies_pairs;
+ }
+
+ /**
+ * Checks for circular dependencies.
+ *
+ * @since 6.5.0
+ *
+ * @param array $dependents Array of dependent plugins.
+ * @param array $dependencies Array of plugins dependencies.
+ * @return array A circular dependency pairing, or an empty array if none exists.
+ */
+ protected static function check_for_circular_dependencies( $dependents, $dependencies ) {
+ $circular_dependencies_pairs = array();
+
+ // Check for a self-dependency.
+ $dependents_location_in_its_own_dependencies = array_intersect( $dependents, $dependencies );
+ if ( ! empty( $dependents_location_in_its_own_dependencies ) ) {
+ foreach ( $dependents_location_in_its_own_dependencies as $self_dependency ) {
+ self::$circular_dependencies_slugs[] = $self_dependency;
+ $circular_dependencies_pairs[] = array( $self_dependency, $self_dependency );
+
+ // No need to check for itself again.
+ unset( $dependencies[ array_search( $self_dependency, $dependencies, true ) ] );
+ }
+ }
+
+ /*
+ * Check each dependency to see:
+ * 1. If it has dependencies.
+ * 2. If its list of dependencies includes one of its own dependents.
+ */
+ foreach ( $dependencies as $dependency ) {
+ // Check if the dependency is also a dependent.
+ $dependency_location_in_dependents = array_search( $dependency, self::$dependent_slugs, true );
+
+ if ( false !== $dependency_location_in_dependents ) {
+ $dependencies_of_the_dependency = self::$dependencies[ $dependency_location_in_dependents ];
+
+ foreach ( $dependents as $dependent ) {
+ // Check if its dependencies includes one of its own dependents.
+ $dependent_location_in_dependency_dependencies = array_search(
+ $dependent,
+ $dependencies_of_the_dependency,
+ true
+ );
+
+ if ( false !== $dependent_location_in_dependency_dependencies ) {
+ self::$circular_dependencies_slugs[] = $dependent;
+ self::$circular_dependencies_slugs[] = $dependency;
+ $circular_dependencies_pairs[] = array( $dependent, $dependency );
+
+ // Remove the dependent from its dependency's dependencies.
+ unset( $dependencies_of_the_dependency[ $dependent_location_in_dependency_dependencies ] );
+ }
+ }
+
+ $dependents[] = $dependency;
+
+ /*
+ * Now check the dependencies of the dependency's dependencies for the dependent.
+ *
+ * Yes, that does make sense.
+ */
+ $circular_dependencies_pairs = array_merge(
+ $circular_dependencies_pairs,
+ self::check_for_circular_dependencies( $dependents, array_unique( $dependencies_of_the_dependency ) )
+ );
+ }
+ }
+
+ return $circular_dependencies_pairs;
+ }
+
+ /**
+ * Converts a plugin filepath to a slug.
+ *
+ * @since 6.5.0
+ *
+ * @param string $plugin_file The plugin's filepath, relative to the plugins directory.
+ * @return string The plugin's slug.
+ */
+ protected static function convert_to_slug( $plugin_file ) {
+ if ( 'hello.php' === $plugin_file ) {
+ return 'hello-dolly';
+ }
+ return str_contains( $plugin_file, '/' ) ? dirname( $plugin_file ) : str_replace( '.php', '', $plugin_file );
+ }
+}
diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php
index e6a3e6b743450..f683a52bd1080 100644
--- a/src/wp-includes/class-wp-query.php
+++ b/src/wp-includes/class-wp-query.php
@@ -1027,7 +1027,7 @@ public function parse_query( $query = '' ) {
}
if ( ! ( $this->is_singular || $this->is_archive || $this->is_search || $this->is_feed
- || ( defined( 'REST_REQUEST' ) && REST_REQUEST && $this->is_main_query() )
+ || ( wp_is_serving_rest_request() && $this->is_main_query() )
|| $this->is_trackback || $this->is_404 || $this->is_admin || $this->is_robots || $this->is_favicon ) ) {
$this->is_home = true;
}
diff --git a/src/wp-includes/class-wp-script-modules.php b/src/wp-includes/class-wp-script-modules.php
index d097785a7d244..b2413d0f2442e 100644
--- a/src/wp-includes/class-wp-script-modules.php
+++ b/src/wp-includes/class-wp-script-modules.php
@@ -1,6 +1,6 @@
*/
private $enqueued_before_registered = array();
/**
- * Registers the module if no module with that module identifier has already
- * been registered.
+ * Registers the script module if no script module with that script module
+ * identifier has already been registered.
*
* @since 6.5.0
*
- * @param string $module_id The identifier of the module.
- * Should be unique. It will be used
- * in the final import map.
- * @param string $src Full URL of the module, or path of
- * the module relative to the
- * WordPress root directory.
- * @param array $deps Optional. An array of module
- * identifiers of the dependencies of
- * this module. The dependencies can
- * be strings or arrays. If they are
- * arrays, they need an `id` key with
- * the module identifier, and can
- * contain an `import` key with either
- * `static` or `dynamic`. By default,
- * dependencies that don't contain an
- * `import` key are considered static.
- * @param string|false|null $version Optional. String specifying the
- * module version number. Defaults to
- * false. It is added to the URL as a
- * query string for cache busting
- * purposes. If $version is set to
- * false, the version number is the
- * currently installed WordPress
- * version. If $version is set to
- * null, no version is added.
+ * @param string $id The identifier of the script module. Should be unique. It will be used in the
+ * final import map.
+ * @param string $src Optional. Full URL of the script module, or path of the script module relative
+ * to the WordPress root directory. If it is provided and the script module has
+ * not been registered yet, it will be registered.
+ * @param array $deps {
+ * Optional. List of dependencies.
+ *
+ * @type string|array $0... {
+ * An array of script module identifiers of the dependencies of this script
+ * module. The dependencies can be strings or arrays. If they are arrays,
+ * they need an `id` key with the script module identifier, and can contain
+ * an `import` key with either `static` or `dynamic`. By default,
+ * dependencies that don't contain an `import` key are considered static.
+ *
+ * @type string $id The script module identifier.
+ * @type string $import Optional. Import type. May be either `static` or
+ * `dynamic`. Defaults to `static`.
+ * }
+ * }
+ * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false.
+ * It is added to the URL as a query string for cache busting purposes. If $version
+ * is set to false, the version number is the currently installed WordPress version.
+ * If $version is set to null, no version is added.
*/
- public function register( $module_id, $src, $deps = array(), $version = false ) {
- if ( ! isset( $this->registered[ $module_id ] ) ) {
+ public function register( string $id, string $src, array $deps = array(), $version = false ) {
+ if ( ! isset( $this->registered[ $id ] ) ) {
$dependencies = array();
foreach ( $deps as $dependency ) {
if ( is_array( $dependency ) ) {
@@ -85,155 +84,124 @@ public function register( $module_id, $src, $deps = array(), $version = false )
}
}
- $this->registered[ $module_id ] = array(
+ $this->registered[ $id ] = array(
'src' => $src,
'version' => $version,
- 'enqueue' => isset( $this->enqueued_before_registered[ $module_id ] ),
+ 'enqueue' => isset( $this->enqueued_before_registered[ $id ] ),
'dependencies' => $dependencies,
- 'enqueued' => false,
- 'preloaded' => false,
);
}
}
/**
- * Marks the module to be enqueued in the page the next time
- * `prints_enqueued_modules` is called.
+ * Marks the script module to be enqueued in the page.
*
- * If a src is provided and the module has not been registered yet, it will be
- * registered.
+ * If a src is provided and the script module has not been registered yet, it
+ * will be registered.
*
* @since 6.5.0
*
- * @param string $module_id The identifier of the module.
- * Should be unique. It will be used
- * in the final import map.
- * @param string $src Optional. Full URL of the module,
- * or path of the module relative to
- * the WordPress root directory. If
- * it is provided and the module has
- * not been registered yet, it will be
- * registered.
- * @param array $deps Optional. An array of module
- * identifiers of the dependencies of
- * this module. The dependencies can
- * be strings or arrays. If they are
- * arrays, they need an `id` key with
- * the module identifier, and can
- * contain an `import` key with either
- * `static` or `dynamic`. By default,
- * dependencies that don't contain an
- * `import` key are considered static.
- * @param string|false|null $version Optional. String specifying the
- * module version number. Defaults to
- * false. It is added to the URL as a
- * query string for cache busting
- * purposes. If $version is set to
- * false, the version number is the
- * currently installed WordPress
- * version. If $version is set to
- * null, no version is added.
+ * @param string $id The identifier of the script module. Should be unique. It will be used in the
+ * final import map.
+ * @param string $src Optional. Full URL of the script module, or path of the script module relative
+ * to the WordPress root directory. If it is provided and the script module has
+ * not been registered yet, it will be registered.
+ * @param array $deps {
+ * Optional. List of dependencies.
+ *
+ * @type string|array $0... {
+ * An array of script module identifiers of the dependencies of this script
+ * module. The dependencies can be strings or arrays. If they are arrays,
+ * they need an `id` key with the script module identifier, and can contain
+ * an `import` key with either `static` or `dynamic`. By default,
+ * dependencies that don't contain an `import` key are considered static.
+ *
+ * @type string $id The script module identifier.
+ * @type string $import Optional. Import type. May be either `static` or
+ * `dynamic`. Defaults to `static`.
+ * }
+ * }
+ * @param string|false|null $version Optional. String specifying the script module version number. Defaults to false.
+ * It is added to the URL as a query string for cache busting purposes. If $version
+ * is set to false, the version number is the currently installed WordPress version.
+ * If $version is set to null, no version is added.
*/
- public function enqueue( $module_id, $src = '', $deps = array(), $version = false ) {
- if ( isset( $this->registered[ $module_id ] ) ) {
- $this->registered[ $module_id ]['enqueue'] = true;
+ public function enqueue( string $id, string $src = '', array $deps = array(), $version = false ) {
+ if ( isset( $this->registered[ $id ] ) ) {
+ $this->registered[ $id ]['enqueue'] = true;
} elseif ( $src ) {
- $this->register( $module_id, $src, $deps, $version );
- $this->registered[ $module_id ]['enqueue'] = true;
+ $this->register( $id, $src, $deps, $version );
+ $this->registered[ $id ]['enqueue'] = true;
} else {
- $this->enqueued_before_registered[ $module_id ] = true;
+ $this->enqueued_before_registered[ $id ] = true;
}
}
/**
- * Unmarks the module so it will no longer be enqueued in the page.
+ * Unmarks the script module so it will no longer be enqueued in the page.
*
* @since 6.5.0
*
- * @param string $module_id The identifier of the module.
+ * @param string $id The identifier of the script module.
*/
- public function dequeue( $module_id ) {
- if ( isset( $this->registered[ $module_id ] ) ) {
- $this->registered[ $module_id ]['enqueue'] = false;
+ public function dequeue( string $id ) {
+ if ( isset( $this->registered[ $id ] ) ) {
+ $this->registered[ $id ]['enqueue'] = false;
}
- unset( $this->enqueued_before_registered[ $module_id ] );
+ unset( $this->enqueued_before_registered[ $id ] );
}
/**
- * Adds the hooks to print the import map, enqueued modules and module
- * preloads.
- *
- * It adds the actions to print the enqueued modules and module preloads to
- * both `wp_head` and `wp_footer` because in classic themes, the modules
- * used by the theme and plugins will likely be able to be printed in the
- * `head`, but the ones used by the blocks will need to be enqueued in the
- * `footer`.
+ * Adds the hooks to print the import map, enqueued script modules and script
+ * module preloads.
*
- * As all modules are deferred and dependencies are handled by the browser,
- * the order of the modules is not important, but it's still better to print
- * the ones that are available when the `wp_head` is rendered, so the browser
- * starts downloading those as soon as possible.
- *
- * The import map is also printed in the footer to be able to include the
- * dependencies of all the modules, including the ones printed in the footer.
+ * In classic themes, the script modules used by the blocks are not yet known
+ * when the `wp_head` actions is fired, so it needs to print everything in the
+ * footer.
*
* @since 6.5.0
*/
public function add_hooks() {
- add_action( 'wp_head', array( $this, 'print_enqueued_modules' ) );
- add_action( 'wp_head', array( $this, 'print_module_preloads' ) );
- add_action( 'wp_footer', array( $this, 'print_enqueued_modules' ) );
- add_action( 'wp_footer', array( $this, 'print_module_preloads' ) );
- add_action( 'wp_footer', array( $this, 'print_import_map' ) );
+ $position = wp_is_block_theme() ? 'wp_head' : 'wp_footer';
+ add_action( $position, array( $this, 'print_import_map' ) );
+ add_action( $position, array( $this, 'print_enqueued_script_modules' ) );
+ add_action( $position, array( $this, 'print_script_module_preloads' ) );
}
/**
- * Prints the enqueued modules using script tags with type="module"
+ * Prints the enqueued script modules using script tags with type="module"
* attributes.
*
- * If a enqueued module has already been printed, it will not be printed again
- * on subsequent calls to this function.
- *
* @since 6.5.0
*/
- public function print_enqueued_modules() {
- foreach ( $this->get_marked_for_enqueue() as $module_id => $module ) {
- if ( false === $module['enqueued'] ) {
- // Mark it as enqueued so it doesn't get enqueued again.
- $this->registered[ $module_id ]['enqueued'] = true;
-
- wp_print_script_tag(
- array(
- 'type' => 'module',
- 'src' => $this->get_versioned_src( $module ),
- 'id' => $module_id . '-js-module',
- )
- );
- }
+ public function print_enqueued_script_modules() {
+ foreach ( $this->get_marked_for_enqueue() as $id => $script_module ) {
+ wp_print_script_tag(
+ array(
+ 'type' => 'module',
+ 'src' => $this->get_versioned_src( $script_module ),
+ 'id' => $id . '-js-module',
+ )
+ );
}
}
/**
- * Prints the the static dependencies of the enqueued modules using link tags
- * with rel="modulepreload" attributes.
+ * Prints the the static dependencies of the enqueued script modules using
+ * link tags with rel="modulepreload" attributes.
*
- * If a module is marked for enqueue, it will not be preloaded. If a preloaded
- * module has already been printed, it will not be printed again on subsequent
- * calls to this function.
+ * If a script module is marked for enqueue, it will not be preloaded.
*
* @since 6.5.0
*/
- public function print_module_preloads() {
- foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ), array( 'static' ) ) as $module_id => $module ) {
- // Don't preload if it's marked for enqueue or has already been preloaded.
- if ( true !== $module['enqueue'] && false === $module['preloaded'] ) {
- // Mark it as preloaded so it doesn't get preloaded again.
- $this->registered[ $module_id ]['preloaded'] = true;
-
+ public function print_script_module_preloads() {
+ foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ), array( 'static' ) ) as $id => $script_module ) {
+ // Don't preload if it's marked for enqueue.
+ if ( true !== $script_module['enqueue'] ) {
echo sprintf(
' ',
- esc_url( $this->get_versioned_src( $module ) ),
- esc_attr( $module_id . '-js-modulepreload' )
+ esc_url( $this->get_versioned_src( $script_module ) ),
+ esc_attr( $id . '-js-modulepreload' )
);
}
}
@@ -243,10 +211,26 @@ public function print_module_preloads() {
* Prints the import map using a script tag with a type="importmap" attribute.
*
* @since 6.5.0
+ *
+ * @global WP_Scripts $wp_scripts The WP_Scripts object for printing the polyfill.
*/
public function print_import_map() {
$import_map = $this->get_import_map();
if ( ! empty( $import_map['imports'] ) ) {
+ global $wp_scripts;
+ if ( isset( $wp_scripts ) ) {
+ wp_print_inline_script_tag(
+ wp_get_script_polyfill(
+ $wp_scripts,
+ array(
+ 'HTMLScriptElement.supports && HTMLScriptElement.supports("importmap")' => 'wp-polyfill-importmap',
+ )
+ ),
+ array(
+ 'id' => 'wp-load-polyfill-importmap',
+ )
+ );
+ }
wp_print_inline_script_tag(
wp_json_encode( $import_map, JSON_HEX_TAG | JSON_HEX_AMP ),
array(
@@ -262,37 +246,37 @@ public function print_import_map() {
*
* @since 6.5.0
*
- * @return array Array with an `imports` key mapping to an array of module identifiers and their respective URLs,
- * including the version query.
+ * @return array Array with an `imports` key mapping to an array of script module identifiers and their respective
+ * URLs, including the version query.
*/
- private function get_import_map() {
+ private function get_import_map(): array {
$imports = array();
- foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ) ) as $module_id => $module ) {
- $imports[ $module_id ] = $this->get_versioned_src( $module );
+ foreach ( $this->get_dependencies( array_keys( $this->get_marked_for_enqueue() ) ) as $id => $script_module ) {
+ $imports[ $id ] = $this->get_versioned_src( $script_module );
}
return array( 'imports' => $imports );
}
/**
- * Retrieves the list of modules marked for enqueue.
+ * Retrieves the list of script modules marked for enqueue.
*
* @since 6.5.0
*
- * @return array Modules marked for enqueue, keyed by module identifier.
+ * @return array Script modules marked for enqueue, keyed by script module identifier.
*/
- private function get_marked_for_enqueue() {
+ private function get_marked_for_enqueue(): array {
$enqueued = array();
- foreach ( $this->registered as $module_id => $module ) {
- if ( true === $module['enqueue'] ) {
- $enqueued[ $module_id ] = $module;
+ foreach ( $this->registered as $id => $script_module ) {
+ if ( true === $script_module['enqueue'] ) {
+ $enqueued[ $id ] = $script_module;
}
}
return $enqueued;
}
/**
- * Retrieves all the dependencies for the given module identifiers, filtered
- * by import types.
+ * Retrieves all the dependencies for the given script module identifiers,
+ * filtered by import types.
*
* It will consolidate an array containing a set of unique dependencies based
* on the requested import types: 'static', 'dynamic', or both. This method is
@@ -300,33 +284,34 @@ private function get_marked_for_enqueue() {
*
* @since 6.5.0
*
- * @param array $module_ids The identifiers of the modules for which to gather dependencies.
- * @param array $import_types Optional. Import types of dependencies to retrieve: 'static', 'dynamic', or both.
- * Default is both.
- * @return array List of dependencies, keyed by module identifier.
+
+ * @param string[] $ids The identifiers of the script modules for which to gather dependencies.
+ * @param array $import_types Optional. Import types of dependencies to retrieve: 'static', 'dynamic', or both.
+ * Default is both.
+ * @return array List of dependencies, keyed by script module identifier.
*/
- private function get_dependencies( $module_ids, $import_types = array( 'static', 'dynamic' ) ) {
+ private function get_dependencies( array $ids, array $import_types = array( 'static', 'dynamic' ) ) {
return array_reduce(
- $module_ids,
- function ( $dependency_modules, $module_id ) use ( $import_types ) {
+ $ids,
+ function ( $dependency_script_modules, $id ) use ( $import_types ) {
$dependencies = array();
- foreach ( $this->registered[ $module_id ]['dependencies'] as $dependency ) {
+ foreach ( $this->registered[ $id ]['dependencies'] as $dependency ) {
if (
in_array( $dependency['import'], $import_types, true ) &&
isset( $this->registered[ $dependency['id'] ] ) &&
- ! isset( $dependency_modules[ $dependency['id'] ] )
+ ! isset( $dependency_script_modules[ $dependency['id'] ] )
) {
$dependencies[ $dependency['id'] ] = $this->registered[ $dependency['id'] ];
}
}
- return array_merge( $dependency_modules, $dependencies, $this->get_dependencies( array_keys( $dependencies ), $import_types ) );
+ return array_merge( $dependency_script_modules, $dependencies, $this->get_dependencies( array_keys( $dependencies ), $import_types ) );
},
array()
);
}
/**
- * Gets the versioned URL for a module src.
+ * Gets the versioned URL for a script module src.
*
* If $version is set to false, the version number is the currently installed
* WordPress version. If $version is set to null, no version is added.
@@ -334,19 +319,19 @@ function ( $dependency_modules, $module_id ) use ( $import_types ) {
*
* @since 6.5.0
*
- * @param array $module The module.
- * @return string The module src with a version if relevant.
+ * @param array $script_module The script module.
+ * @return string The script module src with a version if relevant.
*/
- private function get_versioned_src( array $module ) {
+ private function get_versioned_src( array $script_module ): string {
$args = array();
- if ( false === $module['version'] ) {
+ if ( false === $script_module['version'] ) {
$args['ver'] = get_bloginfo( 'version' );
- } elseif ( null !== $module['version'] ) {
- $args['ver'] = $module['version'];
+ } elseif ( null !== $script_module['version'] ) {
+ $args['ver'] = $script_module['version'];
}
if ( $args ) {
- return add_query_arg( $args, $module['src'] );
+ return add_query_arg( $args, $script_module['src'] );
}
- return $module['src'];
+ return $script_module['src'];
}
}
diff --git a/src/wp-includes/class-wp-scripts.php b/src/wp-includes/class-wp-scripts.php
index 116e98f673bca..7e4bd2732a85f 100644
--- a/src/wp-includes/class-wp-scripts.php
+++ b/src/wp-includes/class-wp-scripts.php
@@ -524,33 +524,6 @@ public function get_inline_script_data( $handle, $position = 'after' ) {
return trim( implode( "\n", $data ), "\n" );
}
- /**
- * Gets unaliased dependencies.
- *
- * An alias is a dependency whose src is false. It is used as a way to bundle multiple dependencies in a single
- * handle. This in effect flattens an alias dependency tree.
- *
- * @since 6.3.0
- *
- * @param string[] $deps Dependency handles.
- * @return string[] Unaliased handles.
- */
- private function get_unaliased_deps( array $deps ) {
- $flattened = array();
- foreach ( $deps as $dep ) {
- if ( ! isset( $this->registered[ $dep ] ) ) {
- continue;
- }
-
- if ( $this->registered[ $dep ]->src ) {
- $flattened[] = $dep;
- } elseif ( $this->registered[ $dep ]->deps ) {
- array_push( $flattened, ...$this->get_unaliased_deps( $this->registered[ $dep ]->deps ) );
- }
- }
- return $flattened;
- }
-
/**
* Gets tags for inline scripts registered for a specific handle.
*
diff --git a/src/wp-includes/class-wp-textdomain-registry.php b/src/wp-includes/class-wp-textdomain-registry.php
index 8ff8ad0ae23de..b2cbd72fa52bb 100644
--- a/src/wp-includes/class-wp-textdomain-registry.php
+++ b/src/wp-includes/class-wp-textdomain-registry.php
@@ -150,21 +150,21 @@ public function set_custom_path( $domain, $path ) {
}
/**
- * Retrieves .mo files from the specified path.
+ * Retrieves translation files from the specified path.
*
* Allows early retrieval through the {@see 'pre_get_mo_files_from_path'} filter to optimize
* performance, especially in directories with many files.
*
* @since 6.5.0
*
- * @param string $path The directory path to search for .mo files.
- * @return array Array of .mo file paths.
+ * @param string $path The directory path to search for translation files.
+ * @return array Array of translation file paths. Can contain .mo and .l10n.php files.
*/
public function get_language_files_from_path( $path ) {
$path = rtrim( $path, '/' ) . '/';
/**
- * Filters the .mo files retrieved from a specified path before the actual lookup.
+ * Filters the translation files retrieved from a specified path before the actual lookup.
*
* Returning a non-null value from the filter will effectively short-circuit
* the MO files lookup, returning that value instead.
@@ -174,27 +174,33 @@ public function get_language_files_from_path( $path ) {
*
* @since 6.5.0
*
- * @param null|array $mo_files List of .mo files. Default null.
- * @param string $path The path from which .mo files are being fetched.
+ * @param null|array $files List of translation files. Default null.
+ * @param string $path The path from which translation files are being fetched.
**/
- $mo_files = apply_filters( 'pre_get_language_files_from_path', null, $path );
+ $files = apply_filters( 'pre_get_language_files_from_path', null, $path );
- if ( null !== $mo_files ) {
- return $mo_files;
+ if ( null !== $files ) {
+ return $files;
}
$cache_key = 'cached_mo_files_' . md5( $path );
- $mo_files = wp_cache_get( $cache_key, 'translations' );
+ $files = wp_cache_get( $cache_key, 'translations' );
- if ( false === $mo_files ) {
- $mo_files = glob( $path . '*.mo' );
- if ( false === $mo_files ) {
- $mo_files = array();
+ if ( false === $files ) {
+ $files = glob( $path . '*.mo' );
+ if ( false === $files ) {
+ $files = array();
}
- wp_cache_set( $cache_key, $mo_files, 'translations' );
+
+ $php_files = glob( $path . '*.l10n.php' );
+ if ( is_array( $php_files ) ) {
+ $files = array_merge( $files, $php_files );
+ }
+
+ wp_cache_set( $cache_key, $files, 'translations' );
}
- return $mo_files;
+ return $files;
}
/**
@@ -225,10 +231,13 @@ public function get_language_files_from_path( $path ) {
* @type string $version The version of a theme, plugin, or core.
* }
* }
- * @return void
*/
public function invalidate_mo_files_cache( $upgrader, $hook_extra ) {
- if ( 'translation' !== $hook_extra['type'] || array() === $hook_extra['translations'] ) {
+ if (
+ ! isset( $hook_extra['type'] ) ||
+ 'translation' !== $hook_extra['type'] ||
+ array() === $hook_extra['translations']
+ ) {
return;
}
@@ -292,17 +301,18 @@ private function get_path_from_lang_dir( $domain, $locale ) {
foreach ( $locations as $location ) {
$files = $this->get_language_files_from_path( $location );
- $path = "$location/$domain-$locale.mo";
+ $mo_path = "$location/$domain-$locale.mo";
+ $php_path = "$location/$domain-$locale.l10n.php";
- foreach ( $files as $mo_path ) {
+ foreach ( $files as $file_path ) {
if (
! in_array( $domain, $this->domains_with_translations, true ) &&
- str_starts_with( str_replace( "$location/", '', $mo_path ), "$domain-" )
+ str_starts_with( str_replace( "$location/", '', $file_path ), "$domain-" )
) {
$this->domains_with_translations[] = $domain;
}
- if ( $mo_path === $path ) {
+ if ( $file_path === $mo_path || $file_path === $php_path ) {
$found_location = rtrim( $location, '/' ) . '/';
}
}
diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php
index 37f4d11ce9fb4..6fd954705e85e 100644
--- a/src/wp-includes/class-wp-theme-json.php
+++ b/src/wp-includes/class-wp-theme-json.php
@@ -204,10 +204,12 @@ class WP_Theme_JSON {
* @since 6.2.0 Added `outline-*`, and `min-height` properties.
* @since 6.3.0 Added `column-count` property.
* @since 6.4.0 Added `writing-mode` property.
+ * @since 6.5.0 Added `aspect-ratio` property.
*
* @var array
*/
const PROPERTIES_METADATA = array(
+ 'aspect-ratio' => array( 'dimensions', 'aspectRatio' ),
'background' => array( 'color', 'gradient' ),
'background-color' => array( 'color', 'background' ),
'border-radius' => array( 'border', 'radius' ),
@@ -344,8 +346,8 @@ class WP_Theme_JSON {
* @since 6.3.0 Added support for `typography.textColumns`, removed `layout.definitions`.
* @since 6.4.0 Added support for `layout.allowEditing`, `background.backgroundImage`,
* `typography.writingMode`, `lightbox.enabled` and `lightbox.allowEditing`.
- * @since 6.5.0 Added support for `layout.allowCustomContentAndWideSize` and
- * `background.backgroundSize`.
+ * @since 6.5.0 Added support for `layout.allowCustomContentAndWideSize`,
+ * `background.backgroundSize` and `dimensions.aspectRatio`.
* @var array
*/
const VALID_SETTINGS = array(
@@ -380,7 +382,8 @@ class WP_Theme_JSON {
),
'custom' => null,
'dimensions' => array(
- 'minHeight' => null,
+ 'aspectRatio' => null,
+ 'minHeight' => null,
),
'layout' => array(
'contentSize' => null,
@@ -426,6 +429,38 @@ class WP_Theme_JSON {
),
);
+ /*
+ * The valid properties for fontFamilies under settings key.
+ *
+ * @since 6.5.0
+ *
+ * @var array
+ */
+ const FONT_FAMILY_SCHEMA = array(
+ array(
+ 'fontFamily' => null,
+ 'name' => null,
+ 'slug' => null,
+ 'fontFace' => array(
+ array(
+ 'ascentOverride' => null,
+ 'descentOverride' => null,
+ 'fontDisplay' => null,
+ 'fontFamily' => null,
+ 'fontFeatureSettings' => null,
+ 'fontStyle' => null,
+ 'fontStretch' => null,
+ 'fontVariationSettings' => null,
+ 'fontWeight' => null,
+ 'lineGapOverride' => null,
+ 'sizeAdjust' => null,
+ 'src' => null,
+ 'unicodeRange' => null,
+ ),
+ ),
+ ),
+ );
+
/**
* The valid properties under the styles key.
*
@@ -438,6 +473,7 @@ class WP_Theme_JSON {
* updated `blockGap` to be allowed at any level.
* @since 6.2.0 Added `outline`, and `minHeight` properties.
* @since 6.3.0 Added support for `typography.textColumns`.
+ * @since 6.5.0 Added support for `dimensions.aspectRatio`.
*
* @var array
*/
@@ -458,7 +494,8 @@ class WP_Theme_JSON {
'text' => null,
),
'dimensions' => array(
- 'minHeight' => null,
+ 'aspectRatio' => null,
+ 'minHeight' => null,
),
'filter' => array(
'duotone' => null,
@@ -551,6 +588,52 @@ class WP_Theme_JSON {
'typography' => 'typography',
);
+ /**
+ * Return the input schema at the root and per origin.
+ *
+ * @since 6.5.0
+ *
+ * @param array $schema The base schema.
+ * @return array The schema at the root and per origin.
+ *
+ * Example:
+ * schema_in_root_and_per_origin(
+ * array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * )
+ * )
+ *
+ * Returns:
+ * array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * 'default' => array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * ),
+ * 'blocks' => array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * ),
+ * 'theme' => array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * ),
+ * 'custom' => array(
+ * 'fontFamily' => null,
+ * 'slug' => null,
+ * ),
+ * )
+ */
+ protected static function schema_in_root_and_per_origin( $schema ) {
+ $schema_in_root_and_per_origin = $schema;
+ foreach ( static::VALID_ORIGINS as $origin ) {
+ $schema_in_root_and_per_origin[ $origin ] = $schema;
+ }
+ return $schema_in_root_and_per_origin;
+ }
+
/**
* Returns a class name by an element name.
*
@@ -575,7 +658,7 @@ public static function get_element_class_name( $element ) {
* @since 6.0.0
* @since 6.2.0 Added `dimensions.minHeight` and `position.sticky`.
* @since 6.4.0 Added `background.backgroundImage`.
- * @since 6.5.0 Added `background.backgroundSize`.
+ * @since 6.5.0 Added `background.backgroundSize` and `dimensions.aspectRatio`.
* @var array
*/
const APPEARANCE_TOOLS_OPT_INS = array(
@@ -589,6 +672,7 @@ public static function get_element_class_name( $element ) {
array( 'color', 'heading' ),
array( 'color', 'button' ),
array( 'color', 'caption' ),
+ array( 'dimensions', 'aspectRatio' ),
array( 'dimensions', 'minHeight' ),
array( 'position', 'sticky' ),
array( 'spacing', 'blockGap' ),
@@ -791,11 +875,12 @@ protected static function sanitize( $input, $valid_block_names, $valid_element_n
$schema_styles_blocks[ $block ]['variations'] = $schema_styles_variations;
}
- $schema['styles'] = static::VALID_STYLES;
- $schema['styles']['blocks'] = $schema_styles_blocks;
- $schema['styles']['elements'] = $schema_styles_elements;
- $schema['settings'] = static::VALID_SETTINGS;
- $schema['settings']['blocks'] = $schema_settings_blocks;
+ $schema['styles'] = static::VALID_STYLES;
+ $schema['styles']['blocks'] = $schema_styles_blocks;
+ $schema['styles']['elements'] = $schema_styles_elements;
+ $schema['settings'] = static::VALID_SETTINGS;
+ $schema['settings']['blocks'] = $schema_settings_blocks;
+ $schema['settings']['typography']['fontFamilies'] = static::schema_in_root_and_per_origin( static::FONT_FAMILY_SCHEMA );
// Remove anything that's not present in the schema.
foreach ( array( 'styles', 'settings' ) as $subtree ) {
@@ -935,7 +1020,7 @@ protected static function get_blocks_metadata() {
if ( $duotone_support ) {
$root_selector = wp_get_block_css_selector( $block_type );
- $duotone_selector = WP_Theme_JSON::scope_selector( $root_selector, $duotone_support );
+ $duotone_selector = static::scope_selector( $root_selector, $duotone_support );
}
}
@@ -947,8 +1032,7 @@ protected static function get_blocks_metadata() {
if ( ! empty( $block_type->styles ) ) {
$style_selectors = array();
foreach ( $block_type->styles as $style ) {
- // The style variation classname is duplicated in the selector to ensure that it overrides core block styles.
- $style_selectors[ $style['name'] ] = static::append_to_selector( '.is-style-' . $style['name'] . '.is-style-' . $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
+ $style_selectors[ $style['name'] ] = static::get_block_style_variation_selector( $style['name'], static::$blocks_metadata[ $block_name ]['selector'] );
}
static::$blocks_metadata[ $block_name ]['styleVariations'] = $style_selectors;
}
@@ -969,18 +1053,39 @@ protected static function get_blocks_metadata() {
* @return array The modified $tree.
*/
protected static function remove_keys_not_in_schema( $tree, $schema ) {
- $tree = array_intersect_key( $tree, $schema );
+ if ( ! is_array( $tree ) ) {
+ return $tree;
+ }
- foreach ( $schema as $key => $data ) {
- if ( ! isset( $tree[ $key ] ) ) {
+ foreach ( $tree as $key => $value ) {
+ // Remove keys not in the schema or with null/empty values.
+ if ( ! array_key_exists( $key, $schema ) ) {
+ unset( $tree[ $key ] );
continue;
}
- if ( is_array( $schema[ $key ] ) && is_array( $tree[ $key ] ) ) {
- $tree[ $key ] = static::remove_keys_not_in_schema( $tree[ $key ], $schema[ $key ] );
+ // Check if the value is an array and requires further processing.
+ if ( is_array( $value ) && is_array( $schema[ $key ] ) ) {
+ // Determine if it is an associative or indexed array.
+ $schema_is_assoc = self::is_assoc( $value );
+
+ if ( $schema_is_assoc ) {
+ // If associative, process as a single object.
+ $tree[ $key ] = self::remove_keys_not_in_schema( $value, $schema[ $key ] );
- if ( empty( $tree[ $key ] ) ) {
- unset( $tree[ $key ] );
+ if ( empty( $tree[ $key ] ) ) {
+ unset( $tree[ $key ] );
+ }
+ } else {
+ // If indexed, process each item in the array.
+ foreach ( $value as $item_key => $item_value ) {
+ if ( isset( $schema[ $key ][0] ) && is_array( $schema[ $key ][0] ) ) {
+ $tree[ $key ][ $item_key ] = self::remove_keys_not_in_schema( $item_value, $schema[ $key ][0] );
+ } else {
+ // If the schema does not define a further structure, keep the value as is.
+ $tree[ $key ][ $item_key ] = $item_value;
+ }
+ }
}
} elseif ( is_array( $schema[ $key ] ) && ! is_array( $tree[ $key ] ) ) {
unset( $tree[ $key ] );
@@ -990,6 +1095,20 @@ protected static function remove_keys_not_in_schema( $tree, $schema ) {
return $tree;
}
+ /**
+ * Checks if the given array is associative.
+ *
+ * @since 6.5.0
+ * @param array $data The array to check.
+ * @return bool True if the array is associative, false otherwise.
+ */
+ protected static function is_assoc( $data ) {
+ if ( array() === $data ) {
+ return false;
+ }
+ return array_keys( $data ) !== range( 0, count( $data ) - 1 );
+ }
+
/**
* Returns the existing settings for each block.
*
@@ -1070,6 +1189,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets'
foreach ( $style_nodes as &$node ) {
$node['selector'] = static::scope_selector( $options['scope'], $node['selector'] );
}
+ unset( $node );
}
if ( ! empty( $options['root_selector'] ) ) {
@@ -1077,7 +1197,7 @@ public function get_stylesheet( $types = array( 'variables', 'styles', 'presets'
$setting_nodes[ $root_settings_key ]['selector'] = $options['root_selector'];
}
if ( false !== $root_style_key ) {
- $setting_nodes[ $root_style_key ]['selector'] = $options['root_selector'];
+ $style_nodes[ $root_style_key ]['selector'] = $options['root_selector'];
}
}
@@ -1921,6 +2041,7 @@ protected static function flatten_tree( $tree, $prefix = '', $token = '--' ) {
* @since 5.8.0
* @since 5.9.0 Added the `$settings` and `$properties` parameters.
* @since 6.1.0 Added `$theme_json`, `$selector`, and `$use_root_padding` parameters.
+ * @since 6.5.0 Output a `min-height: unset` rule when `aspect-ratio` is set.
*
* @param array $styles Styles to process.
* @param array $settings Theme settings.
@@ -1992,6 +2113,15 @@ protected static function compute_style_properties( $styles, $settings = array()
$value = wp_get_typography_font_size_value( array( 'size' => $value ) );
}
+ if ( 'aspect-ratio' === $css_property ) {
+ // For aspect ratio to work, other dimensions rules must be unset.
+ // This ensures that a fixed height does not override the aspect ratio.
+ $declarations[] = array(
+ 'name' => 'min-height',
+ 'value' => 'unset',
+ );
+ }
+
$declarations[] = array(
'name' => $css_property,
'value' => $value,
@@ -3795,4 +3925,38 @@ function ( $carry, $item ) {
$theme_json->theme_json['styles'] = self::convert_variables_to_value( $styles, $vars );
return $theme_json;
}
+
+ /**
+ * Generates a selector for a block style variation.
+ *
+ * @since 6.5.0
+ *
+ * @param string $variation_name Name of the block style variation.
+ * @param string $block_selector CSS selector for the block.
+ * @return string Block selector with block style variation selector added to it.
+ */
+ protected static function get_block_style_variation_selector( $variation_name, $block_selector ) {
+ $variation_class = ".is-style-$variation_name";
+
+ if ( ! $block_selector ) {
+ return $variation_class;
+ }
+
+ $limit = 1;
+ $selector_parts = explode( ',', $block_selector );
+ $result = array();
+
+ foreach ( $selector_parts as $part ) {
+ $result[] = preg_replace_callback(
+ '/((?::\([^)]+\))?\s*)([^\s:]+)/',
+ function ( $matches ) use ( $variation_class ) {
+ return $matches[1] . $matches[2] . $variation_class;
+ },
+ $part,
+ $limit
+ );
+ }
+
+ return implode( ',', $result );
+ }
}
diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php
index 09905bee1b93f..2058a9e557c46 100644
--- a/src/wp-includes/class-wp-theme.php
+++ b/src/wp-includes/class-wp-theme.php
@@ -1263,7 +1263,7 @@ public function get_screenshot( $uri = 'uri' ) {
return false;
}
- foreach ( array( 'png', 'gif', 'jpg', 'jpeg', 'webp' ) as $ext ) {
+ foreach ( array( 'png', 'gif', 'jpg', 'jpeg', 'webp', 'avif' ) as $ext ) {
if ( file_exists( $this->get_stylesheet_directory() . "/screenshot.$ext" ) ) {
$this->cache_add( 'screenshot', 'screenshot.' . $ext );
if ( 'relative' === $uri ) {
diff --git a/src/wp-includes/comment.php b/src/wp-includes/comment.php
index de23a72130e0f..37d36364ce3da 100644
--- a/src/wp-includes/comment.php
+++ b/src/wp-includes/comment.php
@@ -3174,10 +3174,10 @@ function privacy_ping_filter( $sites ) {
* @param string $trackback_url URL to send trackbacks.
* @param string $title Title of post.
* @param string $excerpt Excerpt of post.
- * @param int $ID Post ID.
+ * @param int $post_id Post ID.
* @return int|false|void Database query from update.
*/
-function trackback( $trackback_url, $title, $excerpt, $ID ) {
+function trackback( $trackback_url, $title, $excerpt, $post_id ) {
global $wpdb;
if ( empty( $trackback_url ) ) {
@@ -3188,7 +3188,7 @@ function trackback( $trackback_url, $title, $excerpt, $ID ) {
$options['timeout'] = 10;
$options['body'] = array(
'title' => $title,
- 'url' => get_permalink( $ID ),
+ 'url' => get_permalink( $post_id ),
'blog_name' => get_option( 'blogname' ),
'excerpt' => $excerpt,
);
@@ -3199,8 +3199,8 @@ function trackback( $trackback_url, $title, $excerpt, $ID ) {
return;
}
- $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET pinged = CONCAT(pinged, '\n', %s) WHERE ID = %d", $trackback_url, $ID ) );
- return $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $trackback_url, $ID ) );
+ $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET pinged = CONCAT(pinged, '\n', %s) WHERE ID = %d", $trackback_url, $post_id ) );
+ return $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET to_ping = TRIM(REPLACE(to_ping, %s, '')) WHERE ID = %d", $trackback_url, $post_id ) );
}
/**
diff --git a/src/wp-includes/compat.php b/src/wp-includes/compat.php
index 5bfdbc23d6d60..95c4af484d8ea 100644
--- a/src/wp-includes/compat.php
+++ b/src/wp-includes/compat.php
@@ -420,6 +420,38 @@ function array_key_last( array $array ) { // phpcs:ignore Universal.NamingConven
}
}
+if ( ! function_exists( 'array_is_list' ) ) {
+ /**
+ * Polyfill for `array_is_list()` function added in PHP 8.1.
+ *
+ * Determines if the given array is a list.
+ *
+ * An array is considered a list if its keys consist of consecutive numbers from 0 to count($array)-1.
+ *
+ * @see https://github.com/symfony/polyfill-php81/tree/main
+ *
+ * @since 6.5.0
+ *
+ * @param array $arr The array being evaluated.
+ * @return bool True if array is a list, false otherwise.
+ */
+ function array_is_list( $arr ) {
+ if ( ( array() === $arr ) || ( array_values( $arr ) === $arr ) ) {
+ return true;
+ }
+
+ $next_key = -1;
+
+ foreach ( $arr as $k => $v ) {
+ if ( ++$next_key !== $k ) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
if ( ! function_exists( 'str_contains' ) ) {
/**
* Polyfill for `str_contains()` function added in PHP 8.0.
@@ -497,3 +529,13 @@ function str_ends_with( $haystack, $needle ) {
if ( ! defined( 'IMG_WEBP' ) ) {
define( 'IMG_WEBP', IMAGETYPE_WEBP );
}
+
+// IMAGETYPE_AVIF constant is only defined in PHP 8.x or later.
+if ( ! defined( 'IMAGETYPE_AVIF' ) ) {
+ define( 'IMAGETYPE_AVIF', 19 );
+}
+
+// IMG_AVIF constant is only defined in PHP 8.x or later.
+if ( ! defined( 'IMG_AVIF' ) ) {
+ define( 'IMG_AVIF', IMAGETYPE_AVIF );
+}
diff --git a/src/wp-includes/css/buttons.css b/src/wp-includes/css/buttons.css
index 787efacab6953..5146be4274254 100644
--- a/src/wp-includes/css/buttons.css
+++ b/src/wp-includes/css/buttons.css
@@ -185,6 +185,11 @@ TABLE OF CONTENTS:
transform: none !important;
}
+.wp-core-ui .button[aria-disabled="true"],
+.wp-core-ui .button-secondary[aria-disabled="true"] {
+ cursor: default;
+}
+
/* Buttons that look like links, for a cross of good semantics with the visual */
.wp-core-ui .button-link {
margin: 0;
@@ -210,11 +215,9 @@ TABLE OF CONTENTS:
.wp-core-ui .button-link:focus {
color: #043959;
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
- outline: 1px solid transparent;
+ outline: 2px solid transparent;
}
.wp-core-ui .button-link-delete {
@@ -283,6 +286,10 @@ TABLE OF CONTENTS:
cursor: default;
}
+.wp-core-ui .button-primary[aria-disabled="true"] {
+ cursor: default;
+}
+
/* ----------------------------------------------------------------------------
4.0 - Button Groups
---------------------------------------------------------------------------- */
diff --git a/src/wp-includes/css/editor.css b/src/wp-includes/css/editor.css
index c445a32b43910..86952c7c9b213 100644
--- a/src/wp-includes/css/editor.css
+++ b/src/wp-includes/css/editor.css
@@ -87,8 +87,9 @@
.mce-window-head .mce-close:focus .mce-i-remove,
div.mce-tab:focus {
- box-shadow: 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.mce-window .mce-window-head .mce-dragh {
@@ -113,7 +114,9 @@ div.mce-tab:focus {
.mce-checkbox:focus i.mce-i-checkbox,
#wp-link .query-results:focus {
border-color: #4f94d4;
- box-shadow: 0 0 2px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.mce-window .mce-wp-help {
@@ -409,10 +412,10 @@ div.mce-path {
.qt-dfw:hover,
.qt-dfw:focus {
background: #f6f7f7;
- border-color: #50575e;
color: #1d2327;
- box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba(0, 0, 0, 0.08);
- outline: none;
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.mce-toolbar .mce-btn-group .mce-btn.mce-active,
@@ -420,7 +423,6 @@ div.mce-path {
.qt-dfw.active {
background: #f0f0f1;
border-color: #50575e;
- box-shadow: inset 0 2px 5px -3px rgba(0, 0, 0, 0.3);
}
.mce-btn.mce-active,
@@ -532,12 +534,13 @@ div.mce-path {
direction: ltr;
background: #fff;
border: 1px solid #dcdcde;
- box-shadow: inset 0 1px 1px -1px rgba(0, 0, 0, 0.2);
}
.mce-toolbar .mce-btn-group .mce-btn.mce-listbox:hover,
.mce-toolbar .mce-btn-group .mce-btn.mce-listbox:focus {
- border-color: #c3c4c7;
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
.mce-panel .mce-btn i.mce-caret {
@@ -635,9 +638,9 @@ div.mce-menubar {
.mce-menubar .mce-menubtn:focus {
color: #043959;
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
}
div.mce-menu .mce-menu-item-sep,
@@ -1131,10 +1134,9 @@ i.mce-i-wp_code:before {
}
.wp-switch-editor:focus {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
- outline: none;
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
color: #1d2327;
}
@@ -1445,10 +1447,7 @@ i.mce-i-wp_code:before {
}
#wp-link-close:focus {
- outline: none;
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
outline-offset: -2px;
@@ -1845,7 +1844,6 @@ html:lang(he-il) .rtl .quicktags-toolbar input {
/* HiDPI */
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
.wp-media-buttons .add_media span.wp-media-buttons-icon {
background: none;
diff --git a/src/wp-includes/css/jquery-ui-dialog.css b/src/wp-includes/css/jquery-ui-dialog.css
index e457b38ddd33e..528d368251889 100644
--- a/src/wp-includes/css/jquery-ui-dialog.css
+++ b/src/wp-includes/css/jquery-ui-dialog.css
@@ -312,9 +312,7 @@
}
.ui-button.ui-dialog-titlebar-close:focus {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
outline-offset: -2px;
diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css
index eaa9562fca27f..c681f6df78d77 100644
--- a/src/wp-includes/css/media-views.css
+++ b/src/wp-includes/css/media-views.css
@@ -45,12 +45,10 @@
}
.media-frame a:focus {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
color: #043959;
/* Only visible in Windows High Contrast mode */
- outline: 1px solid transparent;
+ outline: 2px solid transparent;
}
.media-frame a.button {
@@ -649,12 +647,10 @@
}
.media-menu .media-menu-item:focus {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
color: #043959;
/* Only visible in Windows High Contrast mode */
- outline: 1px solid transparent;
+ outline: 2px solid transparent;
}
.media-menu .separator {
@@ -704,12 +700,10 @@
}
.media-router .media-menu-item:focus {
- box-shadow:
- 0 0 0 1px #4f94d4,
- 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
color: #043959;
/* Only visible in Windows High Contrast mode */
- outline: 1px solid transparent;
+ outline: 2px solid transparent;
}
.media-router .active,
@@ -2017,8 +2011,8 @@
.wp-core-ui.media-modal .image-editor .imgedit-help-toggle:focus {
color: #2271b1;
- border-color: #4f94d4;
- box-shadow: 0 0 3px rgba(34, 113, 177, 0.8);
+ border-color: #2271b1;
+ box-shadow: 0 0 0 1px #2271b1;
/* Only visible in Windows High Contrast mode */
outline: 2px solid transparent;
}
@@ -2134,8 +2128,8 @@
}
.mejs-container:focus {
- outline: 1px solid #4f94d4;
- box-shadow: 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ outline: 1px solid #2271b1;
+ box-shadow: 0 0 0 2px #2271b1;
}
.image-details .media-modal {
@@ -2905,7 +2899,6 @@
* HiDPI Displays
*/
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
.wp-core-ui .media-modal-icon {
diff --git a/src/wp-includes/css/wp-auth-check.css b/src/wp-includes/css/wp-auth-check.css
index 8994f4933ab63..42f623e8e13ec 100644
--- a/src/wp-includes/css/wp-auth-check.css
+++ b/src/wp-includes/css/wp-auth-check.css
@@ -68,7 +68,6 @@
}
@media print,
- (-webkit-min-device-pixel-ratio: 1.25),
(min-resolution: 120dpi) {
#wp-auth-check-form.loading:before {
diff --git a/src/wp-includes/css/wp-embed-template.css b/src/wp-includes/css/wp-embed-template.css
index c1f1cc5c847b9..6b1ca43f0bc61 100644
--- a/src/wp-includes/css/wp-embed-template.css
+++ b/src/wp-includes/css/wp-embed-template.css
@@ -216,7 +216,9 @@ p.wp-embed-heading {
.wp-embed-share-dialog-open:focus .dashicons,
.wp-embed-share-dialog-close:focus .dashicons {
- box-shadow: 0 0 0 1px #4f94d4, 0 0 2px 1px rgba(79, 148, 212, 0.8);
+ box-shadow: 0 0 0 2px #2271b1;
+ /* Only visible in Windows High Contrast mode */
+ outline: 2px solid transparent;
border-radius: 100%;
}
diff --git a/src/wp-includes/customize/class-wp-customize-media-control.php b/src/wp-includes/customize/class-wp-customize-media-control.php
index f63689292522b..3bdc4e2dc1a7c 100644
--- a/src/wp-includes/customize/class-wp-customize-media-control.php
+++ b/src/wp-includes/customize/class-wp-customize-media-control.php
@@ -93,7 +93,7 @@ public function to_json() {
* Note that the default value must be a URL, NOT an attachment ID.
*/
$ext = substr( $this->setting->default, -3 );
- $type = in_array( $ext, array( 'jpg', 'png', 'gif', 'bmp', 'webp' ), true ) ? 'image' : 'document';
+ $type = in_array( $ext, array( 'jpg', 'png', 'gif', 'bmp', 'webp', 'avif' ), true ) ? 'image' : 'document';
$default_attachment = array(
'id' => 1,
diff --git a/src/wp-includes/customize/class-wp-customize-nav-menu-location-control.php b/src/wp-includes/customize/class-wp-customize-nav-menu-location-control.php
index 4877ada9e16b7..b0340b1eeed4f 100644
--- a/src/wp-includes/customize/class-wp-customize-nav-menu-location-control.php
+++ b/src/wp-includes/customize/class-wp-customize-nav-menu-location-control.php
@@ -77,7 +77,7 @@ public function render_content() {
link(); ?>>
choices as $value => $label ) :
- echo 'value(), $value, false ) . '>' . $label . ' ';
+ echo 'value(), $value, false ) . '>' . esc_html( $label ) . ' ';
endforeach;
?>
diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php
index 9cb447181aefd..2d9f5368d46c8 100644
--- a/src/wp-includes/default-filters.php
+++ b/src/wp-includes/default-filters.php
@@ -687,6 +687,7 @@
add_action( 'embed_head', 'wp_robots' );
add_action( 'embed_head', 'rel_canonical' );
add_action( 'embed_head', 'locale_stylesheet', 30 );
+add_action( 'enqueue_embed_scripts', 'wp_enqueue_emoji_styles' );
add_action( 'embed_content_meta', 'print_embed_comments_button' );
add_action( 'embed_content_meta', 'print_embed_sharing_button' );
@@ -747,5 +748,8 @@
// Font management.
add_action( 'wp_head', 'wp_print_font_faces', 50 );
+add_action( 'deleted_post', '_wp_after_delete_font_family', 10, 2 );
+add_action( 'before_delete_post', '_wp_before_delete_font_face', 10, 2 );
+add_action( 'init', '_wp_register_default_font_collections' );
unset( $filter, $action );
diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php
index e63708f91bb50..45b4f89a9e4be 100644
--- a/src/wp-includes/deprecated.php
+++ b/src/wp-includes/deprecated.php
@@ -3336,7 +3336,9 @@ function gd_edit_image_support($mime_type) {
return (imagetypes() & IMG_GIF) != 0;
case 'image/webp':
return (imagetypes() & IMG_WEBP) != 0;
- }
+ case 'image/avif':
+ return (imagetypes() & IMG_AVIF) != 0;
+ }
} else {
switch( $mime_type ) {
case 'image/jpeg':
@@ -3347,6 +3349,8 @@ function gd_edit_image_support($mime_type) {
return function_exists('imagecreatefromgif');
case 'image/webp':
return function_exists('imagecreatefromwebp');
+ case 'image/avif':
+ return function_exists('imagecreatefromavif');
}
}
return false;
@@ -5436,7 +5440,7 @@ function _wp_theme_json_webfonts_handler() {
$settings = WP_Theme_JSON_Resolver::get_merged_data()->get_settings();
// If in the editor, add webfonts defined in variations.
- if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
+ if ( is_admin() || wp_is_rest_endpoint() ) {
$variations = WP_Theme_JSON_Resolver::get_style_variations();
foreach ( $variations as $variation ) {
// Skip if fontFamilies are not defined in the variation.
@@ -6239,3 +6243,60 @@ function the_block_template_skip_link() {
registered['wp-block-query-view'] ) &&
+ ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-query-view']->deps, true )
+ ) {
+ $wp_scripts->registered['wp-block-query-view']->deps[] = 'wp-interactivity';
+ }
+}
+
+/**
+ * Ensure that the view script has the `wp-interactivity` dependency.
+ *
+ * @since 6.4.0
+ * @deprecated 6.5.0
+ *
+ * @global WP_Scripts $wp_scripts
+ */
+function block_core_file_ensure_interactivity_dependency() {
+ _deprecated_function( __FUNCTION__, '6.5.0', 'wp_register_script_module' );
+ global $wp_scripts;
+ if (
+ isset( $wp_scripts->registered['wp-block-file-view'] ) &&
+ ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-file-view']->deps, true )
+ ) {
+ $wp_scripts->registered['wp-block-file-view']->deps[] = 'wp-interactivity';
+ }
+}
+
+/**
+ * Ensures that the view script has the `wp-interactivity` dependency.
+ *
+ * @since 6.4.0
+ * @deprecated 6.5.0
+ *
+ * @global WP_Scripts $wp_scripts
+ */
+function block_core_image_ensure_interactivity_dependency() {
+ _deprecated_function( __FUNCTION__, '6.5.0', 'wp_register_script_module' );
+ global $wp_scripts;
+ if (
+ isset( $wp_scripts->registered['wp-block-image-view'] ) &&
+ ! in_array( 'wp-interactivity', $wp_scripts->registered['wp-block-image-view']->deps, true )
+ ) {
+ $wp_scripts->registered['wp-block-image-view']->deps[] = 'wp-interactivity';
+ }
+}
diff --git a/src/wp-includes/fonts.php b/src/wp-includes/fonts.php
index 87503c275f390..dfd0b45857a0e 100644
--- a/src/wp-includes/fonts.php
+++ b/src/wp-includes/fonts.php
@@ -51,3 +51,150 @@ function wp_print_font_faces( $fonts = array() ) {
$wp_font_face = new WP_Font_Face();
$wp_font_face->generate_and_print( $fonts );
}
+
+/**
+ * Registers a new Font Collection in the Font Library.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slug Font collection slug. May only contain alphanumeric characters, dashes,
+ * and underscores. See sanitize_title().
+ * @param array|string $data_or_file {
+ * Font collection data array or a path/URL to a JSON file containing the font collection.
+ *
+ * @link https://schemas.wp.org/trunk/font-collection.json
+ *
+ * @type string $name Required. Name of the font collection shown in the Font Library.
+ * @type string $description Optional. A short descriptive summary of the font collection. Default empty.
+ * @type array $font_families Required. Array of font family definitions that are in the collection.
+ * @type array $categories Optional. Array of categories, each with a name and slug, that are used by the
+ * fonts in the collection. Default empty.
+ * }
+ * @return WP_Font_Collection|WP_Error A font collection if it was registered
+ * successfully, or WP_Error object on failure.
+ */
+function wp_register_font_collection( $slug, $data_or_file ) {
+ return WP_Font_Library::get_instance()->register_font_collection( $slug, $data_or_file );
+}
+
+/**
+ * Unregisters a font collection from the Font Library.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slug Font collection slug.
+ * @return bool True if the font collection was unregistered successfully, else false.
+ */
+function wp_unregister_font_collection( $slug ) {
+ return WP_Font_Library::get_instance()->unregister_font_collection( $slug );
+}
+
+/**
+ * Returns an array containing the current fonts upload directory's path and URL.
+ *
+ * @since 6.5.0
+ *
+ * @param array $defaults {
+ * Array of information about the upload directory.
+ *
+ * @type string $path Base directory and subdirectory or full path to the fonts upload directory.
+ * @type string $url Base URL and subdirectory or absolute URL to the fonts upload directory.
+ * @type string $subdir Subdirectory
+ * @type string $basedir Path without subdir.
+ * @type string $baseurl URL path without subdir.
+ * @type string|false $error False or error message.
+ * }
+ * @return array $defaults {
+ * Array of information about the upload directory.
+ *
+ * @type string $path Base directory and subdirectory or full path to the fonts upload directory.
+ * @type string $url Base URL and subdirectory or absolute URL to the fonts upload directory.
+ * @type string $subdir Subdirectory
+ * @type string $basedir Path without subdir.
+ * @type string $baseurl URL path without subdir.
+ * @type string|false $error False or error message.
+ * }
+ */
+function wp_get_font_dir( $defaults = array() ) {
+ $site_path = '';
+ if ( is_multisite() && ! ( is_main_network() && is_main_site() ) ) {
+ $site_path = '/sites/' . get_current_blog_id();
+ }
+
+ // Sets the defaults.
+ $defaults['path'] = path_join( WP_CONTENT_DIR, 'fonts' ) . $site_path;
+ $defaults['url'] = untrailingslashit( content_url( 'fonts' ) ) . $site_path;
+ $defaults['subdir'] = '';
+ $defaults['basedir'] = path_join( WP_CONTENT_DIR, 'fonts' ) . $site_path;
+ $defaults['baseurl'] = untrailingslashit( content_url( 'fonts' ) ) . $site_path;
+ $defaults['error'] = false;
+
+ /**
+ * Filters the fonts directory data.
+ *
+ * This filter allows developers to modify the fonts directory data.
+ *
+ * @since 6.5.0
+ *
+ * @param array $defaults The original fonts directory data.
+ */
+ return apply_filters( 'font_dir', $defaults );
+}
+
+/**
+ * Deletes child font faces when a font family is deleted.
+ *
+ * @access private
+ * @since 6.5.0
+ *
+ * @param int $post_id Post ID.
+ * @param WP_Post $post Post object.
+ */
+function _wp_after_delete_font_family( $post_id, $post ) {
+ if ( 'wp_font_family' !== $post->post_type ) {
+ return;
+ }
+
+ $font_faces = get_children(
+ array(
+ 'post_parent' => $post_id,
+ 'post_type' => 'wp_font_face',
+ )
+ );
+
+ foreach ( $font_faces as $font_face ) {
+ wp_delete_post( $font_face->ID, true );
+ }
+}
+
+/**
+ * Deletes associated font files when a font face is deleted.
+ *
+ * @access private
+ * @since 6.5.0
+ *
+ * @param int $post_id Post ID.
+ * @param WP_Post $post Post object.
+ */
+function _wp_before_delete_font_face( $post_id, $post ) {
+ if ( 'wp_font_face' !== $post->post_type ) {
+ return;
+ }
+
+ $font_files = get_post_meta( $post_id, '_wp_font_face_file', false );
+ $font_dir = wp_get_font_dir()['path'];
+
+ foreach ( $font_files as $font_file ) {
+ wp_delete_file( $font_dir . '/' . $font_file );
+ }
+}
+
+/**
+ * Register the default font collections.
+ *
+ * @access private
+ * @since 6.5.0
+ */
+function _wp_register_default_font_collections() {
+ wp_register_font_collection( 'google-fonts', 'https://s.w.org/images/fonts/17.7/collections/google-fonts-with-preview.json' );
+}
diff --git a/src/wp-includes/fonts/class-wp-font-collection.php b/src/wp-includes/fonts/class-wp-font-collection.php
new file mode 100644
index 0000000000000..240bba35e94f8
--- /dev/null
+++ b/src/wp-includes/fonts/class-wp-font-collection.php
@@ -0,0 +1,260 @@
+slug = sanitize_title( $slug );
+ if ( $this->slug !== $slug ) {
+ _doing_it_wrong(
+ __METHOD__,
+ /* translators: %s: Font collection slug. */
+ sprintf( __( 'Font collection slug "%s" is not valid. Slugs must use only alphanumeric characters, dashes, and underscores.' ), $slug ),
+ '6.5.0'
+ );
+ }
+
+ if ( is_array( $data_or_file ) ) {
+ $this->data = $this->sanitize_and_validate_data( $data_or_file );
+ } else {
+ // JSON data is lazy loaded by ::get_data().
+ $this->src = $data_or_file;
+ }
+ }
+
+ /**
+ * Retrieves the font collection data.
+ *
+ * @since 6.5.0
+ *
+ * @return array|WP_Error An array containing the font collection data, or a WP_Error on failure.
+ */
+ public function get_data() {
+ // If the collection uses JSON data, load it and cache the data/error.
+ if ( $this->src && empty( $this->data ) ) {
+ $this->data = $this->load_from_json( $this->src );
+ }
+
+ if ( is_wp_error( $this->data ) ) {
+ return $this->data;
+ }
+
+ // Set defaults for optional properties.
+ $defaults = array(
+ 'description' => '',
+ 'categories' => array(),
+ );
+
+ return wp_parse_args( $this->data, $defaults );
+ }
+
+ /**
+ * Loads font collection data from a JSON file or URL.
+ *
+ * @since 6.5.0
+ *
+ * @param string $file_or_url File path or URL to a JSON file containing the font collection data.
+ * @return array|WP_Error An array containing the font collection data on success,
+ * else an instance of WP_Error on failure.
+ */
+ private function load_from_json( $file_or_url ) {
+ $url = wp_http_validate_url( $file_or_url );
+ $file = file_exists( $file_or_url ) ? wp_normalize_path( realpath( $file_or_url ) ) : false;
+
+ if ( ! $url && ! $file ) {
+ // translators: %s: File path or URL to font collection JSON file.
+ $message = __( 'Font collection JSON file is invalid or does not exist.' );
+ _doing_it_wrong( __METHOD__, $message, '6.5.0' );
+ return new WP_Error( 'font_collection_json_missing', $message );
+ }
+
+ return $url ? $this->load_from_url( $url ) : $this->load_from_file( $file );
+ }
+
+ /**
+ * Loads the font collection data from a JSON file path.
+ *
+ * @since 6.5.0
+ *
+ * @param string $file File path to a JSON file containing the font collection data.
+ * @return array|WP_Error An array containing the font collection data on success,
+ * else an instance of WP_Error on failure.
+ */
+ private function load_from_file( $file ) {
+ $data = wp_json_file_decode( $file, array( 'associative' => true ) );
+ if ( empty( $data ) ) {
+ return new WP_Error( 'font_collection_decode_error', __( 'Error decoding the font collection JSON file contents.' ) );
+ }
+
+ return $this->sanitize_and_validate_data( $data );
+ }
+
+ /**
+ * Loads the font collection data from a JSON file URL.
+ *
+ * @since 6.5.0
+ *
+ * @param string $url URL to a JSON file containing the font collection data.
+ * @return array|WP_Error An array containing the font collection data on success,
+ * else an instance of WP_Error on failure.
+ */
+ private function load_from_url( $url ) {
+ // Limit key to 167 characters to avoid failure in the case of a long URL.
+ $transient_key = substr( 'wp_font_collection_url_' . $url, 0, 167 );
+ $data = get_site_transient( $transient_key );
+
+ if ( false === $data ) {
+ $response = wp_safe_remote_get( $url );
+ if ( is_wp_error( $response ) || 200 !== wp_remote_retrieve_response_code( $response ) ) {
+ // translators: %s: Font collection URL.
+ return new WP_Error( 'font_collection_request_error', sprintf( __( 'Error fetching the font collection data from "%s".' ), $url ) );
+ }
+
+ $data = json_decode( wp_remote_retrieve_body( $response ), true );
+ if ( empty( $data ) ) {
+ return new WP_Error( 'font_collection_decode_error', __( 'Error decoding the font collection data from the HTTP response JSON.' ) );
+ }
+
+ // Make sure the data is valid before storing it in a transient.
+ $data = $this->sanitize_and_validate_data( $data );
+ if ( is_wp_error( $data ) ) {
+ return $data;
+ }
+
+ set_site_transient( $transient_key, $data, DAY_IN_SECONDS );
+ }
+
+ return $data;
+ }
+
+ /**
+ * Sanitizes and validates the font collection data.
+ *
+ * @since 6.5.0
+ *
+ * @param array $data Font collection data to sanitize and validate.
+ * @return array|WP_Error Sanitized data if valid, otherwise a WP_Error instance.
+ */
+ private function sanitize_and_validate_data( $data ) {
+ $schema = self::get_sanitization_schema();
+ $data = WP_Font_Utils::sanitize_from_schema( $data, $schema );
+
+ $required_properties = array( 'name', 'font_families' );
+ foreach ( $required_properties as $property ) {
+ if ( empty( $data[ $property ] ) ) {
+ $message = sprintf(
+ // translators: 1: Font collection slug, 2: Missing property name, e.g. "font_families".
+ __( 'Font collection "%1$s" has missing or empty property: "%2$s".' ),
+ $this->slug,
+ $property
+ );
+ _doing_it_wrong( __METHOD__, $message, '6.5.0' );
+ return new WP_Error( 'font_collection_missing_property', $message );
+ }
+ }
+
+ return $data;
+ }
+
+ /**
+ * Retrieves the font collection sanitization schema.
+ *
+ * @since 6.5.0
+ *
+ * @return array Font collection sanitization schema.
+ */
+ private static function get_sanitization_schema() {
+ return array(
+ 'name' => 'sanitize_text_field',
+ 'description' => 'sanitize_text_field',
+ 'font_families' => array(
+ array(
+ 'font_family_settings' => array(
+ 'name' => 'sanitize_text_field',
+ 'slug' => 'sanitize_title',
+ 'fontFamily' => 'sanitize_text_field',
+ 'preview' => 'sanitize_url',
+ 'fontFace' => array(
+ array(
+ 'fontFamily' => 'sanitize_text_field',
+ 'fontStyle' => 'sanitize_text_field',
+ 'fontWeight' => 'sanitize_text_field',
+ 'src' => static function ( $value ) {
+ return is_array( $value )
+ ? array_map( 'sanitize_text_field', $value )
+ : sanitize_text_field( $value );
+ },
+ 'preview' => 'sanitize_url',
+ 'fontDisplay' => 'sanitize_text_field',
+ 'fontStretch' => 'sanitize_text_field',
+ 'ascentOverride' => 'sanitize_text_field',
+ 'descentOverride' => 'sanitize_text_field',
+ 'fontVariant' => 'sanitize_text_field',
+ 'fontFeatureSettings' => 'sanitize_text_field',
+ 'fontVariationSettings' => 'sanitize_text_field',
+ 'lineGapOverride' => 'sanitize_text_field',
+ 'sizeAdjust' => 'sanitize_text_field',
+ 'unicodeRange' => 'sanitize_text_field',
+ ),
+ ),
+ ),
+ 'categories' => array( 'sanitize_title' ),
+ ),
+ ),
+ 'categories' => array(
+ array(
+ 'name' => 'sanitize_text_field',
+ 'slug' => 'sanitize_title',
+ ),
+ ),
+ );
+ }
+}
diff --git a/src/wp-includes/fonts/class-wp-font-library.php b/src/wp-includes/fonts/class-wp-font-library.php
new file mode 100644
index 0000000000000..f9ca90327121d
--- /dev/null
+++ b/src/wp-includes/fonts/class-wp-font-library.php
@@ -0,0 +1,143 @@
+is_collection_registered( $new_collection->slug ) ) {
+ $error_message = sprintf(
+ /* translators: %s: Font collection slug. */
+ __( 'Font collection with slug: "%s" is already registered.' ),
+ $new_collection->slug
+ );
+ _doing_it_wrong(
+ __METHOD__,
+ $error_message,
+ '6.5.0'
+ );
+ return new WP_Error( 'font_collection_registration_error', $error_message );
+ }
+ $this->collections[ $new_collection->slug ] = $new_collection;
+ return $new_collection;
+ }
+
+ /**
+ * Unregisters a previously registered font collection.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slug Font collection slug.
+ * @return bool True if the font collection was unregistered successfully and false otherwise.
+ */
+ public function unregister_font_collection( $slug ) {
+ if ( ! $this->is_collection_registered( $slug ) ) {
+ _doing_it_wrong(
+ __METHOD__,
+ /* translators: %s: Font collection slug. */
+ sprintf( __( 'Font collection "%s" not found.' ), $slug ),
+ '6.5.0'
+ );
+ return false;
+ }
+ unset( $this->collections[ $slug ] );
+ return true;
+ }
+
+ /**
+ * Checks if a font collection is registered.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slug Font collection slug.
+ * @return bool True if the font collection is registered and false otherwise.
+ */
+ private function is_collection_registered( $slug ) {
+ return array_key_exists( $slug, $this->collections );
+ }
+
+ /**
+ * Gets all the font collections available.
+ *
+ * @since 6.5.0
+ *
+ * @return array List of font collections.
+ */
+ public function get_font_collections() {
+ return $this->collections;
+ }
+
+ /**
+ * Gets a font collection.
+ *
+ * @since 6.5.0
+ *
+ * @param string $slug Font collection slug.
+ * @return WP_Font_Collection|null Font collection object, or null if the font collection doesn't exist.
+ */
+ public function get_font_collection( $slug ) {
+ if ( $this->is_collection_registered( $slug ) ) {
+ return $this->collections[ $slug ];
+ }
+ return null;
+ }
+
+ /**
+ * Utility method to retrieve the main instance of the class.
+ *
+ * The instance will be created if it does not exist yet.
+ *
+ * @since 6.5.0
+ *
+ * @return WP_Font_Library The main instance.
+ */
+ public static function get_instance() {
+ if ( null === self::$instance ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+}
diff --git a/src/wp-includes/fonts/class-wp-font-utils.php b/src/wp-includes/fonts/class-wp-font-utils.php
new file mode 100644
index 0000000000000..5bca536d2d58a
--- /dev/null
+++ b/src/wp-includes/fonts/class-wp-font-utils.php
@@ -0,0 +1,238 @@
+ '',
+ 'fontStyle' => 'normal',
+ 'fontWeight' => '400',
+ 'fontStretch' => '100%',
+ 'unicodeRange' => 'U+0-10FFFF',
+ );
+ $settings = wp_parse_args( $settings, $defaults );
+
+ $font_family = mb_strtolower( $settings['fontFamily'] );
+ $font_style = strtolower( $settings['fontStyle'] );
+ $font_weight = strtolower( $settings['fontWeight'] );
+ $font_stretch = strtolower( $settings['fontStretch'] );
+ $unicode_range = strtoupper( $settings['unicodeRange'] );
+
+ // Convert weight keywords to numeric strings.
+ $font_weight = str_replace( array( 'normal', 'bold' ), array( '400', '700' ), $font_weight );
+
+ // Convert stretch keywords to numeric strings.
+ $font_stretch_map = array(
+ 'ultra-condensed' => '50%',
+ 'extra-condensed' => '62.5%',
+ 'condensed' => '75%',
+ 'semi-condensed' => '87.5%',
+ 'normal' => '100%',
+ 'semi-expanded' => '112.5%',
+ 'expanded' => '125%',
+ 'extra-expanded' => '150%',
+ 'ultra-expanded' => '200%',
+ );
+ $font_stretch = str_replace( array_keys( $font_stretch_map ), array_values( $font_stretch_map ), $font_stretch );
+
+ $slug_elements = array( $font_family, $font_style, $font_weight, $font_stretch, $unicode_range );
+
+ $slug_elements = array_map(
+ function ( $elem ) {
+ // Remove quotes to normalize font-family names, and ';' to use as a separator.
+ $elem = trim( str_replace( array( '"', "'", ';' ), '', $elem ) );
+
+ // Normalize comma separated lists by removing whitespace in between items,
+ // but keep whitespace within items (e.g. "Open Sans" and "OpenSans" are different fonts).
+ // CSS spec for whitespace includes: U+000A LINE FEED, U+0009 CHARACTER TABULATION, or U+0020 SPACE,
+ // which by default are all matched by \s in PHP.
+ return preg_replace( '/,\s+/', ',', $elem );
+ },
+ $slug_elements
+ );
+
+ return sanitize_text_field( join( ';', $slug_elements ) );
+ }
+
+ /**
+ * Sanitizes a tree of data using a schema.
+ *
+ * The schema structure should mirror the data tree. Each value provided in the
+ * schema should be a callable that will be applied to sanitize the corresponding
+ * value in the data tree. Keys that are in the data tree, but not present in the
+ * schema, will be removed in the sanitized data. Nested arrays are traversed recursively.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ *
+ * @param array $tree The data to sanitize.
+ * @param array $schema The schema used for sanitization.
+ * @return array The sanitized data.
+ */
+ public static function sanitize_from_schema( $tree, $schema ) {
+ if ( ! is_array( $tree ) || ! is_array( $schema ) ) {
+ return array();
+ }
+
+ foreach ( $tree as $key => $value ) {
+ // Remove keys not in the schema or with null/empty values.
+ if ( ! array_key_exists( $key, $schema ) ) {
+ unset( $tree[ $key ] );
+ continue;
+ }
+
+ $is_value_array = is_array( $value );
+ $is_schema_array = is_array( $schema[ $key ] ) && ! is_callable( $schema[ $key ] );
+
+ if ( $is_value_array && $is_schema_array ) {
+ if ( wp_is_numeric_array( $value ) ) {
+ // If indexed, process each item in the array.
+ foreach ( $value as $item_key => $item_value ) {
+ $tree[ $key ][ $item_key ] = isset( $schema[ $key ][0] ) && is_array( $schema[ $key ][0] )
+ ? self::sanitize_from_schema( $item_value, $schema[ $key ][0] )
+ : self::apply_sanitizer( $item_value, $schema[ $key ][0] );
+ }
+ } else {
+ // If it is an associative or indexed array, process as a single object.
+ $tree[ $key ] = self::sanitize_from_schema( $value, $schema[ $key ] );
+ }
+ } elseif ( ! $is_value_array && $is_schema_array ) {
+ // If the value is not an array but the schema is, remove the key.
+ unset( $tree[ $key ] );
+ } elseif ( ! $is_schema_array ) {
+ // If the schema is not an array, apply the sanitizer to the value.
+ $tree[ $key ] = self::apply_sanitizer( $value, $schema[ $key ] );
+ }
+
+ // Remove keys with null/empty values.
+ if ( empty( $tree[ $key ] ) ) {
+ unset( $tree[ $key ] );
+ }
+ }
+
+ return $tree;
+ }
+
+ /**
+ * Applies a sanitizer function to a value.
+ *
+ * @since 6.5.0
+ *
+ * @param mixed $value The value to sanitize.
+ * @param mixed $sanitizer The sanitizer function to apply.
+ * @return mixed The sanitized value.
+ */
+ private static function apply_sanitizer( $value, $sanitizer ) {
+ if ( null === $sanitizer ) {
+ return $value;
+
+ }
+ return call_user_func( $sanitizer, $value );
+ }
+
+ /**
+ * Returns the expected mime-type values for font files, depending on PHP version.
+ *
+ * This is needed because font mime types vary by PHP version, so checking the PHP version
+ * is necessary until a list of valid mime-types for each file extension can be provided to
+ * the 'upload_mimes' filter.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ *
+ * @return array A collection of mime types keyed by file extension.
+ */
+ public static function get_allowed_font_mime_types() {
+ $php_7_ttf_mime_type = PHP_VERSION_ID >= 70300 ? 'application/font-sfnt' : 'application/x-font-ttf';
+
+ return array(
+ 'otf' => 'application/vnd.ms-opentype',
+ 'ttf' => PHP_VERSION_ID >= 70400 ? 'font/sfnt' : $php_7_ttf_mime_type,
+ 'woff' => PHP_VERSION_ID >= 80100 ? 'font/woff' : 'application/font-woff',
+ 'woff2' => PHP_VERSION_ID >= 80100 ? 'font/woff2' : 'application/font-woff2',
+ );
+ }
+}
diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php
index 05b103e6f755f..ce8d0354209e2 100644
--- a/src/wp-includes/formatting.php
+++ b/src/wp-includes/formatting.php
@@ -3464,7 +3464,7 @@ function translate_smiley( $matches ) {
$matches = array();
$ext = preg_match( '/\.([^.]+)$/', $img, $matches ) ? strtolower( $matches[1] ) : false;
- $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'webp' );
+ $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'webp', 'avif' );
// Don't convert smilies that aren't images - they're probably emoji.
if ( ! in_array( $ext, $image_exts, true ) ) {
diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php
index a3a5e56bfad18..461918bd53299 100644
--- a/src/wp-includes/functions.php
+++ b/src/wp-includes/functions.php
@@ -1548,11 +1548,11 @@ function nocache_headers() {
* @since 2.1.0
*/
function cache_javascript_headers() {
- $expiresOffset = 10 * DAY_IN_SECONDS;
+ $expires_offset = 10 * DAY_IN_SECONDS;
header( 'Content-Type: text/javascript; charset=' . get_bloginfo( 'charset' ) );
header( 'Vary: Accept-Encoding' ); // Handle proxies.
- header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + $expiresOffset ) . ' GMT' );
+ header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + $expires_offset ) . ' GMT' );
}
/**
@@ -1692,7 +1692,7 @@ function do_feed_atom( $for_comments ) {
* Displays the default robots.txt file content.
*
* @since 2.1.0
- * @since 5.3.0 Remove the "Disallow: /" output if search engine visiblity is
+ * @since 5.3.0 Remove the "Disallow: /" output if search engine visibility is
* discouraged in favor of robots meta HTML tag via wp_robots_no_robots()
* filter callback.
*/
@@ -3117,6 +3117,7 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
'image/bmp' => 'bmp',
'image/tiff' => 'tif',
'image/webp' => 'webp',
+ 'image/avif' => 'avif',
)
);
@@ -3295,6 +3296,7 @@ function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
*
* @since 4.7.1
* @since 5.8.0 Added support for WebP images.
+ * @since 6.5.0 Added support for AVIF images.
*
* @param string $file Full path to the file.
* @return string|false The actual mime type or false if the type cannot be determined.
@@ -3349,6 +3351,25 @@ function wp_get_image_mime( $file ) {
) {
$mime = 'image/webp';
}
+
+ /**
+ * Add AVIF fallback detection when image library doesn't support AVIF.
+ *
+ * Detection based on section 4.3.1 File-type box definition of the ISO/IEC 14496-12
+ * specification and the AV1-AVIF spec, see https://aomediacodec.github.io/av1-avif/v1.1.0.html#brands.
+ */
+
+ // Divide the header string into 4 byte groups.
+ $magic = str_split( $magic, 8 );
+
+ if (
+ isset( $magic[1] ) &&
+ isset( $magic[2] ) &&
+ 'ftyp' === hex2bin( $magic[1] ) &&
+ ( 'avif' === hex2bin( $magic[2] ) || 'avis' === hex2bin( $magic[2] ) )
+ ) {
+ $mime = 'image/avif';
+ }
} catch ( Exception $e ) {
$mime = false;
}
@@ -3388,6 +3409,7 @@ function wp_get_mime_types() {
'bmp' => 'image/bmp',
'tiff|tif' => 'image/tiff',
'webp' => 'image/webp',
+ 'avif' => 'image/avif',
'ico' => 'image/x-icon',
'heic' => 'image/heic',
// Video formats.
@@ -3509,7 +3531,7 @@ function wp_get_ext_types() {
return apply_filters(
'ext2type',
array(
- 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic', 'webp' ),
+ 'image' => array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'bmp', 'tif', 'tiff', 'ico', 'heic', 'webp', 'avif' ),
'audio' => array( 'aac', 'ac3', 'aif', 'aiff', 'flac', 'm3a', 'm4a', 'm4b', 'mka', 'mp1', 'mp2', 'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
'video' => array( '3g2', '3gp', '3gpp', 'asf', 'avi', 'divx', 'dv', 'flv', 'm4v', 'mkv', 'mov', 'mp4', 'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt', 'rm', 'vob', 'wmv' ),
'document' => array( 'doc', 'docx', 'docm', 'dotm', 'odt', 'pages', 'pdf', 'xps', 'oxps', 'rtf', 'wp', 'wpd', 'psd', 'xcf' ),
@@ -3718,7 +3740,7 @@ function wp_die( $message = '', $title = '', $args = array() ) {
* @param callable $callback Callback function name.
*/
$callback = apply_filters( 'wp_die_json_handler', '_json_wp_die_handler' );
- } elseif ( defined( 'REST_REQUEST' ) && REST_REQUEST && wp_is_jsonp_request() ) {
+ } elseif ( wp_is_serving_rest_request() && wp_is_jsonp_request() ) {
/**
* Filters the callback for killing WordPress execution for JSONP REST requests.
*
@@ -3883,21 +3905,16 @@ function _default_wp_die_handler( $message, $title = '', $args = array() ) {
font-size: 14px ;
}
a {
- color: #0073aa;
+ color: #2271b1;
}
a:hover,
a:active {
- color: #006799;
+ color: #135e96;
}
a:focus {
- color: #124964;
- -webkit-box-shadow:
- 0 0 0 1px #5b9dd9,
- 0 0 2px 1px rgba(30, 140, 190, 0.8);
- box-shadow:
- 0 0 0 1px #5b9dd9,
- 0 0 2px 1px rgba(30, 140, 190, 0.8);
- outline: none;
+ color: #043959;
+ box-shadow: 0 0 0 2px #2271b1;
+ outline: 2px solid transparent;
}
.button {
background: #f3f5f6;
@@ -4441,7 +4458,7 @@ function _wp_json_prepare_data( $value ) {
* @param int $flags Optional. Options to be passed to json_encode(). Default 0.
*/
function wp_send_json( $response, $status_code = null, $flags = 0 ) {
- if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
+ if ( wp_is_serving_rest_request() ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
@@ -4697,6 +4714,23 @@ function _mce_set_direction( $mce_init ) {
return $mce_init;
}
+/**
+ * Determines whether WordPress is currently serving a REST API request.
+ *
+ * The function relies on the 'REST_REQUEST' global. As such, it only returns true when an actual REST _request_ is
+ * being made. It does not return true when a REST endpoint is hit as part of another request, e.g. for preloading a
+ * REST response. See {@see wp_is_rest_endpoint()} for that purpose.
+ *
+ * This function should not be called until the {@see 'parse_request'} action, as the constant is only defined then,
+ * even for an actual REST request.
+ *
+ * @since 6.5.0
+ *
+ * @return bool True if it's a WordPress REST API request, false otherwise.
+ */
+function wp_is_serving_rest_request() {
+ return defined( 'REST_REQUEST' ) && REST_REQUEST;
+}
/**
* Converts smiley code to the icon graphic file equivalent.
@@ -5356,7 +5390,7 @@ function wp_widgets_add_menu() {
if ( wp_is_block_theme() || current_theme_supports( 'block-template-parts' ) ) {
$submenu['themes.php'][] = array( $menu_name, 'edit_theme_options', 'widgets.php' );
} else {
- $submenu['themes.php'][7] = array( $menu_name, 'edit_theme_options', 'widgets.php' );
+ $submenu['themes.php'][8] = array( $menu_name, 'edit_theme_options', 'widgets.php' );
}
ksort( $submenu['themes.php'], SORT_NUMERIC );
@@ -6533,7 +6567,7 @@ function wp_timezone_choice( $selected_zone, $locale = null ) {
if ( ! $mo_loaded || $locale !== $locale_loaded ) {
$locale_loaded = $locale ? $locale : get_locale();
$mofile = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
- unload_textdomain( 'continents-cities' );
+ unload_textdomain( 'continents-cities', true );
load_textdomain( 'continents-cities', $mofile, $locale_loaded );
$mo_loaded = true;
}
diff --git a/src/wp-includes/global-styles-and-settings.php b/src/wp-includes/global-styles-and-settings.php
index acca33be1e844..fae7ae6ffb6ea 100644
--- a/src/wp-includes/global-styles-and-settings.php
+++ b/src/wp-includes/global-styles-and-settings.php
@@ -54,7 +54,7 @@ function wp_get_global_settings( $path = array(), $context = array() ) {
* is always fresh from the potential modifications done via hooks
* that can use dynamic data (modify the stylesheet depending on some option,
* settings depending on user permissions, etc.).
- * See some of the existing hooks to modify theme.json behaviour:
+ * See some of the existing hooks to modify theme.json behavior:
* https://make.wordpress.org/core/2022/10/10/filters-for-theme-json-data/
*
* A different alternative considered was to invalidate the cache upon certain
@@ -298,8 +298,12 @@ function wp_get_global_styles_custom_css() {
* Adds global style rules to the inline style for each block.
*
* @since 6.1.0
+ *
+ * @global WP_Styles $wp_styles
*/
function wp_add_global_styles_for_blocks() {
+ global $wp_styles;
+
$tree = WP_Theme_JSON_Resolver::get_merged_data();
$block_nodes = $tree->get_styles_block_nodes();
foreach ( $block_nodes as $metadata ) {
@@ -311,17 +315,26 @@ function wp_add_global_styles_for_blocks() {
}
$stylesheet_handle = 'global-styles';
+
+ /*
+ * When `wp_should_load_separate_core_block_assets()` is true, block styles are
+ * enqueued for each block on the page in class WP_Block's render function.
+ * This means there will be a handle in the styles queue for each of those blocks.
+ * Block-specific global styles should be attached to the global-styles handle, but
+ * only for blocks on the page, thus we check if the block's handle is in the queue
+ * before adding the inline style.
+ * This conditional loading only applies to core blocks.
+ */
if ( isset( $metadata['name'] ) ) {
- /*
- * These block styles are added on block_render.
- * This hooks inline CSS to them so that they are loaded conditionally
- * based on whether or not the block is used on the page.
- */
if ( str_starts_with( $metadata['name'], 'core/' ) ) {
- $block_name = str_replace( 'core/', '', $metadata['name'] );
- $stylesheet_handle = 'wp-block-' . $block_name;
+ $block_name = str_replace( 'core/', '', $metadata['name'] );
+ $block_handle = 'wp-block-' . $block_name;
+ if ( in_array( $block_handle, $wp_styles->queue ) ) {
+ wp_add_inline_style( $stylesheet_handle, $block_css );
+ }
+ } else {
+ wp_add_inline_style( $stylesheet_handle, $block_css );
}
- wp_add_inline_style( $stylesheet_handle, $block_css );
}
// The likes of block element styles from theme.json do not have $metadata['name'] set.
@@ -329,10 +342,14 @@ function wp_add_global_styles_for_blocks() {
$block_name = wp_get_block_name_from_theme_json_path( $metadata['path'] );
if ( $block_name ) {
if ( str_starts_with( $block_name, 'core/' ) ) {
- $block_name = str_replace( 'core/', '', $block_name );
- $stylesheet_handle = 'wp-block-' . $block_name;
+ $block_name = str_replace( 'core/', '', $block_name );
+ $block_handle = 'wp-block-' . $block_name;
+ if ( in_array( $block_handle, $wp_styles->queue ) ) {
+ wp_add_inline_style( $stylesheet_handle, $block_css );
+ }
+ } else {
+ wp_add_inline_style( $stylesheet_handle, $block_css );
}
- wp_add_inline_style( $stylesheet_handle, $block_css );
}
}
}
diff --git a/src/wp-includes/html-api/class-wp-html-processor.php b/src/wp-includes/html-api/class-wp-html-processor.php
index cce26a60c5350..dd8e8d5f2d6e8 100644
--- a/src/wp-includes/html-api/class-wp-html-processor.php
+++ b/src/wp-includes/html-api/class-wp-html-processor.php
@@ -101,18 +101,18 @@
*
* - Containers: ADDRESS, BLOCKQUOTE, DETAILS, DIALOG, DIV, FOOTER, HEADER, MAIN, MENU, SPAN, SUMMARY.
* - Custom elements: All custom elements are supported. :)
- * - Form elements: BUTTON, DATALIST, FIELDSET, LABEL, LEGEND, METER, PROGRESS, SEARCH.
- * - Formatting elements: B, BIG, CODE, EM, FONT, I, SMALL, STRIKE, STRONG, TT, U.
+ * - Form elements: BUTTON, DATALIST, FIELDSET, INPUT, LABEL, LEGEND, METER, PROGRESS, SEARCH.
+ * - Formatting elements: B, BIG, CODE, EM, FONT, I, PRE, SMALL, STRIKE, STRONG, TT, U, WBR.
* - Heading elements: H1, H2, H3, H4, H5, H6, HGROUP.
* - Links: A.
- * - Lists: DD, DL, DT, LI, OL, LI.
- * - Media elements: AUDIO, CANVAS, FIGCAPTION, FIGURE, IMG, MAP, PICTURE, VIDEO.
- * - Paragraph: P.
- * - Phrasing elements: ABBR, BDI, BDO, CITE, DATA, DEL, DFN, INS, MARK, OUTPUT, Q, SAMP, SUB, SUP, TIME, VAR.
- * - Sectioning elements: ARTICLE, ASIDE, NAV, SECTION.
+ * - Lists: DD, DL, DT, LI, OL, UL.
+ * - Media elements: AUDIO, CANVAS, EMBED, FIGCAPTION, FIGURE, IMG, MAP, PICTURE, SOURCE, TRACK, VIDEO.
+ * - Paragraph: BR, P.
+ * - Phrasing elements: ABBR, AREA, BDI, BDO, CITE, DATA, DEL, DFN, INS, MARK, OUTPUT, Q, SAMP, SUB, SUP, TIME, VAR.
+ * - Sectioning elements: ARTICLE, ASIDE, HR, NAV, SECTION.
* - Templating elements: SLOT.
* - Text decoration: RUBY.
- * - Deprecated elements: ACRONYM, BLINK, CENTER, DIR, ISINDEX, MULTICOL, NEXTID, SPACER.
+ * - Deprecated elements: ACRONYM, BLINK, CENTER, DIR, ISINDEX, KEYGEN, LISTING, MULTICOL, NEXTID, PARAM, SPACER.
*
* ### Supported markup
*
@@ -149,17 +149,6 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor {
*/
const MAX_BOOKMARKS = 100;
- /**
- * Static query for instructing the Tag Processor to visit every token.
- *
- * @access private
- *
- * @since 6.4.0
- *
- * @var array
- */
- const VISIT_EVERYTHING = array( 'tag_closers' => 'visit' );
-
/**
* Holds the working state of the parser, including the stack of
* open elements and the stack of active formatting elements.
@@ -424,6 +413,30 @@ public function next_tag( $query = null ) {
return false;
}
+ /**
+ * Ensures internal accounting is maintained for HTML semantic rules while
+ * the underlying Tag Processor class is seeking to a bookmark.
+ *
+ * This doesn't currently have a way to represent non-tags and doesn't process
+ * semantic rules for text nodes. For access to the raw tokens consider using
+ * WP_HTML_Tag_Processor instead.
+ *
+ * @since 6.5.0 Added for internal support; do not use.
+ *
+ * @access private
+ *
+ * @return bool
+ */
+ public function next_token() {
+ $found_a_token = parent::next_token();
+
+ if ( '#tag' === $this->get_token_type() ) {
+ $this->step( self::PROCESS_CURRENT_NODE );
+ }
+
+ return $found_a_token;
+ }
+
/**
* Indicates if the currently-matched tag matches the given breadcrumbs.
*
@@ -500,7 +513,7 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ) {
return false;
}
- if ( self::PROCESS_NEXT_NODE === $node_to_process ) {
+ if ( self::REPROCESS_CURRENT_NODE !== $node_to_process ) {
/*
* Void elements still hop onto the stack of open elements even though
* there's no corresponding closing tag. This is important for managing
@@ -519,8 +532,12 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ) {
if ( $top_node && self::is_void( $top_node->node_name ) ) {
$this->state->stack_of_open_elements->pop();
}
+ }
- parent::next_tag( self::VISIT_EVERYTHING );
+ if ( self::PROCESS_NEXT_NODE === $node_to_process ) {
+ while ( parent::next_token() && '#tag' !== $this->get_token_type() ) {
+ continue;
+ }
}
// Finish stepping when there are no more tokens in the document.
@@ -531,7 +548,7 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ) {
$this->state->current_token = new WP_HTML_Token(
$this->bookmark_tag(),
$this->get_tag(),
- $this->is_tag_closer(),
+ $this->has_self_closing_flag(),
$this->release_internal_bookmark_on_destruct
);
@@ -684,10 +701,12 @@ private function step_in_body() {
case '-FOOTER':
case '-HEADER':
case '-HGROUP':
+ case '-LISTING':
case '-MAIN':
case '-MENU':
case '-NAV':
case '-OL':
+ case '-PRE':
case '-SEARCH':
case '-SECTION':
case '-SUMMARY':
@@ -732,6 +751,18 @@ private function step_in_body() {
$this->insert_html_element( $this->state->current_token );
return true;
+ /*
+ * > A start tag whose tag name is one of: "pre", "listing"
+ */
+ case '+PRE':
+ case '+LISTING':
+ if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
+ $this->close_a_p_element();
+ }
+ $this->insert_html_element( $this->state->current_token );
+ $this->state->frameset_ok = false;
+ return true;
+
/*
* > An end tag whose tag name is one of: "h1", "h2", "h3", "h4", "h5", "h6"
*/
@@ -934,11 +965,64 @@ private function step_in_body() {
$this->run_adoption_agency_algorithm();
return true;
+ /*
+ * > An end tag whose tag name is "br"
+ * > Parse error. Drop the attributes from the token, and act as described in the next
+ * > entry; i.e. act as if this was a "br" start tag token with no attributes, rather
+ * > than the end tag token that it actually is.
+ */
+ case '-BR':
+ $this->last_error = self::ERROR_UNSUPPORTED;
+ throw new WP_HTML_Unsupported_Exception( 'Closing BR tags require unimplemented special handling.' );
+
/*
* > A start tag whose tag name is one of: "area", "br", "embed", "img", "keygen", "wbr"
*/
+ case '+AREA':
+ case '+BR':
+ case '+EMBED':
case '+IMG':
+ case '+KEYGEN':
+ case '+WBR':
$this->reconstruct_active_formatting_elements();
+ $this->insert_html_element( $this->state->current_token );
+ $this->state->frameset_ok = false;
+ return true;
+
+ /*
+ * > A start tag whose tag name is "input"
+ */
+ case '+INPUT':
+ $this->reconstruct_active_formatting_elements();
+ $this->insert_html_element( $this->state->current_token );
+ $type_attribute = $this->get_attribute( 'type' );
+ /*
+ * > If the token does not have an attribute with the name "type", or if it does,
+ * > but that attribute's value is not an ASCII case-insensitive match for the
+ * > string "hidden", then: set the frameset-ok flag to "not ok".
+ */
+ if ( ! is_string( $type_attribute ) || 'hidden' !== strtolower( $type_attribute ) ) {
+ $this->state->frameset_ok = false;
+ }
+ return true;
+
+ /*
+ * > A start tag whose tag name is "hr"
+ */
+ case '+HR':
+ if ( $this->state->stack_of_open_elements->has_p_in_button_scope() ) {
+ $this->close_a_p_element();
+ }
+ $this->insert_html_element( $this->state->current_token );
+ $this->state->frameset_ok = false;
+ return true;
+
+ /*
+ * > A start tag whose tag name is one of: "param", "source", "track"
+ */
+ case '+PARAM':
+ case '+SOURCE':
+ case '+TRACK':
$this->insert_html_element( $this->state->current_token );
return true;
}
@@ -961,30 +1045,20 @@ private function step_in_body() {
*/
switch ( $tag_name ) {
case 'APPLET':
- case 'AREA':
case 'BASE':
case 'BASEFONT':
case 'BGSOUND':
case 'BODY':
- case 'BR':
case 'CAPTION':
case 'COL':
case 'COLGROUP':
- case 'DD':
- case 'DT':
- case 'EMBED':
case 'FORM':
case 'FRAME':
case 'FRAMESET':
case 'HEAD':
- case 'HR':
case 'HTML':
case 'IFRAME':
- case 'INPUT':
- case 'KEYGEN':
- case 'LI':
case 'LINK':
- case 'LISTING':
case 'MARQUEE':
case 'MATH':
case 'META':
@@ -993,12 +1067,9 @@ private function step_in_body() {
case 'NOFRAMES':
case 'NOSCRIPT':
case 'OBJECT':
- case 'OL':
case 'OPTGROUP':
case 'OPTION':
- case 'PARAM':
case 'PLAINTEXT':
- case 'PRE':
case 'RB':
case 'RP':
case 'RT':
@@ -1006,7 +1077,6 @@ private function step_in_body() {
case 'SARCASM':
case 'SCRIPT':
case 'SELECT':
- case 'SOURCE':
case 'STYLE':
case 'SVG':
case 'TABLE':
@@ -1019,9 +1089,6 @@ private function step_in_body() {
case 'THEAD':
case 'TITLE':
case 'TR':
- case 'TRACK':
- case 'UL':
- case 'WBR':
case 'XMP':
$this->last_error = self::ERROR_UNSUPPORTED;
throw new WP_HTML_Unsupported_Exception( "Cannot process {$tag_name} element." );
@@ -1675,14 +1742,19 @@ public static function is_void( $tag_name ) {
return (
'AREA' === $tag_name ||
'BASE' === $tag_name ||
+ 'BASEFONT' === $tag_name || // Obsolete but still treated as void.
+ 'BGSOUND' === $tag_name || // Obsolete but still treated as void.
'BR' === $tag_name ||
'COL' === $tag_name ||
'EMBED' === $tag_name ||
+ 'FRAME' === $tag_name ||
'HR' === $tag_name ||
'IMG' === $tag_name ||
'INPUT' === $tag_name ||
+ 'KEYGEN' === $tag_name || // Obsolete but still treated as void.
'LINK' === $tag_name ||
'META' === $tag_name ||
+ 'PARAM' === $tag_name || // Obsolete but still treated as void.
'SOURCE' === $tag_name ||
'TRACK' === $tag_name ||
'WBR' === $tag_name
@@ -1711,6 +1783,15 @@ public static function is_void( $tag_name ) {
*/
const REPROCESS_CURRENT_NODE = 'reprocess-current-node';
+ /**
+ * Indicates that the current HTML token should be processed without advancing the parser.
+ *
+ * @since 6.5.0
+ *
+ * @var string
+ */
+ const PROCESS_CURRENT_NODE = 'process-current-node';
+
/**
* Indicates that the parser encountered unsupported markup and has bailed.
*
diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php
index ee6209c69e0ae..447f4dac1b6e2 100644
--- a/src/wp-includes/html-api/class-wp-html-tag-processor.php
+++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php
@@ -247,6 +247,95 @@
* }
* }
*
+ * ## Tokens and finer-grained processing.
+ *
+ * It's possible to scan through every lexical token in the
+ * HTML document using the `next_token()` function. This
+ * alternative form takes no argument and provides no built-in
+ * query syntax.
+ *
+ * Example:
+ *
+ * $title = '(untitled)';
+ * $text = '';
+ * while ( $processor->next_token() ) {
+ * switch ( $processor->get_token_name() ) {
+ * case '#text':
+ * $text .= $processor->get_modifiable_text();
+ * break;
+ *
+ * case 'BR':
+ * $text .= "\n";
+ * break;
+ *
+ * case 'TITLE':
+ * $title = $processor->get_modifiable_text();
+ * break;
+ * }
+ * }
+ * return trim( "# {$title}\n\n{$text}" );
+ *
+ * ### Tokens and _modifiable text_.
+ *
+ * #### Special "atomic" HTML elements.
+ *
+ * Not all HTML elements are able to contain other elements inside of them.
+ * For instance, the contents inside a TITLE element are plaintext (except
+ * that character references like & will be decoded). This means that
+ * if the string ` ` appears inside a TITLE element, then it's not an
+ * image tag, but rather it's text describing an image tag. Likewise, the
+ * contents of a SCRIPT or STYLE element are handled entirely separately in
+ * a browser than the contents of other elements because they represent a
+ * different language than HTML.
+ *
+ * For these elements the Tag Processor treats the entire sequence as one,
+ * from the opening tag, including its contents, through its closing tag.
+ * This means that the it's not possible to match the closing tag for a
+ * SCRIPT element unless it's unexpected; the Tag Processor already matched
+ * it when it found the opening tag.
+ *
+ * The inner contents of these elements are that element's _modifiable text_.
+ *
+ * The special elements are:
+ * - `SCRIPT` whose contents are treated as raw plaintext but supports a legacy
+ * style of including Javascript inside of HTML comments to avoid accidentally
+ * closing the SCRIPT from inside a Javascript string. E.g. `console.log( '' )`.
+ * - `TITLE` and `TEXTAREA` whose contents are treated as plaintext and then any
+ * character references are decoded. E.g. `1 < 2 < 3` becomes `1 < 2 < 3`.
+ * - `IFRAME`, `NOSCRIPT`, `NOEMBED`, `NOFRAME`, `STYLE` whose contents are treated as
+ * raw plaintext and left as-is. E.g. `1 < 2 < 3` remains `1 < 2 < 3`.
+ *
+ * #### Other tokens with modifiable text.
+ *
+ * There are also non-elements which are void/self-closing in nature and contain
+ * modifiable text that is part of that individual syntax token itself.
+ *
+ * - `#text` nodes, whose entire token _is_ the modifiable text.
+ * - HTML comments and tokens that become comments due to some syntax error. The
+ * text for these tokens is the portion of the comment inside of the syntax.
+ * E.g. for `` the text is `" comment "` (note the spaces are included).
+ * - `CDATA` sections, whose text is the content inside of the section itself. E.g. for
+ * `` the text is `"some content"` (with restrictions [1]).
+ * - "Funky comments," which are a special case of invalid closing tags whose name is
+ * invalid. The text for these nodes is the text that a browser would transform into
+ * an HTML comment when parsing. E.g. for `%post_author>` the text is `%post_author`.
+ * - `DOCTYPE` declarations like `` which have no closing tag.
+ * - XML Processing instruction nodes like `` (with restrictions [2]).
+ * - The empty end tag `>` which is ignored in the browser and DOM.
+ *
+ * [1]: There are no CDATA sections in HTML. When encountering `` becomes a bogus HTML comment, meaning there can be no CDATA
+ * section in an HTML document containing `>`. The Tag Processor will first find
+ * all valid and bogus HTML comments, and then if the comment _would_ have been a
+ * CDATA section _were they to exist_, it will indicate this as the type of comment.
+ *
+ * [2]: XML allows a broader range of characters in a processing instruction's target name
+ * and disallows "xml" as a name, since it's special. The Tag Processor only recognizes
+ * target names with an ASCII-representable subset of characters. It also exhibits the
+ * same constraint as with CDATA sections, in that `>` cannot exist within the token
+ * since Processing Instructions do no exist within HTML and their syntax transforms
+ * into a bogus comment in the DOM.
+ *
* ## Design and limitations
*
* The Tag Processor is designed to linearly scan HTML documents and tokenize
@@ -320,7 +409,8 @@
* @since 6.2.1 Fix: Support for various invalid comments; attribute updates are case-insensitive.
* @since 6.3.2 Fix: Skip HTML-like content inside rawtext elements such as STYLE.
* @since 6.5.0 Pauses processor when input ends in an incomplete syntax token.
- * Introduces "special" elements which act like void elements, e.g. STYLE.
+ * Introduces "special" elements which act like void elements, e.g. TITLE, STYLE.
+ * Allows scanning through all tokens and processing modifiable text, where applicable.
*/
class WP_HTML_Tag_Processor {
/**
@@ -396,23 +486,47 @@ class WP_HTML_Tag_Processor {
/**
* Specifies mode of operation of the parser at any given time.
*
- * | State | Meaning |
- * | --------------|----------------------------------------------------------------------|
- * | *Ready* | The parser is ready to run. |
- * | *Complete* | There is nothing left to parse. |
- * | *Incomplete* | The HTML ended in the middle of a token; nothing more can be parsed. |
- * | *Matched tag* | Found an HTML tag; it's possible to modify its attributes. |
+ * | State | Meaning |
+ * | ----------------|----------------------------------------------------------------------|
+ * | *Ready* | The parser is ready to run. |
+ * | *Complete* | There is nothing left to parse. |
+ * | *Incomplete* | The HTML ended in the middle of a token; nothing more can be parsed. |
+ * | *Matched tag* | Found an HTML tag; it's possible to modify its attributes. |
+ * | *Text node* | Found a #text node; this is plaintext and modifiable. |
+ * | *CDATA node* | Found a CDATA section; this is modifiable. |
+ * | *Comment* | Found a comment or bogus comment; this is modifiable. |
+ * | *Presumptuous* | Found an empty tag closer: `>`. |
+ * | *Funky comment* | Found a tag closer with an invalid tag name; this is modifiable. |
*
* @since 6.5.0
*
* @see WP_HTML_Tag_Processor::STATE_READY
* @see WP_HTML_Tag_Processor::STATE_COMPLETE
- * @see WP_HTML_Tag_Processor::STATE_INCOMPLETE
+ * @see WP_HTML_Tag_Processor::STATE_INCOMPLETE_INPUT
* @see WP_HTML_Tag_Processor::STATE_MATCHED_TAG
+ * @see WP_HTML_Tag_Processor::STATE_TEXT_NODE
+ * @see WP_HTML_Tag_Processor::STATE_CDATA_NODE
+ * @see WP_HTML_Tag_Processor::STATE_COMMENT
+ * @see WP_HTML_Tag_Processor::STATE_DOCTYPE
+ * @see WP_HTML_Tag_Processor::STATE_PRESUMPTUOUS_TAG
+ * @see WP_HTML_Tag_Processor::STATE_FUNKY_COMMENT
*
* @var string
*/
- private $parser_state = self::STATE_READY;
+ protected $parser_state = self::STATE_READY;
+
+ /**
+ * What kind of syntax token became an HTML comment.
+ *
+ * Since there are many ways in which HTML syntax can create an HTML comment,
+ * this indicates which of those caused it. This allows the Tag Processor to
+ * represent more from the original input document than would appear in the DOM.
+ *
+ * @since 6.5.0
+ *
+ * @var string|null
+ */
+ protected $comment_type = null;
/**
* How many bytes from the original HTML document have been read and parsed.
@@ -490,6 +604,24 @@ class WP_HTML_Tag_Processor {
*/
private $tag_name_length;
+ /**
+ * Byte offset into input document where current modifiable text starts.
+ *
+ * @since 6.5.0
+ *
+ * @var int
+ */
+ private $text_starts_at;
+
+ /**
+ * Byte length of modifiable text.
+ *
+ * @since 6.5.0
+ *
+ * @var string
+ */
+ private $text_length;
+
/**
* Whether the current tag is an opening tag, e.g. , or a closing tag, e.g.
.
*
@@ -705,13 +837,13 @@ public function next_tag( $query = null ) {
* @return bool Whether a token was parsed.
*/
public function next_token() {
- $this->get_updated_html();
$was_at = $this->bytes_already_parsed;
+ $this->get_updated_html();
// Don't proceed if there's nothing more to scan.
if (
self::STATE_COMPLETE === $this->parser_state ||
- self::STATE_INCOMPLETE === $this->parser_state
+ self::STATE_INCOMPLETE_INPUT === $this->parser_state
) {
return false;
}
@@ -729,13 +861,27 @@ public function next_token() {
// Find the next tag if it exists.
if ( false === $this->parse_next_tag() ) {
- if ( self::STATE_INCOMPLETE === $this->parser_state ) {
+ if ( self::STATE_INCOMPLETE_INPUT === $this->parser_state ) {
$this->bytes_already_parsed = $was_at;
}
return false;
}
+ /*
+ * For legacy reasons the rest of this function handles tags and their
+ * attributes. If the processor has reached the end of the document
+ * or if it matched any other token then it should return here to avoid
+ * attempting to process tag-specific syntax.
+ */
+ if (
+ self::STATE_INCOMPLETE_INPUT !== $this->parser_state &&
+ self::STATE_COMPLETE !== $this->parser_state &&
+ self::STATE_MATCHED_TAG !== $this->parser_state
+ ) {
+ return true;
+ }
+
// Parse all of its attributes.
while ( $this->parse_next_attribute() ) {
continue;
@@ -743,11 +889,11 @@ public function next_token() {
// Ensure that the tag closes before the end of the document.
if (
- self::STATE_INCOMPLETE === $this->parser_state ||
+ self::STATE_INCOMPLETE_INPUT === $this->parser_state ||
$this->bytes_already_parsed >= strlen( $this->html )
) {
// Does this appropriately clear state (parsed attributes)?
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
$this->bytes_already_parsed = $was_at;
return false;
@@ -755,14 +901,14 @@ public function next_token() {
$tag_ends_at = strpos( $this->html, '>', $this->bytes_already_parsed );
if ( false === $tag_ends_at ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
$this->bytes_already_parsed = $was_at;
return false;
}
$this->parser_state = self::STATE_MATCHED_TAG;
$this->token_length = $tag_ends_at - $this->token_starts_at;
- $this->bytes_already_parsed = $tag_ends_at;
+ $this->bytes_already_parsed = $tag_ends_at + 1;
/*
* For non-DATA sections which might contain text that looks like HTML tags but
@@ -771,8 +917,8 @@ public function next_token() {
*/
$t = $this->html[ $this->tag_name_starts_at ];
if (
- ! $this->is_closing_tag &&
- (
+ $this->is_closing_tag ||
+ ! (
'i' === $t || 'I' === $t ||
'n' === $t || 'N' === $t ||
's' === $t || 'S' === $t ||
@@ -780,38 +926,81 @@ public function next_token() {
'x' === $t || 'X' === $t
)
) {
- $tag_name = $this->get_tag();
+ return true;
+ }
- if ( 'SCRIPT' === $tag_name && ! $this->skip_script_data() ) {
- $this->parser_state = self::STATE_INCOMPLETE;
- $this->bytes_already_parsed = $was_at;
+ $tag_name = $this->get_tag();
- return false;
- } elseif (
- ( 'TEXTAREA' === $tag_name || 'TITLE' === $tag_name ) &&
- ! $this->skip_rcdata( $tag_name )
- ) {
- $this->parser_state = self::STATE_INCOMPLETE;
- $this->bytes_already_parsed = $was_at;
+ /*
+ * Preserve the opening tag pointers, as these will be overwritten
+ * when finding the closing tag. They will be reset after finding
+ * the closing to tag to point to the opening of the special atomic
+ * tag sequence.
+ */
+ $tag_name_starts_at = $this->tag_name_starts_at;
+ $tag_name_length = $this->tag_name_length;
+ $tag_ends_at = $this->token_starts_at + $this->token_length;
+ $attributes = $this->attributes;
+ $duplicate_attributes = $this->duplicate_attributes;
+
+ // Find the closing tag if necessary.
+ $found_closer = false;
+ switch ( $tag_name ) {
+ case 'SCRIPT':
+ $found_closer = $this->skip_script_data();
+ break;
- return false;
- } elseif (
- (
- 'IFRAME' === $tag_name ||
- 'NOEMBED' === $tag_name ||
- 'NOFRAMES' === $tag_name ||
- 'STYLE' === $tag_name ||
- 'XMP' === $tag_name
- ) &&
- ! $this->skip_rawtext( $tag_name )
- ) {
- $this->parser_state = self::STATE_INCOMPLETE;
- $this->bytes_already_parsed = $was_at;
+ case 'TEXTAREA':
+ case 'TITLE':
+ $found_closer = $this->skip_rcdata( $tag_name );
+ break;
- return false;
- }
+ /*
+ * In the browser this list would include the NOSCRIPT element,
+ * but the Tag Processor is an environment with the scripting
+ * flag disabled, meaning that it needs to descend into the
+ * NOSCRIPT element to be able to properly process what will be
+ * sent to a browser.
+ *
+ * Note that this rule makes HTML5 syntax incompatible with XML,
+ * because the parsing of this token depends on client application.
+ * The NOSCRIPT element cannot be represented in the XHTML syntax.
+ */
+ case 'IFRAME':
+ case 'NOEMBED':
+ case 'NOFRAMES':
+ case 'STYLE':
+ case 'XMP':
+ $found_closer = $this->skip_rawtext( $tag_name );
+ break;
+
+ // No other tags should be treated in their entirety here.
+ default:
+ return true;
+ }
+
+ if ( ! $found_closer ) {
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
+ $this->bytes_already_parsed = $was_at;
+ return false;
}
+ /*
+ * The values here look like they reference the opening tag but they reference
+ * the closing tag instead. This is why the opening tag values were stored
+ * above in a variable. It reads confusingly here, but that's because the
+ * functions that skip the contents have moved all the internal cursors past
+ * the inner content of the tag.
+ */
+ $this->token_starts_at = $was_at;
+ $this->token_length = $this->bytes_already_parsed - $this->token_starts_at;
+ $this->text_starts_at = $tag_ends_at + 1;
+ $this->text_length = $this->tag_name_starts_at - $this->text_starts_at;
+ $this->tag_name_starts_at = $tag_name_starts_at;
+ $this->tag_name_length = $tag_name_length;
+ $this->attributes = $attributes;
+ $this->duplicate_attributes = $duplicate_attributes;
+
return true;
}
@@ -830,7 +1019,7 @@ public function next_token() {
* @return bool Whether the parse paused at the start of an incomplete token.
*/
public function paused_at_incomplete_token() {
- return self::STATE_INCOMPLETE === $this->parser_state;
+ return self::STATE_INCOMPLETE_INPUT === $this->parser_state;
}
/**
@@ -1007,7 +1196,10 @@ public function has_class( $wanted_class ) {
*/
public function set_bookmark( $name ) {
// It only makes sense to set a bookmark if the parser has paused on a concrete token.
- if ( self::STATE_MATCHED_TAG !== $this->parser_state ) {
+ if (
+ self::STATE_COMPLETE === $this->parser_state ||
+ self::STATE_INCOMPLETE_INPUT === $this->parser_state
+ ) {
return false;
}
@@ -1082,15 +1274,15 @@ private function skip_rcdata( $tag_name ) {
$at = $this->bytes_already_parsed;
while ( false !== $at && $at < $doc_length ) {
- $at = strpos( $this->html, '', $at );
+ $at = strpos( $this->html, '', $at );
+ $this->tag_name_starts_at = $at;
// Fail if there is no possible tag closer.
if ( false === $at || ( $at + $tag_length ) >= $doc_length ) {
return false;
}
- $closer_potentially_starts_at = $at;
- $at += 2;
+ $at += 2;
/*
* Find a case-insensitive match to the tag name.
@@ -1131,13 +1323,23 @@ private function skip_rcdata( $tag_name ) {
while ( $this->parse_next_attribute() ) {
continue;
}
+
$at = $this->bytes_already_parsed;
if ( $at >= strlen( $this->html ) ) {
return false;
}
- if ( '>' === $html[ $at ] || '/' === $html[ $at ] ) {
- $this->bytes_already_parsed = $closer_potentially_starts_at;
+ if ( '>' === $html[ $at ] ) {
+ $this->bytes_already_parsed = $at + 1;
+ return true;
+ }
+
+ if ( $at + 1 >= strlen( $this->html ) ) {
+ return false;
+ }
+
+ if ( '/' === $html[ $at ] && '>' === $html[ $at + 1 ] ) {
+ $this->bytes_already_parsed = $at + 2;
return true;
}
}
@@ -1259,6 +1461,7 @@ private function skip_script_data() {
if ( $is_closing ) {
$this->bytes_already_parsed = $closer_potentially_starts_at;
+ $this->tag_name_starts_at = $closer_potentially_starts_at;
if ( $this->bytes_already_parsed >= $doc_length ) {
return false;
}
@@ -1268,13 +1471,13 @@ private function skip_script_data() {
}
if ( $this->bytes_already_parsed >= $doc_length ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
if ( '>' === $html[ $this->bytes_already_parsed ] ) {
- $this->bytes_already_parsed = $closer_potentially_starts_at;
+ ++$this->bytes_already_parsed;
return true;
}
}
@@ -1303,7 +1506,8 @@ private function parse_next_tag() {
$html = $this->html;
$doc_length = strlen( $html );
- $at = $this->bytes_already_parsed;
+ $was_at = $this->bytes_already_parsed;
+ $at = $was_at;
while ( false !== $at && $at < $doc_length ) {
$at = strpos( $html, '<', $at );
@@ -1313,7 +1517,50 @@ private function parse_next_tag() {
* can be nothing left in the document other than a #text node.
*/
if ( false === $at ) {
- return false;
+ $this->parser_state = self::STATE_TEXT_NODE;
+ $this->token_starts_at = $was_at;
+ $this->token_length = strlen( $html ) - $was_at;
+ $this->text_starts_at = $was_at;
+ $this->text_length = $this->token_length;
+ $this->bytes_already_parsed = strlen( $html );
+ return true;
+ }
+
+ if ( $at > $was_at ) {
+ /*
+ * A "<" normally starts a new HTML tag or syntax token, but in cases where the
+ * following character can't produce a valid token, the "<" is instead treated
+ * as plaintext and the parser should skip over it. This avoids a problem when
+ * following earlier practices of typing emoji with text, e.g. "<3". This
+ * should be a heart, not a tag. It's supposed to be rendered, not hidden.
+ *
+ * At this point the parser checks if this is one of those cases and if it is
+ * will continue searching for the next "<" in search of a token boundary.
+ *
+ * @see https://html.spec.whatwg.org/#tag-open-state
+ */
+ if ( strlen( $html ) > $at + 1 ) {
+ $next_character = $html[ $at + 1 ];
+ $at_another_node = (
+ '!' === $next_character ||
+ '/' === $next_character ||
+ '?' === $next_character ||
+ ( 'A' <= $next_character && $next_character <= 'Z' ) ||
+ ( 'a' <= $next_character && $next_character <= 'z' )
+ );
+ if ( ! $at_another_node ) {
+ ++$at;
+ continue;
+ }
+ }
+
+ $this->parser_state = self::STATE_TEXT_NODE;
+ $this->token_starts_at = $was_at;
+ $this->token_length = $at - $was_at;
+ $this->text_starts_at = $was_at;
+ $this->text_length = $this->token_length;
+ $this->bytes_already_parsed = $at;
+ return true;
}
$this->token_starts_at = $at;
@@ -1342,8 +1589,9 @@ private function parse_next_tag() {
$tag_name_prefix_length = strspn( $html, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', $at + 1 );
if ( $tag_name_prefix_length > 0 ) {
++$at;
- $this->tag_name_length = $tag_name_prefix_length + strcspn( $html, " \t\f\r\n/>", $at + $tag_name_prefix_length );
+ $this->parser_state = self::STATE_MATCHED_TAG;
$this->tag_name_starts_at = $at;
+ $this->tag_name_length = $tag_name_prefix_length + strcspn( $html, " \t\f\r\n/>", $at + $tag_name_prefix_length );
$this->bytes_already_parsed = $at + $this->tag_name_length;
return true;
}
@@ -1353,18 +1601,18 @@ private function parse_next_tag() {
* the document. There is nothing left to parse.
*/
if ( $at + 1 >= $doc_length ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
/*
- *
+ * ``. Unlike other comment
+ * and bogus comment syntax, these leave no clear insertion point for text and
+ * they need to be modified specially in order to contain text. E.g. to store
+ * `?` as the modifiable text, the `` needs to become ``, which
+ * involves inserting an additional `-` into the token after the modifiable text.
+ */
+ $this->parser_state = self::STATE_COMMENT;
+ $this->comment_type = self::COMMENT_AS_ABRUPTLY_CLOSED_COMMENT;
+ $this->token_length = $closer_at + $span_of_dashes + 1 - $this->token_starts_at;
+
+ // Only provide modifiable text if the token is long enough to contain it.
+ if ( $span_of_dashes >= 2 ) {
+ $this->comment_type = self::COMMENT_AS_HTML_COMMENT;
+ $this->text_starts_at = $this->token_starts_at + 4;
+ $this->text_length = $span_of_dashes - 2;
+ }
+
+ $this->bytes_already_parsed = $closer_at + $span_of_dashes + 1;
+ return true;
}
/*
@@ -1397,51 +1664,39 @@ private function parse_next_tag() {
while ( ++$closer_at < $doc_length ) {
$closer_at = strpos( $html, '--', $closer_at );
if ( false === $closer_at ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
if ( $closer_at + 2 < $doc_length && '>' === $html[ $closer_at + 2 ] ) {
- $at = $closer_at + 3;
- continue 2;
+ $this->parser_state = self::STATE_COMMENT;
+ $this->comment_type = self::COMMENT_AS_HTML_COMMENT;
+ $this->token_length = $closer_at + 3 - $this->token_starts_at;
+ $this->text_starts_at = $this->token_starts_at + 4;
+ $this->text_length = $closer_at - $this->text_starts_at;
+ $this->bytes_already_parsed = $closer_at + 3;
+ return true;
}
- if ( $closer_at + 3 < $doc_length && '!' === $html[ $closer_at + 2 ] && '>' === $html[ $closer_at + 3 ] ) {
- $at = $closer_at + 4;
- continue 2;
+ if (
+ $closer_at + 3 < $doc_length &&
+ '!' === $html[ $closer_at + 2 ] &&
+ '>' === $html[ $closer_at + 3 ]
+ ) {
+ $this->parser_state = self::STATE_COMMENT;
+ $this->comment_type = self::COMMENT_AS_HTML_COMMENT;
+ $this->token_length = $closer_at + 4 - $this->token_starts_at;
+ $this->text_starts_at = $this->token_starts_at + 4;
+ $this->text_length = $closer_at - $this->text_starts_at;
+ $this->bytes_already_parsed = $closer_at + 4;
+ return true;
}
}
}
/*
- *
- * The CDATA is case-sensitive.
- * https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
- */
- if (
- $doc_length > $at + 8 &&
- '[' === $html[ $at + 2 ] &&
- 'C' === $html[ $at + 3 ] &&
- 'D' === $html[ $at + 4 ] &&
- 'A' === $html[ $at + 5 ] &&
- 'T' === $html[ $at + 6 ] &&
- 'A' === $html[ $at + 7 ] &&
- '[' === $html[ $at + 8 ]
- ) {
- $closer_at = strpos( $html, ']]>', $at + 9 );
- if ( false === $closer_at ) {
- $this->parser_state = self::STATE_INCOMPLETE;
-
- return false;
- }
-
- $at = $closer_at + 3;
- continue;
- }
-
- /*
- *
+ * `
* These are ASCII-case-insensitive.
* https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
*/
@@ -1457,13 +1712,17 @@ private function parse_next_tag() {
) {
$closer_at = strpos( $html, '>', $at + 9 );
if ( false === $closer_at ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
- $at = $closer_at + 1;
- continue;
+ $this->parser_state = self::STATE_DOCTYPE;
+ $this->token_length = $closer_at + 1 - $this->token_starts_at;
+ $this->text_starts_at = $this->token_starts_at + 9;
+ $this->text_length = $closer_at - $this->text_starts_at;
+ $this->bytes_already_parsed = $closer_at + 1;
+ return true;
}
/*
@@ -1471,14 +1730,54 @@ private function parse_next_tag() {
* to the bogus comment state - skip to the nearest >. If no closer is
* found then the HTML was truncated inside the markup declaration.
*/
- $at = strpos( $html, '>', $at + 1 );
- if ( false === $at ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $closer_at = strpos( $html, '>', $at + 1 );
+ if ( false === $closer_at ) {
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
- continue;
+ $this->parser_state = self::STATE_COMMENT;
+ $this->comment_type = self::COMMENT_AS_INVALID_HTML;
+ $this->token_length = $closer_at + 1 - $this->token_starts_at;
+ $this->text_starts_at = $this->token_starts_at + 2;
+ $this->text_length = $closer_at - $this->text_starts_at;
+ $this->bytes_already_parsed = $closer_at + 1;
+
+ /*
+ * Identify nodes that would be CDATA if HTML had CDATA sections.
+ *
+ * This section must occur after identifying the bogus comment end
+ * because in an HTML parser it will span to the nearest `>`, even
+ * if there's no `]]>` as would be required in an XML document. It
+ * is therefore not possible to parse a CDATA section containing
+ * a `>` in the HTML syntax.
+ *
+ * Inside foreign elements there is a discrepancy between browsers
+ * and the specification on this.
+ *
+ * @todo Track whether the Tag Processor is inside a foreign element
+ * and require the proper closing `]]>` in those cases.
+ */
+ if (
+ $this->token_length >= 10 &&
+ '[' === $html[ $this->token_starts_at + 2 ] &&
+ 'C' === $html[ $this->token_starts_at + 3 ] &&
+ 'D' === $html[ $this->token_starts_at + 4 ] &&
+ 'A' === $html[ $this->token_starts_at + 5 ] &&
+ 'T' === $html[ $this->token_starts_at + 6 ] &&
+ 'A' === $html[ $this->token_starts_at + 7 ] &&
+ '[' === $html[ $this->token_starts_at + 8 ] &&
+ ']' === $html[ $closer_at - 1 ] &&
+ ']' === $html[ $closer_at - 2 ]
+ ) {
+ $this->parser_state = self::STATE_COMMENT;
+ $this->comment_type = self::COMMENT_AS_CDATA_LOOKALIKE;
+ $this->text_starts_at += 7;
+ $this->text_length -= 9;
+ }
+
+ return true;
}
/*
@@ -1491,30 +1790,80 @@ private function parse_next_tag() {
* See https://html.spec.whatwg.org/#parse-error-missing-end-tag-name
*/
if ( '>' === $html[ $at + 1 ] ) {
- ++$at;
- continue;
+ $this->parser_state = self::STATE_PRESUMPTUOUS_TAG;
+ $this->token_length = $at + 2 - $this->token_starts_at;
+ $this->bytes_already_parsed = $at + 2;
+ return true;
}
/*
- * transitions to a bogus comment state – skip to the nearest >
+ * `` transitions to a bogus comment state – skip to the nearest >
* See https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state
*/
if ( '?' === $html[ $at + 1 ] ) {
$closer_at = strpos( $html, '>', $at + 2 );
if ( false === $closer_at ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
- $at = $closer_at + 1;
- continue;
+ $this->parser_state = self::STATE_COMMENT;
+ $this->comment_type = self::COMMENT_AS_INVALID_HTML;
+ $this->token_length = $closer_at + 1 - $this->token_starts_at;
+ $this->text_starts_at = $this->token_starts_at + 2;
+ $this->text_length = $closer_at - $this->text_starts_at;
+ $this->bytes_already_parsed = $closer_at + 1;
+
+ /*
+ * Identify a Processing Instruction node were HTML to have them.
+ *
+ * This section must occur after identifying the bogus comment end
+ * because in an HTML parser it will span to the nearest `>`, even
+ * if there's no `?>` as would be required in an XML document. It
+ * is therefore not possible to parse a Processing Instruction node
+ * containing a `>` in the HTML syntax.
+ *
+ * XML allows for more target names, but this code only identifies
+ * those with ASCII-representable target names. This means that it
+ * may identify some Processing Instruction nodes as bogus comments,
+ * but it will not misinterpret the HTML structure. By limiting the
+ * identification to these target names the Tag Processor can avoid
+ * the need to start parsing UTF-8 sequences.
+ *
+ * > NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] |
+ * [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] |
+ * [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] |
+ * [#x10000-#xEFFFF]
+ * > NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040]
+ *
+ * @see https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-PITarget
+ */
+ if ( $this->token_length >= 5 && '?' === $html[ $closer_at - 1 ] ) {
+ $comment_text = substr( $html, $this->token_starts_at + 2, $this->token_length - 4 );
+ $pi_target_length = strspn( $comment_text, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:_' );
+
+ if ( 0 < $pi_target_length ) {
+ $pi_target_length += strspn( $comment_text, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:_-.', $pi_target_length );
+
+ $this->comment_type = self::COMMENT_AS_PI_NODE_LOOKALIKE;
+ $this->tag_name_starts_at = $this->token_starts_at + 2;
+ $this->tag_name_length = $pi_target_length;
+ $this->text_starts_at += $pi_target_length;
+ $this->text_length -= $pi_target_length + 1;
+ }
+ }
+
+ return true;
}
/*
* If a non-alpha starts the tag name in a tag closer it's a comment.
* Find the first `>`, which closes the comment.
*
+ * This parser classifies these particular comments as special "funky comments"
+ * which are made available for further processing.
+ *
* See https://html.spec.whatwg.org/#parse-error-invalid-first-character-of-tag-name
*/
if ( $this->is_closing_tag ) {
@@ -1525,13 +1874,17 @@ private function parse_next_tag() {
$closer_at = strpos( $html, '>', $at + 3 );
if ( false === $closer_at ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
- $at = $closer_at + 1;
- continue;
+ $this->parser_state = self::STATE_FUNKY_COMMENT;
+ $this->token_length = $closer_at + 1 - $this->token_starts_at;
+ $this->text_starts_at = $this->token_starts_at + 2;
+ $this->text_length = $closer_at - $this->text_starts_at;
+ $this->bytes_already_parsed = $closer_at + 1;
+ return true;
}
++$at;
@@ -1551,7 +1904,7 @@ private function parse_next_attribute() {
// Skip whitespace and slashes.
$this->bytes_already_parsed += strspn( $this->html, " \t\f\r\n/", $this->bytes_already_parsed );
if ( $this->bytes_already_parsed >= strlen( $this->html ) ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
@@ -1575,14 +1928,14 @@ private function parse_next_attribute() {
$attribute_name = substr( $this->html, $attribute_start, $name_length );
$this->bytes_already_parsed += $name_length;
if ( $this->bytes_already_parsed >= strlen( $this->html ) ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
$this->skip_whitespace();
if ( $this->bytes_already_parsed >= strlen( $this->html ) ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
@@ -1592,7 +1945,7 @@ private function parse_next_attribute() {
++$this->bytes_already_parsed;
$this->skip_whitespace();
if ( $this->bytes_already_parsed >= strlen( $this->html ) ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
@@ -1620,7 +1973,7 @@ private function parse_next_attribute() {
}
if ( $attribute_end >= strlen( $this->html ) ) {
- $this->parser_state = self::STATE_INCOMPLETE;
+ $this->parser_state = self::STATE_INCOMPLETE_INPUT;
return false;
}
@@ -1692,8 +2045,11 @@ private function after_tag() {
$this->token_length = null;
$this->tag_name_starts_at = null;
$this->tag_name_length = null;
+ $this->text_starts_at = 0;
+ $this->text_length = 0;
$this->is_closing_tag = null;
$this->attributes = array();
+ $this->comment_type = null;
$this->duplicate_attributes = null;
}
@@ -1985,7 +2341,8 @@ public function seek( $bookmark_name ) {
// Point this tag processor before the sought tag opener and consume it.
$this->bytes_already_parsed = $this->bookmarks[ $bookmark_name ]->start;
- return $this->next_tag( array( 'tag_closers' => 'visit' ) );
+ $this->parser_state = self::STATE_READY;
+ return $this->next_token();
}
/**
@@ -2216,13 +2573,24 @@ public function get_attribute_names_with_prefix( $prefix ) {
* @return string|null Name of currently matched tag in input HTML, or `null` if none found.
*/
public function get_tag() {
- if ( self::STATE_MATCHED_TAG !== $this->parser_state ) {
+ if ( null === $this->tag_name_starts_at ) {
return null;
}
$tag_name = substr( $this->html, $this->tag_name_starts_at, $this->tag_name_length );
- return strtoupper( $tag_name );
+ if ( self::STATE_MATCHED_TAG === $this->parser_state ) {
+ return strtoupper( $tag_name );
+ }
+
+ if (
+ self::STATE_COMMENT === $this->parser_state &&
+ self::COMMENT_AS_PI_NODE_LOOKALIKE === $this->get_comment_type()
+ ) {
+ return $tag_name;
+ }
+
+ return null;
}
/**
@@ -2281,6 +2649,191 @@ public function is_tag_closer() {
);
}
+ /**
+ * Indicates the kind of matched token, if any.
+ *
+ * This differs from `get_token_name()` in that it always
+ * returns a static string indicating the type, whereas
+ * `get_token_name()` may return values derived from the
+ * token itself, such as a tag name or processing
+ * instruction tag.
+ *
+ * Possible values:
+ * - `#tag` when matched on a tag.
+ * - `#text` when matched on a text node.
+ * - `#cdata-section` when matched on a CDATA node.
+ * - `#comment` when matched on a comment.
+ * - `#doctype` when matched on a DOCTYPE declaration.
+ * - `#presumptuous-tag` when matched on an empty tag closer.
+ * - `#funky-comment` when matched on a funky comment.
+ *
+ * @since 6.5.0
+ *
+ * @return string|null What kind of token is matched, or null.
+ */
+ public function get_token_type() {
+ switch ( $this->parser_state ) {
+ case self::STATE_MATCHED_TAG:
+ return '#tag';
+
+ case self::STATE_DOCTYPE:
+ return '#doctype';
+
+ default:
+ return $this->get_token_name();
+ }
+ }
+
+ /**
+ * Returns the node name represented by the token.
+ *
+ * This matches the DOM API value `nodeName`. Some values
+ * are static, such as `#text` for a text node, while others
+ * are dynamically generated from the token itself.
+ *
+ * Dynamic names:
+ * - Uppercase tag name for tag matches.
+ * - `html` for DOCTYPE declarations.
+ *
+ * Note that if the Tag Processor is not matched on a token
+ * then this function will return `null`, either because it
+ * hasn't yet found a token or because it reached the end
+ * of the document without matching a token.
+ *
+ * @since 6.5.0
+ *
+ * @return string|null Name of the matched token.
+ */
+ public function get_token_name() {
+ switch ( $this->parser_state ) {
+ case self::STATE_MATCHED_TAG:
+ return $this->get_tag();
+
+ case self::STATE_TEXT_NODE:
+ return '#text';
+
+ case self::STATE_CDATA_NODE:
+ return '#cdata-section';
+
+ case self::STATE_COMMENT:
+ return '#comment';
+
+ case self::STATE_DOCTYPE:
+ return 'html';
+
+ case self::STATE_PRESUMPTUOUS_TAG:
+ return '#presumptuous-tag';
+
+ case self::STATE_FUNKY_COMMENT:
+ return '#funky-comment';
+ }
+ }
+
+ /**
+ * Indicates what kind of comment produced the comment node.
+ *
+ * Because there are different kinds of HTML syntax which produce
+ * comments, the Tag Processor tracks and exposes this as a type
+ * for the comment. Nominally only regular HTML comments exist as
+ * they are commonly known, but a number of unrelated syntax errors
+ * also produce comments.
+ *
+ * @see self::COMMENT_AS_ABRUPTLY_CLOSED_COMMENT
+ * @see self::COMMENT_AS_CDATA_LOOKALIKE
+ * @see self::COMMENT_AS_INVALID_HTML
+ * @see self::COMMENT_AS_HTML_COMMENT
+ * @see self::COMMENT_AS_PI_NODE_LOOKALIKE
+ *
+ * @since 6.5.0
+ *
+ * @return string|null
+ */
+ public function get_comment_type() {
+ if ( self::STATE_COMMENT !== $this->parser_state ) {
+ return null;
+ }
+
+ return $this->comment_type;
+ }
+
+ /**
+ * Returns the modifiable text for a matched token, or an empty string.
+ *
+ * Modifiable text is text content that may be read and changed without
+ * changing the HTML structure of the document around it. This includes
+ * the contents of `#text` nodes in the HTML as well as the inner
+ * contents of HTML comments, Processing Instructions, and others, even
+ * though these nodes aren't part of a parsed DOM tree. They also contain
+ * the contents of SCRIPT and STYLE tags, of TEXTAREA tags, and of any
+ * other section in an HTML document which cannot contain HTML markup (DATA).
+ *
+ * If a token has no modifiable text then an empty string is returned to
+ * avoid needless crashing or type errors. An empty string does not mean
+ * that a token has modifiable text, and a token with modifiable text may
+ * have an empty string (e.g. a comment with no contents).
+ *
+ * @since 6.5.0
+ *
+ * @return string
+ */
+ public function get_modifiable_text() {
+ if ( null === $this->text_starts_at ) {
+ return '';
+ }
+
+ $text = substr( $this->html, $this->text_starts_at, $this->text_length );
+
+ // Comment data is not decoded.
+ if (
+ self::STATE_CDATA_NODE === $this->parser_state ||
+ self::STATE_COMMENT === $this->parser_state ||
+ self::STATE_DOCTYPE === $this->parser_state ||
+ self::STATE_FUNKY_COMMENT === $this->parser_state
+ ) {
+ return $text;
+ }
+
+ $tag_name = $this->get_tag();
+ if (
+ // Script data is not decoded.
+ 'SCRIPT' === $tag_name ||
+
+ // RAWTEXT data is not decoded.
+ 'IFRAME' === $tag_name ||
+ 'NOEMBED' === $tag_name ||
+ 'NOFRAMES' === $tag_name ||
+ 'STYLE' === $tag_name ||
+ 'XMP' === $tag_name
+ ) {
+ return $text;
+ }
+
+ $decoded = html_entity_decode( $text, ENT_QUOTES | ENT_HTML5 | ENT_SUBSTITUTE );
+
+ if ( empty( $decoded ) ) {
+ return '';
+ }
+
+ /*
+ * TEXTAREA skips a leading newline, but this newline may appear not only as the
+ * literal character `\n`, but also as a character reference, such as in the
+ * following markup: ``.
+ *
+ * For these cases it's important to first decode the text content before checking
+ * for a leading newline and removing it.
+ */
+ if (
+ self::STATE_MATCHED_TAG === $this->parser_state &&
+ 'TEXTAREA' === $tag_name &&
+ strlen( $decoded ) > 0 &&
+ "\n" === $decoded[0]
+ ) {
+ return substr( $decoded, 1 );
+ }
+
+ return $decoded;
+ }
+
/**
* Updates or creates a new attribute on the currently matched tag with the passed value.
*
@@ -2746,7 +3299,7 @@ private function matches() {
}
/**
- * Parser Ready State
+ * Parser Ready State.
*
* Indicates that the parser is ready to run and waiting for a state transition.
* It may not have started yet, or it may have just finished parsing a token and
@@ -2759,7 +3312,7 @@ private function matches() {
const STATE_READY = 'STATE_READY';
/**
- * Parser Complete State
+ * Parser Complete State.
*
* Indicates that the parser has reached the end of the document and there is
* nothing left to scan. It finished parsing the last token completely.
@@ -2771,7 +3324,7 @@ private function matches() {
const STATE_COMPLETE = 'STATE_COMPLETE';
/**
- * Parser Incomplete State
+ * Parser Incomplete Input State.
*
* Indicates that the parser has reached the end of the document before finishing
* a token. It started parsing a token but there is a possibility that the input
@@ -2784,10 +3337,10 @@ private function matches() {
*
* @access private
*/
- const STATE_INCOMPLETE = 'STATE_INCOMPLETE';
+ const STATE_INCOMPLETE_INPUT = 'STATE_INCOMPLETE_INPUT';
/**
- * Parser Matched Tag State
+ * Parser Matched Tag State.
*
* Indicates that the parser has found an HTML tag and it's possible to get
* the tag name and read or modify its attributes (if it's not a closing tag).
@@ -2797,4 +3350,153 @@ private function matches() {
* @access private
*/
const STATE_MATCHED_TAG = 'STATE_MATCHED_TAG';
+
+ /**
+ * Parser Text Node State.
+ *
+ * Indicates that the parser has found a text node and it's possible
+ * to read and modify that text.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ */
+ const STATE_TEXT_NODE = 'STATE_TEXT_NODE';
+
+ /**
+ * Parser CDATA Node State.
+ *
+ * Indicates that the parser has found a CDATA node and it's possible
+ * to read and modify its modifiable text. Note that in HTML there are
+ * no CDATA nodes outside of foreign content (SVG and MathML). Outside
+ * of foreign content, they are treated as HTML comments.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ */
+ const STATE_CDATA_NODE = 'STATE_CDATA_NODE';
+
+ /**
+ * Indicates that the parser has found an HTML comment and it's
+ * possible to read and modify its modifiable text.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ */
+ const STATE_COMMENT = 'STATE_COMMENT';
+
+ /**
+ * Indicates that the parser has found a DOCTYPE node and it's
+ * possible to read and modify its modifiable text.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ */
+ const STATE_DOCTYPE = 'STATE_DOCTYPE';
+
+ /**
+ * Indicates that the parser has found an empty tag closer `>`.
+ *
+ * Note that in HTML there are no empty tag closers, and they
+ * are ignored. Nonetheless, the Tag Processor still
+ * recognizes them as they appear in the HTML stream.
+ *
+ * These were historically discussed as a "presumptuous tag
+ * closer," which would close the nearest open tag, but were
+ * dismissed in favor of explicitly-closing tags.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ */
+ const STATE_PRESUMPTUOUS_TAG = 'STATE_PRESUMPTUOUS_TAG';
+
+ /**
+ * Indicates that the parser has found a "funky comment"
+ * and it's possible to read and modify its modifiable text.
+ *
+ * Example:
+ *
+ * %url>
+ * {"wp-bit":"query/post-author"}>
+ * 2>
+ *
+ * Funky comments are tag closers with invalid tag names. Note
+ * that in HTML these are turn into bogus comments. Nonetheless,
+ * the Tag Processor recognizes them in a stream of HTML and
+ * exposes them for inspection and modification.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ */
+ const STATE_FUNKY_COMMENT = 'STATE_WP_FUNKY';
+
+ /**
+ * Indicates that a comment was created when encountering abruptly-closed HTML comment.
+ *
+ * Example:
+ *
+ *
+ *
+ *
+ * @since 6.5.0
+ */
+ const COMMENT_AS_ABRUPTLY_CLOSED_COMMENT = 'COMMENT_AS_ABRUPTLY_CLOSED_COMMENT';
+
+ /**
+ * Indicates that a comment would be parsed as a CDATA node,
+ * were HTML to allow CDATA nodes outside of foreign content.
+ *
+ * Example:
+ *
+ *
+ *
+ * This is an HTML comment, but it looks like a CDATA node.
+ *
+ * @since 6.5.0
+ */
+ const COMMENT_AS_CDATA_LOOKALIKE = 'COMMENT_AS_CDATA_LOOKALIKE';
+
+ /**
+ * Indicates that a comment was created when encountering
+ * normative HTML comment syntax.
+ *
+ * Example:
+ *
+ *
+ *
+ * @since 6.5.0
+ */
+ const COMMENT_AS_HTML_COMMENT = 'COMMENT_AS_HTML_COMMENT';
+
+ /**
+ * Indicates that a comment would be parsed as a Processing
+ * Instruction node, were they to exist within HTML.
+ *
+ * Example:
+ *
+ *
+ *
+ * This is an HTML comment, but it looks like a CDATA node.
+ *
+ * @since 6.5.0
+ */
+ const COMMENT_AS_PI_NODE_LOOKALIKE = 'COMMENT_AS_PI_NODE_LOOKALIKE';
+
+ /**
+ * Indicates that a comment was created when encountering invalid
+ * HTML input, a so-called "bogus comment."
+ *
+ * Example:
+ *
+ *
+ *
+ *
+ * @since 6.5.0
+ */
+ const COMMENT_AS_INVALID_HTML = 'COMMENT_AS_INVALID_HTML';
}
diff --git a/src/wp-includes/images/smilies/icon_cry.gif b/src/wp-includes/images/smilies/icon_cry.gif
index b78b2b33fc5a3..15a571ff7b0b1 100644
Binary files a/src/wp-includes/images/smilies/icon_cry.gif and b/src/wp-includes/images/smilies/icon_cry.gif differ
diff --git a/src/wp-includes/images/smilies/icon_lol.gif b/src/wp-includes/images/smilies/icon_lol.gif
index 83bcad32b5c97..4ad3baa3a7fa8 100644
Binary files a/src/wp-includes/images/smilies/icon_lol.gif and b/src/wp-includes/images/smilies/icon_lol.gif differ
diff --git a/src/wp-includes/images/smilies/icon_redface.gif b/src/wp-includes/images/smilies/icon_redface.gif
index c837b6276bfc3..6dd3a617fed9b 100644
Binary files a/src/wp-includes/images/smilies/icon_redface.gif and b/src/wp-includes/images/smilies/icon_redface.gif differ
diff --git a/src/wp-includes/images/smilies/icon_rolleyes.gif b/src/wp-includes/images/smilies/icon_rolleyes.gif
index 20fbc902abd5c..f038278b88a07 100644
Binary files a/src/wp-includes/images/smilies/icon_rolleyes.gif and b/src/wp-includes/images/smilies/icon_rolleyes.gif differ
diff --git a/src/wp-includes/images/wpspin-2x.gif b/src/wp-includes/images/wpspin-2x.gif
index 08e47e8211c4d..978f585b983b2 100644
Binary files a/src/wp-includes/images/wpspin-2x.gif and b/src/wp-includes/images/wpspin-2x.gif differ
diff --git a/src/wp-includes/images/wpspin.gif b/src/wp-includes/images/wpspin.gif
index fbf9be46c1094..b9b7ae4875168 100644
Binary files a/src/wp-includes/images/wpspin.gif and b/src/wp-includes/images/wpspin.gif differ
diff --git a/src/wp-includes/images/xit.gif b/src/wp-includes/images/xit.gif
index b11c5d43e9bce..9e62856adb47e 100644
Binary files a/src/wp-includes/images/xit.gif and b/src/wp-includes/images/xit.gif differ
diff --git a/src/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php b/src/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php
new file mode 100644
index 0000000000000..24201e82fdd0a
--- /dev/null
+++ b/src/wp-includes/interactivity-api/class-wp-interactivity-api-directives-processor.php
@@ -0,0 +1,244 @@
+get_tag() ) {
+ return null;
+ }
+
+ $positions = $this->get_after_opener_tag_and_before_closer_tag_positions();
+ if ( ! $positions ) {
+ return null;
+ }
+ list( $after_opener_tag, $before_closer_tag ) = $positions;
+
+ return substr( $this->html, $after_opener_tag, $before_closer_tag - $after_opener_tag );
+ }
+
+ /**
+ * Sets the content between two balanced tags.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ *
+ * @param string $new_content The string to replace the content between the matching tags.
+ * @return bool Whether the content was successfully replaced.
+ */
+ public function set_content_between_balanced_tags( string $new_content ): bool {
+ $positions = $this->get_after_opener_tag_and_before_closer_tag_positions( true );
+ if ( ! $positions ) {
+ return false;
+ }
+ list( $after_opener_tag, $before_closer_tag ) = $positions;
+
+ $this->lexical_updates[] = new WP_HTML_Text_Replacement(
+ $after_opener_tag,
+ $before_closer_tag - $after_opener_tag,
+ esc_html( $new_content )
+ );
+
+ return true;
+ }
+
+ /**
+ * Appends content after the closing tag of a template tag.
+ *
+ * It positions the cursor in the closer tag of the balanced template tag,
+ * if it exists.
+ *
+ * @access private
+ *
+ * @param string $new_content The string to append after the closing template tag.
+ * @return bool Whether the content was successfully appended.
+ */
+ public function append_content_after_template_tag_closer( string $new_content ): bool {
+ if ( empty( $new_content ) || 'TEMPLATE' !== $this->get_tag() || ! $this->is_tag_closer() ) {
+ return false;
+ }
+
+ // Flushes any changes.
+ $this->get_updated_html();
+
+ $bookmark = 'append_content_after_template_tag_closer';
+ $this->set_bookmark( $bookmark );
+ $after_closing_tag = $this->bookmarks[ $bookmark ]->start + $this->bookmarks[ $bookmark ]->length + 1;
+ $this->release_bookmark( $bookmark );
+
+ // Appends the new content.
+ $this->lexical_updates[] = new WP_HTML_Text_Replacement( $after_closing_tag, 0, $new_content );
+
+ return true;
+ }
+
+ /**
+ * Gets the positions right after the opener tag and right before the closer
+ * tag in a balanced tag.
+ *
+ * By default, it positions the cursor in the closer tag of the balanced tag.
+ * If $rewind is true, it seeks back to the opener tag.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ *
+ * @param bool $rewind Optional. Whether to seek back to the opener tag after finding the positions. Defaults to false.
+ * @return array|null Start and end byte position, or null when no balanced tag bookmarks.
+ */
+ private function get_after_opener_tag_and_before_closer_tag_positions( bool $rewind = false ) {
+ // Flushes any changes.
+ $this->get_updated_html();
+
+ $bookmarks = $this->get_balanced_tag_bookmarks();
+ if ( ! $bookmarks ) {
+ return null;
+ }
+ list( $opener_tag, $closer_tag ) = $bookmarks;
+
+ $after_opener_tag = $this->bookmarks[ $opener_tag ]->start + $this->bookmarks[ $opener_tag ]->length + 1;
+ $before_closer_tag = $this->bookmarks[ $closer_tag ]->start;
+
+ if ( $rewind ) {
+ $this->seek( $opener_tag );
+ }
+
+ $this->release_bookmark( $opener_tag );
+ $this->release_bookmark( $closer_tag );
+
+ return array( $after_opener_tag, $before_closer_tag );
+ }
+
+ /**
+ * Returns a pair of bookmarks for the current opener tag and the matching
+ * closer tag.
+ *
+ * It positions the cursor in the closer tag of the balanced tag, if it
+ * exists.
+ *
+ * @since 6.5.0
+ *
+ * @return array|null A pair of bookmarks, or null if there's no matching closing tag.
+ */
+ private function get_balanced_tag_bookmarks() {
+ static $i = 0;
+ $opener_tag = 'opener_tag_of_balanced_tag_' . ++$i;
+
+ $this->set_bookmark( $opener_tag );
+ if ( ! $this->next_balanced_tag_closer_tag() ) {
+ $this->release_bookmark( $opener_tag );
+ return null;
+ }
+
+ $closer_tag = 'closer_tag_of_balanced_tag_' . ++$i;
+ $this->set_bookmark( $closer_tag );
+
+ return array( $opener_tag, $closer_tag );
+ }
+
+ /**
+ * Finds the matching closing tag for an opening tag.
+ *
+ * When called while the processor is on an open tag, it traverses the HTML
+ * until it finds the matching closer tag, respecting any in-between content,
+ * including nested tags of the same name. Returns false when called on a
+ * closer tag, a tag that doesn't have a closer tag (void), a tag that
+ * doesn't visit the closer tag, or if no matching closing tag was found.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ *
+ * @return bool Whether a matching closing tag was found.
+ */
+ public function next_balanced_tag_closer_tag(): bool {
+ $depth = 0;
+ $tag_name = $this->get_tag();
+
+ if ( ! $this->has_and_visits_its_closer_tag() ) {
+ return false;
+ }
+
+ while ( $this->next_tag(
+ array(
+ 'tag_name' => $tag_name,
+ 'tag_closers' => 'visit',
+ )
+ ) ) {
+ if ( ! $this->is_tag_closer() ) {
+ ++$depth;
+ continue;
+ }
+
+ if ( 0 === $depth ) {
+ return true;
+ }
+
+ --$depth;
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks whether the current tag has and will visit its matching closer tag.
+ *
+ * @since 6.5.0
+ *
+ * @access private
+ *
+ * @return bool Whether the current tag has a closer tag.
+ */
+ public function has_and_visits_its_closer_tag(): bool {
+ $tag_name = $this->get_tag();
+
+ return null !== $tag_name && (
+ ! WP_HTML_Processor::is_void( $tag_name ) &&
+ ! in_array( $tag_name, self::TAGS_THAT_DONT_VISIT_CLOSER_TAG, true )
+ );
+ }
+}
diff --git a/src/wp-includes/interactivity-api/class-wp-interactivity-api.php b/src/wp-includes/interactivity-api/class-wp-interactivity-api.php
new file mode 100644
index 0000000000000..bb491a54f4ee2
--- /dev/null
+++ b/src/wp-includes/interactivity-api/class-wp-interactivity-api.php
@@ -0,0 +1,950 @@
+ 'data_wp_interactive_processor',
+ 'data-wp-router-region' => 'data_wp_router_region_processor',
+ 'data-wp-context' => 'data_wp_context_processor',
+ 'data-wp-bind' => 'data_wp_bind_processor',
+ 'data-wp-class' => 'data_wp_class_processor',
+ 'data-wp-style' => 'data_wp_style_processor',
+ 'data-wp-text' => 'data_wp_text_processor',
+ /*
+ * `data-wp-each` needs to be processed in the last place because it moves
+ * the cursor to the end of the processed items to prevent them to be
+ * processed twice.
+ */
+ 'data-wp-each' => 'data_wp_each_processor',
+ );
+
+ /**
+ * Holds the initial state of the different Interactivity API stores.
+ *
+ * This state is used during the server directive processing. Then, it is
+ * serialized and sent to the client as part of the interactivity data to be
+ * recovered during the hydration of the client interactivity stores.
+ *
+ * @since 6.5.0
+ * @var array
+ */
+ private $state_data = array();
+
+ /**
+ * Holds the configuration required by the different Interactivity API stores.
+ *
+ * This configuration is serialized and sent to the client as part of the
+ * interactivity data and can be accessed by the client interactivity stores.
+ *
+ * @since 6.5.0
+ * @var array
+ */
+ private $config_data = array();
+
+ /**
+ * Flag that indicates whether the `data-wp-router-region` directive has
+ * been found in the HTML and processed.
+ *
+ * The value is saved in a private property of the WP_Interactivity_API
+ * instance instead of using a static variable inside the processor
+ * function, which would hold the same value for all instances
+ * independently of whether they have processed any
+ * `data-wp-router-region` directive or not.
+ *
+ * @since 6.5.0
+ * @var bool
+ */
+ private $has_processed_router_region = false;
+
+ /**
+ * Gets and/or sets the initial state of an Interactivity API store for a
+ * given namespace.
+ *
+ * If state for that store namespace already exists, it merges the new
+ * provided state with the existing one.
+ *
+ * @since 6.5.0
+ *
+ * @param string $store_namespace The unique store namespace identifier.
+ * @param array $state Optional. The array that will be merged with the existing state for the specified
+ * store namespace.
+ * @return array The current state for the specified store namespace. This will be the updated state if a $state
+ * argument was provided.
+ */
+ public function state( string $store_namespace, array $state = array() ): array {
+ if ( ! isset( $this->state_data[ $store_namespace ] ) ) {
+ $this->state_data[ $store_namespace ] = array();
+ }
+ if ( is_array( $state ) ) {
+ $this->state_data[ $store_namespace ] = array_replace_recursive(
+ $this->state_data[ $store_namespace ],
+ $state
+ );
+ }
+ return $this->state_data[ $store_namespace ];
+ }
+
+ /**
+ * Gets and/or sets the configuration of the Interactivity API for a given
+ * store namespace.
+ *
+ * If configuration for that store namespace exists, it merges the new
+ * provided configuration with the existing one.
+ *
+ * @since 6.5.0
+ *
+ * @param string $store_namespace The unique store namespace identifier.
+ * @param array $config Optional. The array that will be merged with the existing configuration for the
+ * specified store namespace.
+ * @return array The configuration for the specified store namespace. This will be the updated configuration if a
+ * $config argument was provided.
+ */
+ public function config( string $store_namespace, array $config = array() ): array {
+ if ( ! isset( $this->config_data[ $store_namespace ] ) ) {
+ $this->config_data[ $store_namespace ] = array();
+ }
+ if ( is_array( $config ) ) {
+ $this->config_data[ $store_namespace ] = array_replace_recursive(
+ $this->config_data[ $store_namespace ],
+ $config
+ );
+ }
+ return $this->config_data[ $store_namespace ];
+ }
+
+ /**
+ * Prints the serialized client-side interactivity data.
+ *
+ * Encodes the config and initial state into JSON and prints them inside a
+ * script tag of type "application/json". Once in the browser, the state will
+ * be parsed and used to hydrate the client-side interactivity stores and the
+ * configuration will be available using a `getConfig` utility.
+ *
+ * @since 6.5.0
+ */
+ public function print_client_interactivity_data() {
+ $store = array();
+ $has_state = ! empty( $this->state_data );
+ $has_config = ! empty( $this->config_data );
+
+ if ( $has_state || $has_config ) {
+ if ( $has_config ) {
+ $store['config'] = $this->config_data;
+ }
+ if ( $has_state ) {
+ $store['state'] = $this->state_data;
+ }
+ wp_print_inline_script_tag(
+ wp_json_encode(
+ $store,
+ JSON_HEX_TAG | JSON_HEX_AMP
+ ),
+ array(
+ 'type' => 'application/json',
+ 'id' => 'wp-interactivity-data',
+ )
+ );
+ }
+ }
+
+ /**
+ * Registers the `@wordpress/interactivity` script modules.
+ *
+ * @since 6.5.0
+ */
+ public function register_script_modules() {
+ $suffix = wp_scripts_get_suffix();
+
+ wp_register_script_module(
+ '@wordpress/interactivity',
+ includes_url( "js/dist/interactivity$suffix.js" )
+ );
+
+ wp_register_script_module(
+ '@wordpress/interactivity-router',
+ includes_url( "js/dist/interactivity-router$suffix.js" ),
+ array( '@wordpress/interactivity' )
+ );
+ }
+
+ /**
+ * Adds the necessary hooks for the Interactivity API.
+ *
+ * @since 6.5.0
+ */
+ public function add_hooks() {
+ add_action( 'wp_enqueue_scripts', array( $this, 'register_script_modules' ) );
+ add_action( 'wp_footer', array( $this, 'print_client_interactivity_data' ) );
+ }
+
+ /**
+ * Processes the interactivity directives contained within the HTML content
+ * and updates the markup accordingly.
+ *
+ * @since 6.5.0
+ *
+ * @param string $html The HTML content to process.
+ * @return string The processed HTML content. It returns the original content when the HTML contains unbalanced tags.
+ */
+ public function process_directives( string $html ): string {
+ $context_stack = array();
+ $namespace_stack = array();
+ $result = $this->process_directives_args( $html, $context_stack, $namespace_stack );
+ return null === $result ? $html : $result;
+ }
+
+ /**
+ * Processes the interactivity directives contained within the HTML content
+ * and updates the markup accordingly.
+ *
+ * It needs the context and namespace stacks to be passed by reference, and
+ * it returns null if the HTML contains unbalanced tags.
+ *
+ * @since 6.5.0
+ *
+ * @param string $html The HTML content to process.
+ * @param array $context_stack The reference to the array used to keep track of contexts during processing.
+ * @param array $namespace_stack The reference to the array used to manage namespaces during processing.
+ * @return string|null The processed HTML content. It returns null when the HTML contains unbalanced tags.
+ */
+ private function process_directives_args( string $html, array &$context_stack, array &$namespace_stack ) {
+ $p = new WP_Interactivity_API_Directives_Processor( $html );
+ $tag_stack = array();
+ $unbalanced = false;
+
+ $directive_processor_prefixes = array_keys( self::$directive_processors );
+ $directive_processor_prefixes_reversed = array_reverse( $directive_processor_prefixes );
+
+ while ( $p->next_tag( array( 'tag_closers' => 'visit' ) ) ) {
+ $tag_name = $p->get_tag();
+
+ if ( 'SVG' === $tag_name || 'MATH' === $tag_name ) {
+ $unbalanced = true;
+ break;
+ }
+
+ if ( $p->is_tag_closer() ) {
+ list( $opening_tag_name, $directives_prefixes ) = end( $tag_stack );
+
+ if ( 0 === count( $tag_stack ) || $opening_tag_name !== $tag_name ) {
+
+ /*
+ * If the tag stack is empty or the matching opening tag is not the
+ * same than the closing tag, it means the HTML is unbalanced and it
+ * stops processing it.
+ */
+ $unbalanced = true;
+ break;
+ } else {
+ // Remove the last tag from the stack.
+ array_pop( $tag_stack );
+ }
+ } else {
+ if ( 0 !== count( $p->get_attribute_names_with_prefix( 'data-wp-each-child' ) ) ) {
+ /*
+ * If the tag has a `data-wp-each-child` directive, jump to its closer
+ * tag because those tags have already been processed.
+ */
+ $p->next_balanced_tag_closer_tag();
+ continue;
+ } else {
+ $directives_prefixes = array();
+
+ // Checks if there is a server directive processor registered for each directive.
+ foreach ( $p->get_attribute_names_with_prefix( 'data-wp-' ) as $attribute_name ) {
+ list( $directive_prefix ) = $this->extract_prefix_and_suffix( $attribute_name );
+ if ( array_key_exists( $directive_prefix, self::$directive_processors ) ) {
+ $directives_prefixes[] = $directive_prefix;
+ }
+ }
+
+ /*
+ * If this tag will visit its closer tag, it adds it to the tag stack
+ * so it can process its closing tag and check for unbalanced tags.
+ */
+ if ( $p->has_and_visits_its_closer_tag() ) {
+ $tag_stack[] = array( $tag_name, $directives_prefixes );
+ }
+ }
+ }
+ /*
+ * If the matching opener tag didn't have any directives, it can skip the
+ * processing.
+ */
+ if ( 0 === count( $directives_prefixes ) ) {
+ continue;
+ }
+
+ /*
+ * Sorts the attributes by the order of the `directives_processor` array
+ * and checks what directives are present in this element. The processing
+ * order is reversed for tag closers.
+ */
+ $directives_prefixes = array_intersect(
+ $p->is_tag_closer()
+ ? $directive_processor_prefixes_reversed
+ : $directive_processor_prefixes,
+ $directives_prefixes
+ );
+
+ // Executes the directive processors present in this element.
+ foreach ( $directives_prefixes as $directive_prefix ) {
+ $func = is_array( self::$directive_processors[ $directive_prefix ] )
+ ? self::$directive_processors[ $directive_prefix ]
+ : array( $this, self::$directive_processors[ $directive_prefix ] );
+ call_user_func_array(
+ $func,
+ array( $p, &$context_stack, &$namespace_stack, &$tag_stack )
+ );
+ }
+ }
+
+ /*
+ * It returns null if the HTML is unbalanced because unbalanced HTML is
+ * not safe to process. In that case, the Interactivity API runtime will
+ * update the HTML on the client side during the hydration.
+ */
+ return $unbalanced || 0 < count( $tag_stack ) ? null : $p->get_updated_html();
+ }
+
+ /**
+ * Evaluates the reference path passed to a directive based on the current
+ * store namespace, state and context.
+ *
+ * @since 6.5.0
+ *
+ * @param string|true $directive_value The directive attribute value string or `true` when it's a boolean attribute.
+ * @param string $default_namespace The default namespace to use if none is explicitly defined in the directive
+ * value.
+ * @param array|false $context The current context for evaluating the directive or false if there is no
+ * context.
+ * @return mixed|null The result of the evaluation. Null if the reference path doesn't exist.
+ */
+ private function evaluate( $directive_value, string $default_namespace, $context = false ) {
+ list( $ns, $path ) = $this->extract_directive_value( $directive_value, $default_namespace );
+ if ( empty( $path ) ) {
+ return null;
+ }
+
+ $store = array(
+ 'state' => $this->state_data[ $ns ] ?? array(),
+ 'context' => $context[ $ns ] ?? array(),
+ );
+
+ // Checks if the reference path is preceded by a negation operator (!).
+ $should_negate_value = '!' === $path[0];
+ $path = $should_negate_value ? substr( $path, 1 ) : $path;
+
+ // Extracts the value from the store using the reference path.
+ $path_segments = explode( '.', $path );
+ $current = $store;
+ foreach ( $path_segments as $path_segment ) {
+ if ( isset( $current[ $path_segment ] ) ) {
+ $current = $current[ $path_segment ];
+ } else {
+ return null;
+ }
+ }
+
+ // Returns the opposite if it contains a negation operator (!).
+ return $should_negate_value ? ! $current : $current;
+ }
+
+ /**
+ * Extracts the directive attribute name to separate and return the directive
+ * prefix and an optional suffix.
+ *
+ * The suffix is the string after the first double hyphen and the prefix is
+ * everything that comes before the suffix.
+ *
+ * Example:
+ *
+ * extract_prefix_and_suffix( 'data-wp-interactive' ) => array( 'data-wp-interactive', null )
+ * extract_prefix_and_suffix( 'data-wp-bind--src' ) => array( 'data-wp-bind', 'src' )
+ * extract_prefix_and_suffix( 'data-wp-foo--and--bar' ) => array( 'data-wp-foo', 'and--bar' )
+ *
+ * @since 6.5.0
+ *
+ * @param string $directive_name The directive attribute name.
+ * @return array An array containing the directive prefix and optional suffix.
+ */
+ private function extract_prefix_and_suffix( string $directive_name ): array {
+ return explode( '--', $directive_name, 2 );
+ }
+
+ /**
+ * Parses and extracts the namespace and reference path from the given
+ * directive attribute value.
+ *
+ * If the value doesn't contain an explicit namespace, it returns the
+ * default one. If the value contains a JSON object instead of a reference
+ * path, the function tries to parse it and return the resulting array. If
+ * the value contains strings that represent booleans ("true" and "false"),
+ * numbers ("1" and "1.2") or "null", the function also transform them to
+ * regular booleans, numbers and `null`.
+ *
+ * Example:
+ *
+ * extract_directive_value( 'actions.foo', 'myPlugin' ) => array( 'myPlugin', 'actions.foo' )
+ * extract_directive_value( 'otherPlugin::actions.foo', 'myPlugin' ) => array( 'otherPlugin', 'actions.foo' )
+ * extract_directive_value( '{ "isOpen": false }', 'myPlugin' ) => array( 'myPlugin', array( 'isOpen' => false ) )
+ * extract_directive_value( 'otherPlugin::{ "isOpen": false }', 'myPlugin' ) => array( 'otherPlugin', array( 'isOpen' => false ) )
+ *
+ * @since 6.5.0
+ *
+ * @param string|true $directive_value The directive attribute value. It can be `true` when it's a boolean
+ * attribute.
+ * @param string|null $default_namespace Optional. The default namespace if none is explicitly defined.
+ * @return array An array containing the namespace in the first item and the JSON, the reference path, or null on the
+ * second item.
+ */
+ private function extract_directive_value( $directive_value, $default_namespace = null ): array {
+ if ( empty( $directive_value ) || is_bool( $directive_value ) ) {
+ return array( $default_namespace, null );
+ }
+
+ // Replaces the value and namespace if there is a namespace in the value.
+ if ( 1 === preg_match( '/^([\w\-_\/]+)::./', $directive_value ) ) {
+ list($default_namespace, $directive_value) = explode( '::', $directive_value, 2 );
+ }
+
+ /*
+ * Tries to decode the value as a JSON object. If it fails and the value
+ * isn't `null`, it returns the value as it is. Otherwise, it returns the
+ * decoded JSON or null for the string `null`.
+ */
+ $decoded_json = json_decode( $directive_value, true );
+ if ( null !== $decoded_json || 'null' === $directive_value ) {
+ $directive_value = $decoded_json;
+ }
+
+ return array( $default_namespace, $directive_value );
+ }
+
+ /**
+ * Transforms a kebab-case string to camelCase.
+ *
+ * @param string $str The kebab-case string to transform to camelCase.
+ * @return string The transformed camelCase string.
+ */
+ private function kebab_to_camel_case( string $str ): string {
+ return lcfirst(
+ preg_replace_callback(
+ '/(-)([a-z])/',
+ function ( $matches ) {
+ return strtoupper( $matches[2] );
+ },
+ strtolower( rtrim( $str, '-' ) )
+ )
+ );
+ }
+
+ /**
+ * Processes the `data-wp-interactive` directive.
+ *
+ * It adds the default store namespace defined in the directive value to the
+ * stack so that it's available for the nested interactivity elements.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
+ * @param array $context_stack The reference to the context stack.
+ * @param array $namespace_stack The reference to the store namespace stack.
+ */
+ private function data_wp_interactive_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
+ // In closing tags, it removes the last namespace from the stack.
+ if ( $p->is_tag_closer() ) {
+ array_pop( $namespace_stack );
+ return;
+ }
+
+ // Tries to decode the `data-wp-interactive` attribute value.
+ $attribute_value = $p->get_attribute( 'data-wp-interactive' );
+
+ /*
+ * Pushes the newly defined namespace or the current one if the
+ * `data-wp-interactive` definition was invalid or does not contain a
+ * namespace. It does so because the function pops out the current namespace
+ * from the stack whenever it finds a `data-wp-interactive`'s closing tag,
+ * independently of whether the previous `data-wp-interactive` definition
+ * contained a valid namespace.
+ */
+ $new_namespace = null;
+ if ( is_string( $attribute_value ) && ! empty( $attribute_value ) ) {
+ $decoded_json = json_decode( $attribute_value, true );
+ if ( is_array( $decoded_json ) ) {
+ $new_namespace = $decoded_json['namespace'] ?? null;
+ } else {
+ $new_namespace = $attribute_value;
+ }
+ }
+ $namespace_stack[] = ( $new_namespace && 1 === preg_match( '/^([\w\-_\/]+)/', $new_namespace ) )
+ ? $new_namespace
+ : end( $namespace_stack );
+ }
+
+ /**
+ * Processes the `data-wp-context` directive.
+ *
+ * It adds the context defined in the directive value to the stack so that
+ * it's available for the nested interactivity elements.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
+ * @param array $context_stack The reference to the context stack.
+ * @param array $namespace_stack The reference to the store namespace stack.
+ */
+ private function data_wp_context_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
+ // In closing tags, it removes the last context from the stack.
+ if ( $p->is_tag_closer() ) {
+ array_pop( $context_stack );
+ return;
+ }
+
+ $attribute_value = $p->get_attribute( 'data-wp-context' );
+ $namespace_value = end( $namespace_stack );
+
+ // Separates the namespace from the context JSON object.
+ list( $namespace_value, $decoded_json ) = is_string( $attribute_value ) && ! empty( $attribute_value )
+ ? $this->extract_directive_value( $attribute_value, $namespace_value )
+ : array( $namespace_value, null );
+
+ /*
+ * If there is a namespace, it adds a new context to the stack merging the
+ * previous context with the new one.
+ */
+ if ( is_string( $namespace_value ) ) {
+ $context_stack[] = array_replace_recursive(
+ end( $context_stack ) !== false ? end( $context_stack ) : array(),
+ array( $namespace_value => is_array( $decoded_json ) ? $decoded_json : array() )
+ );
+ } else {
+ /*
+ * If there is no namespace, it pushes the current context to the stack.
+ * It needs to do so because the function pops out the current context
+ * from the stack whenever it finds a `data-wp-context`'s closing tag.
+ */
+ $context_stack[] = end( $context_stack );
+ }
+ }
+
+ /**
+ * Processes the `data-wp-bind` directive.
+ *
+ * It updates or removes the bound attributes based on the evaluation of its
+ * associated reference.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
+ * @param array $context_stack The reference to the context stack.
+ * @param array $namespace_stack The reference to the store namespace stack.
+ */
+ private function data_wp_bind_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
+ if ( ! $p->is_tag_closer() ) {
+ $all_bind_directives = $p->get_attribute_names_with_prefix( 'data-wp-bind--' );
+
+ foreach ( $all_bind_directives as $attribute_name ) {
+ list( , $bound_attribute ) = $this->extract_prefix_and_suffix( $attribute_name );
+ if ( empty( $bound_attribute ) ) {
+ return;
+ }
+
+ $attribute_value = $p->get_attribute( $attribute_name );
+ $result = $this->evaluate( $attribute_value, end( $namespace_stack ), end( $context_stack ) );
+
+ if ( null !== $result && ( false !== $result || '-' === $bound_attribute[4] ) ) {
+ /*
+ * If the result of the evaluation is a boolean and the attribute is
+ * `aria-` or `data-, convert it to a string "true" or "false". It
+ * follows the exact same logic as Preact because it needs to
+ * replicate what Preact will later do in the client:
+ * https://github.com/preactjs/preact/blob/ea49f7a0f9d1ff2c98c0bdd66aa0cbc583055246/src/diff/props.js#L131C24-L136
+ */
+ if ( is_bool( $result ) && '-' === $bound_attribute[4] ) {
+ $result = $result ? 'true' : 'false';
+ }
+ $p->set_attribute( $bound_attribute, $result );
+ } else {
+ $p->remove_attribute( $bound_attribute );
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes the `data-wp-class` directive.
+ *
+ * It adds or removes CSS classes in the current HTML element based on the
+ * evaluation of its associated references.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
+ * @param array $context_stack The reference to the context stack.
+ * @param array $namespace_stack The reference to the store namespace stack.
+ */
+ private function data_wp_class_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
+ if ( ! $p->is_tag_closer() ) {
+ $all_class_directives = $p->get_attribute_names_with_prefix( 'data-wp-class--' );
+
+ foreach ( $all_class_directives as $attribute_name ) {
+ list( , $class_name ) = $this->extract_prefix_and_suffix( $attribute_name );
+ if ( empty( $class_name ) ) {
+ return;
+ }
+
+ $attribute_value = $p->get_attribute( $attribute_name );
+ $result = $this->evaluate( $attribute_value, end( $namespace_stack ), end( $context_stack ) );
+
+ if ( $result ) {
+ $p->add_class( $class_name );
+ } else {
+ $p->remove_class( $class_name );
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes the `data-wp-style` directive.
+ *
+ * It updates the style attribute value of the current HTML element based on
+ * the evaluation of its associated references.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
+ * @param array $context_stack The reference to the context stack.
+ * @param array $namespace_stack The reference to the store namespace stack.
+ */
+ private function data_wp_style_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
+ if ( ! $p->is_tag_closer() ) {
+ $all_style_attributes = $p->get_attribute_names_with_prefix( 'data-wp-style--' );
+
+ foreach ( $all_style_attributes as $attribute_name ) {
+ list( , $style_property ) = $this->extract_prefix_and_suffix( $attribute_name );
+ if ( empty( $style_property ) ) {
+ continue;
+ }
+
+ $directive_attribute_value = $p->get_attribute( $attribute_name );
+ $style_property_value = $this->evaluate( $directive_attribute_value, end( $namespace_stack ), end( $context_stack ) );
+ $style_attribute_value = $p->get_attribute( 'style' );
+ $style_attribute_value = ( $style_attribute_value && ! is_bool( $style_attribute_value ) ) ? $style_attribute_value : '';
+
+ /*
+ * Checks first if the style property is not falsy and the style
+ * attribute value is not empty because if it is, it doesn't need to
+ * update the attribute value.
+ */
+ if ( $style_property_value || $style_attribute_value ) {
+ $style_attribute_value = $this->merge_style_property( $style_attribute_value, $style_property, $style_property_value );
+ /*
+ * If the style attribute value is not empty, it sets it. Otherwise,
+ * it removes it.
+ */
+ if ( ! empty( $style_attribute_value ) ) {
+ $p->set_attribute( 'style', $style_attribute_value );
+ } else {
+ $p->remove_attribute( 'style' );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Merges an individual style property in the `style` attribute of an HTML
+ * element, updating or removing the property when necessary.
+ *
+ * If a property is modified, the old one is removed and the new one is added
+ * at the end of the list.
+ *
+ * @since 6.5.0
+ *
+ * Example:
+ *
+ * merge_style_property( 'color:green;', 'color', 'red' ) => 'color:red;'
+ * merge_style_property( 'background:green;', 'color', 'red' ) => 'background:green;color:red;'
+ * merge_style_property( 'color:green;', 'color', null ) => ''
+ *
+ * @param string $style_attribute_value The current style attribute value.
+ * @param string $style_property_name The style property name to set.
+ * @param string|false|null $style_property_value The value to set for the style property. With false, null or an
+ * empty string, it removes the style property.
+ * @return string The new style attribute value after the specified property has been added, updated or removed.
+ */
+ private function merge_style_property( string $style_attribute_value, string $style_property_name, $style_property_value ): string {
+ $style_assignments = explode( ';', $style_attribute_value );
+ $result = array();
+ $style_property_value = ! empty( $style_property_value ) ? rtrim( trim( $style_property_value ), ';' ) : null;
+ $new_style_property = $style_property_value ? $style_property_name . ':' . $style_property_value . ';' : '';
+
+ // Generates an array with all the properties but the modified one.
+ foreach ( $style_assignments as $style_assignment ) {
+ if ( empty( trim( $style_assignment ) ) ) {
+ continue;
+ }
+ list( $name, $value ) = explode( ':', $style_assignment );
+ if ( trim( $name ) !== $style_property_name ) {
+ $result[] = trim( $name ) . ':' . trim( $value ) . ';';
+ }
+ }
+
+ // Adds the new/modified property at the end of the list.
+ $result[] = $new_style_property;
+
+ return implode( '', $result );
+ }
+
+ /**
+ * Processes the `data-wp-text` directive.
+ *
+ * It updates the inner content of the current HTML element based on the
+ * evaluation of its associated reference.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
+ * @param array $context_stack The reference to the context stack.
+ * @param array $namespace_stack The reference to the store namespace stack.
+ */
+ private function data_wp_text_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack ) {
+ if ( ! $p->is_tag_closer() ) {
+ $attribute_value = $p->get_attribute( 'data-wp-text' );
+ $result = $this->evaluate( $attribute_value, end( $namespace_stack ), end( $context_stack ) );
+
+ /*
+ * Follows the same logic as Preact in the client and only changes the
+ * content if the value is a string or a number. Otherwise, it removes the
+ * content.
+ */
+ if ( is_string( $result ) || is_numeric( $result ) ) {
+ $p->set_content_between_balanced_tags( esc_html( $result ) );
+ } else {
+ $p->set_content_between_balanced_tags( '' );
+ }
+ }
+ }
+
+ /**
+ * Returns the CSS styles for animating the top loading bar in the router.
+ *
+ * @since 6.5.0
+ *
+ * @return string The CSS styles for the router's top loading bar animation.
+ */
+ private function get_router_animation_styles(): string {
+ return <<
+
+HTML;
+ }
+
+ /**
+ * Processes the `data-wp-router-region` directive.
+ *
+ * It renders in the footer a set of HTML elements to notify users about
+ * client-side navigations. More concretely, the elements added are 1) a
+ * top loading bar to visually inform that a navigation is in progress
+ * and 2) an `aria-live` region for accessible navigation announcements.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
+ */
+ private function data_wp_router_region_processor( WP_Interactivity_API_Directives_Processor $p ) {
+ if ( ! $p->is_tag_closer() && ! $this->has_processed_router_region ) {
+ $this->has_processed_router_region = true;
+
+ // Initialize the `core/router` store.
+ $this->state(
+ 'core/router',
+ array(
+ 'navigation' => array(
+ 'texts' => array(
+ 'loading' => __( 'Loading page, please wait.' ),
+ 'loaded' => __( 'Page Loaded.' ),
+ ),
+ ),
+ )
+ );
+
+ // Enqueues as an inline style.
+ wp_register_style( 'wp-interactivity-router-animations', false );
+ wp_add_inline_style( 'wp-interactivity-router-animations', $this->get_router_animation_styles() );
+ wp_enqueue_style( 'wp-interactivity-router-animations' );
+
+ // Adds the necessary markup to the footer.
+ add_action( 'wp_footer', array( $this, 'print_router_loading_and_screen_reader_markup' ) );
+ }
+ }
+
+ /**
+ * Processes the `data-wp-each` directive.
+ *
+ * This directive gets an array passed as reference and iterates over it
+ * generating new content for each item based on the inner markup of the
+ * `template` tag.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance.
+ * @param array $context_stack The reference to the context stack.
+ * @param array $namespace_stack The reference to the store namespace stack.
+ * @param array $tag_stack The reference to the tag stack.
+ */
+ private function data_wp_each_processor( WP_Interactivity_API_Directives_Processor $p, array &$context_stack, array &$namespace_stack, array &$tag_stack ) {
+ if ( ! $p->is_tag_closer() && 'TEMPLATE' === $p->get_tag() ) {
+ $attribute_name = $p->get_attribute_names_with_prefix( 'data-wp-each' )[0];
+ $extracted_suffix = $this->extract_prefix_and_suffix( $attribute_name );
+ $item_name = isset( $extracted_suffix[1] ) ? $this->kebab_to_camel_case( $extracted_suffix[1] ) : 'item';
+ $attribute_value = $p->get_attribute( $attribute_name );
+ $result = $this->evaluate( $attribute_value, end( $namespace_stack ), end( $context_stack ) );
+
+ // Gets the content between the template tags and leaves the cursor in the closer tag.
+ $inner_content = $p->get_content_between_balanced_template_tags();
+
+ // Checks if there is a manual server-side directive processing.
+ $template_end = 'data-wp-each: template end';
+ $p->set_bookmark( $template_end );
+ $p->next_tag();
+ $manual_sdp = $p->get_attribute( 'data-wp-each-child' );
+ $p->seek( $template_end ); // Rewinds to the template closer tag.
+ $p->release_bookmark( $template_end );
+
+ /*
+ * It doesn't process in these situations:
+ * - Manual server-side directive processing.
+ * - Empty or non-array values.
+ * - Associative arrays because those are deserialized as objects in JS.
+ * - Templates that contain top-level texts because those texts can't be
+ * identified and removed in the client.
+ */
+ if (
+ $manual_sdp ||
+ empty( $result ) ||
+ ! is_array( $result ) ||
+ ! array_is_list( $result ) ||
+ ! str_starts_with( trim( $inner_content ), '<' ) ||
+ ! str_ends_with( trim( $inner_content ), '>' )
+ ) {
+ array_pop( $tag_stack );
+ return;
+ }
+
+ // Extracts the namespace from the directive attribute value.
+ $namespace_value = end( $namespace_stack );
+ list( $namespace_value ) = is_string( $attribute_value ) && ! empty( $attribute_value )
+ ? $this->extract_directive_value( $attribute_value, $namespace_value )
+ : array( $namespace_value, null );
+
+ // Processes the inner content for each item of the array.
+ $processed_content = '';
+ foreach ( $result as $item ) {
+ // Creates a new context that includes the current item of the array.
+ $context_stack[] = array_replace_recursive(
+ end( $context_stack ) !== false ? end( $context_stack ) : array(),
+ array( $namespace_value => array( $item_name => $item ) )
+ );
+
+ // Processes the inner content with the new context.
+ $processed_item = $this->process_directives_args( $inner_content, $context_stack, $namespace_stack );
+
+ if ( null === $processed_item ) {
+ // If the HTML is unbalanced, stop processing it.
+ array_pop( $context_stack );
+ return;
+ }
+
+ // Adds the `data-wp-each-child` to each top-level tag.
+ $i = new WP_Interactivity_API_Directives_Processor( $processed_item );
+ while ( $i->next_tag() ) {
+ $i->set_attribute( 'data-wp-each-child', true );
+ $i->next_balanced_tag_closer_tag();
+ }
+ $processed_content .= $i->get_updated_html();
+
+ // Removes the current context from the stack.
+ array_pop( $context_stack );
+ }
+
+ // Appends the processed content after the tag closer of the template.
+ $p->append_content_after_template_tag_closer( $processed_content );
+
+ // Pops the last tag because it skipped the closing tag of the template tag.
+ array_pop( $tag_stack );
+ }
+ }
+}
diff --git a/src/wp-includes/interactivity-api/interactivity-api.php b/src/wp-includes/interactivity-api/interactivity-api.php
new file mode 100644
index 0000000000000..548fcc3638fb7
--- /dev/null
+++ b/src/wp-includes/interactivity-api/interactivity-api.php
@@ -0,0 +1,166 @@
+get_registered( $block_name );
+
+ if (
+ isset( $block_name ) &&
+ ( ( isset( $block_type->supports['interactivity'] ) && true === $block_type->supports['interactivity'] ) ||
+ ( isset( $block_type->supports['interactivity']['interactive'] ) && true === $block_type->supports['interactivity']['interactive'] ) )
+ ) {
+ // Annotates the root interactive block for processing.
+ $root_interactive_block = array( $block_name, $parsed_block );
+
+ /*
+ * Adds a filter to process the root interactive block once it has
+ * finished rendering.
+ */
+ $process_interactive_blocks = static function ( string $content, array $parsed_block ) use ( &$root_interactive_block, &$process_interactive_blocks ): string {
+ // Checks whether the current block is the root interactive block.
+ list($root_block_name, $root_parsed_block) = $root_interactive_block;
+ if ( $root_block_name === $parsed_block['blockName'] && $parsed_block === $root_parsed_block ) {
+ // The root interactive blocks has finished rendering, process it.
+ $content = wp_interactivity_process_directives( $content );
+ // Removes the filter and reset the root interactive block.
+ remove_filter( 'render_block_' . $parsed_block['blockName'], $process_interactive_blocks );
+ $root_interactive_block = null;
+ }
+ return $content;
+ };
+
+ /*
+ * Uses a priority of 20 to ensure that other filters can add additional
+ * directives before the processing starts.
+ */
+ add_filter( 'render_block_' . $block_name, $process_interactive_blocks, 20, 2 );
+ }
+ }
+
+ return $parsed_block;
+}
+add_filter( 'render_block_data', 'wp_interactivity_process_directives_of_interactive_blocks' );
+
+/**
+ * Retrieves the main WP_Interactivity_API instance.
+ *
+ * It provides access to the WP_Interactivity_API instance, creating one if it
+ * doesn't exist yet.
+ *
+ * @global WP_Interactivity_API $wp_interactivity
+ *
+ * @since 6.5.0
+ *
+ * @return WP_Interactivity_API The main WP_Interactivity_API instance.
+ */
+function wp_interactivity(): WP_Interactivity_API {
+ global $wp_interactivity;
+ if ( ! ( $wp_interactivity instanceof WP_Interactivity_API ) ) {
+ $wp_interactivity = new WP_Interactivity_API();
+ }
+ return $wp_interactivity;
+}
+
+/**
+ * Processes the interactivity directives contained within the HTML content
+ * and updates the markup accordingly.
+ *
+ * @since 6.5.0
+ *
+ * @param string $html The HTML content to process.
+ * @return string The processed HTML content. It returns the original content when the HTML contains unbalanced tags.
+ */
+function wp_interactivity_process_directives( string $html ): string {
+ return wp_interactivity()->process_directives( $html );
+}
+
+/**
+ * Gets and/or sets the initial state of an Interactivity API store for a
+ * given namespace.
+ *
+ * If state for that store namespace already exists, it merges the new
+ * provided state with the existing one.
+ *
+ * @since 6.5.0
+ *
+ * @param string $store_namespace The unique store namespace identifier.
+ * @param array $state Optional. The array that will be merged with the existing state for the specified
+ * store namespace.
+ * @return array The state for the specified store namespace. This will be the updated state if a $state argument was
+ * provided.
+ */
+function wp_interactivity_state( string $store_namespace, array $state = array() ): array {
+ return wp_interactivity()->state( $store_namespace, $state );
+}
+
+/**
+ * Gets and/or sets the configuration of the Interactivity API for a given
+ * store namespace.
+ *
+ * If configuration for that store namespace exists, it merges the new
+ * provided configuration with the existing one.
+ *
+ * @since 6.5.0
+ *
+ * @param string $store_namespace The unique store namespace identifier.
+ * @param array $config Optional. The array that will be merged with the existing configuration for the
+ * specified store namespace.
+ * @return array The configuration for the specified store namespace. This will be the updated configuration if a
+ * $config argument was provided.
+ */
+function wp_interactivity_config( string $store_namespace, array $config = array() ): array {
+ return wp_interactivity()->config( $store_namespace, $config );
+}
+
+/**
+ * Generates a `data-wp-context` directive attribute by encoding a context
+ * array.
+ *
+ * This helper function simplifies the creation of `data-wp-context` directives
+ * by providing a way to pass an array of data, which encodes into a JSON string
+ * safe for direct use as a HTML attribute value.
+ *
+ * Example:
+ *
+ * true, 'count' => 0 ) ); ?>>
+ *
+ * @since 6.5.0
+ *
+ * @param array $context The array of context data to encode.
+ * @param string $store_namespace Optional. The unique store namespace identifier.
+ * @return string A complete `data-wp-context` directive with a JSON encoded value representing the context array and
+ * the store namespace if specified.
+ */
+function data_wp_context( array $context, string $store_namespace = '' ): string {
+ return 'data-wp-context=\'' .
+ ( $store_namespace ? $store_namespace . '::' : '' ) .
+ ( empty( $context ) ? '{}' : wp_json_encode( $context, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP ) ) .
+ '\'';
+}
diff --git a/src/wp-includes/l10n.php b/src/wp-includes/l10n.php
index 726e3da1a5a56..8191b88cee840 100644
--- a/src/wp-includes/l10n.php
+++ b/src/wp-includes/l10n.php
@@ -789,32 +789,71 @@ function load_textdomain( $domain, $mofile, $locale = null ) {
*/
$mofile = apply_filters( 'load_textdomain_mofile', $mofile, $domain );
- if ( ! is_readable( $mofile ) ) {
- return false;
- }
-
if ( ! $locale ) {
$locale = determine_locale();
}
- $mo = new MO();
- if ( ! $mo->import_from_file( $mofile ) ) {
- $wp_textdomain_registry->set( $domain, $locale, false );
+ $i18n_controller = WP_Translation_Controller::get_instance();
- return false;
+ // Ensures the correct locale is set as the current one, in case it was filtered.
+ $i18n_controller->set_locale( $locale );
+
+ /**
+ * Filters the preferred file format for translation files.
+ *
+ * Can be used to disable the use of PHP files for translations.
+ *
+ * @since 6.5.0
+ *
+ * @param string $preferred_format Preferred file format. Possible values: 'php', 'mo'. Default: 'php'.
+ * @param string $domain The text domain.
+ */
+ $preferred_format = apply_filters( 'translation_file_format', 'php', $domain );
+ if ( ! in_array( $preferred_format, array( 'php', 'mo' ), true ) ) {
+ $preferred_format = 'php';
}
- if ( isset( $l10n[ $domain ] ) ) {
- $mo->merge_with( $l10n[ $domain ] );
+ $translation_files = array();
+
+ if ( 'mo' !== $preferred_format ) {
+ $translation_files[] = substr_replace( $mofile, ".l10n.$preferred_format", - strlen( '.mo' ) );
}
- unset( $l10n_unloaded[ $domain ] );
+ $translation_files[] = $mofile;
- $l10n[ $domain ] = &$mo;
+ foreach ( $translation_files as $file ) {
+ /**
+ * Filters the file path for loading translations for the given text domain.
+ *
+ * Similar to the {@see 'load_textdomain_mofile'} filter with the difference that
+ * the file path could be for an MO or PHP file.
+ *
+ * @since 6.5.0
+ *
+ * @param string $file Path to the translation file to load.
+ * @param string $domain The text domain.
+ */
+ $file = (string) apply_filters( 'load_translation_file', $file, $domain );
- $wp_textdomain_registry->set( $domain, $locale, dirname( $mofile ) );
+ $success = $i18n_controller->load_file( $file, $domain, $locale );
- return true;
+ if ( $success ) {
+ if ( isset( $l10n[ $domain ] ) && $l10n[ $domain ] instanceof MO ) {
+ $i18n_controller->load_file( $l10n[ $domain ]->get_filename(), $domain, $locale );
+ }
+
+ // Unset NOOP_Translations reference in get_translations_for_domain().
+ unset( $l10n[ $domain ] );
+
+ $l10n[ $domain ] = new WP_Translations( $i18n_controller, $domain );
+
+ $wp_textdomain_registry->set( $domain, $locale, dirname( $file ) );
+
+ return true;
+ }
+ }
+
+ return false;
}
/**
@@ -866,6 +905,11 @@ function unload_textdomain( $domain, $reloadable = false ) {
*/
do_action( 'unload_textdomain', $domain, $reloadable );
+ // Since multiple locales are supported, reloadable text domains don't actually need to be unloaded.
+ if ( ! $reloadable ) {
+ WP_Translation_Controller::get_instance()->unload_textdomain( $domain );
+ }
+
if ( isset( $l10n[ $domain ] ) ) {
if ( $l10n[ $domain ] instanceof NOOP_Translations ) {
unset( $l10n[ $domain ] );
@@ -904,7 +948,7 @@ function load_default_textdomain( $locale = null ) {
}
// Unload previously loaded strings so we can switch translations.
- unload_textdomain( 'default' );
+ unload_textdomain( 'default', true );
$return = load_textdomain( 'default', WP_LANG_DIR . "/$locale.mo", $locale );
diff --git a/src/wp-includes/l10n/class-wp-translation-controller.php b/src/wp-includes/l10n/class-wp-translation-controller.php
new file mode 100644
index 0000000000000..b44384c013dcd
--- /dev/null
+++ b/src/wp-includes/l10n/class-wp-translation-controller.php
@@ -0,0 +1,437 @@
+ [ Textdomain => [ ..., ... ] ] ]
+ *
+ * @since 6.5.0
+ * @var array
>
+ */
+ protected $loaded_translations = array();
+
+ /**
+ * List of loaded translation files.
+ *
+ * [ Filename => [ Locale => [ Textdomain => WP_Translation_File ] ] ]
+ *
+ * @since 6.5.0
+ * @var array>>
+ */
+ protected $loaded_files = array();
+
+ /**
+ * Container for the main instance of the class.
+ *
+ * @since 6.5.0
+ * @var WP_Translation_Controller|null
+ */
+ private static $instance = null;
+
+ /**
+ * Utility method to retrieve the main instance of the class.
+ *
+ * The instance will be created if it does not exist yet.
+ *
+ * @since 6.5.0
+ *
+ * @return WP_Translation_Controller
+ */
+ public static function get_instance(): WP_Translation_Controller {
+ if ( null === self::$instance ) {
+ self::$instance = new self();
+ }
+
+ return self::$instance;
+ }
+
+ /**
+ * Returns the current locale.
+ *
+ * @since 6.5.0
+ *
+ * @return string Locale.
+ */
+ public function get_locale(): string {
+ return $this->current_locale;
+ }
+
+ /**
+ * Sets the current locale.
+ *
+ * @since 6.5.0
+ *
+ * @param string $locale Locale.
+ */
+ public function set_locale( string $locale ) {
+ $this->current_locale = $locale;
+ }
+
+ /**
+ * Loads a translation file for a given text domain.
+ *
+ * @since 6.5.0
+ *
+ * @param string $translation_file Translation file.
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @param string $locale Optional. Locale. Default current locale.
+ * @return bool True on success, false otherwise.
+ */
+ public function load_file( string $translation_file, string $textdomain = 'default', string $locale = null ): bool {
+ if ( null === $locale ) {
+ $locale = $this->current_locale;
+ }
+
+ $translation_file = realpath( $translation_file );
+
+ if ( false === $translation_file ) {
+ return false;
+ }
+
+ if (
+ isset( $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] ) &&
+ false !== $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ]
+ ) {
+ return null === $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ]->error();
+ }
+
+ if (
+ isset( $this->loaded_files[ $translation_file ][ $locale ] ) &&
+ array() !== $this->loaded_files[ $translation_file ][ $locale ]
+ ) {
+ $moe = reset( $this->loaded_files[ $translation_file ][ $locale ] );
+ } else {
+ $moe = WP_Translation_File::create( $translation_file );
+ if ( false === $moe || null !== $moe->error() ) {
+ $moe = false;
+ }
+ }
+
+ $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] = $moe;
+
+ if ( ! $moe instanceof WP_Translation_File ) {
+ return false;
+ }
+
+ if ( ! isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) {
+ $this->loaded_translations[ $locale ][ $textdomain ] = array();
+ }
+
+ $this->loaded_translations[ $locale ][ $textdomain ][] = $moe;
+
+ return true;
+ }
+
+ /**
+ * Unloads a translation file for a given text domain.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Translation_File|string $file Translation file instance or file name.
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @param string $locale Optional. Locale. Defaults to all locales.
+ * @return bool True on success, false otherwise.
+ */
+ public function unload_file( $file, string $textdomain = 'default', string $locale = null ): bool {
+ if ( is_string( $file ) ) {
+ $file = realpath( $file );
+ }
+
+ if ( null !== $locale ) {
+ if ( isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) {
+ foreach ( $this->loaded_translations[ $locale ][ $textdomain ] as $i => $moe ) {
+ if ( $file === $moe || $file === $moe->get_file() ) {
+ unset( $this->loaded_translations[ $locale ][ $textdomain ][ $i ] );
+ unset( $this->loaded_files[ $moe->get_file() ][ $locale ][ $textdomain ] );
+ return true;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ foreach ( $this->loaded_translations as $l => $domains ) {
+ if ( ! isset( $domains[ $textdomain ] ) ) {
+ continue;
+ }
+
+ foreach ( $domains[ $textdomain ] as $i => $moe ) {
+ if ( $file === $moe || $file === $moe->get_file() ) {
+ unset( $this->loaded_translations[ $l ][ $textdomain ][ $i ] );
+ unset( $this->loaded_files[ $moe->get_file() ][ $l ][ $textdomain ] );
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Unloads all translation files for a given text domain.
+ *
+ * @since 6.5.0
+ *
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @param string $locale Optional. Locale. Defaults to all locales.
+ * @return bool True on success, false otherwise.
+ */
+ public function unload_textdomain( string $textdomain = 'default', string $locale = null ): bool {
+ $unloaded = false;
+
+ if ( null !== $locale ) {
+ if ( isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) {
+ $unloaded = true;
+ foreach ( $this->loaded_translations[ $locale ][ $textdomain ] as $moe ) {
+ unset( $this->loaded_files[ $moe->get_file() ][ $locale ][ $textdomain ] );
+ }
+ }
+
+ unset( $this->loaded_translations[ $locale ][ $textdomain ] );
+
+ return $unloaded;
+ }
+
+ foreach ( $this->loaded_translations as $l => $domains ) {
+ if ( ! isset( $domains[ $textdomain ] ) ) {
+ continue;
+ }
+
+ $unloaded = true;
+
+ foreach ( $domains[ $textdomain ] as $moe ) {
+ unset( $this->loaded_files[ $moe->get_file() ][ $l ][ $textdomain ] );
+ }
+
+ unset( $this->loaded_translations[ $l ][ $textdomain ] );
+ }
+
+ return $unloaded;
+ }
+
+ /**
+ * Determines whether translations are loaded for a given text domain.
+ *
+ * @since 6.5.0
+ *
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @param string $locale Optional. Locale. Default current locale.
+ * @return bool True if there are any loaded translations, false otherwise.
+ */
+ public function is_textdomain_loaded( string $textdomain = 'default', string $locale = null ): bool {
+ if ( null === $locale ) {
+ $locale = $this->current_locale;
+ }
+
+ return isset( $this->loaded_translations[ $locale ][ $textdomain ] ) &&
+ array() !== $this->loaded_translations[ $locale ][ $textdomain ];
+ }
+
+ /**
+ * Translates a singular string.
+ *
+ * @since 6.5.0
+ *
+ * @param string $text Text to translate.
+ * @param string $context Optional. Context for the string. Default empty string.
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @param string $locale Optional. Locale. Default current locale.
+ * @return string|false Translation on success, false otherwise.
+ */
+ public function translate( string $text, string $context = '', string $textdomain = 'default', string $locale = null ) {
+ if ( '' !== $context ) {
+ $context .= "\4";
+ }
+
+ $translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale );
+
+ if ( false === $translation ) {
+ return false;
+ }
+
+ return $translation['entries'][0];
+ }
+
+ /**
+ * Translates plurals.
+ *
+ * Checks both singular+plural combinations as well as just singulars,
+ * in case the translation file does not store the plural.
+ *
+ * @since 6.5.0
+ *
+ * @param array{0: string, 1: string} $plurals {
+ * Pair of singular and plural translations.
+ *
+ * @type string $0 Singular translation.
+ * @type string $1 Plural translation.
+ * }
+ * @param int $number Number of items.
+ * @param string $context Optional. Context for the string. Default empty string.
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @param string $locale Optional. Locale. Default current locale.
+ * @return string|false Translation on success, false otherwise.
+ */
+ public function translate_plural( array $plurals, int $number, string $context = '', string $textdomain = 'default', string $locale = null ) {
+ if ( '' !== $context ) {
+ $context .= "\4";
+ }
+
+ $text = implode( "\0", $plurals );
+ $translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale );
+
+ if ( false === $translation ) {
+ $text = $plurals[0];
+ $translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale );
+
+ if ( false === $translation ) {
+ return false;
+ }
+ }
+
+ /** @var WP_Translation_File $source */
+ $source = $translation['source'];
+ $num = $source->get_plural_form( $number );
+
+ // See \Translations::translate_plural().
+ return $translation['entries'][ $num ] ?? $translation['entries'][0];
+ }
+
+ /**
+ * Returns all existing headers for a given text domain.
+ *
+ * @since 6.5.0
+ *
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @return array Headers.
+ */
+ public function get_headers( string $textdomain = 'default' ): array {
+ if ( array() === $this->loaded_translations ) {
+ return array();
+ }
+
+ $headers = array();
+
+ foreach ( $this->get_files( $textdomain ) as $moe ) {
+ foreach ( $moe->headers() as $header => $value ) {
+ $headers[ $this->normalize_header( $header ) ] = $value;
+ }
+ }
+
+ return $headers;
+ }
+
+ /**
+ * Normalizes header names to be capitalized.
+ *
+ * @since 6.5.0
+ *
+ * @param string $header Header name.
+ * @return string Normalized header name.
+ */
+ protected function normalize_header( string $header ): string {
+ $parts = explode( '-', $header );
+ $parts = array_map( 'ucfirst', $parts );
+ return implode( '-', $parts );
+ }
+
+ /**
+ * Returns all entries for a given text domain.
+ *
+ * @since 6.5.0
+ *
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @return array Entries.
+ */
+ public function get_entries( string $textdomain = 'default' ): array {
+ if ( array() === $this->loaded_translations ) {
+ return array();
+ }
+
+ $entries = array();
+
+ foreach ( $this->get_files( $textdomain ) as $moe ) {
+ $entries = array_merge( $entries, $moe->entries() );
+ }
+
+ return $entries;
+ }
+
+ /**
+ * Locates translation for a given string and text domain.
+ *
+ * @since 6.5.0
+ *
+ * @param string $singular Singular translation.
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @param string $locale Optional. Locale. Default current locale.
+ * @return array{source: WP_Translation_File, entries: string[]}|false {
+ * Translations on success, false otherwise.
+ *
+ * @type WP_Translation_File $source Translation file instance.
+ * @type string[] $entries Array of translation entries.
+ * }
+ */
+ protected function locate_translation( string $singular, string $textdomain = 'default', string $locale = null ) {
+ if ( array() === $this->loaded_translations ) {
+ return false;
+ }
+
+ // Find the translation in all loaded files for this text domain.
+ foreach ( $this->get_files( $textdomain, $locale ) as $moe ) {
+ $translation = $moe->translate( $singular );
+ if ( false !== $translation ) {
+ return array(
+ 'entries' => explode( "\0", $translation ),
+ 'source' => $moe,
+ );
+ }
+ if ( null !== $moe->error() ) {
+ // Unload this file, something is wrong.
+ $this->unload_file( $moe, $textdomain, $locale );
+ }
+ }
+
+ // Nothing could be found.
+ return false;
+ }
+
+ /**
+ * Returns all translation files for a given text domain.
+ *
+ * @since 6.5.0
+ *
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ * @param string $locale Optional. Locale. Default current locale.
+ * @return WP_Translation_File[] List of translation files.
+ */
+ protected function get_files( string $textdomain = 'default', string $locale = null ): array {
+ if ( null === $locale ) {
+ $locale = $this->current_locale;
+ }
+
+ return $this->loaded_translations[ $locale ][ $textdomain ] ?? array();
+ }
+}
diff --git a/src/wp-includes/l10n/class-wp-translation-file-mo.php b/src/wp-includes/l10n/class-wp-translation-file-mo.php
new file mode 100644
index 0000000000000..bf39cc70ec38b
--- /dev/null
+++ b/src/wp-includes/l10n/class-wp-translation-file-mo.php
@@ -0,0 +1,227 @@
+error = 'Magic marker does not exist';
+ return false;
+ }
+
+ /**
+ * Parses the file.
+ *
+ * @since 6.5.0
+ *
+ * @return bool True on success, false otherwise.
+ */
+ protected function parse_file(): bool {
+ $this->parsed = true;
+
+ $file_contents = file_get_contents( $this->file ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
+
+ if ( false === $file_contents ) {
+ return false;
+ }
+
+ $file_length = strlen( $file_contents );
+
+ if ( $file_length < 24 ) {
+ $this->error = 'Invalid data';
+ return false;
+ }
+
+ $this->uint32 = $this->detect_endian_and_validate_file( substr( $file_contents, 0, 4 ) );
+
+ if ( false === $this->uint32 ) {
+ return false;
+ }
+
+ $offsets = substr( $file_contents, 4, 24 );
+
+ if ( false === $offsets ) {
+ return false;
+ }
+
+ $offsets = unpack( "{$this->uint32}rev/{$this->uint32}total/{$this->uint32}originals_addr/{$this->uint32}translations_addr/{$this->uint32}hash_length/{$this->uint32}hash_addr", $offsets );
+
+ if ( false === $offsets ) {
+ return false;
+ }
+
+ $offsets['originals_length'] = $offsets['translations_addr'] - $offsets['originals_addr'];
+ $offsets['translations_length'] = $offsets['hash_addr'] - $offsets['translations_addr'];
+
+ if ( $offsets['rev'] > 0 ) {
+ $this->error = 'Unsupported revision';
+ return false;
+ }
+
+ if ( $offsets['translations_addr'] > $file_length || $offsets['originals_addr'] > $file_length ) {
+ $this->error = 'Invalid data';
+ return false;
+ }
+
+ // Load the Originals.
+ $original_data = str_split( substr( $file_contents, $offsets['originals_addr'], $offsets['originals_length'] ), 8 );
+ $translations_data = str_split( substr( $file_contents, $offsets['translations_addr'], $offsets['translations_length'] ), 8 );
+
+ foreach ( array_keys( $original_data ) as $i ) {
+ $o = unpack( "{$this->uint32}length/{$this->uint32}pos", $original_data[ $i ] );
+ $t = unpack( "{$this->uint32}length/{$this->uint32}pos", $translations_data[ $i ] );
+
+ if ( false === $o || false === $t ) {
+ continue;
+ }
+
+ $original = substr( $file_contents, $o['pos'], $o['length'] );
+ $translation = substr( $file_contents, $t['pos'], $t['length'] );
+ // GlotPress bug.
+ $translation = rtrim( $translation, "\0" );
+
+ // Metadata about the MO file is stored in the first translation entry.
+ if ( '' === $original ) {
+ foreach ( explode( "\n", $translation ) as $meta_line ) {
+ if ( '' === $meta_line ) {
+ continue;
+ }
+
+ list( $name, $value ) = array_map( 'trim', explode( ':', $meta_line, 2 ) );
+
+ $this->headers[ strtolower( $name ) ] = $value;
+ }
+ } else {
+ /*
+ * In MO files, the key normally contains both singular and plural versions.
+ * However, this just adds the singular string for lookup,
+ * which caters for cases where both __( 'Product' ) and _n( 'Product', 'Products' )
+ * are used and the translation is expected to be the same for both.
+ */
+ $parts = explode( "\0", (string) $original );
+
+ $this->entries[ $parts[0] ] = $translation;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Exports translation contents as a string.
+ *
+ * @since 6.5.0
+ *
+ * @return string Translation file contents.
+ */
+ public function export(): string {
+ // Prefix the headers as the first key.
+ $headers_string = '';
+ foreach ( $this->headers as $header => $value ) {
+ $headers_string .= "{$header}: $value\n";
+ }
+ $entries = array_merge( array( '' => $headers_string ), $this->entries );
+ $entry_count = count( $entries );
+
+ if ( false === $this->uint32 ) {
+ $this->uint32 = 'V';
+ }
+
+ $bytes_for_entries = $entry_count * 4 * 2;
+ // Pair of 32bit ints per entry.
+ $originals_addr = 28; /* header */
+ $translations_addr = $originals_addr + $bytes_for_entries;
+ $hash_addr = $translations_addr + $bytes_for_entries;
+ $entry_offsets = $hash_addr;
+
+ $file_header = pack( $this->uint32 . '*', self::MAGIC_MARKER, 0 /* rev */, $entry_count, $originals_addr, $translations_addr, 0 /* hash_length */, $hash_addr );
+
+ $o_entries = '';
+ $t_entries = '';
+ $o_addr = '';
+ $t_addr = '';
+
+ foreach ( array_keys( $entries ) as $original ) {
+ $o_addr .= pack( $this->uint32 . '*', strlen( $original ), $entry_offsets );
+ $entry_offsets += strlen( $original ) + 1;
+ $o_entries .= $original . "\0";
+ }
+
+ foreach ( $entries as $translations ) {
+ $t_addr .= pack( $this->uint32 . '*', strlen( $translations ), $entry_offsets );
+ $entry_offsets += strlen( $translations ) + 1;
+ $t_entries .= $translations . "\0";
+ }
+
+ return $file_header . $o_addr . $t_addr . $o_entries . $t_entries;
+ }
+}
diff --git a/src/wp-includes/l10n/class-wp-translation-file-php.php b/src/wp-includes/l10n/class-wp-translation-file-php.php
new file mode 100644
index 0000000000000..f93dd0163fddc
--- /dev/null
+++ b/src/wp-includes/l10n/class-wp-translation-file-php.php
@@ -0,0 +1,79 @@
+parsed = true;
+
+ $result = include $this->file;
+ if ( ! $result || ! is_array( $result ) ) {
+ $this->error = 'Invalid data';
+ return;
+ }
+
+ if ( isset( $result['messages'] ) && is_array( $result['messages'] ) ) {
+ foreach ( $result['messages'] as $original => $translation ) {
+ $this->entries[ (string) $original ] = $translation;
+ }
+ unset( $result['messages'] );
+ }
+
+ $this->headers = array_change_key_case( $result );
+ }
+
+ /**
+ * Exports translation contents as a string.
+ *
+ * @since 6.5.0
+ *
+ * @return string Translation file contents.
+ */
+ public function export(): string {
+ $data = array_merge( $this->headers, array( 'messages' => $this->entries ) );
+
+ return 'var_export( $data ) . ';' . PHP_EOL;
+ }
+
+ /**
+ * Outputs or returns a parsable string representation of a variable.
+ *
+ * Like {@see var_export()} but "minified", using short array syntax
+ * and no newlines.
+ *
+ * @since 6.5.0
+ *
+ * @param mixed $value The variable you want to export.
+ * @return string The variable representation.
+ */
+ private function var_export( $value ): string {
+ if ( ! is_array( $value ) ) {
+ return var_export( $value, true );
+ }
+
+ $entries = array();
+
+ $is_list = array_is_list( $value );
+
+ foreach ( $value as $key => $val ) {
+ $entries[] = $is_list ? $this->var_export( $val ) : var_export( $key, true ) . '=>' . $this->var_export( $val );
+ }
+
+ return '[' . implode( ',', $entries ) . ']';
+ }
+}
diff --git a/src/wp-includes/l10n/class-wp-translation-file.php b/src/wp-includes/l10n/class-wp-translation-file.php
new file mode 100644
index 0000000000000..e550f9c2f042a
--- /dev/null
+++ b/src/wp-includes/l10n/class-wp-translation-file.php
@@ -0,0 +1,312 @@
+
+ */
+ protected $headers = array();
+
+ /**
+ * Whether file has been parsed.
+ *
+ * @since 6.5.0
+ * @var bool
+ */
+ protected $parsed = false;
+
+ /**
+ * Error information.
+ *
+ * @since 6.5.0
+ * @var string|null Error message or null if no error.
+ */
+ protected $error;
+
+ /**
+ * File name.
+ *
+ * @since 6.5.0
+ * @var string
+ */
+ protected $file = '';
+
+ /**
+ * Translation entries.
+ *
+ * @since 6.5.0
+ * @var array
+ */
+ protected $entries = array();
+
+ /**
+ * Plural forms function.
+ *
+ * @since 6.5.0
+ * @var callable|null Plural forms.
+ */
+ protected $plural_forms = null;
+
+ /**
+ * Constructor.
+ *
+ * @since 6.5.0
+ *
+ * @param string $file File to load.
+ */
+ protected function __construct( string $file ) {
+ $this->file = $file;
+ }
+
+ /**
+ * Creates a new WP_Translation_File instance for a given file.
+ *
+ * @since 6.5.0
+ *
+ * @param string $file File name.
+ * @param string|null $filetype Optional. File type. Default inferred from file name.
+ * @return false|WP_Translation_File
+ */
+ public static function create( string $file, string $filetype = null ) {
+ if ( ! is_readable( $file ) ) {
+ return false;
+ }
+
+ if ( null === $filetype ) {
+ $pos = strrpos( $file, '.' );
+ if ( false !== $pos ) {
+ $filetype = substr( $file, $pos + 1 );
+ }
+ }
+
+ switch ( $filetype ) {
+ case 'mo':
+ return new WP_Translation_File_MO( $file );
+ case 'php':
+ return new WP_Translation_File_PHP( $file );
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Creates a new WP_Translation_File instance for a given file.
+ *
+ * @since 6.5.0
+ *
+ * @param string $file Source file name.
+ * @param string $filetype Desired target file type.
+ * @return string|false Transformed translation file contents on success, false otherwise.
+ */
+ public static function transform( string $file, string $filetype ) {
+ $source = self::create( $file );
+
+ if ( false === $source ) {
+ return false;
+ }
+
+ switch ( $filetype ) {
+ case 'mo':
+ $destination = new WP_Translation_File_MO( '' );
+ break;
+ case 'php':
+ $destination = new WP_Translation_File_PHP( '' );
+ break;
+ default:
+ return false;
+ }
+
+ $success = $destination->import( $source );
+
+ if ( ! $success ) {
+ return false;
+ }
+
+ return $destination->export();
+ }
+
+ /**
+ * Returns all headers.
+ *
+ * @since 6.5.0
+ *
+ * @return array Headers.
+ */
+ public function headers(): array {
+ if ( ! $this->parsed ) {
+ $this->parse_file();
+ }
+ return $this->headers;
+ }
+
+ /**
+ * Returns all entries.
+ *
+ * @since 6.5.0
+ *
+ * @return array Entries.
+ */
+ public function entries(): array {
+ if ( ! $this->parsed ) {
+ $this->parse_file();
+ }
+
+ return $this->entries;
+ }
+
+ /**
+ * Returns the current error information.
+ *
+ * @since 6.5.0
+ *
+ * @return string|null Error message or null if no error.
+ */
+ public function error() {
+ return $this->error;
+ }
+
+ /**
+ * Returns the file name.
+ *
+ * @since 6.5.0
+ *
+ * @return string File name.
+ */
+ public function get_file(): string {
+ return $this->file;
+ }
+
+ /**
+ * Translates a given string.
+ *
+ * @since 6.5.0
+ *
+ * @param string $text String to translate.
+ * @return false|string Translation(s) on success, false otherwise.
+ */
+ public function translate( string $text ) {
+ if ( ! $this->parsed ) {
+ $this->parse_file();
+ }
+
+ return $this->entries[ $text ] ?? false;
+ }
+
+ /**
+ * Returns the plural form for a given number.
+ *
+ * @since 6.5.0
+ *
+ * @param int $number Count.
+ * @return int Plural form.
+ */
+ public function get_plural_form( int $number ): int {
+ if ( ! $this->parsed ) {
+ $this->parse_file();
+ }
+
+ if ( null === $this->plural_forms && isset( $this->headers['plural-forms'] ) ) {
+ $expression = $this->get_plural_expression_from_header( $this->headers['plural-forms'] );
+ $this->plural_forms = $this->make_plural_form_function( $expression );
+ }
+
+ if ( is_callable( $this->plural_forms ) ) {
+ /**
+ * Plural form.
+ *
+ * @var int $result Plural form.
+ */
+ $result = call_user_func( $this->plural_forms, $number );
+
+ return $result;
+ }
+
+ // Default plural form matches English, only "One" is considered singular.
+ return ( 1 === $number ? 0 : 1 );
+ }
+
+ /**
+ * Returns the plural forms expression as a tuple.
+ *
+ * @since 6.5.0
+ *
+ * @param string $header Plural-Forms header string.
+ * @return string Plural forms expression.
+ */
+ protected function get_plural_expression_from_header( string $header ): string {
+ if ( preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s+plural\s*=\s*(.+)$/', $header, $matches ) ) {
+ return trim( $matches[2] );
+ }
+
+ return 'n != 1';
+ }
+
+ /**
+ * Makes a function, which will return the right translation index, according to the
+ * plural forms header.
+ *
+ * @since 6.5.0
+ *
+ * @param string $expression Plural form expression.
+ * @return callable(int $num): int Plural forms function.
+ */
+ protected function make_plural_form_function( string $expression ): callable {
+ try {
+ $handler = new Plural_Forms( rtrim( $expression, ';' ) );
+ return array( $handler, 'get' );
+ } catch ( Exception $e ) {
+ // Fall back to default plural-form function.
+ return $this->make_plural_form_function( 'n != 1' );
+ }
+ }
+
+ /**
+ * Imports translations from another file.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Translation_File $source Source file.
+ * @return bool True on success, false otherwise.
+ */
+ protected function import( WP_Translation_File $source ): bool {
+ if ( null !== $source->error() ) {
+ return false;
+ }
+
+ $this->headers = $source->headers();
+ $this->entries = $source->entries();
+ $this->error = $source->error();
+
+ return null === $this->error;
+ }
+
+ /**
+ * Parses the file.
+ *
+ * @since 6.5.0
+ */
+ abstract protected function parse_file();
+
+ /**
+ * Exports translation contents as a string.
+ *
+ * @since 6.5.0
+ *
+ * @return string Translation file contents.
+ */
+ abstract public function export();
+}
diff --git a/src/wp-includes/l10n/class-wp-translations.php b/src/wp-includes/l10n/class-wp-translations.php
new file mode 100644
index 0000000000000..e177e1d8c536b
--- /dev/null
+++ b/src/wp-includes/l10n/class-wp-translations.php
@@ -0,0 +1,152 @@
+ $headers
+ * @property-read array $entries
+ */
+class WP_Translations {
+ /**
+ * Text domain.
+ *
+ * @since 6.5.0
+ * @var string
+ */
+ protected $textdomain = 'default';
+
+ /**
+ * Translation controller instance.
+ *
+ * @since 6.5.0
+ * @var WP_Translation_Controller
+ */
+ protected $controller;
+
+ /**
+ * Constructor.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Translation_Controller $controller I18N controller.
+ * @param string $textdomain Optional. Text domain. Default 'default'.
+ */
+ public function __construct( WP_Translation_Controller $controller, string $textdomain = 'default' ) {
+ $this->controller = $controller;
+ $this->textdomain = $textdomain;
+ }
+
+ /**
+ * Magic getter for backward compatibility.
+ *
+ * @since 6.5.0
+ *
+ * @param string $name Property name.
+ * @return mixed
+ */
+ public function __get( string $name ) {
+ if ( 'entries' === $name ) {
+ $entries = $this->controller->get_entries( $this->textdomain );
+
+ $result = array();
+
+ foreach ( $entries as $original => $translations ) {
+ $result[] = $this->make_entry( $original, $translations );
+ }
+
+ return $result;
+ }
+
+ if ( 'headers' === $name ) {
+ return $this->controller->get_headers( $this->textdomain );
+ }
+
+ return null;
+ }
+
+ /**
+ * Builds a Translation_Entry from original string and translation strings.
+ *
+ * @see MO::make_entry()
+ *
+ * @since 6.5.0
+ *
+ * @param string $original Original string to translate from MO file. Might contain
+ * 0x04 as context separator or 0x00 as singular/plural separator.
+ * @param string $translations Translation strings from MO file.
+ * @return Translation_Entry Entry instance.
+ */
+ private function make_entry( $original, $translations ): Translation_Entry {
+ $entry = new Translation_Entry();
+
+ // Look for context, separated by \4.
+ $parts = explode( "\4", $original );
+ if ( isset( $parts[1] ) ) {
+ $original = $parts[1];
+ $entry->context = $parts[0];
+ }
+
+ $entry->singular = $original;
+ $entry->translations = explode( "\0", $translations );
+ $entry->is_plural = count( $entry->translations ) > 1;
+
+ return $entry;
+ }
+
+ /**
+ * Translates a plural string.
+ *
+ * @since 6.5.0
+ *
+ * @param string|null $singular Singular string.
+ * @param string|null $plural Plural string.
+ * @param int|float $count Count. Should be an integer, but some plugins pass floats.
+ * @param string|null $context Context.
+ * @return string|null Translation if it exists, or the unchanged singular string.
+ */
+ public function translate_plural( $singular, $plural, $count = 1, $context = '' ) {
+ if ( null === $singular || null === $plural ) {
+ return $singular;
+ }
+
+ $translation = $this->controller->translate_plural( array( $singular, $plural ), (int) $count, (string) $context, $this->textdomain );
+ if ( false !== $translation ) {
+ return $translation;
+ }
+
+ // Fall back to the original with English grammar rules.
+ return ( 1 === $count ? $singular : $plural );
+ }
+
+ /**
+ * Translates a singular string.
+ *
+ * @since 6.5.0
+ *
+ * @param string|null $singular Singular string.
+ * @param string|null $context Context.
+ * @return string|null Translation if it exists, or the unchanged singular string
+ */
+ public function translate( $singular, $context = '' ) {
+ if ( null === $singular ) {
+ return null;
+ }
+
+ $translation = $this->controller->translate( $singular, (string) $context, $this->textdomain );
+ if ( false !== $translation ) {
+ return $translation;
+ }
+
+ // Fall back to the original.
+ return $singular;
+ }
+}
diff --git a/src/wp-includes/link-template.php b/src/wp-includes/link-template.php
index 9f3d9a97ee440..a782edfb85548 100644
--- a/src/wp-includes/link-template.php
+++ b/src/wp-includes/link-template.php
@@ -4768,7 +4768,7 @@ function get_the_privacy_policy_link( $before = '', $after = '' ) {
* By default the list of internal hosts is comprised of the host name of
* the site's home_url() (as parsed by wp_parse_url()).
*
- * This list is used when determining if a specificed URL is a link to a page on
+ * This list is used when determining if a specified URL is a link to a page on
* the site itself or a link offsite (to an external host). This is used, for
* example, when determining if the "nofollow" attribute should be applied to a
* link.
diff --git a/src/wp-includes/load.php b/src/wp-includes/load.php
index 520902cdd64ba..78961bccec9e2 100644
--- a/src/wp-includes/load.php
+++ b/src/wp-includes/load.php
@@ -598,6 +598,10 @@ function wp_debug_mode() {
error_reporting( E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR );
}
+ /*
+ * The 'REST_REQUEST' check here is optimistic as the constant is most
+ * likely not set at this point even if it is in fact a REST request.
+ */
if ( defined( 'XMLRPC_REQUEST' ) || defined( 'REST_REQUEST' ) || defined( 'MS_FILES_REQUEST' )
|| ( defined( 'WP_INSTALLING' ) && WP_INSTALLING )
|| wp_doing_ajax() || wp_is_json_request()
@@ -982,6 +986,7 @@ function wp_get_active_and_valid_plugins() {
$network_plugins = is_multisite() ? wp_get_active_network_plugins() : false;
+ $invalid_plugins = array();
foreach ( $active_plugins as $plugin ) {
if ( ! validate_file( $plugin ) // $plugin must validate as file.
&& str_ends_with( $plugin, '.php' ) // $plugin must end with '.php'.
@@ -990,6 +995,20 @@ function wp_get_active_and_valid_plugins() {
&& ( ! $network_plugins || ! in_array( WP_PLUGIN_DIR . '/' . $plugin, $network_plugins, true ) )
) {
$plugins[] = WP_PLUGIN_DIR . '/' . $plugin;
+ } else {
+ $invalid_plugins[] = $plugin;
+ }
+ }
+
+ if ( ! empty( $invalid_plugins ) ) {
+ $all_plugin_data = get_option( 'plugin_data', array() );
+
+ if ( ! empty( $all_plugin_data ) ) {
+ foreach ( $invalid_plugins as $invalid_plugin ) {
+ unset( $all_plugin_data[ $invalid_plugin ] );
+ }
+
+ update_option( 'plugin_data', $all_plugin_data );
}
}
@@ -1186,6 +1205,7 @@ function is_protected_ajax_action() {
'search-install-plugins', // Searching for a plugin in the plugin install screen.
'update-plugin', // Update an existing plugin.
'update-theme', // Update an existing theme.
+ 'activate-plugin', // Activating an existing plugin.
);
/**
@@ -1480,6 +1500,11 @@ function wp_load_translations_early() {
// Translation and localization.
require_once ABSPATH . WPINC . '/pomo/mo.php';
+ require_once ABSPATH . WPINC . '/l10n/class-wp-translation-controller.php';
+ require_once ABSPATH . WPINC . '/l10n/class-wp-translations.php';
+ require_once ABSPATH . WPINC . '/l10n/class-wp-translation-file.php';
+ require_once ABSPATH . WPINC . '/l10n/class-wp-translation-file-mo.php';
+ require_once ABSPATH . WPINC . '/l10n/class-wp-translation-file-php.php';
require_once ABSPATH . WPINC . '/l10n.php';
require_once ABSPATH . WPINC . '/class-wp-textdomain-registry.php';
require_once ABSPATH . WPINC . '/class-wp-locale.php';
diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php
index 38ec2213b7506..69a6d53299cab 100644
--- a/src/wp-includes/media.php
+++ b/src/wp-includes/media.php
@@ -4100,6 +4100,7 @@ function _wp_image_editor_choose( $args = array() ) {
require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';
require_once ABSPATH . WPINC . '/class-wp-image-editor-imagick.php';
+ require_once ABSPATH . WPINC . '/class-avif-info.php';
/**
* Filters the list of image editing library classes.
*
@@ -4204,6 +4205,11 @@ function wp_plupload_default_settings() {
$defaults['webp_upload_error'] = true;
}
+ // Check if AVIF images can be edited.
+ if ( ! wp_image_editor_supports( array( 'mime_type' => 'image/avif' ) ) ) {
+ $defaults['avif_upload_error'] = true;
+ }
+
/**
* Filters the Plupload default settings.
*
@@ -5480,6 +5486,7 @@ function wp_show_heic_upload_error( $plupload_settings ) {
*
* @since 5.7.0
* @since 5.8.0 Added support for WebP images.
+ * @since 6.5.0 Added support for AVIF images.
*
* @param string $filename The file path.
* @param array $image_info Optional. Extended image information (passed by reference).
@@ -5512,7 +5519,11 @@ function wp_getimagesize( $filename, array &$image_info = null ) {
}
}
- if ( false !== $info ) {
+ if (
+ ! empty( $info ) &&
+ // Some PHP versions return 0x0 sizes from `getimagesize` for unrecognized image formats, including AVIFs.
+ ! ( empty( $info[0] ) && empty( $info[1] ) )
+ ) {
return $info;
}
@@ -5541,10 +5552,75 @@ function wp_getimagesize( $filename, array &$image_info = null ) {
}
}
+ // For PHP versions that don't support AVIF images, extract the image size info from the file headers.
+ if ( 'image/avif' === wp_get_image_mime( $filename ) ) {
+ $avif_info = wp_get_avif_info( $filename );
+
+ $width = $avif_info['width'];
+ $height = $avif_info['height'];
+
+ // Mimic the native return format.
+ if ( $width && $height ) {
+ return array(
+ $width,
+ $height,
+ IMAGETYPE_AVIF,
+ sprintf(
+ 'width="%d" height="%d"',
+ $width,
+ $height
+ ),
+ 'mime' => 'image/avif',
+ );
+ }
+ }
+
// The image could not be parsed.
return false;
}
+/**
+ * Extracts meta information about an AVIF file: width, height, bit depth, and number of channels.
+ *
+ * @since 6.5.0
+ *
+ * @param string $filename Path to an AVIF file.
+ * @return array {
+ * An array of AVIF image information.
+ *
+ * @type int|false $width Image width on success, false on failure.
+ * @type int|false $height Image height on success, false on failure.
+ * @type int|false $bit_depth Image bit depth on success, false on failure.
+ * @type int|false $num_channels Image number of channels on success, false on failure.
+ * }
+ */
+function wp_get_avif_info( $filename ) {
+ $results = array(
+ 'width' => false,
+ 'height' => false,
+ 'bit_depth' => false,
+ 'num_channels' => false,
+ );
+
+ if ( 'image/avif' !== wp_get_image_mime( $filename ) ) {
+ return $results;
+ }
+
+ // Parse the file using libavifinfo's PHP implementation.
+ require_once ABSPATH . WPINC . '/class-avif-info.php';
+
+ $handle = fopen( $filename, 'rb' );
+ if ( $handle ) {
+ $parser = new Avifinfo\Parser( $handle );
+ $success = $parser->parse_ftyp() && $parser->parse_file();
+ fclose( $handle );
+ if ( $success ) {
+ $results = $parser->features->primary_item_features;
+ }
+ }
+ return $results;
+}
+
/**
* Extracts meta information about a WebP file: width, height, and type.
*
diff --git a/src/wp-includes/pomo/po.php b/src/wp-includes/pomo/po.php
index 7b9ec0b88bb2c..a4e3cab4ef17a 100644
--- a/src/wp-includes/pomo/po.php
+++ b/src/wp-includes/pomo/po.php
@@ -53,7 +53,7 @@ public function export_headers() {
/**
* Exports all entries to PO format
*
- * @return string sequence of mgsgid/msgstr PO strings, doesn't containt newline at the end
+ * @return string sequence of msgid/msgstr PO strings, doesn't contain a newline at the end
*/
public function export_entries() {
// TODO: Sorting.
@@ -64,7 +64,7 @@ public function export_entries() {
* Exports the whole PO file as a string
*
* @param bool $include_headers whether to include the headers in the export
- * @return string ready for inclusion in PO file string for headers and all the enrtries
+ * @return string ready for inclusion in PO file string for headers and all the entries
*/
public function export( $include_headers = true ) {
$res = '';
@@ -127,7 +127,7 @@ public static function poify( $input_string ) {
$input_string = str_replace( array_keys( $replaces ), array_values( $replaces ), $input_string );
$po = $quote . implode( "{$slash}n{$quote}{$newline}{$quote}", explode( $newline, $input_string ) ) . $quote;
- // Add empty string on first line for readbility.
+ // Add empty string on first line for readability.
if ( str_contains( $input_string, $newline ) &&
( substr_count( $input_string, $newline ) > 1 || substr( $input_string, -strlen( $newline ) ) !== $newline ) ) {
$po = "$quote$quote$newline$po";
@@ -141,7 +141,7 @@ public static function poify( $input_string ) {
* Gives back the original string from a PO-formatted string
*
* @param string $input_string PO-formatted string
- * @return string enascaped string
+ * @return string unescaped string
*/
public static function unpoify( $input_string ) {
$escapes = array(
diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php
index 69a63625524d1..5fa058363af9b 100644
--- a/src/wp-includes/post.php
+++ b/src/wp-includes/post.php
@@ -564,6 +564,72 @@ function create_initial_post_types() {
)
);
+ register_post_type(
+ 'wp_font_family',
+ array(
+ 'labels' => array(
+ 'name' => __( 'Font Families' ),
+ 'singular_name' => __( 'Font Family' ),
+ ),
+ 'public' => false,
+ '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+ 'hierarchical' => false,
+ 'capabilities' => array(
+ 'read' => 'edit_theme_options',
+ 'read_private_posts' => 'edit_theme_options',
+ 'create_posts' => 'edit_theme_options',
+ 'publish_posts' => 'edit_theme_options',
+ 'edit_posts' => 'edit_theme_options',
+ 'edit_others_posts' => 'edit_theme_options',
+ 'edit_published_posts' => 'edit_theme_options',
+ 'delete_posts' => 'edit_theme_options',
+ 'delete_others_posts' => 'edit_theme_options',
+ 'delete_published_posts' => 'edit_theme_options',
+ ),
+ 'map_meta_cap' => true,
+ 'query_var' => false,
+ 'rewrite' => false,
+ 'show_in_rest' => true,
+ 'rest_base' => 'font-families',
+ 'rest_controller_class' => 'WP_REST_Font_Families_Controller',
+ // Disable autosave endpoints for font families.
+ 'autosave_rest_controller_class' => 'stdClass',
+ )
+ );
+
+ register_post_type(
+ 'wp_font_face',
+ array(
+ 'labels' => array(
+ 'name' => __( 'Font Faces' ),
+ 'singular_name' => __( 'Font Face' ),
+ ),
+ 'public' => false,
+ '_builtin' => true, /* internal use only. don't use this when registering your own post type. */
+ 'hierarchical' => false,
+ 'capabilities' => array(
+ 'read' => 'edit_theme_options',
+ 'read_private_posts' => 'edit_theme_options',
+ 'create_posts' => 'edit_theme_options',
+ 'publish_posts' => 'edit_theme_options',
+ 'edit_posts' => 'edit_theme_options',
+ 'edit_others_posts' => 'edit_theme_options',
+ 'edit_published_posts' => 'edit_theme_options',
+ 'delete_posts' => 'edit_theme_options',
+ 'delete_others_posts' => 'edit_theme_options',
+ 'delete_published_posts' => 'edit_theme_options',
+ ),
+ 'map_meta_cap' => true,
+ 'query_var' => false,
+ 'rewrite' => false,
+ 'show_in_rest' => true,
+ 'rest_base' => 'font-families/(?P[\d]+)/font-faces',
+ 'rest_controller_class' => 'WP_REST_Font_Faces_Controller',
+ // Disable autosave endpoints for font faces.
+ 'autosave_rest_controller_class' => 'stdClass',
+ )
+ );
+
register_post_status(
'publish',
array(
@@ -6700,7 +6766,7 @@ function wp_attachment_is( $type, $post = null ) {
switch ( $type ) {
case 'image':
- $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'webp' );
+ $image_exts = array( 'jpg', 'jpeg', 'jpe', 'gif', 'png', 'webp', 'avif' );
return in_array( $ext, $image_exts, true );
case 'audio':
diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php
index 61e324e801445..b44b205afb6ef 100644
--- a/src/wp-includes/rest-api.php
+++ b/src/wp-includes/rest-api.php
@@ -209,7 +209,7 @@ function rest_api_register_rewrites() {
* @since 4.4.0
*/
function rest_api_default_filters() {
- if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
+ if ( wp_is_serving_rest_request() ) {
// Deprecated reporting.
add_action( 'deprecated_function_run', 'rest_handle_deprecated_function', 10, 3 );
add_filter( 'deprecated_function_trigger_error', '__return_false' );
@@ -391,6 +391,10 @@ function create_initial_rest_routes() {
// Navigation Fallback.
$controller = new WP_REST_Navigation_Fallback_Controller();
$controller->register_routes();
+
+ // Font Collections.
+ $font_collections_controller = new WP_REST_Font_Collections_Controller();
+ $font_collections_controller->register_routes();
}
/**
@@ -3389,3 +3393,38 @@ static function ( $status, $error_data ) {
return new WP_REST_Response( $data, $status );
}
+
+/**
+ * Checks whether a REST API endpoint request is currently being handled.
+ *
+ * This may be a standalone REST API request, or an internal request dispatched from within a regular page load.
+ *
+ * @since 6.5.0
+ *
+ * @global WP_REST_Server $wp_rest_server REST server instance.
+ *
+ * @return bool True if a REST endpoint request is currently being handled, false otherwise.
+ */
+function wp_is_rest_endpoint() {
+ /* @var WP_REST_Server $wp_rest_server */
+ global $wp_rest_server;
+
+ // Check whether this is a standalone REST request.
+ $is_rest_endpoint = wp_is_serving_rest_request();
+ if ( ! $is_rest_endpoint ) {
+ // Otherwise, check whether an internal REST request is currently being handled.
+ $is_rest_endpoint = isset( $wp_rest_server )
+ && $wp_rest_server->is_dispatching();
+ }
+
+ /**
+ * Filters whether a REST endpoint request is currently being handled.
+ *
+ * This may be a standalone REST API request, or an internal request dispatched from within a regular page load.
+ *
+ * @since 6.5.0
+ *
+ * @param bool $is_request_endpoint Whether a REST endpoint request is currently being handled.
+ */
+ return (bool) apply_filters( 'wp_is_rest_endpoint', $is_rest_endpoint );
+}
diff --git a/src/wp-includes/rest-api/class-wp-rest-server.php b/src/wp-includes/rest-api/class-wp-rest-server.php
index 6838579ce8609..861f5115e6ae9 100644
--- a/src/wp-includes/rest-api/class-wp-rest-server.php
+++ b/src/wp-includes/rest-api/class-wp-rest-server.php
@@ -87,6 +87,14 @@ class WP_REST_Server {
*/
protected $embed_cache = array();
+ /**
+ * Stores request objects that are currently being handled.
+ *
+ * @since 6.5.0
+ * @var array
+ */
+ protected $dispatching_requests = array();
+
/**
* Instantiates the REST server.
*
@@ -983,6 +991,8 @@ public function get_route_options( $route ) {
* @return WP_REST_Response Response returned by the callback.
*/
public function dispatch( $request ) {
+ $this->dispatching_requests[] = $request;
+
/**
* Filters the pre-calculated result of a REST API dispatch request.
*
@@ -1008,6 +1018,7 @@ public function dispatch( $request ) {
$result = $this->error_to_response( $result );
}
+ array_pop( $this->dispatching_requests );
return $result;
}
@@ -1015,7 +1026,9 @@ public function dispatch( $request ) {
$matched = $this->match_request_to_handler( $request );
if ( is_wp_error( $matched ) ) {
- return $this->error_to_response( $matched );
+ $response = $this->error_to_response( $matched );
+ array_pop( $this->dispatching_requests );
+ return $response;
}
list( $route, $handler ) = $matched;
@@ -1040,7 +1053,22 @@ public function dispatch( $request ) {
}
}
- return $this->respond_to_request( $request, $route, $handler, $error );
+ $response = $this->respond_to_request( $request, $route, $handler, $error );
+ array_pop( $this->dispatching_requests );
+ return $response;
+ }
+
+ /**
+ * Returns whether the REST server is currently dispatching / responding to a request.
+ *
+ * This may be a standalone REST API request, or an internal request dispatched from within a regular page load.
+ *
+ * @since 6.5.0
+ *
+ * @return bool Whether the REST server is currently handling a request.
+ */
+ public function is_dispatching() {
+ return (bool) $this->dispatching_requests;
}
/**
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
index 7367c0fc57a07..8a26a79a67932 100644
--- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php
@@ -186,6 +186,12 @@ public function create_item( $request ) {
return $fields_update;
}
+ $terms_update = $this->handle_terms( $attachment_id, $request );
+
+ if ( is_wp_error( $terms_update ) ) {
+ return $terms_update;
+ }
+
$request->set_param( 'context', 'edit' );
/**
@@ -201,7 +207,7 @@ public function create_item( $request ) {
wp_after_insert_post( $attachment, false, null );
- if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
+ if ( wp_is_serving_rest_request() ) {
/*
* Set a custom header with the attachment_id.
* Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
@@ -450,7 +456,7 @@ public function edit_media_item( $request ) {
);
}
- $supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp' );
+ $supported_types = array( 'image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif' );
$mime_type = get_post_mime_type( $attachment_id );
if ( ! in_array( $mime_type, $supported_types, true ) ) {
return new WP_Error(
@@ -630,7 +636,7 @@ public function edit_media_item( $request ) {
update_post_meta( $new_attachment_id, '_wp_attachment_image_alt', wp_slash( $image_alt ) );
}
- if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
+ if ( wp_is_serving_rest_request() ) {
/*
* Set a custom header with the attachment_id.
* Used by the browser/client to resume creating image sub-sizes after a PHP fatal error.
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php
index 852143d96ec35..7bf2f6af4af2e 100644
--- a/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php
@@ -280,6 +280,7 @@ public function prepare_item_for_response( $item, $request ) {
'keywords',
'parent',
'ancestor',
+ 'allowed_blocks',
'provides_context',
'uses_context',
'selectors',
@@ -292,6 +293,7 @@ public function prepare_item_for_response( $item, $request ) {
'view_script_handles',
'editor_style_handles',
'style_handles',
+ 'view_style_handles',
'variations',
'block_hooks',
),
@@ -602,6 +604,16 @@ public function get_item_schema() {
'context' => array( 'embed', 'view', 'edit' ),
'readonly' => true,
),
+ 'view_style_handles' => array(
+ 'description' => __( 'Public facing style handles.' ),
+ 'type' => array( 'array' ),
+ 'default' => array(),
+ 'items' => array(
+ 'type' => 'string',
+ ),
+ 'context' => array( 'embed', 'view', 'edit' ),
+ 'readonly' => true,
+ ),
'styles' => array(
'description' => __( 'Block style variations.' ),
'type' => 'array',
@@ -712,6 +724,17 @@ public function get_item_schema() {
'context' => array( 'embed', 'view', 'edit' ),
'readonly' => true,
),
+ 'allowed_blocks' => array(
+ 'description' => __( 'Allowed child block types.' ),
+ 'type' => array( 'array', 'null' ),
+ 'items' => array(
+ 'type' => 'string',
+ 'pattern' => self::NAME_PATTERN,
+ ),
+ 'default' => null,
+ 'context' => array( 'embed', 'view', 'edit' ),
+ 'readonly' => true,
+ ),
'keywords' => $keywords_definition,
'example' => $example_definition,
'block_hooks' => array(
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php
new file mode 100644
index 0000000000000..05ef0c7b11b64
--- /dev/null
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php
@@ -0,0 +1,322 @@
+rest_base = 'font-collections';
+ $this->namespace = 'wp/v2';
+ }
+
+ /**
+ * Registers the routes for the objects of the controller.
+ *
+ * @since 6.5.0
+ */
+ public function register_routes() {
+ register_rest_route(
+ $this->namespace,
+ '/' . $this->rest_base,
+ array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_items' ),
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
+ 'args' => $this->get_collection_params(),
+
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ )
+ );
+
+ register_rest_route(
+ $this->namespace,
+ '/' . $this->rest_base . '/(?P[\/\w-]+)',
+ array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_item' ),
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
+ 'args' => array(
+ 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
+ ),
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ )
+ );
+ }
+
+ /**
+ * Gets the font collections available.
+ *
+ * @since 6.5.0
+ *
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function get_items( $request ) {
+ $collections_all = WP_Font_Library::get_instance()->get_font_collections();
+
+ $page = $request['page'];
+ $per_page = $request['per_page'];
+ $total_items = count( $collections_all );
+ $max_pages = ceil( $total_items / $per_page );
+
+ if ( $page > $max_pages && $total_items > 0 ) {
+ return new WP_Error(
+ 'rest_post_invalid_page_number',
+ __( 'The page number requested is larger than the number of pages available.' ),
+ array( 'status' => 400 )
+ );
+ }
+
+ $collections_page = array_slice( $collections_all, ( $page - 1 ) * $per_page, $per_page );
+
+ $items = array();
+ foreach ( $collections_page as $collection ) {
+ $item = $this->prepare_item_for_response( $collection, $request );
+
+ // If there's an error loading a collection, skip it and continue loading valid collections.
+ if ( is_wp_error( $item ) ) {
+ continue;
+ }
+ $item = $this->prepare_response_for_collection( $item );
+ $items[] = $item;
+ }
+
+ $response = rest_ensure_response( $items );
+
+ $response->header( 'X-WP-Total', (int) $total_items );
+ $response->header( 'X-WP-TotalPages', (int) $max_pages );
+
+ $request_params = $request->get_query_params();
+ $collection_url = rest_url( $this->namespace . '/' . $this->rest_base );
+ $base = add_query_arg( urlencode_deep( $request_params ), $collection_url );
+
+ if ( $page > 1 ) {
+ $prev_page = $page - 1;
+
+ if ( $prev_page > $max_pages ) {
+ $prev_page = $max_pages;
+ }
+
+ $prev_link = add_query_arg( 'page', $prev_page, $base );
+ $response->link_header( 'prev', $prev_link );
+ }
+ if ( $max_pages > $page ) {
+ $next_page = $page + 1;
+ $next_link = add_query_arg( 'page', $next_page, $base );
+
+ $response->link_header( 'next', $next_link );
+ }
+
+ return $response;
+ }
+
+ /**
+ * Gets a font collection.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function get_item( $request ) {
+ $slug = $request->get_param( 'slug' );
+ $collection = WP_Font_Library::get_instance()->get_font_collection( $slug );
+
+ if ( ! $collection ) {
+ return new WP_Error( 'rest_font_collection_not_found', __( 'Font collection not found.' ), array( 'status' => 404 ) );
+ }
+
+ return $this->prepare_item_for_response( $collection, $request );
+ }
+
+ /**
+ * Prepare a single collection output for response.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Font_Collection $item Font collection object.
+ * @param WP_REST_Request $request Request object.
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function prepare_item_for_response( $item, $request ) {
+ $fields = $this->get_fields_for_response( $request );
+ $data = array();
+
+ if ( rest_is_field_included( 'slug', $fields ) ) {
+ $data['slug'] = $item->slug;
+ }
+
+ // If any data fields are requested, get the collection data.
+ $data_fields = array( 'name', 'description', 'font_families', 'categories' );
+ if ( ! empty( array_intersect( $fields, $data_fields ) ) ) {
+ $collection_data = $item->get_data();
+ if ( is_wp_error( $collection_data ) ) {
+ $collection_data->add_data( array( 'status' => 500 ) );
+ return $collection_data;
+ }
+
+ foreach ( $data_fields as $field ) {
+ if ( rest_is_field_included( $field, $fields ) ) {
+ $data[ $field ] = $collection_data[ $field ];
+ }
+ }
+ }
+
+ $response = rest_ensure_response( $data );
+
+ if ( rest_is_field_included( '_links', $fields ) ) {
+ $links = $this->prepare_links( $item );
+ $response->add_links( $links );
+ }
+
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
+ $response->data = $this->add_additional_fields_to_object( $response->data, $request );
+ $response->data = $this->filter_response_by_context( $response->data, $context );
+
+ /**
+ * Filters the font collection data for a REST API response.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Response $response The response object.
+ * @param WP_Font_Collection $item The font collection object.
+ * @param WP_REST_Request $request Request used to generate the response.
+ */
+ return apply_filters( 'rest_prepare_font_collection', $response, $item, $request );
+ }
+
+ /**
+ * Retrieves the font collection's schema, conforming to JSON Schema.
+ *
+ * @since 6.5.0
+ *
+ * @return array Item schema data.
+ */
+ public function get_item_schema() {
+ if ( $this->schema ) {
+ return $this->add_additional_fields_schema( $this->schema );
+ }
+
+ $schema = array(
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
+ 'title' => 'font-collection',
+ 'type' => 'object',
+ 'properties' => array(
+ 'slug' => array(
+ 'description' => __( 'Unique identifier for the font collection.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'name' => array(
+ 'description' => __( 'The name for the font collection.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ 'description' => array(
+ 'description' => __( 'The description for the font collection.' ),
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ 'font_families' => array(
+ 'description' => __( 'The font families for the font collection.' ),
+ 'type' => 'array',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ 'categories' => array(
+ 'description' => __( 'The categories for the font collection.' ),
+ 'type' => 'array',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ ),
+ );
+
+ $this->schema = $schema;
+
+ return $this->add_additional_fields_schema( $this->schema );
+ }
+
+ /**
+ * Prepares links for the request.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Font_Collection $collection Font collection data
+ * @return array Links for the given font collection.
+ */
+ protected function prepare_links( $collection ) {
+ return array(
+ 'self' => array(
+ 'href' => rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $collection->slug ) ),
+ ),
+ 'collection' => array(
+ 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
+ ),
+ );
+ }
+
+ /**
+ * Retrieves the search params for the font collections.
+ *
+ * @since 6.5.0
+ *
+ * @return array Collection parameters.
+ */
+ public function get_collection_params() {
+ $query_params = parent::get_collection_params();
+
+ $query_params['context'] = $this->get_context_param( array( 'default' => 'view' ) );
+
+ unset( $query_params['search'] );
+
+ /**
+ * Filters REST API collection parameters for the font collections controller.
+ *
+ * @since 6.5.0
+ *
+ * @param array $query_params JSON Schema-formatted collection parameters.
+ */
+ return apply_filters( 'rest_font_collections_collection_params', $query_params );
+ }
+
+ /**
+ * Checks whether the user has permissions to use the Fonts Collections.
+ *
+ * @since 6.5.0
+ *
+ * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise.
+ */
+ public function get_items_permissions_check( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
+ if ( current_user_can( 'edit_theme_options' ) ) {
+ return true;
+ }
+
+ return new WP_Error(
+ 'rest_cannot_read',
+ __( 'Sorry, you are not allowed to access font collections.' ),
+ array(
+ 'status' => rest_authorization_required_code(),
+ )
+ );
+ }
+}
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php
new file mode 100644
index 0000000000000..0a870b8c705ce
--- /dev/null
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php
@@ -0,0 +1,950 @@
+namespace,
+ '/' . $this->rest_base,
+ array(
+ 'args' => array(
+ 'font_family_id' => array(
+ 'description' => __( 'The ID for the parent font family of the font face.' ),
+ 'type' => 'integer',
+ 'required' => true,
+ ),
+ ),
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_items' ),
+ 'permission_callback' => array( $this, 'get_items_permissions_check' ),
+ 'args' => $this->get_collection_params(),
+ ),
+ array(
+ 'methods' => WP_REST_Server::CREATABLE,
+ 'callback' => array( $this, 'create_item' ),
+ 'permission_callback' => array( $this, 'create_item_permissions_check' ),
+ 'args' => $this->get_create_params(),
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ )
+ );
+
+ register_rest_route(
+ $this->namespace,
+ '/' . $this->rest_base . '/(?P[\d]+)',
+ array(
+ 'args' => array(
+ 'font_family_id' => array(
+ 'description' => __( 'The ID for the parent font family of the font face.' ),
+ 'type' => 'integer',
+ 'required' => true,
+ ),
+ 'id' => array(
+ 'description' => __( 'Unique identifier for the font face.' ),
+ 'type' => 'integer',
+ 'required' => true,
+ ),
+ ),
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_item' ),
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
+ 'args' => array(
+ 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
+ ),
+ ),
+ array(
+ 'methods' => WP_REST_Server::DELETABLE,
+ 'callback' => array( $this, 'delete_item' ),
+ 'permission_callback' => array( $this, 'delete_item_permissions_check' ),
+ 'args' => array(
+ 'force' => array(
+ 'type' => 'boolean',
+ 'default' => false,
+ 'description' => __( 'Whether to bypass Trash and force deletion.', 'default' ),
+ ),
+ ),
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ )
+ );
+ }
+
+ /**
+ * Checks if a given request has access to font faces.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
+ */
+ public function get_items_permissions_check( $request ) {
+ $post_type = get_post_type_object( $this->post_type );
+
+ if ( ! current_user_can( $post_type->cap->read ) ) {
+ return new WP_Error(
+ 'rest_cannot_read',
+ __( 'Sorry, you are not allowed to access font faces.' ),
+ array( 'status' => rest_authorization_required_code() )
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if a given request has access to a font face.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
+ */
+ public function get_item_permissions_check( $request ) {
+ $post = $this->get_post( $request['id'] );
+ if ( is_wp_error( $post ) ) {
+ return $post;
+ }
+
+ if ( ! current_user_can( 'read_post', $post->ID ) ) {
+ return new WP_Error(
+ 'rest_cannot_read',
+ __( 'Sorry, you are not allowed to access this font face.' ),
+ array( 'status' => rest_authorization_required_code() )
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Validates settings when creating a font face.
+ *
+ * @since 6.5.0
+ *
+ * @param string $value Encoded JSON string of font face settings.
+ * @param WP_REST_Request $request Request object.
+ * @return true|WP_Error True if the settings are valid, otherwise a WP_Error object.
+ */
+ public function validate_create_font_face_settings( $value, $request ) {
+ $settings = json_decode( $value, true );
+
+ // Check settings string is valid JSON.
+ if ( null === $settings ) {
+ return new WP_Error(
+ 'rest_invalid_param',
+ __( 'font_face_settings parameter must be a valid JSON string.' ),
+ array( 'status' => 400 )
+ );
+ }
+
+ // Check that the font face settings match the theme.json schema.
+ $schema = $this->get_item_schema()['properties']['font_face_settings'];
+ $has_valid_settings = rest_validate_value_from_schema( $settings, $schema, 'font_face_settings' );
+
+ if ( is_wp_error( $has_valid_settings ) ) {
+ $has_valid_settings->add_data( array( 'status' => 400 ) );
+ return $has_valid_settings;
+ }
+
+ // Check that none of the required settings are empty values.
+ $required = $schema['required'];
+ foreach ( $required as $key ) {
+ if ( isset( $settings[ $key ] ) && ! $settings[ $key ] ) {
+ return new WP_Error(
+ 'rest_invalid_param',
+ /* translators: %s: Name of the missing font face settings parameter, e.g. "font_face_settings[src]". */
+ sprintf( __( '%s cannot be empty.' ), "font_face_setting[ $key ]" ),
+ array( 'status' => 400 )
+ );
+ }
+ }
+
+ $srcs = is_array( $settings['src'] ) ? $settings['src'] : array( $settings['src'] );
+ $files = $request->get_file_params();
+
+ foreach ( $srcs as $src ) {
+ // Check that each src is a non-empty string.
+ $src = ltrim( $src );
+ if ( empty( $src ) ) {
+ return new WP_Error(
+ 'rest_invalid_param',
+ /* translators: %s: Font face source parameter name: "font_face_settings[src]". */
+ sprintf( __( '%s values must be non-empty strings.' ), 'font_face_settings[src]' ),
+ array( 'status' => 400 )
+ );
+ }
+
+ // Check that srcs are valid URLs or file references.
+ if ( false === wp_http_validate_url( $src ) && ! isset( $files[ $src ] ) ) {
+ return new WP_Error(
+ 'rest_invalid_param',
+ /* translators: 1: Font face source parameter name: "font_face_settings[src]", 2: The invalid src value. */
+ sprintf( __( '%1$s value "%2$s" must be a valid URL or file reference.' ), 'font_face_settings[src]', $src ),
+ array( 'status' => 400 )
+ );
+ }
+ }
+
+ // Check that each file in the request references a src in the settings.
+ foreach ( array_keys( $files ) as $file ) {
+ if ( ! in_array( $file, $srcs, true ) ) {
+ return new WP_Error(
+ 'rest_invalid_param',
+ /* translators: 1: File key (e.g. "file-0") in the request data, 2: Font face source parameter name: "font_face_settings[src]". */
+ sprintf( __( 'File %1$s must be used in %2$s.' ), $file, 'font_face_settings[src]' ),
+ array( 'status' => 400 )
+ );
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Sanitizes the font face settings when creating a font face.
+ *
+ * @since 6.5.0
+ *
+ * @param string $value Encoded JSON string of font face settings.
+ * @return array Decoded and sanitized array of font face settings.
+ */
+ public function sanitize_font_face_settings( $value ) {
+ // Settings arrive as stringified JSON, since this is a multipart/form-data request.
+ $settings = json_decode( $value, true );
+ $schema = $this->get_item_schema()['properties']['font_face_settings']['properties'];
+
+ // Sanitize settings based on callbacks in the schema.
+ foreach ( $settings as $key => $value ) {
+ $sanitize_callback = $schema[ $key ]['arg_options']['sanitize_callback'];
+ $settings[ $key ] = call_user_func( $sanitize_callback, $value );
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Retrieves a collection of font faces within the parent font family.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function get_items( $request ) {
+ $font_family = $this->get_parent_font_family_post( $request['font_family_id'] );
+ if ( is_wp_error( $font_family ) ) {
+ return $font_family;
+ }
+
+ return parent::get_items( $request );
+ }
+
+ /**
+ * Retrieves a single font face within the parent font family.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function get_item( $request ) {
+ $post = $this->get_post( $request['id'] );
+ if ( is_wp_error( $post ) ) {
+ return $post;
+ }
+
+ // Check that the font face has a valid parent font family.
+ $font_family = $this->get_parent_font_family_post( $request['font_family_id'] );
+ if ( is_wp_error( $font_family ) ) {
+ return $font_family;
+ }
+
+ if ( (int) $font_family->ID !== (int) $post->post_parent ) {
+ return new WP_Error(
+ 'rest_font_face_parent_id_mismatch',
+ /* translators: %d: A post id. */
+ sprintf( __( 'The font face does not belong to the specified font family with id of "%d".' ), $font_family->ID ),
+ array( 'status' => 404 )
+ );
+ }
+
+ return parent::get_item( $request );
+ }
+
+ /**
+ * Creates a font face for the parent font family.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function create_item( $request ) {
+ $font_family = $this->get_parent_font_family_post( $request['font_family_id'] );
+ if ( is_wp_error( $font_family ) ) {
+ return $font_family;
+ }
+
+ // Settings have already been decoded by ::sanitize_font_face_settings().
+ $settings = $request->get_param( 'font_face_settings' );
+ $file_params = $request->get_file_params();
+
+ // Check that the necessary font face properties are unique.
+ $query = new WP_Query(
+ array(
+ 'post_type' => $this->post_type,
+ 'posts_per_page' => 1,
+ 'title' => WP_Font_Utils::get_font_face_slug( $settings ),
+ 'update_post_meta_cache' => false,
+ 'update_post_term_cache' => false,
+ )
+ );
+ if ( ! empty( $query->posts ) ) {
+ return new WP_Error(
+ 'rest_duplicate_font_face',
+ __( 'A font face matching those settings already exists.' ),
+ array( 'status' => 400 )
+ );
+ }
+
+ // Move the uploaded font asset from the temp folder to the fonts directory.
+ if ( ! function_exists( 'wp_handle_upload' ) ) {
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ }
+
+ $srcs = is_string( $settings['src'] ) ? array( $settings['src'] ) : $settings['src'];
+ $processed_srcs = array();
+ $font_file_meta = array();
+
+ foreach ( $srcs as $src ) {
+ // If src not a file reference, use it as is.
+ if ( ! isset( $file_params[ $src ] ) ) {
+ $processed_srcs[] = $src;
+ continue;
+ }
+
+ $file = $file_params[ $src ];
+ $font_file = $this->handle_font_file_upload( $file );
+ if ( is_wp_error( $font_file ) ) {
+ return $font_file;
+ }
+
+ $processed_srcs[] = $font_file['url'];
+ $font_file_meta[] = $this->relative_fonts_path( $font_file['file'] );
+ }
+
+ // Store the updated settings for prepare_item_for_database to use.
+ $settings['src'] = count( $processed_srcs ) === 1 ? $processed_srcs[0] : $processed_srcs;
+ $request->set_param( 'font_face_settings', $settings );
+
+ // Ensure that $settings data is slashed, so values with quotes are escaped.
+ // WP_REST_Posts_Controller::create_item uses wp_slash() on the post_content.
+ $font_face_post = parent::create_item( $request );
+
+ if ( is_wp_error( $font_face_post ) ) {
+ return $font_face_post;
+ }
+
+ $font_face_id = $font_face_post->data['id'];
+
+ foreach ( $font_file_meta as $font_file_path ) {
+ add_post_meta( $font_face_id, '_wp_font_face_file', $font_file_path );
+ }
+
+ return $font_face_post;
+ }
+
+ /**
+ * Deletes a single font face.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function delete_item( $request ) {
+ $post = $this->get_post( $request['id'] );
+ if ( is_wp_error( $post ) ) {
+ return $post;
+ }
+
+ $font_family = $this->get_parent_font_family_post( $request['font_family_id'] );
+ if ( is_wp_error( $font_family ) ) {
+ return $font_family;
+ }
+
+ if ( (int) $font_family->ID !== (int) $post->post_parent ) {
+ return new WP_Error(
+ 'rest_font_face_parent_id_mismatch',
+ /* translators: %d: A post id. */
+ sprintf( __( 'The font face does not belong to the specified font family with id of "%d".' ), $font_family->ID ),
+ array( 'status' => 404 )
+ );
+ }
+
+ $force = isset( $request['force'] ) ? (bool) $request['force'] : false;
+
+ // We don't support trashing for font faces.
+ if ( ! $force ) {
+ return new WP_Error(
+ 'rest_trash_not_supported',
+ /* translators: %s: force=true */
+ sprintf( __( 'Font faces do not support trashing. Set "%s" to delete.' ), 'force=true' ),
+ array( 'status' => 501 )
+ );
+ }
+
+ return parent::delete_item( $request );
+ }
+
+ /**
+ * Prepares a single font face output for response.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Post $item Post object.
+ * @param WP_REST_Request $request Request object.
+ * @return WP_REST_Response Response object.
+ */
+ public function prepare_item_for_response( $item, $request ) {
+ $fields = $this->get_fields_for_response( $request );
+ $data = array();
+
+ if ( rest_is_field_included( 'id', $fields ) ) {
+ $data['id'] = $item->ID;
+ }
+ if ( rest_is_field_included( 'theme_json_version', $fields ) ) {
+ $data['theme_json_version'] = static::LATEST_THEME_JSON_VERSION_SUPPORTED;
+ }
+
+ if ( rest_is_field_included( 'parent', $fields ) ) {
+ $data['parent'] = $item->post_parent;
+ }
+
+ if ( rest_is_field_included( 'font_face_settings', $fields ) ) {
+ $data['font_face_settings'] = $this->get_settings_from_post( $item );
+ }
+
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
+ $data = $this->add_additional_fields_to_object( $data, $request );
+ $data = $this->filter_response_by_context( $data, $context );
+
+ $response = rest_ensure_response( $data );
+
+ if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) {
+ $links = $this->prepare_links( $item );
+ $response->add_links( $links );
+ }
+
+ /**
+ * Filters the font face data for a REST API response.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Response $response The response object.
+ * @param WP_Post $post Font face post object.
+ * @param WP_REST_Request $request Request object.
+ */
+ return apply_filters( 'rest_prepare_wp_font_face', $response, $item, $request );
+ }
+
+ /**
+ * Retrieves the post's schema, conforming to JSON Schema.
+ *
+ * @since 6.5.0
+ *
+ * @return array Item schema data.
+ */
+ public function get_item_schema() {
+ if ( $this->schema ) {
+ return $this->add_additional_fields_schema( $this->schema );
+ }
+
+ $schema = array(
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
+ 'title' => $this->post_type,
+ 'type' => 'object',
+ // Base properties for every Post.
+ 'properties' => array(
+ 'id' => array(
+ 'description' => __( 'Unique identifier for the post.', 'default' ),
+ 'type' => 'integer',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'theme_json_version' => array(
+ 'description' => __( 'Version of the theme.json schema used for the typography settings.' ),
+ 'type' => 'integer',
+ 'default' => static::LATEST_THEME_JSON_VERSION_SUPPORTED,
+ 'minimum' => 2,
+ 'maximum' => static::LATEST_THEME_JSON_VERSION_SUPPORTED,
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ 'parent' => array(
+ 'description' => __( 'The ID for the parent font family of the font face.' ),
+ 'type' => 'integer',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ // Font face settings come directly from theme.json schema
+ // See https://schemas.wp.org/trunk/theme.json
+ 'font_face_settings' => array(
+ 'description' => __( 'font-face declaration in theme.json format.' ),
+ 'type' => 'object',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'properties' => array(
+ 'fontFamily' => array(
+ 'description' => __( 'CSS font-family value.' ),
+ 'type' => 'string',
+ 'default' => '',
+ 'arg_options' => array(
+ 'sanitize_callback' => array( 'WP_Font_Utils', 'sanitize_font_family' ),
+ ),
+ ),
+ 'fontStyle' => array(
+ 'description' => __( 'CSS font-style value.' ),
+ 'type' => 'string',
+ 'default' => 'normal',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'fontWeight' => array(
+ 'description' => __( 'List of available font weights, separated by a space.' ),
+ 'default' => '400',
+ // Changed from `oneOf` to avoid errors from loose type checking.
+ // e.g. a fontWeight of "400" validates as both a string and an integer due to is_numeric check.
+ 'type' => array( 'string', 'integer' ),
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'fontDisplay' => array(
+ 'description' => __( 'CSS font-display value.' ),
+ 'type' => 'string',
+ 'default' => 'fallback',
+ 'enum' => array(
+ 'auto',
+ 'block',
+ 'fallback',
+ 'swap',
+ 'optional',
+ ),
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'src' => array(
+ 'description' => __( 'Paths or URLs to the font files.' ),
+ // Changed from `oneOf` to `anyOf` due to rest_sanitize_array converting a string into an array,
+ // and causing a "matches more than one of the expected formats" error.
+ 'anyOf' => array(
+ array(
+ 'type' => 'string',
+ ),
+ array(
+ 'type' => 'array',
+ 'items' => array(
+ 'type' => 'string',
+ ),
+ ),
+ ),
+ 'default' => array(),
+ 'arg_options' => array(
+ 'sanitize_callback' => function ( $value ) {
+ return is_array( $value ) ? array_map( array( $this, 'sanitize_src' ), $value ) : $this->sanitize_src( $value );
+ },
+ ),
+ ),
+ 'fontStretch' => array(
+ 'description' => __( 'CSS font-stretch value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'ascentOverride' => array(
+ 'description' => __( 'CSS ascent-override value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'descentOverride' => array(
+ 'description' => __( 'CSS descent-override value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'fontVariant' => array(
+ 'description' => __( 'CSS font-variant value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'fontFeatureSettings' => array(
+ 'description' => __( 'CSS font-feature-settings value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'fontVariationSettings' => array(
+ 'description' => __( 'CSS font-variation-settings value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'lineGapOverride' => array(
+ 'description' => __( 'CSS line-gap-override value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'sizeAdjust' => array(
+ 'description' => __( 'CSS size-adjust value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'unicodeRange' => array(
+ 'description' => __( 'CSS unicode-range value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'preview' => array(
+ 'description' => __( 'URL to a preview image of the font face.' ),
+ 'type' => 'string',
+ 'format' => 'uri',
+ 'default' => '',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_url',
+ ),
+ ),
+ ),
+ 'required' => array( 'fontFamily', 'src' ),
+ 'additionalProperties' => false,
+ ),
+ ),
+ );
+
+ $this->schema = $schema;
+
+ return $this->add_additional_fields_schema( $this->schema );
+ }
+
+ /**
+ * Retrieves the item's schema for display / public consumption purposes.
+ *
+ * @since 6.5.0
+ *
+ * @return array Public item schema data.
+ */
+ public function get_public_item_schema() {
+
+ $schema = parent::get_public_item_schema();
+
+ // Also remove `arg_options' from child font_family_settings properties, since the parent
+ // controller only handles the top level properties.
+ foreach ( $schema['properties']['font_face_settings']['properties'] as &$property ) {
+ unset( $property['arg_options'] );
+ }
+
+ return $schema;
+ }
+
+ /**
+ * Retrieves the query params for the font face collection.
+ *
+ * @since 6.5.0
+ *
+ * @return array Collection parameters.
+ */
+ public function get_collection_params() {
+ $query_params = parent::get_collection_params();
+
+ // Remove unneeded params.
+ unset(
+ $query_params['after'],
+ $query_params['modified_after'],
+ $query_params['before'],
+ $query_params['modified_before'],
+ $query_params['search'],
+ $query_params['search_columns'],
+ $query_params['slug'],
+ $query_params['status']
+ );
+
+ $query_params['orderby']['default'] = 'id';
+ $query_params['orderby']['enum'] = array( 'id', 'include' );
+
+ /**
+ * Filters collection parameters for the font face controller.
+ *
+ * @since 6.5.0
+ *
+ * @param array $query_params JSON Schema-formatted collection parameters.
+ */
+ return apply_filters( 'rest_wp_font_face_collection_params', $query_params );
+ }
+
+ /**
+ * Get the params used when creating a new font face.
+ *
+ * @since 6.5.0
+ *
+ * @return array Font face create arguments.
+ */
+ public function get_create_params() {
+ $properties = $this->get_item_schema()['properties'];
+ return array(
+ 'theme_json_version' => $properties['theme_json_version'],
+ // When creating, font_face_settings is stringified JSON, to work with multipart/form-data used
+ // when uploading font files.
+ 'font_face_settings' => array(
+ 'description' => __( 'font-face declaration in theme.json format, encoded as a string.' ),
+ 'type' => 'string',
+ 'required' => true,
+ 'validate_callback' => array( $this, 'validate_create_font_face_settings' ),
+ 'sanitize_callback' => array( $this, 'sanitize_font_face_settings' ),
+ ),
+ );
+ }
+
+ /**
+ * Get the parent font family, if the ID is valid.
+ *
+ * @since 6.5.0
+ *
+ * @param int $font_family_id Supplied ID.
+ * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise.
+ */
+ protected function get_parent_font_family_post( $font_family_id ) {
+ $error = new WP_Error(
+ 'rest_post_invalid_parent',
+ __( 'Invalid post parent ID.', 'default' ),
+ array( 'status' => 404 )
+ );
+
+ if ( (int) $font_family_id <= 0 ) {
+ return $error;
+ }
+
+ $font_family_post = get_post( (int) $font_family_id );
+
+ if ( empty( $font_family_post ) || empty( $font_family_post->ID )
+ || 'wp_font_family' !== $font_family_post->post_type
+ ) {
+ return $error;
+ }
+
+ return $font_family_post;
+ }
+
+ /**
+ * Prepares links for the request.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Post $post Post object.
+ * @return array Links for the given post.
+ */
+ protected function prepare_links( $post ) {
+ // Entity meta.
+ return array(
+ 'self' => array(
+ 'href' => rest_url( $this->namespace . '/font-families/' . $post->post_parent . '/font-faces/' . $post->ID ),
+ ),
+ 'collection' => array(
+ 'href' => rest_url( $this->namespace . '/font-families/' . $post->post_parent . '/font-faces' ),
+ ),
+ 'parent' => array(
+ 'href' => rest_url( $this->namespace . '/font-families/' . $post->post_parent ),
+ ),
+ );
+ }
+
+ /**
+ * Prepares a single font face post for creation.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Request object.
+ * @return stdClass Post object.
+ */
+ protected function prepare_item_for_database( $request ) {
+ $prepared_post = new stdClass();
+
+ // Settings have already been decoded by ::sanitize_font_face_settings().
+ $settings = $request->get_param( 'font_face_settings' );
+
+ // Store this "slug" as the post_title rather than post_name, since it uses the fontFamily setting,
+ // which may contain multibyte characters.
+ $title = WP_Font_Utils::get_font_face_slug( $settings );
+
+ $prepared_post->post_type = $this->post_type;
+ $prepared_post->post_parent = $request['font_family_id'];
+ $prepared_post->post_status = 'publish';
+ $prepared_post->post_title = $title;
+ $prepared_post->post_name = sanitize_title( $title );
+ $prepared_post->post_content = wp_json_encode( $settings );
+
+ return $prepared_post;
+ }
+
+ /**
+ * Sanitizes a single src value for a font face.
+ *
+ * @since 6.5.0
+ *
+ * @param string $value Font face src that is a URL or the key for a $_FILES array item.
+ * @return string Sanitized value.
+ */
+ protected function sanitize_src( $value ) {
+ $value = ltrim( $value );
+ return false === wp_http_validate_url( $value ) ? (string) $value : sanitize_url( $value );
+ }
+
+ /**
+ * Handles the upload of a font file using wp_handle_upload().
+ *
+ * @since 6.5.0
+ *
+ * @param array $file Single file item from $_FILES.
+ * @return array|WP_Error Array containing uploaded file attributes on success, or WP_Error object on failure.
+ */
+ protected function handle_font_file_upload( $file ) {
+ add_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) );
+ add_filter( 'upload_dir', 'wp_get_font_dir' );
+
+ $overrides = array(
+ 'upload_error_handler' => array( $this, 'handle_font_file_upload_error' ),
+ // Arbitrary string to avoid the is_uploaded_file() check applied
+ // when using 'wp_handle_upload'.
+ 'action' => 'wp_handle_font_upload',
+ // Not testing a form submission.
+ 'test_form' => false,
+ // Seems mime type for files that are not images cannot be tested.
+ // See wp_check_filetype_and_ext().
+ 'test_type' => true,
+ // Only allow uploading font files for this request.
+ 'mimes' => WP_Font_Utils::get_allowed_font_mime_types(),
+ );
+
+ $uploaded_file = wp_handle_upload( $file, $overrides );
+
+ remove_filter( 'upload_dir', 'wp_get_font_dir' );
+ remove_filter( 'upload_mimes', array( 'WP_Font_Utils', 'get_allowed_font_mime_types' ) );
+
+ return $uploaded_file;
+ }
+
+ /**
+ * Handles file upload error.
+ *
+ * @since 6.5.0
+ *
+ * @param array $file File upload data.
+ * @param string $message Error message from wp_handle_upload().
+ * @return WP_Error WP_Error object.
+ */
+ public function handle_font_file_upload_error( $file, $message ) {
+ $status = 500;
+ $code = 'rest_font_upload_unknown_error';
+
+ if ( __( 'Sorry, you are not allowed to upload this file type.' ) === $message ) {
+ $status = 400;
+ $code = 'rest_font_upload_invalid_file_type';
+ }
+
+ return new WP_Error( $code, $message, array( 'status' => $status ) );
+ }
+
+ /**
+ * Returns relative path to an uploaded font file.
+ *
+ * The path is relative to the current fonts directory.
+ *
+ * @since 6.5.0
+ * @access private
+ *
+ * @param string $path Full path to the file.
+ * @return string Relative path on success, unchanged path on failure.
+ */
+ protected function relative_fonts_path( $path ) {
+ $new_path = $path;
+
+ $fonts_dir = wp_get_font_dir();
+ if ( str_starts_with( $new_path, $fonts_dir['path'] ) ) {
+ $new_path = str_replace( $fonts_dir, '', $new_path );
+ $new_path = ltrim( $new_path, '/' );
+ }
+
+ return $new_path;
+ }
+
+ /**
+ * Gets the font face's settings from the post.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Post $post Font face post object.
+ * @return array Font face settings array.
+ */
+ protected function get_settings_from_post( $post ) {
+ $settings = json_decode( $post->post_content, true );
+ $properties = $this->get_item_schema()['properties']['font_face_settings']['properties'];
+
+ // Provide required, empty settings if needed.
+ if ( null === $settings ) {
+ $settings = array(
+ 'fontFamily' => '',
+ 'src' => array(),
+ );
+ }
+
+ // Only return the properties defined in the schema.
+ return array_intersect_key( $settings, $properties );
+ }
+}
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php
new file mode 100644
index 0000000000000..184b42d141dd3
--- /dev/null
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php
@@ -0,0 +1,564 @@
+post_type );
+
+ if ( ! current_user_can( $post_type->cap->read ) ) {
+ return new WP_Error(
+ 'rest_cannot_read',
+ __( 'Sorry, you are not allowed to access font families.' ),
+ array( 'status' => rest_authorization_required_code() )
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Checks if a given request has access to a font family.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
+ */
+ public function get_item_permissions_check( $request ) {
+ $post = $this->get_post( $request['id'] );
+ if ( is_wp_error( $post ) ) {
+ return $post;
+ }
+
+ if ( ! current_user_can( 'read_post', $post->ID ) ) {
+ return new WP_Error(
+ 'rest_cannot_read',
+ __( 'Sorry, you are not allowed to access this font family.' ),
+ array( 'status' => rest_authorization_required_code() )
+ );
+ }
+
+ return true;
+ }
+
+ /**
+ * Validates settings when creating or updating a font family.
+ *
+ * @since 6.5.0
+ *
+ * @param string $value Encoded JSON string of font family settings.
+ * @param WP_REST_Request $request Request object.
+ * @return true|WP_Error True if the settings are valid, otherwise a WP_Error object.
+ */
+ public function validate_font_family_settings( $value, $request ) {
+ $settings = json_decode( $value, true );
+
+ // Check settings string is valid JSON.
+ if ( null === $settings ) {
+ return new WP_Error(
+ 'rest_invalid_param',
+ /* translators: %s: Parameter name: "font_family_settings". */
+ sprintf( __( '%s parameter must be a valid JSON string.' ), 'font_family_settings' ),
+ array( 'status' => 400 )
+ );
+ }
+
+ $schema = $this->get_item_schema()['properties']['font_family_settings'];
+ $required = $schema['required'];
+
+ if ( isset( $request['id'] ) ) {
+ // Allow sending individual properties if we are updating an existing font family.
+ unset( $schema['required'] );
+
+ // But don't allow updating the slug, since it is used as a unique identifier.
+ if ( isset( $settings['slug'] ) ) {
+ return new WP_Error(
+ 'rest_invalid_param',
+ /* translators: %s: Name of parameter being updated: font_family_settings[slug]". */
+ sprintf( __( '%s cannot be updated.' ), 'font_family_settings[slug]' ),
+ array( 'status' => 400 )
+ );
+ }
+ }
+
+ // Check that the font face settings match the theme.json schema.
+ $has_valid_settings = rest_validate_value_from_schema( $settings, $schema, 'font_family_settings' );
+
+ if ( is_wp_error( $has_valid_settings ) ) {
+ $has_valid_settings->add_data( array( 'status' => 400 ) );
+ return $has_valid_settings;
+ }
+
+ // Check that none of the required settings are empty values.
+ foreach ( $required as $key ) {
+ if ( isset( $settings[ $key ] ) && ! $settings[ $key ] ) {
+ return new WP_Error(
+ 'rest_invalid_param',
+ /* translators: %s: Name of the empty font family setting parameter, e.g. "font_family_settings[slug]". */
+ sprintf( __( '%s cannot be empty.' ), "font_family_settings[ $key ]" ),
+ array( 'status' => 400 )
+ );
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Sanitizes the font family settings when creating or updating a font family.
+ *
+ * @since 6.5.0
+ *
+ * @param string $value Encoded JSON string of font family settings.
+ * @return array Decoded array of font family settings.
+ */
+ public function sanitize_font_family_settings( $value ) {
+ // Settings arrive as stringified JSON, since this is a multipart/form-data request.
+ $settings = json_decode( $value, true );
+ $schema = $this->get_item_schema()['properties']['font_family_settings']['properties'];
+
+ // Sanitize settings based on callbacks in the schema.
+ foreach ( $settings as $key => $value ) {
+ $sanitize_callback = $schema[ $key ]['arg_options']['sanitize_callback'];
+ $settings[ $key ] = call_user_func( $sanitize_callback, $value );
+ }
+
+ return $settings;
+ }
+
+ /**
+ * Creates a single font family.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function create_item( $request ) {
+ $settings = $request->get_param( 'font_family_settings' );
+
+ // Check that the font family slug is unique.
+ $query = new WP_Query(
+ array(
+ 'post_type' => $this->post_type,
+ 'posts_per_page' => 1,
+ 'name' => $settings['slug'],
+ 'update_post_meta_cache' => false,
+ 'update_post_term_cache' => false,
+ )
+ );
+ if ( ! empty( $query->posts ) ) {
+ return new WP_Error(
+ 'rest_duplicate_font_family',
+ /* translators: %s: Font family slug. */
+ sprintf( __( 'A font family with slug "%s" already exists.' ), $settings['slug'] ),
+ array( 'status' => 400 )
+ );
+ }
+
+ return parent::create_item( $request );
+ }
+
+ /**
+ * Deletes a single font family.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function delete_item( $request ) {
+ $force = isset( $request['force'] ) ? (bool) $request['force'] : false;
+
+ // We don't support trashing for font families.
+ if ( ! $force ) {
+ return new WP_Error(
+ 'rest_trash_not_supported',
+ /* translators: %s: force=true */
+ sprintf( __( 'Font faces do not support trashing. Set "%s" to delete.' ), 'force=true' ),
+ array( 'status' => 501 )
+ );
+ }
+
+ return parent::delete_item( $request );
+ }
+
+ /**
+ * Prepares a single font family output for response.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Post $item Post object.
+ * @param WP_REST_Request $request Request object.
+ * @return WP_REST_Response Response object.
+ */
+ public function prepare_item_for_response( $item, $request ) {
+ $fields = $this->get_fields_for_response( $request );
+ $data = array();
+
+ if ( rest_is_field_included( 'id', $fields ) ) {
+ $data['id'] = $item->ID;
+ }
+
+ if ( rest_is_field_included( 'theme_json_version', $fields ) ) {
+ $data['theme_json_version'] = static::LATEST_THEME_JSON_VERSION_SUPPORTED;
+ }
+
+ if ( rest_is_field_included( 'font_faces', $fields ) ) {
+ $data['font_faces'] = $this->get_font_face_ids( $item->ID );
+ }
+
+ if ( rest_is_field_included( 'font_family_settings', $fields ) ) {
+ $data['font_family_settings'] = $this->get_settings_from_post( $item );
+ }
+
+ $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
+ $data = $this->add_additional_fields_to_object( $data, $request );
+ $data = $this->filter_response_by_context( $data, $context );
+
+ $response = rest_ensure_response( $data );
+
+ if ( rest_is_field_included( '_links', $fields ) ) {
+ $links = $this->prepare_links( $item );
+ $response->add_links( $links );
+ }
+
+ /**
+ * Filters the font family data for a REST API response.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Response $response The response object.
+ * @param WP_Post $post Font family post object.
+ * @param WP_REST_Request $request Request object.
+ */
+ return apply_filters( 'rest_prepare_wp_font_family', $response, $item, $request );
+ }
+
+ /**
+ * Retrieves the post's schema, conforming to JSON Schema.
+ *
+ * @since 6.5.0
+ *
+ * @return array Item schema data.
+ */
+ public function get_item_schema() {
+ if ( $this->schema ) {
+ return $this->add_additional_fields_schema( $this->schema );
+ }
+
+ $schema = array(
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
+ 'title' => $this->post_type,
+ 'type' => 'object',
+ // Base properties for every Post.
+ 'properties' => array(
+ 'id' => array(
+ 'description' => __( 'Unique identifier for the post.', 'default' ),
+ 'type' => 'integer',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'readonly' => true,
+ ),
+ 'theme_json_version' => array(
+ 'description' => __( 'Version of the theme.json schema used for the typography settings.' ),
+ 'type' => 'integer',
+ 'default' => static::LATEST_THEME_JSON_VERSION_SUPPORTED,
+ 'minimum' => 2,
+ 'maximum' => static::LATEST_THEME_JSON_VERSION_SUPPORTED,
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ 'font_faces' => array(
+ 'description' => __( 'The IDs of the child font faces in the font family.' ),
+ 'type' => 'array',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'items' => array(
+ 'type' => 'integer',
+ ),
+ ),
+ // Font family settings come directly from theme.json schema
+ // See https://schemas.wp.org/trunk/theme.json
+ 'font_family_settings' => array(
+ 'description' => __( 'font-face definition in theme.json format.' ),
+ 'type' => 'object',
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'properties' => array(
+ 'name' => array(
+ 'description' => __( 'Name of the font family preset, translatable.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_text_field',
+ ),
+ ),
+ 'slug' => array(
+ 'description' => __( 'Kebab-case unique identifier for the font family preset.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_title',
+ ),
+ ),
+ 'fontFamily' => array(
+ 'description' => __( 'CSS font-family value.' ),
+ 'type' => 'string',
+ 'arg_options' => array(
+ 'sanitize_callback' => array( 'WP_Font_Utils', 'sanitize_font_family' ),
+ ),
+ ),
+ 'preview' => array(
+ 'description' => __( 'URL to a preview image of the font family.' ),
+ 'type' => 'string',
+ 'format' => 'uri',
+ 'default' => '',
+ 'arg_options' => array(
+ 'sanitize_callback' => 'sanitize_url',
+ ),
+ ),
+ ),
+ 'required' => array( 'name', 'slug', 'fontFamily' ),
+ 'additionalProperties' => false,
+ ),
+ ),
+ );
+
+ $this->schema = $schema;
+
+ return $this->add_additional_fields_schema( $this->schema );
+ }
+
+ /**
+ * Retrieves the item's schema for display / public consumption purposes.
+ *
+ * @since 6.5.0
+ *
+ * @return array Public item schema data.
+ */
+ public function get_public_item_schema() {
+
+ $schema = parent::get_public_item_schema();
+
+ // Also remove `arg_options' from child font_family_settings properties, since the parent
+ // controller only handles the top level properties.
+ foreach ( $schema['properties']['font_family_settings']['properties'] as &$property ) {
+ unset( $property['arg_options'] );
+ }
+
+ return $schema;
+ }
+
+ /**
+ * Retrieves the query params for the font family collection.
+ *
+ * @since 6.5.0
+ *
+ * @return array Collection parameters.
+ */
+ public function get_collection_params() {
+ $query_params = parent::get_collection_params();
+
+ // Remove unneeded params.
+ unset(
+ $query_params['after'],
+ $query_params['modified_after'],
+ $query_params['before'],
+ $query_params['modified_before'],
+ $query_params['search'],
+ $query_params['search_columns'],
+ $query_params['status']
+ );
+
+ $query_params['orderby']['default'] = 'id';
+ $query_params['orderby']['enum'] = array( 'id', 'include' );
+
+ /**
+ * Filters collection parameters for the font family controller.
+ *
+ * @since 6.5.0
+ *
+ * @param array $query_params JSON Schema-formatted collection parameters.
+ */
+ return apply_filters( 'rest_wp_font_family_collection_params', $query_params );
+ }
+
+ /**
+ * Get the arguments used when creating or updating a font family.
+ *
+ * @since 6.5.0
+ *
+ * @return array Font family create/edit arguments.
+ */
+ public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) {
+ if ( WP_REST_Server::CREATABLE === $method || WP_REST_Server::EDITABLE === $method ) {
+ $properties = $this->get_item_schema()['properties'];
+ return array(
+ 'theme_json_version' => $properties['theme_json_version'],
+ // When creating or updating, font_family_settings is stringified JSON, to work with multipart/form-data.
+ // Font families don't currently support file uploads, but may accept preview files in the future.
+ 'font_family_settings' => array(
+ 'description' => __( 'font-family declaration in theme.json format, encoded as a string.' ),
+ 'type' => 'string',
+ 'required' => true,
+ 'validate_callback' => array( $this, 'validate_font_family_settings' ),
+ 'sanitize_callback' => array( $this, 'sanitize_font_family_settings' ),
+ ),
+ );
+ }
+
+ return parent::get_endpoint_args_for_item_schema( $method );
+ }
+
+ /**
+ * Get the child font face post IDs.
+ *
+ * @since 6.5.0
+ *
+ * @param int $font_family_id Font family post ID.
+ * @return int[] Array of child font face post IDs.
+ */
+ protected function get_font_face_ids( $font_family_id ) {
+ $query = new WP_Query(
+ array(
+ 'fields' => 'ids',
+ 'post_parent' => $font_family_id,
+ 'post_type' => 'wp_font_face',
+ 'posts_per_page' => 99,
+ 'order' => 'ASC',
+ 'orderby' => 'id',
+ 'update_post_meta_cache' => false,
+ 'update_post_term_cache' => false,
+ )
+ );
+
+ return $query->posts;
+ }
+
+ /**
+ * Prepares font family links for the request.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Post $post Post object.
+ * @return array Links for the given post.
+ */
+ protected function prepare_links( $post ) {
+ // Entity meta.
+ $links = parent::prepare_links( $post );
+
+ return array(
+ 'self' => $links['self'],
+ 'collection' => $links['collection'],
+ 'font_faces' => $this->prepare_font_face_links( $post->ID ),
+ );
+ }
+
+ /**
+ * Prepares child font face links for the request.
+ *
+ * @param int $font_family_id Font family post ID.
+ * @return array Links for the child font face posts.
+ */
+ protected function prepare_font_face_links( $font_family_id ) {
+ $font_face_ids = $this->get_font_face_ids( $font_family_id );
+ $links = array();
+ foreach ( $font_face_ids as $font_face_id ) {
+ $links[] = array(
+ 'embeddable' => true,
+ 'href' => rest_url( sprintf( '%s/%s/%s/font-faces/%s', $this->namespace, $this->rest_base, $font_family_id, $font_face_id ) ),
+ );
+ }
+ return $links;
+ }
+
+ /**
+ * Prepares a single font family post for create or update.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Request object.
+ * @return stdClass|WP_Error Post object or WP_Error.
+ */
+ protected function prepare_item_for_database( $request ) {
+ $prepared_post = new stdClass();
+ // Settings have already been decoded by ::sanitize_font_family_settings().
+ $settings = $request->get_param( 'font_family_settings' );
+
+ // This is an update and we merge with the existing font family.
+ if ( isset( $request['id'] ) ) {
+ $existing_post = $this->get_post( $request['id'] );
+ if ( is_wp_error( $existing_post ) ) {
+ return $existing_post;
+ }
+
+ $prepared_post->ID = $existing_post->ID;
+ $existing_settings = $this->get_settings_from_post( $existing_post );
+ $settings = array_merge( $existing_settings, $settings );
+ }
+
+ $prepared_post->post_type = $this->post_type;
+ $prepared_post->post_status = 'publish';
+ $prepared_post->post_title = $settings['name'];
+ $prepared_post->post_name = sanitize_title( $settings['slug'] );
+
+ // Remove duplicate information from settings.
+ unset( $settings['name'] );
+ unset( $settings['slug'] );
+
+ $prepared_post->post_content = wp_json_encode( $settings );
+
+ return $prepared_post;
+ }
+
+ /**
+ * Gets the font family's settings from the post.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Post $post Font family post object.
+ * @return array Font family settings array.
+ */
+ protected function get_settings_from_post( $post ) {
+ $settings_json = json_decode( $post->post_content, true );
+
+ // Default to empty strings if the settings are missing.
+ return array(
+ 'name' => isset( $post->post_title ) && $post->post_title ? $post->post_title : '',
+ 'slug' => isset( $post->post_name ) && $post->post_name ? $post->post_name : '',
+ 'fontFamily' => isset( $settings_json['fontFamily'] ) && $settings_json['fontFamily'] ? $settings_json['fontFamily'] : '',
+ 'preview' => isset( $settings_json['preview'] ) && $settings_json['preview'] ? $settings_json['preview'] : '',
+ );
+ }
+}
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php
index 9ce7e2b3df66a..db1be197e5ab4 100644
--- a/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php
@@ -47,6 +47,7 @@ public function __construct() {
* Registers the controller's routes.
*
* @since 6.3.0
+ * @since 6.5.0 Added route to fetch individual global styles revisions.
*/
public function register_routes() {
register_rest_route(
@@ -68,6 +69,32 @@ public function register_routes() {
'schema' => array( $this, 'get_public_item_schema' ),
)
);
+
+ register_rest_route(
+ $this->namespace,
+ '/' . $this->parent_base . '/(?P[\d]+)/' . $this->rest_base . '/(?P[\d]+)',
+ array(
+ 'args' => array(
+ 'parent' => array(
+ 'description' => __( 'The ID for the parent of the global styles revision.' ),
+ 'type' => 'integer',
+ ),
+ 'id' => array(
+ 'description' => __( 'Unique identifier for the global styles revision.' ),
+ 'type' => 'integer',
+ ),
+ ),
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_item' ),
+ 'permission_callback' => array( $this, 'get_item_permissions_check' ),
+ 'args' => array(
+ 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
+ ),
+ ),
+ 'schema' => array( $this, 'get_public_item_schema' ),
+ )
+ );
}
/**
@@ -241,6 +268,56 @@ public function get_items( $request ) {
return $response;
}
+ /**
+ * Retrieves one global styles revision from the collection.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_REST_Request $request Full details about the request.
+ * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
+ */
+ public function get_item( $request ) {
+ $parent = $this->get_parent( $request['parent'] );
+ if ( is_wp_error( $parent ) ) {
+ return $parent;
+ }
+
+ $revision = $this->get_revision( $request['id'] );
+ if ( is_wp_error( $revision ) ) {
+ return $revision;
+ }
+
+ $response = $this->prepare_item_for_response( $revision, $request );
+ return rest_ensure_response( $response );
+ }
+
+ /**
+ * Gets the global styles revision, if the ID is valid.
+ *
+ * @since 6.5.0
+ *
+ * @param int $id Supplied ID.
+ * @return WP_Post|WP_Error Revision post object if ID is valid, WP_Error otherwise.
+ */
+ protected function get_revision( $id ) {
+ $error = new WP_Error(
+ 'rest_post_invalid_id',
+ __( 'Invalid global styles revision ID.' ),
+ array( 'status' => 404 )
+ );
+
+ if ( (int) $id <= 0 ) {
+ return $error;
+ }
+
+ $revision = get_post( (int) $id );
+ if ( empty( $revision ) || empty( $revision->ID ) || 'revision' !== $revision->post_type ) {
+ return $error;
+ }
+
+ return $revision;
+ }
+
/**
* Checks the post_date_gmt or modified_gmt and prepare any post or
* modified date for single post output.
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php
index 53f8faa75595b..1549fd4295561 100644
--- a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php
@@ -726,6 +726,14 @@ public function prepare_item_for_response( $item, $request ) {
$data['modified'] = mysql_to_rfc3339( $template->modified );
}
+ if ( rest_is_field_included( 'author_text', $fields ) ) {
+ $data['author_text'] = self::get_wp_templates_author_text_field( $template );
+ }
+
+ if ( rest_is_field_included( 'original_source', $fields ) ) {
+ $data['original_source'] = self::get_wp_templates_original_source_field( $template );
+ }
+
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
$data = $this->add_additional_fields_to_object( $data, $request );
$data = $this->filter_response_by_context( $data, $context );
@@ -748,6 +756,83 @@ public function prepare_item_for_response( $item, $request ) {
return $response;
}
+ /**
+ * Returns the source from where the template originally comes from.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Block_Template $template_object Template instance.
+ * @return string Original source of the template one of theme, plugin, site, or user.
+ */
+ private static function get_wp_templates_original_source_field( $template_object ) {
+ if ( 'wp_template' === $template_object->type || 'wp_template_part' === $template_object->type ) {
+ // Added by theme.
+ // Template originally provided by a theme, but customized by a user.
+ // Templates originally didn't have the 'origin' field so identify
+ // older customized templates by checking for no origin and a 'theme'
+ // or 'custom' source.
+ if ( $template_object->has_theme_file &&
+ ( 'theme' === $template_object->origin || (
+ empty( $template_object->origin ) && in_array(
+ $template_object->source,
+ array(
+ 'theme',
+ 'custom',
+ ),
+ true
+ ) )
+ )
+ ) {
+ return 'theme';
+ }
+
+ // Added by plugin.
+ if ( $template_object->has_theme_file && 'plugin' === $template_object->origin ) {
+ return 'plugin';
+ }
+
+ // Added by site.
+ // Template was created from scratch, but has no author. Author support
+ // was only added to templates in WordPress 5.9. Fallback to showing the
+ // site logo and title.
+ if ( empty( $template_object->has_theme_file ) && 'custom' === $template_object->source && empty( $template_object->author ) ) {
+ return 'site';
+ }
+ }
+
+ // Added by user.
+ return 'user';
+ }
+
+ /**
+ * Returns a human readable text for the author of the template.
+ *
+ * @since 6.5.0
+ *
+ * @param WP_Block_Template $template_object Template instance.
+ * @return string Human readable text for the author.
+ */
+ private static function get_wp_templates_author_text_field( $template_object ) {
+ $original_source = self::get_wp_templates_original_source_field( $template_object );
+ switch ( $original_source ) {
+ case 'theme':
+ $theme_name = wp_get_theme( $template_object->theme )->get( 'Name' );
+ return empty( $theme_name ) ? $template_object->theme : $theme_name;
+ case 'plugin':
+ $plugins = get_plugins();
+ $plugin = $plugins[ plugin_basename( sanitize_text_field( $template_object->theme . '.php' ) ) ];
+ return empty( $plugin['Name'] ) ? $template_object->theme : $plugin['Name'];
+ case 'site':
+ return get_bloginfo( 'name' );
+ case 'user':
+ $author = get_user_by( 'id', $template_object->author );
+ if ( ! $author ) {
+ return __( 'Unknown author' );
+ }
+ return $author->get( 'display_name' );
+ }
+ }
+
/**
* Prepares links for the request.
@@ -861,13 +946,13 @@ public function get_item_schema() {
'title' => $this->post_type,
'type' => 'object',
'properties' => array(
- 'id' => array(
+ 'id' => array(
'description' => __( 'ID of template.' ),
'type' => 'string',
'context' => array( 'embed', 'view', 'edit' ),
'readonly' => true,
),
- 'slug' => array(
+ 'slug' => array(
'description' => __( 'Unique slug identifying the template.' ),
'type' => 'string',
'context' => array( 'embed', 'view', 'edit' ),
@@ -875,29 +960,29 @@ public function get_item_schema() {
'minLength' => 1,
'pattern' => '[a-zA-Z0-9_\%-]+',
),
- 'theme' => array(
+ 'theme' => array(
'description' => __( 'Theme identifier for the template.' ),
'type' => 'string',
'context' => array( 'embed', 'view', 'edit' ),
),
- 'type' => array(
+ 'type' => array(
'description' => __( 'Type of template.' ),
'type' => 'string',
'context' => array( 'embed', 'view', 'edit' ),
),
- 'source' => array(
+ 'source' => array(
'description' => __( 'Source of template' ),
'type' => 'string',
'context' => array( 'embed', 'view', 'edit' ),
'readonly' => true,
),
- 'origin' => array(
+ 'origin' => array(
'description' => __( 'Source of a customized template' ),
'type' => 'string',
'context' => array( 'embed', 'view', 'edit' ),
'readonly' => true,
),
- 'content' => array(
+ 'content' => array(
'description' => __( 'Content of template.' ),
'type' => array( 'object', 'string' ),
'default' => '',
@@ -916,7 +1001,7 @@ public function get_item_schema() {
),
),
),
- 'title' => array(
+ 'title' => array(
'description' => __( 'Title of template.' ),
'type' => array( 'object', 'string' ),
'default' => '',
@@ -935,43 +1020,61 @@ public function get_item_schema() {
),
),
),
- 'description' => array(
+ 'description' => array(
'description' => __( 'Description of template.' ),
'type' => 'string',
'default' => '',
'context' => array( 'embed', 'view', 'edit' ),
),
- 'status' => array(
+ 'status' => array(
'description' => __( 'Status of template.' ),
'type' => 'string',
'enum' => array_keys( get_post_stati( array( 'internal' => false ) ) ),
'default' => 'publish',
'context' => array( 'embed', 'view', 'edit' ),
),
- 'wp_id' => array(
+ 'wp_id' => array(
'description' => __( 'Post ID.' ),
'type' => 'integer',
'context' => array( 'embed', 'view', 'edit' ),
'readonly' => true,
),
- 'has_theme_file' => array(
+ 'has_theme_file' => array(
'description' => __( 'Theme file exists.' ),
'type' => 'bool',
'context' => array( 'embed', 'view', 'edit' ),
'readonly' => true,
),
- 'author' => array(
+ 'author' => array(
'description' => __( 'The ID for the author of the template.' ),
'type' => 'integer',
'context' => array( 'view', 'edit', 'embed' ),
),
- 'modified' => array(
+ 'modified' => array(
'description' => __( "The date the template was last modified, in the site's timezone." ),
'type' => 'string',
'format' => 'date-time',
'context' => array( 'view', 'edit' ),
'readonly' => true,
),
+ 'author_text' => array(
+ 'type' => 'string',
+ 'description' => __( 'Human readable text for the author.' ),
+ 'readonly' => true,
+ 'context' => array( 'view', 'edit', 'embed' ),
+ ),
+ 'original_source' => array(
+ 'description' => __( 'Where the template originally comes from e.g. \'theme\'' ),
+ 'type' => 'string',
+ 'readonly' => true,
+ 'context' => array( 'view', 'edit', 'embed' ),
+ 'enum' => array(
+ 'theme',
+ 'plugin',
+ 'site',
+ 'user',
+ ),
+ ),
),
);
diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php
index c9ac6675d093f..7dcc4d79236a1 100644
--- a/src/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php
+++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-url-details-controller.php
@@ -128,7 +128,7 @@ public function get_item_schema() {
*
* @since 5.9.0
*
- * @param WP_REST_REQUEST $request Full details about the request.
+ * @param WP_REST_Request $request Full details about the request.
* @return WP_REST_Response|WP_Error The parsed details as a response object. WP_Error if there are errors.
*/
public function parse_url_details( $request ) {
diff --git a/src/wp-includes/rss.php b/src/wp-includes/rss.php
index 6d8941ab3856d..4d3f35e5cb547 100644
--- a/src/wp-includes/rss.php
+++ b/src/wp-includes/rss.php
@@ -631,6 +631,9 @@ function _response_to_rss ($resp) {
* Set up constants with default values, unless user overrides.
*
* @since 1.5.0
+ *
+ * @global string $wp_version The WordPress version string.
+ *
* @package External
* @subpackage MagpieRSS
*/
diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php
index 8886cb587b170..932fcfc06c6c0 100644
--- a/src/wp-includes/script-loader.php
+++ b/src/wp-includes/script-loader.php
@@ -96,6 +96,7 @@ function wp_default_packages_vendor( $scripts ) {
'lodash',
'wp-polyfill-fetch',
'wp-polyfill-formdata',
+ 'wp-polyfill-importmap',
'wp-polyfill-node-contains',
'wp-polyfill-url',
'wp-polyfill-dom-rect',
@@ -120,6 +121,7 @@ function wp_default_packages_vendor( $scripts ) {
'wp-polyfill-object-fit' => '2.3.5',
'wp-polyfill-inert' => '3.1.2',
'wp-polyfill' => '3.15.0',
+ 'wp-polyfill-importmap' => '1.8.2',
);
foreach ( $vendor_scripts as $handle => $dependencies ) {
@@ -417,6 +419,8 @@ function wp_default_packages_inline_scripts( $scripts ) {
$timezone_abbr = $timezone_date->format( 'T' );
}
+ $gmt_offset = get_option( 'gmt_offset', 0 );
+
$scripts->add_inline_script(
'wp-date',
sprintf(
@@ -437,27 +441,27 @@ function wp_default_packages_inline_scripts( $scripts ) {
'past' => __( '%s ago' ),
/* translators: One second from or to a particular datetime, e.g., "a second ago" or "a second from now". */
's' => __( 'a second' ),
- /* translators: %s: Duration in seconds from or to a particular datetime, e.g., "4 seconds ago" or "4 seconds from now". */
+ /* translators: %d: Duration in seconds from or to a particular datetime, e.g., "4 seconds ago" or "4 seconds from now". */
'ss' => __( '%d seconds' ),
/* translators: One minute from or to a particular datetime, e.g., "a minute ago" or "a minute from now". */
'm' => __( 'a minute' ),
- /* translators: %s: Duration in minutes from or to a particular datetime, e.g., "4 minutes ago" or "4 minutes from now". */
+ /* translators: %d: Duration in minutes from or to a particular datetime, e.g., "4 minutes ago" or "4 minutes from now". */
'mm' => __( '%d minutes' ),
- /* translators: %s: One hour from or to a particular datetime, e.g., "an hour ago" or "an hour from now". */
+ /* translators: One hour from or to a particular datetime, e.g., "an hour ago" or "an hour from now". */
'h' => __( 'an hour' ),
- /* translators: %s: Duration in hours from or to a particular datetime, e.g., "4 hours ago" or "4 hours from now". */
+ /* translators: %d: Duration in hours from or to a particular datetime, e.g., "4 hours ago" or "4 hours from now". */
'hh' => __( '%d hours' ),
- /* translators: %s: One day from or to a particular datetime, e.g., "a day ago" or "a day from now". */
+ /* translators: One day from or to a particular datetime, e.g., "a day ago" or "a day from now". */
'd' => __( 'a day' ),
- /* translators: %s: Duration in days from or to a particular datetime, e.g., "4 days ago" or "4 days from now". */
+ /* translators: %d: Duration in days from or to a particular datetime, e.g., "4 days ago" or "4 days from now". */
'dd' => __( '%d days' ),
- /* translators: %s: One month from or to a particular datetime, e.g., "a month ago" or "a month from now". */
+ /* translators: One month from or to a particular datetime, e.g., "a month ago" or "a month from now". */
'M' => __( 'a month' ),
- /* translators: %s: Duration in months from or to a particular datetime, e.g., "4 months ago" or "4 months from now". */
+ /* translators: %d: Duration in months from or to a particular datetime, e.g., "4 months ago" or "4 months from now". */
'MM' => __( '%d months' ),
- /* translators: %s: One year from or to a particular datetime, e.g., "a year ago" or "a year from now". */
+ /* translators: One year from or to a particular datetime, e.g., "a year ago" or "a year from now". */
'y' => __( 'a year' ),
- /* translators: %s: Duration in years from or to a particular datetime, e.g., "4 years ago" or "4 years from now". */
+ /* translators: %d: Duration in years from or to a particular datetime, e.g., "4 years ago" or "4 years from now". */
'yy' => __( '%d years' ),
),
'startOfWeek' => (int) get_option( 'start_of_week', 0 ),
@@ -473,9 +477,10 @@ function wp_default_packages_inline_scripts( $scripts ) {
'datetimeAbbreviated' => __( 'M j, Y g:i a' ),
),
'timezone' => array(
- 'offset' => (float) get_option( 'gmt_offset', 0 ),
- 'string' => $timezone_string,
- 'abbr' => $timezone_abbr,
+ 'offset' => (float) $gmt_offset,
+ 'offsetFormatted' => str_replace( array( '.25', '.5', '.75' ), array( ':15', ':30', ':45' ), (string) $gmt_offset ),
+ 'string' => $timezone_string,
+ 'abbr' => $timezone_abbr,
),
)
)
@@ -1714,7 +1719,7 @@ function wp_default_styles( $styles ) {
);
$package_styles = array(
- 'block-editor' => array( 'wp-components' ),
+ 'block-editor' => array( 'wp-components', 'wp-preferences' ),
'block-library' => array(),
'block-directory' => array(),
'components' => array(),
@@ -1726,17 +1731,20 @@ function wp_default_styles( $styles ) {
'wp-edit-blocks',
'wp-block-library',
'wp-commands',
+ 'wp-preferences',
),
'editor' => array(
'wp-components',
'wp-block-editor',
'wp-reusable-blocks',
'wp-patterns',
+ 'wp-preferences',
),
'format-library' => array(),
'list-reusable-blocks' => array( 'wp-components' ),
'reusable-blocks' => array( 'wp-components' ),
'patterns' => array( 'wp-components' ),
+ 'preferences' => array( 'wp-components' ),
'nux' => array( 'wp-components' ),
'widgets' => array(
'wp-components',
@@ -1748,6 +1756,7 @@ function wp_default_styles( $styles ) {
'wp-block-library',
'wp-reusable-blocks',
'wp-patterns',
+ 'wp-preferences',
),
'customize-widgets' => array(
'wp-widgets',
@@ -1756,12 +1765,14 @@ function wp_default_styles( $styles ) {
'wp-block-library',
'wp-reusable-blocks',
'wp-patterns',
+ 'wp-preferences',
),
'edit-site' => array(
'wp-components',
'wp-block-editor',
'wp-edit-blocks',
'wp-commands',
+ 'wp-preferences',
),
);
@@ -2586,7 +2597,7 @@ function wp_should_load_block_editor_scripts_and_styles() {
* @return bool Whether separate assets will be loaded.
*/
function wp_should_load_separate_core_block_assets() {
- if ( is_admin() || is_feed() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
+ if ( is_admin() || is_feed() || wp_is_rest_endpoint() ) {
return false;
}
@@ -2834,18 +2845,18 @@ function wp_print_script_tag( $attributes ) {
}
/**
- * Wraps inline JavaScript in `\n", wp_sanitize_script_attributes( $attributes ), $javascript );
+ return sprintf( "\n", wp_sanitize_script_attributes( $attributes ), $data );
}
/**
- * Prints inline JavaScript wrapped in `',
+ 'description' => 'My collection description',
+ 'font_families' => array(
+ array(
+ 'font_family_settings' => array(
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'slug' => 'open-sans',
+ 'name' => 'Open Sans',
+ 'fontFace' => array(
+ array(
+ 'fontFamily' => 'Open Sans',
+ 'fontStyle' => 'normal',
+ 'fontWeight' => '400',
+ 'src' => 'https://example.com/src-as-string.ttf?a=',
+ ),
+ array(
+ 'fontFamily' => 'Open Sans',
+ 'fontStyle' => 'normal',
+ 'fontWeight' => '400',
+ 'src' => array(
+ 'https://example.com/src-as-array.woff2?a=',
+ 'https://example.com/src-as-array.ttf',
+ ),
+ ),
+ ),
+ 'unwanted_property' => 'potentially evil value',
+ ),
+ 'categories' => array( 'sans-serif' ),
+ ),
+ ),
+ 'categories' => array(
+ array(
+ 'name' => 'Mock col',
+ 'slug' => 'mock-col',
+ 'unwanted_property' => 'potentially evil value',
+ ),
+ ),
+ 'unwanted_property' => 'potentially evil value',
+ ),
+ 'expected_data' => array(
+ 'description' => 'My collection description',
+ 'categories' => array(
+ array(
+ 'name' => 'Mock col',
+ 'slug' => 'mock-colalertxss',
+ ),
+ ),
+ 'name' => 'My Collection',
+ 'font_families' => array(
+ array(
+ 'font_family_settings' => array(
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'slug' => 'open-sans',
+ 'name' => 'Open Sans',
+ 'fontFace' => array(
+ array(
+ 'fontFamily' => 'Open Sans',
+ 'fontStyle' => 'normal',
+ 'fontWeight' => '400',
+ 'src' => 'https://example.com/src-as-string.ttf?a=',
+ ),
+ array(
+ 'fontFamily' => 'Open Sans',
+ 'fontStyle' => 'normal',
+ 'fontWeight' => '400',
+ 'src' => array(
+ 'https://example.com/src-as-array.woff2?a=',
+ 'https://example.com/src-as-array.ttf',
+ ),
+ ),
+ ),
+ ),
+ 'categories' => array( 'sans-serifalertxss' ),
+ ),
+ ),
+ ),
+ ),
+
+ );
+ }
+
+ /**
+ * @dataProvider data_should_error_when_missing_properties
+ *
+ * @param array $config Font collection config.
+ */
+ public function test_should_error_when_missing_properties( $config ) {
+ $this->setExpectedIncorrectUsage( 'WP_Font_Collection::sanitize_and_validate_data' );
+
+ $collection = new WP_Font_Collection( 'my-collection', $config );
+ $data = $collection->get_data();
+
+ $this->assertWPError( $data, 'Error is not returned when property is missing or invalid.' );
+ $this->assertSame(
+ $data->get_error_code(),
+ 'font_collection_missing_property',
+ 'Incorrect error code when property is missing or invalid.'
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_should_error_when_missing_properties() {
+ return array(
+ 'missing name' => array(
+ 'config' => array(
+ 'font_families' => array( 'mock' ),
+ ),
+ ),
+ 'empty name' => array(
+ 'config' => array(
+ 'name' => '',
+ 'font_families' => array( 'mock' ),
+ ),
+ ),
+ 'missing font_families' => array(
+ 'config' => array(
+ 'name' => 'My Collection',
+ ),
+ ),
+ 'empty font_families' => array(
+ 'config' => array(
+ 'name' => 'My Collection',
+ 'font_families' => array(),
+ ),
+ ),
+ );
+ }
+
+ public function test_should_error_with_invalid_json_file_path() {
+ $this->setExpectedIncorrectUsage( 'WP_Font_Collection::load_from_json' );
+
+ $collection = new WP_Font_Collection( 'my-collection', 'non-existing.json' );
+ $data = $collection->get_data();
+
+ $this->assertWPError( $data, 'Error is not returned when invalid file path is provided.' );
+ $this->assertSame(
+ $data->get_error_code(),
+ 'font_collection_json_missing',
+ 'Incorrect error code when invalid file path is provided.'
+ );
+ }
+
+ public function test_should_error_with_invalid_json_from_file() {
+ $mock_file = wp_tempnam( 'my-collection-data-' );
+ file_put_contents( $mock_file, 'invalid-json' );
+
+ $collection = new WP_Font_Collection( 'my-collection', $mock_file );
+
+ // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- Testing error response returned by `load_from_json`, not the underlying error from `wp_json_file_decode`.
+ $data = @$collection->get_data();
+
+ $this->assertWPError( $data, 'Error is not returned with invalid json file contents.' );
+ $this->assertSame(
+ $data->get_error_code(),
+ 'font_collection_decode_error',
+ 'Incorrect error code with invalid json file contents.'
+ );
+ }
+
+ public function test_should_error_with_invalid_url() {
+ $this->setExpectedIncorrectUsage( 'WP_Font_Collection::load_from_json' );
+
+ $collection = new WP_Font_Collection( 'my-collection', 'not-a-url' );
+ $data = $collection->get_data();
+
+ $this->assertWPError( $data, 'Error is not returned when invalid url is provided.' );
+ $this->assertSame(
+ $data->get_error_code(),
+ 'font_collection_json_missing',
+ 'Incorrect error code when invalid url is provided.'
+ );
+ }
+
+ public function test_should_error_with_unsuccessful_response_status() {
+ add_filter( 'pre_http_request', array( $this, 'mock_request_unsuccessful_response' ), 10, 3 );
+
+ $collection = new WP_Font_Collection( 'my-collection', 'https://example.com/fonts/missing-collection.json' );
+ $data = $collection->get_data();
+
+ remove_filter( 'pre_http_request', array( $this, 'mock_request_unsuccessful_response' ) );
+
+ $this->assertWPError( $data, 'Error is not returned when response is unsuccessful.' );
+ $this->assertSame(
+ $data->get_error_code(),
+ 'font_collection_request_error',
+ 'Incorrect error code when response is unsuccussful.'
+ );
+ }
+
+ public function test_should_error_with_invalid_json_from_url() {
+ add_filter( 'pre_http_request', array( $this, 'mock_request_invalid_json' ), 10, 3 );
+
+ $collection = new WP_Font_Collection( 'my-collection', 'https://example.com/fonts/invalid-collection.json' );
+ $data = $collection->get_data();
+
+ remove_filter( 'pre_http_request', array( $this, 'mock_request_invalid_json' ) );
+
+ $this->assertWPError( $data, 'Error is not returned when response is invalid json.' );
+ $this->assertSame(
+ $data->get_error_code(),
+ 'font_collection_decode_error',
+ 'Incorrect error code when response is invalid json.'
+ );
+ }
+
+ public function mock_request( $preempt, $args, $url ) {
+ if ( 'https://example.com/fonts/mock-font-collection.json' !== $url ) {
+ return false;
+ }
+
+ return array(
+ 'body' => wp_json_encode( self::$mock_collection_data ),
+ 'response' => array(
+ 'code' => 200,
+ ),
+ );
+ }
+
+ public function mock_request_unsuccessful_response( $preempt, $args, $url ) {
+ if ( 'https://example.com/fonts/missing-collection.json' !== $url ) {
+ return false;
+ }
+
+ return array(
+ 'body' => '',
+ 'response' => array(
+ 'code' => 404,
+ ),
+ );
+ }
+
+ public function mock_request_invalid_json( $preempt, $args, $url ) {
+ if ( 'https://example.com/fonts/invalid-collection.json' !== $url ) {
+ return false;
+ }
+
+ return array(
+ 'body' => 'invalid',
+ 'response' => array(
+ 'code' => 200,
+ ),
+ );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpFontLibrary/base.php b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/base.php
new file mode 100644
index 0000000000000..135329e5add73
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/base.php
@@ -0,0 +1,25 @@
+get_font_collections();
+ foreach ( $collections as $slug => $collection ) {
+ WP_Font_Library::get_instance()->unregister_font_collection( $slug );
+ }
+ }
+
+ public function set_up() {
+ parent::set_up();
+ $this->reset_font_collections();
+ }
+
+ public function tear_down() {
+ parent::tear_down();
+ $this->reset_font_collections();
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpFontLibrary/getFontCollection.php b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/getFontCollection.php
new file mode 100644
index 0000000000000..e01cc2c1a105a
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/getFontCollection.php
@@ -0,0 +1,30 @@
+ 'Test Collection',
+ 'font_families' => array( 'mock' ),
+ );
+
+ wp_register_font_collection( 'my-font-collection', $mock_collection_data );
+ $font_collection = WP_Font_Library::get_instance()->get_font_collection( 'my-font-collection' );
+ $this->assertInstanceOf( 'WP_Font_Collection', $font_collection );
+ }
+
+ public function test_should_get_no_font_collection_if_the_slug_is_not_registered() {
+ $font_collection = WP_Font_Library::get_instance()->get_font_collection( 'not-registered-font-collection' );
+ $this->assertNull( $font_collection );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpFontLibrary/getFontCollections.php b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/getFontCollections.php
new file mode 100644
index 0000000000000..f5ca6389b8ff5
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/getFontCollections.php
@@ -0,0 +1,34 @@
+get_font_collections();
+ $this->assertEmpty( $font_collections, 'Should return an empty array.' );
+ }
+
+ public function test_should_get_mock_font_collection() {
+ $my_font_collection_config = array(
+ 'name' => 'My Font Collection',
+ 'description' => 'Demo about how to a font collection to your WordPress Font Library.',
+ 'font_families' => array( 'mock' ),
+ );
+
+ WP_Font_Library::get_instance()->register_font_collection( 'my-font-collection', $my_font_collection_config );
+
+ $font_collections = WP_Font_Library::get_instance()->get_font_collections();
+ $this->assertNotEmpty( $font_collections, 'Should return an array of font collections.' );
+ $this->assertCount( 1, $font_collections, 'Should return an array with one font collection.' );
+ $this->assertArrayHasKey( 'my-font-collection', $font_collections, 'The array should have the key of the registered font collection id.' );
+ $this->assertInstanceOf( 'WP_Font_Collection', $font_collections['my-font-collection'], 'The value of the array $font_collections[id] should be an instance of WP_Font_Collection class.' );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpFontLibrary/registerFontCollection.php b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/registerFontCollection.php
new file mode 100644
index 0000000000000..d3b0f126e2e7e
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/registerFontCollection.php
@@ -0,0 +1,40 @@
+ 'My Collection',
+ 'font_families' => array( 'mock' ),
+ );
+
+ $collection = WP_Font_Library::get_instance()->register_font_collection( 'my-collection', $config );
+ $this->assertInstanceOf( 'WP_Font_Collection', $collection );
+ }
+
+ public function test_should_return_error_if_slug_is_repeated() {
+ $mock_collection_data = array(
+ 'name' => 'Test Collection',
+ 'font_families' => array( 'mock' ),
+ );
+
+ // Register first collection.
+ $collection1 = WP_Font_Library::get_instance()->register_font_collection( 'my-collection-1', $mock_collection_data );
+ $this->assertInstanceOf( 'WP_Font_Collection', $collection1, 'A collection should be registered.' );
+
+ // Expects a _doing_it_wrong notice.
+ $this->setExpectedIncorrectUsage( 'WP_Font_Library::register_font_collection' );
+
+ // Try to register a second collection with same slug.
+ WP_Font_Library::get_instance()->register_font_collection( 'my-collection-1', $mock_collection_data );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpFontLibrary/unregisterFontCollection.php b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/unregisterFontCollection.php
new file mode 100644
index 0000000000000..ddb0fa91c1d60
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpFontLibrary/unregisterFontCollection.php
@@ -0,0 +1,46 @@
+ 'Test Collection',
+ 'font_families' => array( 'mock' ),
+ );
+
+ // Registers two mock font collections.
+ WP_Font_Library::get_instance()->register_font_collection( 'mock-font-collection-1', $mock_collection_data );
+ WP_Font_Library::get_instance()->register_font_collection( 'mock-font-collection-2', $mock_collection_data );
+
+ // Unregister mock font collection.
+ WP_Font_Library::get_instance()->unregister_font_collection( 'mock-font-collection-1' );
+ $collections = WP_Font_Library::get_instance()->get_font_collections();
+ $this->assertArrayNotHasKey( 'mock-font-collection-1', $collections, 'Font collection was not unregistered.' );
+ $this->assertArrayHasKey( 'mock-font-collection-2', $collections, 'Font collection was unregistered by mistake.' );
+
+ // Unregisters remaining mock font collection.
+ WP_Font_Library::get_instance()->unregister_font_collection( 'mock-font-collection-2' );
+ $collections = WP_Font_Library::get_instance()->get_font_collections();
+ $this->assertArrayNotHasKey( 'mock-font-collection-2', $collections, 'Mock font collection was not unregistered.' );
+
+ // Checks that all font collections were unregistered.
+ $this->assertEmpty( $collections, 'Font collections were not unregistered.' );
+ }
+
+ public function unregister_non_existing_collection() {
+ // Unregisters non-existing font collection.
+ WP_Font_Library::get_instance()->unregister_font_collection( 'non-existing-collection' );
+ $collections = WP_Font_Library::get_instance()->get_font_collections();
+ $this->assertEmpty( $collections, 'No collections should be registered.' );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpFontUtils/getFontFaceSlug.php b/tests/phpunit/tests/fonts/font-library/wpFontUtils/getFontFaceSlug.php
new file mode 100644
index 0000000000000..de0b02e63185e
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpFontUtils/getFontFaceSlug.php
@@ -0,0 +1,92 @@
+assertSame( $expected_slug, $slug );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_get_font_face_slug_normalizes_values() {
+ return array(
+ 'Sets defaults' => array(
+ 'settings' => array(
+ 'fontFamily' => 'Open Sans',
+ ),
+ 'expected_slug' => 'open sans;normal;400;100%;U+0-10FFFF',
+ ),
+ 'Converts normal weight to 400' => array(
+ 'settings' => array(
+ 'fontFamily' => 'Open Sans',
+ 'fontWeight' => 'normal',
+ ),
+ 'expected_slug' => 'open sans;normal;400;100%;U+0-10FFFF',
+ ),
+ 'Converts bold weight to 700' => array(
+ 'settings' => array(
+ 'fontFamily' => 'Open Sans',
+ 'fontWeight' => 'bold',
+ ),
+ 'expected_slug' => 'open sans;normal;700;100%;U+0-10FFFF',
+ ),
+ 'Converts normal font-stretch to 100%' => array(
+ 'settings' => array(
+ 'fontFamily' => 'Open Sans',
+ 'fontStretch' => 'normal',
+ ),
+ 'expected_slug' => 'open sans;normal;400;100%;U+0-10FFFF',
+ ),
+ 'Removes double quotes from fontFamilies' => array(
+ 'settings' => array(
+ 'fontFamily' => '"Open Sans"',
+ ),
+ 'expected_slug' => 'open sans;normal;400;100%;U+0-10FFFF',
+ ),
+ 'Removes single quotes from fontFamilies' => array(
+ 'settings' => array(
+ 'fontFamily' => "'Open Sans'",
+ ),
+ 'expected_slug' => 'open sans;normal;400;100%;U+0-10FFFF',
+ ),
+ 'Removes spaces between comma separated font families' => array(
+ 'settings' => array(
+ 'fontFamily' => 'Open Sans, serif',
+ ),
+ 'expected_slug' => 'open sans,serif;normal;400;100%;U+0-10FFFF',
+ ),
+ 'Removes tabs between comma separated font families' => array(
+ 'settings' => array(
+ 'fontFamily' => "Open Sans,\tserif",
+ ),
+ 'expected_slug' => 'open sans,serif;normal;400;100%;U+0-10FFFF',
+ ),
+ 'Removes new lines between comma separated font families' => array(
+ 'settings' => array(
+ 'fontFamily' => "Open Sans,\nserif",
+ ),
+ 'expected_slug' => 'open sans,serif;normal;400;100%;U+0-10FFFF',
+ ),
+ );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpFontUtils/sanitizeFontFamily.php b/tests/phpunit/tests/fonts/font-library/wpFontUtils/sanitizeFontFamily.php
new file mode 100644
index 0000000000000..71511331c65dc
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpFontUtils/sanitizeFontFamily.php
@@ -0,0 +1,63 @@
+assertSame(
+ $expected,
+ WP_Font_Utils::sanitize_font_family(
+ $font_family
+ )
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_should_sanitize_font_family() {
+ return array(
+ 'data_families_with_spaces_and_numbers' => array(
+ 'font_family' => 'Rock 3D , Open Sans,serif',
+ 'expected' => '"Rock 3D", "Open Sans", serif',
+ ),
+ 'data_single_font_family' => array(
+ 'font_family' => 'Rock 3D',
+ 'expected' => '"Rock 3D"',
+ ),
+ 'data_no_spaces' => array(
+ 'font_family' => 'Rock3D',
+ 'expected' => 'Rock3D',
+ ),
+ 'data_many_spaces_and_existing_quotes' => array(
+ 'font_family' => 'Rock 3D serif, serif,sans-serif, "Open Sans"',
+ 'expected' => '"Rock 3D serif", serif, sans-serif, "Open Sans"',
+ ),
+ 'data_empty_family' => array(
+ 'font_family' => ' ',
+ 'expected' => '',
+ ),
+ 'data_font_family_with_whitespace_tags_new_lines' => array(
+ 'font_family' => " Rock 3D\n ",
+ 'expected' => '"Rock 3D"',
+ ),
+ );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpFontUtils/sanitizeFromSchema.php b/tests/phpunit/tests/fonts/font-library/wpFontUtils/sanitizeFromSchema.php
new file mode 100644
index 0000000000000..88983fe15a14e
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpFontUtils/sanitizeFromSchema.php
@@ -0,0 +1,310 @@
+assertSame( $result, $expected );
+ }
+
+ public function data_sanitize_from_schema() {
+ return array(
+ 'One level associative array' => array(
+ 'data' => array(
+ 'slug' => 'open - sans',
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'src' => 'https://wordpress.org/example.json',
+ ),
+ 'schema' => array(
+ 'slug' => 'sanitize_title',
+ 'fontFamily' => 'sanitize_text_field',
+ 'src' => 'sanitize_url',
+ ),
+ 'expected' => array(
+ 'slug' => 'open-sansalertxss',
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'src' => 'https://wordpress.org/example.json/stylescriptalert(xss)/script',
+ ),
+ ),
+
+ 'Nested associative arrays' => array(
+ 'data' => array(
+ 'slug' => 'open - sans',
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'src' => 'https://wordpress.org/example.json',
+ 'nested' => array(
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ 'nested2' => array(
+ 'key3' => 'value3',
+ 'key4' => 'value4',
+ ),
+ ),
+ ),
+ 'schema' => array(
+ 'slug' => 'sanitize_title',
+ 'fontFamily' => 'sanitize_text_field',
+ 'src' => 'sanitize_url',
+ 'nested' => array(
+ 'key1' => 'sanitize_text_field',
+ 'key2' => 'sanitize_text_field',
+ 'nested2' => array(
+ 'key3' => 'sanitize_text_field',
+ 'key4' => 'sanitize_text_field',
+ ),
+ ),
+ ),
+ 'expected' => array(
+ 'slug' => 'open-sansalertxss',
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'src' => 'https://wordpress.org/example.json/stylescriptalert(xss)/script',
+ 'nested' => array(
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ 'nested2' => array(
+ 'key3' => 'value3',
+ 'key4' => 'value4',
+ ),
+ ),
+ ),
+ ),
+
+ 'Indexed arrays' => array(
+ 'data' => array(
+ 'slug' => 'oPeN SaNs',
+ 'enum' => array(
+ 'value1',
+ 'value2',
+ 'value3',
+ ),
+ ),
+ 'schema' => array(
+ 'slug' => 'sanitize_title',
+ 'enum' => array( 'sanitize_text_field' ),
+ ),
+ 'expected' => array(
+ 'slug' => 'open-sans',
+ 'enum' => array( 'value1', 'value2', 'value3' ),
+ ),
+ ),
+
+ 'Nested indexed arrays' => array(
+ 'data' => array(
+ 'slug' => 'OPEN-SANS',
+ 'name' => 'Open Sans',
+ 'fontFace' => array(
+ array(
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'src' => 'https://wordpress.org/example.json/stylescriptalert(xss)/script',
+ ),
+ array(
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'src' => 'https://wordpress.org/example.json/stylescriptalert(xss)/script',
+ ),
+ ),
+ ),
+ 'schema' => array(
+ 'slug' => 'sanitize_title',
+ 'name' => 'sanitize_text_field',
+ 'fontFace' => array(
+ array(
+ 'fontFamily' => 'sanitize_text_field',
+ 'src' => 'sanitize_url',
+ ),
+ ),
+ ),
+ 'expected' => array(
+ 'slug' => 'open-sans',
+ 'name' => 'Open Sans',
+ 'fontFace' => array(
+ array(
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'src' => 'https://wordpress.org/example.json/stylescriptalert(xss)/script',
+ ),
+ array(
+ 'fontFamily' => 'Open Sans, sans-serif',
+ 'src' => 'https://wordpress.org/example.json/stylescriptalert(xss)/script',
+ ),
+ ),
+ ),
+ ),
+
+ 'Custom sanitization function' => array(
+ 'data' => array(
+ 'key1' => 'abc123edf456ghi789',
+ 'key2' => 'value2',
+ ),
+ 'schema' => array(
+ 'key1' => function ( $value ) {
+ // Remove the six first character.
+ return substr( $value, 6 );
+ },
+ 'key2' => function ( $value ) {
+ // Capitalize the value.
+ return strtoupper( $value );
+ },
+ ),
+ 'expected' => array(
+ 'key1' => 'edf456ghi789',
+ 'key2' => 'VALUE2',
+ ),
+ ),
+
+ 'Null as schema value' => array(
+ 'data' => array(
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ 'nested' => array(
+ 'key3' => 'value3',
+ 'key4' => 'value4',
+ ),
+ ),
+ 'schema' => array(
+ 'key1' => null,
+ 'key2' => 'sanitize_text_field',
+ 'nested' => null,
+ ),
+ 'expected' => array(
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ 'nested' => array(
+ 'key3' => 'value3',
+ 'key4' => 'value4',
+ ),
+ ),
+ ),
+
+ 'Keys to remove' => array(
+ 'data' => array(
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ 'unwanted1' => 'value',
+ 'unwanted2' => 'value',
+ 'nestedAssociative' => array(
+ 'key5' => 'value5',
+ 'unwanted3' => 'value',
+ ),
+ 'nestedIndexed' => array(
+ array(
+ 'key6' => 'value7',
+ 'unwanted4' => 'value',
+ ),
+ array(
+ 'key6' => 'value7',
+ 'unwanted5' => 'value',
+ ),
+ ),
+
+ ),
+ 'schema' => array(
+ 'key1' => 'sanitize_text_field',
+ 'key2' => 'sanitize_text_field',
+ 'nestedAssociative' => array(
+ 'key5' => 'sanitize_text_field',
+ ),
+ 'nestedIndexed' => array(
+ array(
+ 'key6' => 'sanitize_text_field',
+ ),
+ ),
+ ),
+ 'expected' => array(
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ 'nestedAssociative' => array(
+ 'key5' => 'value5',
+ ),
+ 'nestedIndexed' => array(
+ array(
+ 'key6' => 'value7',
+ ),
+ array(
+ 'key6' => 'value7',
+ ),
+ ),
+ ),
+ ),
+
+ 'With empty structure' => array(
+ 'data' => array(
+ 'slug' => 'open-sans',
+ 'nested' => array(
+ 'key1' => 'value',
+ 'nested2' => array(
+ 'key2' => 'value',
+ 'nested3' => array(
+ 'nested4' => array(),
+ ),
+ ),
+ ),
+ ),
+ 'schema' => array(
+ 'slug' => 'sanitize_title',
+ 'nested' => array(
+ 'key1' => 'sanitize_text_field',
+ 'nested2' => array(
+ 'key2' => 'sanitize_text_field',
+ 'nested3' => array(
+ 'key3' => 'sanitize_text_field',
+ 'nested4' => array(
+ 'key4' => 'sanitize_text_field',
+ ),
+ ),
+ ),
+ ),
+ ),
+ 'expected' => array(
+ 'slug' => 'open-sans',
+ 'nested' => array(
+ 'key1' => 'value',
+ 'nested2' => array(
+ 'key2' => 'value',
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+
+ public function test_sanitize_from_schema_with_invalid_data() {
+ $data = 'invalid data';
+ $schema = array(
+ 'key1' => 'sanitize_text_field',
+ 'key2' => 'sanitize_text_field',
+ );
+
+ $result = WP_Font_Utils::sanitize_from_schema( $data, $schema );
+
+ $this->assertSame( $result, array() );
+ }
+
+
+ public function test_sanitize_from_schema_with_invalid_schema() {
+ $data = array(
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ );
+ $schema = 'invalid schema';
+
+ $result = WP_Font_Utils::sanitize_from_schema( $data, $schema );
+
+ $this->assertSame( $result, array() );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpFontsDir.php b/tests/phpunit/tests/fonts/font-library/wpFontsDir.php
new file mode 100644
index 0000000000000..a8f79888315bd
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpFontsDir.php
@@ -0,0 +1,72 @@
+ path_join( WP_CONTENT_DIR, 'fonts' ),
+ 'url' => content_url( 'fonts' ),
+ 'subdir' => '',
+ 'basedir' => path_join( WP_CONTENT_DIR, 'fonts' ),
+ 'baseurl' => content_url( 'fonts' ),
+ 'error' => false,
+ );
+ }
+
+ public function test_fonts_dir() {
+ $font_dir = wp_get_font_dir();
+
+ $this->assertSame( $font_dir, static::$dir_defaults );
+ }
+
+ public function test_fonts_dir_with_filter() {
+ // Define a callback function to pass to the filter.
+ function set_new_values( $defaults ) {
+ $defaults['path'] = '/custom-path/fonts/my-custom-subdir';
+ $defaults['url'] = 'http://example.com/custom-path/fonts/my-custom-subdir';
+ $defaults['subdir'] = 'my-custom-subdir';
+ $defaults['basedir'] = '/custom-path/fonts';
+ $defaults['baseurl'] = 'http://example.com/custom-path/fonts';
+ $defaults['error'] = false;
+ return $defaults;
+ }
+
+ // Add the filter.
+ add_filter( 'font_dir', 'set_new_values' );
+
+ // Gets the fonts dir.
+ $font_dir = wp_get_font_dir();
+
+ $expected = array(
+ 'path' => '/custom-path/fonts/my-custom-subdir',
+ 'url' => 'http://example.com/custom-path/fonts/my-custom-subdir',
+ 'subdir' => 'my-custom-subdir',
+ 'basedir' => '/custom-path/fonts',
+ 'baseurl' => 'http://example.com/custom-path/fonts',
+ 'error' => false,
+ );
+
+ // Remove the filter.
+ remove_filter( 'font_dir', 'set_new_values' );
+
+ $this->assertSame( $expected, $font_dir, 'The wp_get_font_dir() method should return the expected values.' );
+
+ // Gets the fonts dir.
+ $font_dir = wp_get_font_dir();
+
+ $this->assertSame( static::$dir_defaults, $font_dir, 'The wp_get_font_dir() method should return the default values.' );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php b/tests/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php
new file mode 100644
index 0000000000000..0f7fe8f9c662b
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpRestFontCollectionsController.php
@@ -0,0 +1,209 @@
+get_font_collections();
+ foreach ( $collections as $slug => $collection ) {
+ WP_Font_Library::get_instance()->unregister_font_collection( $slug );
+ }
+
+ self::$admin_id = $factory->user->create(
+ array(
+ 'role' => 'administrator',
+ )
+ );
+ self::$editor_id = $factory->user->create(
+ array(
+ 'role' => 'editor',
+ )
+ );
+ $mock_file = wp_tempnam( 'my-collection-data-' );
+ file_put_contents( $mock_file, '{"name": "Mock Collection", "font_families": [ "mock" ], "categories": [ "mock" ] }' );
+
+ wp_register_font_collection( 'mock-col-slug', $mock_file );
+ }
+
+ public static function wpTearDownAfterClass() {
+ self::delete_user( self::$admin_id );
+ self::delete_user( self::$editor_id );
+ wp_unregister_font_collection( 'mock-col-slug' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Collections_Controller::register_routes
+ */
+ public function test_register_routes() {
+ $routes = rest_get_server()->get_routes();
+ $this->assertCount( 1, $routes['/wp/v2/font-collections'], 'Rest server has not the collections path initialized.' );
+ $this->assertCount( 1, $routes['/wp/v2/font-collections/(?P[\/\w-]+)'], 'Rest server has not the collection path initialized.' );
+
+ $this->assertArrayHasKey( 'GET', $routes['/wp/v2/font-collections'][0]['methods'], 'Rest server has not the GET method for collections initialized.' );
+ $this->assertArrayHasKey( 'GET', $routes['/wp/v2/font-collections/(?P[\/\w-]+)'][0]['methods'], 'Rest server has not the GET method for collection initialized.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Collections_Controller::get_items
+ */
+ public function test_get_items() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections' );
+ $response = rest_get_server()->dispatch( $request );
+ $content = $response->get_data();
+ $this->assertIsArray( $content );
+ $this->assertSame( 200, $response->get_status() );
+ }
+
+ /**
+ * @covers WP_REST_Font_Collections_Controller::get_items
+ */
+ public function test_get_items_should_only_return_valid_collections() {
+ $this->setExpectedIncorrectUsage( 'WP_Font_Collection::load_from_json' );
+
+ wp_set_current_user( self::$admin_id );
+ wp_register_font_collection( 'invalid-collection', 'invalid-collection-file' );
+
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections' );
+ $response = rest_get_server()->dispatch( $request );
+ $content = $response->get_data();
+
+ wp_unregister_font_collection( 'invalid-collection' );
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertCount( 1, $content, 'The response should only contain valid collections.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Collections_Controller::get_item
+ */
+ public function test_get_item() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/mock-col-slug' );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+
+ $response_data = $response->get_data();
+ $this->assertArrayHasKey( 'name', $response_data, 'Response data does not have the name key.' );
+ $this->assertArrayHasKey( 'slug', $response_data, 'Response data does not have the slug key.' );
+ $this->assertArrayHasKey( 'description', $response_data, 'Response data does not have the description key.' );
+ $this->assertArrayHasKey( 'font_families', $response_data, 'Response data does not have the font_families key.' );
+ $this->assertArrayHasKey( 'categories', $response_data, 'Response data does not have the categories key.' );
+
+ $this->assertIsString( $response_data['name'], 'name is not a string.' );
+ $this->assertIsString( $response_data['slug'], 'slug is not a string.' );
+ $this->assertIsString( $response_data['description'], 'description is not a string.' );
+
+ $this->assertIsArray( $response_data['font_families'], 'font_families is not an array.' );
+ $this->assertIsArray( $response_data['categories'], 'categories is not an array.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Collections_Controller::get_item
+ */
+ public function test_get_item_invalid_slug() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/non-existing-collection' );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_font_collection_not_found', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Collections_Controller::get_item
+ */
+ public function test_get_item_invalid_collection() {
+ $this->setExpectedIncorrectUsage( 'WP_Font_Collection::load_from_json' );
+
+ wp_set_current_user( self::$admin_id );
+ $slug = 'invalid-collection';
+ wp_register_font_collection( $slug, 'invalid-collection-file' );
+
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/' . $slug );
+ $response = rest_get_server()->dispatch( $request );
+
+ wp_unregister_font_collection( $slug );
+
+ $this->assertErrorResponse( 'font_collection_json_missing', $response, 500, 'When the collection json file is invalid, the response should return an error for "font_collection_json_missing" with 500 status.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Collections_Controller::get_item
+ */
+ public function test_get_item_invalid_id_permission() {
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-collections/mock-col-slug' );
+
+ wp_set_current_user( 0 );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response status should be 401 for non-authenticated users.' );
+
+ wp_set_current_user( self::$editor_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response status should be 403 for users without the right permissions.' );
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function test_context_param() {
+ // Controller does not use get_context_param().
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function test_create_item() {
+ // Controller does not use test_create_item().
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function test_update_item() {
+ // Controller does not use test_update_item().
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function test_delete_item() {
+ // Controller does not use test_delete_item().
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function test_prepare_item() {
+ // Controller does not use test_prepare_item().
+ }
+
+ public function test_get_item_schema() {
+ $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/font-collections' );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $properties = $data['schema']['properties'];
+ $this->assertCount( 5, $properties, 'There should be 5 properties in the response data schema.' );
+ $this->assertArrayHasKey( 'slug', $properties, 'The slug property should exist in the response data schema.' );
+ $this->assertArrayHasKey( 'name', $properties, 'The name property should exist in the response data schema.' );
+ $this->assertArrayHasKey( 'description', $properties, 'The description property should exist in the response data schema.' );
+ $this->assertArrayHasKey( 'font_families', $properties, 'The slug font_families should exist in the response data schema.' );
+ $this->assertArrayHasKey( 'categories', $properties, 'The categories property should exist in the response data schema.' );
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php b/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php
new file mode 100644
index 0000000000000..3e74b23b7cb20
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpRestFontFacesController.php
@@ -0,0 +1,1076 @@
+ '"Open Sans"',
+ 'fontWeight' => '400',
+ 'fontStyle' => 'normal',
+ 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf',
+ );
+
+ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
+ self::$font_family_id = Tests_REST_WpRestFontFamiliesController::create_font_family_post();
+ self::$other_font_family_id = Tests_REST_WpRestFontFamiliesController::create_font_family_post();
+
+ self::$font_face_id1 = self::create_font_face_post(
+ self::$font_family_id,
+ array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '400',
+ 'fontStyle' => 'normal',
+ 'src' => home_url( '/wp-content/fonts/open-sans-medium.ttf' ),
+ )
+ );
+ self::$font_face_id2 = self::create_font_face_post(
+ self::$font_family_id,
+ array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '900',
+ 'fontStyle' => 'normal',
+ 'src' => home_url( '/wp-content/fonts/open-sans-bold.ttf' ),
+ )
+ );
+
+ self::$admin_id = $factory->user->create(
+ array(
+ 'role' => 'administrator',
+ )
+ );
+ self::$editor_id = $factory->user->create(
+ array(
+ 'role' => 'editor',
+ )
+ );
+
+ self::$post_ids_for_cleanup = array();
+ }
+
+ public static function wpTearDownAfterClass() {
+ self::delete_user( self::$admin_id );
+ self::delete_user( self::$editor_id );
+
+ wp_delete_post( self::$font_family_id, true );
+ wp_delete_post( self::$other_font_family_id, true );
+ wp_delete_post( self::$font_face_id1, true );
+ wp_delete_post( self::$font_face_id2, true );
+ }
+
+ public function tear_down() {
+ foreach ( self::$post_ids_for_cleanup as $post_id ) {
+ wp_delete_post( $post_id, true );
+ }
+ self::$post_ids_for_cleanup = array();
+ parent::tear_down();
+ }
+
+ public static function create_font_face_post( $parent_id, $settings = array() ) {
+ $settings = array_merge( self::$default_settings, $settings );
+ $title = WP_Font_Utils::get_font_face_slug( $settings );
+ $post_id = self::factory()->post->create(
+ wp_slash(
+ array(
+ 'post_type' => 'wp_font_face',
+ 'post_status' => 'publish',
+ 'post_title' => $title,
+ 'post_name' => sanitize_title( $title ),
+ 'post_content' => wp_json_encode( $settings ),
+ 'post_parent' => $parent_id,
+ )
+ )
+ );
+
+ self::$post_ids_for_cleanup[] = $post_id;
+
+ return $post_id;
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::register_routes
+ */
+ public function test_register_routes() {
+ $routes = rest_get_server()->get_routes();
+ $this->assertArrayHasKey(
+ '/wp/v2/font-families/(?P[\d]+)/font-faces',
+ $routes,
+ 'Font faces collection for the given font family does not exist'
+ );
+ $this->assertCount(
+ 2,
+ $routes['/wp/v2/font-families/(?P[\d]+)/font-faces'],
+ 'Font faces collection for the given font family does not have exactly two elements'
+ );
+ $this->assertArrayHasKey(
+ '/wp/v2/font-families/(?P[\d]+)/font-faces/(?P[\d]+)',
+ $routes,
+ 'Single font face route for the given font family does not exist'
+ );
+ $this->assertCount(
+ 2,
+ $routes['/wp/v2/font-families/(?P[\d]+)/font-faces/(?P[\d]+)'],
+ 'Font faces collection for the given font family does not have exactly two elements'
+ );
+ }
+
+ public function test_font_faces_no_autosave_routes() {
+ $routes = rest_get_server()->get_routes();
+ $this->assertArrayNotHasKey(
+ '/wp/v2/font-families/(?P[\d]+)/font-faces/(?P[\d]+)/autosaves',
+ $routes,
+ 'Font faces autosaves route exists.'
+ );
+ $this->assertArrayNotHasKey(
+ '/wp/v2/font-families/(?P[\d]+)/font-faces/(?P[\d]+)/autosaves/(?P[\d]+)',
+ $routes,
+ 'Font faces autosaves by id route exists.'
+ );
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function test_context_param() {
+ // See test_get_context_param().
+ }
+
+ /**
+ * @dataProvider data_get_context_param
+ *
+ * @covers WP_REST_Font_Faces_Controller::get_context_param
+ *
+ * @param bool $single_route Whether to test a single route.
+ */
+ public function test_get_context_param( $single_route ) {
+ $route = '/wp/v2/font-families/' . self::$font_family_id . '/font-faces';
+ if ( $single_route ) {
+ $route .= '/' . self::$font_face_id1;
+ }
+
+ $request = new WP_REST_Request( 'OPTIONS', $route );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $endpoint_data = $data['endpoints'][0];
+ $this->assertArrayNotHasKey( 'allow_batch', $endpoint_data, 'The allow_batch property should not exist in the endpoint data.' );
+ $this->assertSame( 'view', $endpoint_data['args']['context']['default'], 'The endpoint\'s args::context::default should be set to view.' );
+ $this->assertSame( array( 'view', 'embed', 'edit' ), $endpoint_data['args']['context']['enum'], 'The endpoint\'s args::context::enum should be set to [ view, embed, edit ].' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_get_context_param() {
+ return array(
+ 'Collection' => array( false ),
+ 'Single' => array( true ),
+ );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_items
+ */
+ public function test_get_items() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200' );
+ $this->assertCount( 2, $data, 'There should be 2 properties in the response data.' );
+ $this->assertArrayHasKey( '_links', $data[0], 'The _links property should exist in the response data 0.' );
+ $this->check_font_face_data( $data[0], self::$font_face_id2, $data[0]['_links'] );
+ $this->assertArrayHasKey( '_links', $data[1], 'The _links property should exist in the response data 1.' );
+ $this->check_font_face_data( $data[1], self::$font_face_id1, $data[1]['_links'] );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_items
+ */
+ public function test_get_items_no_permission() {
+ wp_set_current_user( 0 );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response should return an error with a "rest_cannot_read" code and 401 status.' );
+
+ wp_set_current_user( self::$editor_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response should return an error with a "rest_cannot_read" code and 403 status.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_items
+ */
+ public function test_get_items_missing_parent() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/font-faces' );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_item
+ */
+ public function test_get_item() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id1 );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->check_font_face_data( $data, self::$font_face_id1, $response->get_links() );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::prepare_item_for_response
+ */
+ public function test_get_item_removes_extra_settings() {
+ $font_face_id = self::create_font_face_post( self::$font_family_id, array( 'extra' => array() ) );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertArrayHasKey( 'font_face_settings', $data, 'The font_face_settings property should exist in the response data.' );
+ $this->assertArrayNotHasKey( 'extra', $data['font_face_settings'], 'The extra property should exist in the font_face_settings data.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::prepare_item_for_response
+ */
+ public function test_get_item_malformed_post_content_returns_empty_settings() {
+ $font_face_id = wp_insert_post(
+ array(
+ 'post_type' => 'wp_font_face',
+ 'post_parent' => self::$font_family_id,
+ 'post_status' => 'publish',
+ 'post_content' => 'invalid',
+ )
+ );
+
+ self::$post_ids_for_cleanup[] = $font_face_id;
+
+ $empty_settings = array(
+ 'fontFamily' => '',
+ 'src' => array(),
+ );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertArrayHasKey( 'font_face_settings', $data, 'The font_face_settings property should exist in the response data.' );
+ $this->assertSame( $empty_settings, $data['font_face_settings'], 'The empty settings should exist in the font_face_settings data.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_item
+ */
+ public function test_get_item_invalid_font_face_id() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_item
+ */
+ public function test_get_item_no_permission() {
+ wp_set_current_user( 0 );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id1 );
+
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response should return an error with a "rest_cannot_read" code and 401 status.' );
+
+ wp_set_current_user( self::$editor_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response should return an error with a "rest_cannot_read" code and 403 status.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_item
+ */
+ public function test_get_item_missing_parent() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/font-faces/' . self::$font_face_id1 );
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_item
+ */
+ public function test_get_item_valid_parent_id() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id1 );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertSame( self::$font_family_id, $data['parent'], 'The returned parent id should match the font family id.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_item
+ */
+ public function test_get_item_invalid_parent_id() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$other_font_family_id . '/font-faces/' . self::$font_face_id1 );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_font_face_parent_id_mismatch', $response, 404 );
+
+ $expected_message = 'The font face does not belong to the specified font family with id of "' . self::$other_font_family_id . '".';
+ $this->assertSame( $expected_message, $response->as_error()->get_error_messages()[0], 'The message must contain the correct parent ID.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::create_item
+ */
+ public function test_create_item() {
+ wp_set_current_user( self::$admin_id );
+ $files = $this->setup_font_file_upload( array( 'woff2' ) );
+
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param(
+ 'font_face_settings',
+ wp_json_encode(
+ array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '200',
+ 'fontStyle' => 'normal',
+ 'src' => array_keys( $files )[0],
+ )
+ )
+ );
+ $request->set_file_params( $files );
+
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $this->check_font_face_data( $data, $data['id'], $response->get_links() );
+ $this->check_file_meta( $data['id'], array( $data['font_face_settings']['src'] ) );
+
+ $settings = $data['font_face_settings'];
+ unset( $settings['src'] );
+ $this->assertSame(
+ array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '200',
+ 'fontStyle' => 'normal',
+ ),
+ $settings,
+ 'The font_face_settings data should match the expected data.'
+ );
+
+ $this->assertSame( self::$font_family_id, $data['parent'], 'The returned parent id should match the font family id.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::create_item
+ */
+ public function test_create_item_with_multiple_font_files() {
+ wp_set_current_user( self::$admin_id );
+ $files = $this->setup_font_file_upload( array( 'ttf', 'otf', 'woff', 'woff2' ) );
+
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param(
+ 'font_face_settings',
+ wp_json_encode(
+ array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '200',
+ 'fontStyle' => 'normal',
+ 'src' => array_keys( $files ),
+ )
+ )
+ );
+ $request->set_file_params( $files );
+
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $this->check_font_face_data( $data, $data['id'], $response->get_links() );
+ $this->check_file_meta( $data['id'], $data['font_face_settings']['src'] );
+
+ $settings = $data['font_face_settings'];
+ $this->assertCount( 4, $settings['src'], 'There should be 4 items in the font_face_settings::src data.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::create_item
+ */
+ public function test_create_item_invalid_file_type() {
+ $image_file = DIR_TESTDATA . '/images/canola.jpg';
+ $image_path = wp_tempnam( 'canola.jpg' );
+ copy( $image_file, $image_path );
+
+ $files = array(
+ 'file-0' => array(
+ 'name' => 'canola.jpg',
+ 'full_path' => 'canola.jpg',
+ 'type' => 'font/woff2',
+ 'tmp_name' => $image_path,
+ 'error' => 0,
+ 'size' => filesize( $image_path ),
+ ),
+ );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param(
+ 'font_face_settings',
+ wp_json_encode(
+ array_merge(
+ self::$default_settings,
+ array(
+ 'fontWeight' => '200',
+ 'src' => array_keys( $files )[0],
+ )
+ )
+ )
+ );
+ $request->set_file_params( $files );
+
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_font_upload_invalid_file_type', $response, 400 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::create_item
+ */
+ public function test_create_item_with_url_src() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param(
+ 'font_face_settings',
+ wp_json_encode(
+ array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '200',
+ 'fontStyle' => 'normal',
+ 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf',
+ )
+ )
+ );
+
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $this->check_font_face_data( $data, $data['id'], $response->get_links() );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::create_item
+ */
+ public function test_create_item_with_all_properties() {
+ wp_set_current_user( self::$admin_id );
+
+ $properties = array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '300 500',
+ 'fontStyle' => 'oblique 30deg 50deg',
+ 'fontDisplay' => 'swap',
+ 'fontStretch' => 'expanded',
+ 'ascentOverride' => '70%',
+ 'descentOverride' => '30%',
+ 'fontVariant' => 'normal',
+ 'fontFeatureSettings' => '"swsh" 2',
+ 'fontVariationSettings' => '"xhgt" 0.7',
+ 'lineGapOverride' => '10%',
+ 'sizeAdjust' => '90%',
+ 'unicodeRange' => 'U+0025-00FF, U+4??',
+ 'preview' => 'https://s.w.org/images/fonts/16.7/previews/open-sans/open-sans-400-normal.svg',
+ 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf',
+ );
+
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param( 'font_face_settings', wp_json_encode( $properties ) );
+
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+ wp_delete_post( $data['id'], true );
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $this->assertArrayHasKey( 'font_face_settings', $data, 'The font_face_settings property should exist in the response data.' );
+ $this->assertSame( $properties, $data['font_face_settings'], 'The font_face_settings should match the expected properties.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::create_item
+ */
+ public function test_create_item_missing_parent() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/font-faces' );
+ $request->set_param(
+ 'font_face_settings',
+ wp_json_encode( array_merge( self::$default_settings, array( 'fontWeight' => '100' ) ) )
+ );
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::create_item
+ */
+ public function test_create_item_with_duplicate_properties() {
+ $settings = array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '200',
+ 'fontStyle' => 'italic',
+ 'src' => home_url( '/wp-content/fonts/open-sans-italic-light.ttf' ),
+ );
+ self::create_font_face_post( self::$font_family_id, $settings );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'font_face_settings', wp_json_encode( $settings ) );
+
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_duplicate_font_face', $response, 400, 'The response should return an error for "rest_duplicate_font_face" with 400 status.' );
+ $expected_message = 'A font face matching those settings already exists.';
+ $message = $response->as_error()->get_error_messages()[0];
+ $this->assertSame( $expected_message, $message, 'The response error message should match.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_request
+ */
+ public function test_create_item_default_theme_json_version() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param(
+ 'font_face_settings',
+ wp_json_encode(
+ array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '200',
+ 'src' => 'https://fonts.gstatic.com/s/open-sans/v30/KFOkCnqEu92Fr1MmgWxPKTM1K9nz.ttf',
+ )
+ )
+ );
+
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+ wp_delete_post( $data['id'], true );
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $this->assertArrayHasKey( 'theme_json_version', $data, 'The theme_json_version property should exist in the response data.' );
+ $this->assertSame( WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED, $data['theme_json_version'], 'The default theme.json version should match the latest version supported by the controller.' );
+ }
+
+ /**
+ * @dataProvider data_create_item_invalid_theme_json_version
+ *
+ * @covers WP_REST_Font_Faces_Controller::create_item
+ *
+ * @param int $theme_json_version Version input to test.
+ */
+ public function test_create_item_invalid_theme_json_version( $theme_json_version ) {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', $theme_json_version );
+ $request->set_param( 'font_face_settings', '' );
+
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_create_item_invalid_theme_json_version() {
+ return array(
+ array( 1 ),
+ array( 3 ),
+ );
+ }
+
+ /**
+ * @dataProvider data_create_item_invalid_settings
+ *
+ * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_settings
+ *
+ * @param mixed $settings Settings to test.
+ */
+ public function test_create_item_invalid_settings( $settings ) {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param( 'font_face_settings', wp_json_encode( $settings ) );
+
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_create_item_invalid_settings() {
+ return array(
+ 'Missing fontFamily' => array(
+ 'settings' => array_diff_key( self::$default_settings, array( 'fontFamily' => '' ) ),
+ ),
+ 'Empty fontFamily' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'fontFamily' => '' ) ),
+ ),
+ 'Wrong fontFamily type' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'fontFamily' => 1234 ) ),
+ ),
+ 'Invalid fontDisplay' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'fontDisplay' => 'invalid' ) ),
+ ),
+ 'Missing src' => array(
+ 'settings' => array_diff_key( self::$default_settings, array( 'src' => '' ) ),
+ ),
+ 'Empty src string' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'src' => '' ) ),
+ ),
+ 'Empty src array' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'src' => array() ) ),
+ ),
+ 'Empty src array values' => array(
+ 'settings' => array_merge( self::$default_settings, array( '', '' ) ),
+ ),
+ 'Wrong src type' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'src' => 1234 ) ),
+ ),
+ 'Wrong src array types' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'src' => array( 1234, 5678 ) ) ),
+ ),
+ );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_settings
+ */
+ public function test_create_item_invalid_settings_json() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param( 'font_face_settings', 'invalid' );
+
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' );
+ $expected_message = 'font_face_settings parameter must be a valid JSON string.';
+ $message = $response->as_error()->get_all_error_data()[0]['params']['font_face_settings'];
+ $this->assertSame( $expected_message, $message, 'The response error message should match.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_settings
+ */
+ public function test_create_item_invalid_file_src() {
+ $files = $this->setup_font_file_upload( array( 'woff2' ) );
+
+ wp_set_current_user( self::$admin_id );
+ $src = 'invalid';
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param(
+ 'font_face_settings',
+ wp_json_encode(
+ array_merge( self::$default_settings, array( 'src' => $src ) )
+ )
+ );
+ $request->set_file_params( $files );
+
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' );
+ $expected_message = 'font_face_settings[src] value "' . $src . '" must be a valid URL or file reference.';
+ $message = $response->as_error()->get_all_error_data()[0]['params']['font_face_settings'];
+ $this->assertSame( $expected_message, $message, 'The response error message should match.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::validate_create_font_face_settings
+ */
+ public function test_create_item_missing_file_src() {
+ $files = $this->setup_font_file_upload( array( 'woff2', 'woff' ) );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param(
+ 'font_face_settings',
+ wp_json_encode(
+ array_merge( self::$default_settings, array( 'src' => array( array_keys( $files )[0] ) ) )
+ )
+ );
+ $request->set_file_params( $files );
+
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' );
+ $expected_message = 'File ' . array_keys( $files )[1] . ' must be used in font_face_settings[src].';
+ $message = $response->as_error()->get_all_error_data()[0]['params']['font_face_settings'];
+ $this->assertSame( $expected_message, $message, 'The response error message should match.' );
+ }
+
+ /**
+ * @dataProvider data_sanitize_font_face_settings
+ *
+ * @covers WP_REST_Font_Face_Controller::sanitize_font_face_settings
+ *
+ * @param string $settings Settings to test.
+ * @param string $expected Expected settings result.
+ */
+ public function test_create_item_sanitize_font_face_settings( $settings, $expected ) {
+ $settings = array_merge( self::$default_settings, $settings );
+ $expected = array_merge( self::$default_settings, $expected );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $request->set_param( 'font_face_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+ wp_delete_post( $data['id'], true );
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $this->assertSame( $expected, $data['font_face_settings'], 'The response font_face_settings should match.' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_sanitize_font_face_settings() {
+ return array(
+ 'settings with tags, extra whitespace, new lines' => array(
+ 'settings' => array(
+ 'fontFamily' => " Open Sans\n ",
+ 'fontStyle' => " oblique 20deg 50deg\n ",
+ 'fontWeight' => " 200\n ",
+ 'src' => " https://example.com/ ",
+ 'fontStretch' => " expanded\n ",
+ 'ascentOverride' => " 70%\n ",
+ 'descentOverride' => " 30%\n ",
+ 'fontVariant' => " normal\n ",
+ 'fontFeatureSettings' => " \"swsh\" 2\n ",
+ 'fontVariationSettings' => " \"xhgt\" 0.7\n ",
+ 'lineGapOverride' => " 10%\n ",
+ 'sizeAdjust' => " 90%\n ",
+ 'unicodeRange' => " U+0025-00FF, U+4??\n ",
+ 'preview' => " https://example.com/ ",
+ ),
+ 'expected' => array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontStyle' => 'oblique 20deg 50deg',
+ 'fontWeight' => '200',
+ 'src' => 'https://example.com//stylescriptalert(\'XSS\');/script%20%20%20%20%20%20',
+ 'fontStretch' => 'expanded',
+ 'ascentOverride' => '70%',
+ 'descentOverride' => '30%',
+ 'fontVariant' => 'normal',
+ 'fontFeatureSettings' => '"swsh" 2',
+ 'fontVariationSettings' => '"xhgt" 0.7',
+ 'lineGapOverride' => '10%',
+ 'sizeAdjust' => '90%',
+ 'unicodeRange' => 'U+0025-00FF, U+4??',
+ 'preview' => 'https://example.com//stylescriptalert(\'XSS\');/script%20%20%20%20%20%20',
+ ),
+ ),
+ 'multiword font family name with integer' => array(
+ 'settings' => array(
+ 'fontFamily' => 'Libre Barcode 128 Text',
+ ),
+ 'expected' => array(
+ 'fontFamily' => '"Libre Barcode 128 Text"',
+ ),
+ ),
+ 'multiword font family name' => array(
+ 'settings' => array(
+ 'fontFamily' => 'B612 Mono',
+ ),
+ 'expected' => array(
+ 'fontFamily' => '"B612 Mono"',
+ ),
+ ),
+ 'comma-separated font family names' => array(
+ 'settings' => array(
+ 'fontFamily' => 'Open Sans, Noto Sans, sans-serif',
+ ),
+ 'expected' => array(
+ 'fontFamily' => '"Open Sans", "Noto Sans", sans-serif',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::create_item
+ */
+ // public function test_create_item_no_permission() {}
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::update_item
+ */
+ public function test_update_item() {
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id1 );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_no_route', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::delete_item
+ */
+ public function test_delete_item() {
+ wp_set_current_user( self::$admin_id );
+ $font_face_id = self::create_font_face_post( self::$font_family_id );
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id );
+ $request->set_param( 'force', true );
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 201.' );
+ $this->assertNull( get_post( $font_face_id ), 'The deleted post should not exist.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::delete_item
+ */
+ public function test_delete_item_no_trash() {
+ wp_set_current_user( self::$admin_id );
+ $font_face_id = self::create_font_face_post( self::$font_family_id );
+
+ // Attempt trashing.
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501, 'The response should return an error for "rest_trash_not_supported" with 501 status.' );
+
+ $request->set_param( 'force', 'false' );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501, 'When "force" is false, the response should return an error for "rest_trash_not_supported" with 501 status.' );
+
+ // Ensure the post still exists.
+ $post = get_post( $font_face_id );
+ $this->assertNotEmpty( $post, 'The post should still exists.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::delete_item
+ */
+ public function test_delete_item_invalid_font_face_id() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER );
+ $request->set_param( 'force', true );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::delete
+ */
+ public function test_delete_item_missing_parent() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER . '/font-faces/' . self::$font_face_id1 );
+ $request->set_param( 'force', true );
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_post_invalid_parent', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_item
+ */
+ public function test_delete_item_invalid_parent_id() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$other_font_family_id . '/font-faces/' . self::$font_face_id1 );
+ $request->set_param( 'force', true );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_font_face_parent_id_mismatch', $response, 404, 'The response should return an error for "rest_font_face_parent_id_mismatch" with 404 status.' );
+
+ $expected_message = 'The font face does not belong to the specified font family with id of "' . self::$other_font_family_id . '".';
+ $this->assertSame( $expected_message, $response->as_error()->get_error_messages()[0], 'The message must contain the correct parent ID.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::delete_item
+ */
+ public function test_delete_item_no_permissions() {
+ $font_face_id = $this->create_font_face_post( self::$font_family_id );
+
+ wp_set_current_user( 0 );
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_delete', $response, 401, 'The response should return an error for "rest_cannot_delete" with 401 status for an invalid user.' );
+
+ wp_set_current_user( self::$editor_id );
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . $font_face_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_delete', $response, 403, 'The response should return an error for "rest_cannot_delete" with 403 status for a user without permission.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::prepare_item_for_response
+ */
+ public function test_prepare_item() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces/' . self::$font_face_id2 );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->check_font_face_data( $data, self::$font_face_id2, $response->get_links() );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_item_schema
+ */
+ public function test_get_item_schema() {
+ $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/font-families/' . self::$font_family_id . '/font-faces' );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $properties = $data['schema']['properties'];
+ $this->assertCount( 4, $properties, 'There should be 4 properties in the schema::properties data.' );
+ $this->assertArrayHasKey( 'id', $properties, 'The id property should exist in the schema::properties data.' );
+ $this->assertArrayHasKey( 'theme_json_version', $properties, 'The theme_json_version property should exist in the schema::properties data.' );
+ $this->assertArrayHasKey( 'parent', $properties, 'The parent property should exist in the schema::properties data.' );
+ $this->assertArrayHasKey( 'font_face_settings', $properties, 'The font_face_settings property should exist in the schema::properties data.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_item_schema
+ */
+ public function test_get_item_schema_font_face_settings_should_all_have_sanitize_callbacks() {
+ $schema = ( new WP_REST_Font_Faces_Controller( 'wp_font_face' ) )->get_item_schema();
+ $font_face_settings_schema = $schema['properties']['font_face_settings'];
+
+ $this->assertArrayHasKey( 'properties', $font_face_settings_schema, 'font_face_settings schema is missing properties.' );
+ $this->assertIsArray( $font_face_settings_schema['properties'], 'font_face_settings properties should be an array.' );
+
+ // arg_options should be removed for each setting property.
+ foreach ( $font_face_settings_schema['properties'] as $property ) {
+ $this->assertArrayHasKey( 'arg_options', $property, 'Setting schema should have arg_options.' );
+ $this->assertArrayHasKey( 'sanitize_callback', $property['arg_options'], 'Setting schema should have a sanitize_callback.' );
+ $this->assertIsCallable( $property['arg_options']['sanitize_callback'], 'The sanitize_callback value should be callable.' );
+ }
+ }
+
+ /**
+ * @covers WP_REST_Font_Faces_Controller::get_public_item_schema
+ */
+ public function test_get_public_item_schema_should_not_have_arg_options() {
+ $schema = ( new WP_REST_Font_Faces_Controller( 'wp_font_face' ) )->get_public_item_schema();
+ $font_face_settings_schema = $schema['properties']['font_face_settings'];
+
+ $this->assertArrayHasKey( 'properties', $font_face_settings_schema, 'font_face_settings schema is missing properties.' );
+ $this->assertIsArray( $font_face_settings_schema['properties'], 'font_face_settings properties should be an array.' );
+
+ // arg_options should be removed for each setting property.
+ foreach ( $font_face_settings_schema['properties'] as $property ) {
+ $this->assertArrayNotHasKey( 'arg_options', $property, 'arg_options should be removed from the schema for each setting.' );
+ }
+ }
+
+ /**
+ * If WP_Theme_JSON::LATEST_SCHEMA is changed, the controller should be updated to handle any differences
+ * in `fontFace` structure to ensure support for the latest theme.json schema, and backwards compatibility
+ * for existing wp_font_face posts.
+ */
+ public function test_controller_supports_latest_theme_json_version() {
+ $this->assertSame( WP_Theme_JSON::LATEST_SCHEMA, WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ }
+
+ protected function check_font_face_data( $data, $post_id, $links ) {
+ self::$post_ids_for_cleanup[] = $post_id;
+ $post = get_post( $post_id );
+
+ $this->assertArrayHasKey( 'id', $data, 'The id property should exist in response data.' );
+ $this->assertSame( $post->ID, $data['id'], 'The "id" from the response data should match the post ID.' );
+
+ $this->assertArrayHasKey( 'parent', $data, 'The parent property should exist in response data.' );
+ $this->assertSame( $post->post_parent, $data['parent'], 'The "parent" from the response data should match the post parent.' );
+
+ $this->assertArrayHasKey( 'theme_json_version', $data, 'The theme_json_version property should exist in response data.' );
+ $this->assertSame( WP_REST_Font_Faces_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED, $data['theme_json_version'], 'The "theme_json_version" from the response data should match the latest version supported by the controller.' );
+
+ $this->assertArrayHasKey( 'font_face_settings', $data, 'The font_face_settings property should exist in response data.' );
+ $this->assertSame( $post->post_content, wp_json_encode( $data['font_face_settings'] ), 'The encoded "font_face_settings" from the response data should match the post content.' );
+
+ $this->assertNotEmpty( $links, 'The links should not be empty in the response data.' );
+ $expected = rest_url( 'wp/v2/font-families/' . $post->post_parent . '/font-faces/' . $post->ID );
+ $this->assertSame( $expected, $links['self'][0]['href'], 'The links URL from the response data should match the post\'s REST endpoint.' );
+ $expected = rest_url( 'wp/v2/font-families/' . $post->post_parent . '/font-faces' );
+ $this->assertSame( $expected, $links['collection'][0]['href'], 'The links collection URL from the response data should match the REST endpoint.' );
+ $expected = rest_url( 'wp/v2/font-families/' . $post->post_parent );
+ $this->assertSame( $expected, $links['parent'][0]['href'], 'The links for a parent URL from the response data should match the parent\'s REST endpoint.' );
+ }
+
+ protected function check_file_meta( $font_face_id, $src_attributes ) {
+ $file_meta = get_post_meta( $font_face_id, '_wp_font_face_file' );
+
+ foreach ( $src_attributes as $src_attribute ) {
+ $file_name = basename( $src_attribute );
+ $this->assertContains( $file_name, $file_meta, 'The uploaded font file path should be saved in the post meta.' );
+ }
+ }
+
+ protected function setup_font_file_upload( $formats ) {
+ $files = array();
+ foreach ( $formats as $format ) {
+ $font_file = DIR_TESTDATA . '/fonts/OpenSans-Regular.' . $format;
+ $font_path = wp_tempnam( 'OpenSans-Regular.' . $format );
+ copy( $font_file, $font_path );
+
+ $files[ 'file-' . count( $files ) ] = array(
+ 'name' => 'OpenSans-Regular.' . $format,
+ 'full_path' => 'OpenSans-Regular.' . $format,
+ 'type' => 'font/' . $format,
+ 'tmp_name' => $font_path,
+ 'error' => 0,
+ 'size' => filesize( $font_path ),
+ );
+ }
+
+ return $files;
+ }
+}
diff --git a/tests/phpunit/tests/fonts/font-library/wpRestFontFamiliesController.php b/tests/phpunit/tests/fonts/font-library/wpRestFontFamiliesController.php
new file mode 100644
index 0000000000000..0676c3ce4b88d
--- /dev/null
+++ b/tests/phpunit/tests/fonts/font-library/wpRestFontFamiliesController.php
@@ -0,0 +1,1057 @@
+ 'Open Sans',
+ 'slug' => 'open-sans',
+ 'fontFamily' => '"Open Sans", sans-serif',
+ 'preview' => 'https://s.w.org/images/fonts/16.7/previews/open-sans/open-sans-400-normal.svg',
+ );
+
+ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
+ self::$admin_id = $factory->user->create(
+ array(
+ 'role' => 'administrator',
+ )
+ );
+ self::$editor_id = $factory->user->create(
+ array(
+ 'role' => 'editor',
+ )
+ );
+
+ self::$font_family_id1 = self::create_font_family_post(
+ array(
+ 'name' => 'Open Sans',
+ 'slug' => 'open-sans',
+ 'fontFamily' => '"Open Sans", sans-serif',
+ 'preview' => 'https://s.w.org/images/fonts/16.7/previews/open-sans/open-sans-400-normal.svg',
+ )
+ );
+ self::$font_family_id2 = self::create_font_family_post(
+ array(
+ 'name' => 'Helvetica',
+ 'slug' => 'helvetica',
+ 'fontFamily' => 'Helvetica, Arial, sans-serif',
+ )
+ );
+ self::$font_face_id1 = Tests_REST_WpRestFontFacesController::create_font_face_post(
+ self::$font_family_id1,
+ array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '400',
+ 'fontStyle' => 'normal',
+ 'src' => home_url( '/wp-content/fonts/open-sans-medium.ttf' ),
+ )
+ );
+ self::$font_face_id2 = Tests_REST_WpRestFontFacesController::create_font_face_post(
+ self::$font_family_id1,
+ array(
+ 'fontFamily' => '"Open Sans"',
+ 'fontWeight' => '900',
+ 'fontStyle' => 'normal',
+ 'src' => home_url( '/wp-content/fonts/open-sans-bold.ttf' ),
+ )
+ );
+
+ static::$post_ids_to_cleanup = array();
+ }
+
+ public static function wpTearDownAfterClass() {
+ self::delete_user( self::$admin_id );
+ self::delete_user( self::$editor_id );
+
+ wp_delete_post( self::$font_family_id1 );
+ wp_delete_post( self::$font_family_id2 );
+ wp_delete_post( self::$font_face_id1 );
+ wp_delete_post( self::$font_face_id2 );
+ }
+
+ public function tear_down() {
+ foreach ( static::$post_ids_to_cleanup as $post_id ) {
+ wp_delete_post( $post_id, true );
+ }
+ static::$post_ids_to_cleanup = array();
+
+ parent::tear_down();
+ }
+
+ public static function create_font_family_post( $settings = array() ) {
+ $settings = array_merge( self::$default_settings, $settings );
+ $post_id = self::factory()->post->create(
+ wp_slash(
+ array(
+ 'post_type' => 'wp_font_family',
+ 'post_status' => 'publish',
+ 'post_title' => $settings['name'],
+ 'post_name' => $settings['slug'],
+ 'post_content' => wp_json_encode(
+ array(
+ 'fontFamily' => $settings['fontFamily'],
+ 'preview' => $settings['preview'],
+ )
+ ),
+ )
+ )
+ );
+
+ static::$post_ids_to_cleanup[] = $post_id;
+
+ return $post_id;
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::register_routes
+ */
+ public function test_register_routes() {
+ $routes = rest_get_server()->get_routes();
+ $this->assertArrayHasKey(
+ '/wp/v2/font-families',
+ $routes,
+ 'Font faces collection for the given font family does not exist'
+ );
+ $this->assertCount(
+ 2,
+ $routes['/wp/v2/font-families'],
+ 'Font faces collection for the given font family does not have exactly two elements'
+ );
+ $this->assertArrayHasKey(
+ '/wp/v2/font-families/(?P[\d]+)',
+ $routes,
+ 'Single font face route for the given font family does not exist'
+ );
+ $this->assertCount(
+ 3,
+ $routes['/wp/v2/font-families/(?P[\d]+)'],
+ 'Font faces collection for the given font family does not have exactly two elements'
+ );
+ }
+
+ public function test_font_families_no_autosave_routes() {
+ $routes = rest_get_server()->get_routes();
+ $this->assertArrayNotHasKey(
+ '/wp/v2/font-families/(?P[\d]+)/autosaves',
+ $routes,
+ 'Font families autosaves route exists.'
+ );
+ $this->assertArrayNotHasKey(
+ '/wp/v2/font-families/(?P[\d]+)/autosaves/(?P[\d]+)',
+ $routes,
+ 'Font families autosaves by id route exists.'
+ );
+ }
+
+ /**
+ * @doesNotPerformAssertions
+ */
+ public function test_context_param() {
+ // See test_get_context_param().
+ }
+
+ /**
+ * @dataProvider data_get_context_param
+ *
+ * @covers WP_REST_Font_Families_Controller::get_context_param
+ *
+ * @param bool $single_route Whether to test a single route.
+ */
+ public function test_get_context_param( $single_route ) {
+ $route = '/wp/v2/font-families';
+ if ( $single_route ) {
+ $route .= '/' . self::$font_family_id1;
+ }
+
+ $request = new WP_REST_Request( 'OPTIONS', $route );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $endpoint_data = $data['endpoints'][0];
+ $this->assertArrayNotHasKey( 'allow_batch', $endpoint_data, 'The allow_batch property should not exist in the endpoint data.' );
+ $this->assertSame( 'view', $endpoint_data['args']['context']['default'], 'The endpoint\'s args::context::default should be set to view.' );
+ $this->assertSame( array( 'view', 'embed', 'edit' ), $endpoint_data['args']['context']['enum'], 'The endpoint\'s args::context::enum should be set to [ view, embed, edit ].' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_get_context_param() {
+ return array(
+ 'Collection' => array( false ),
+ 'Single' => array( true ),
+ );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_items
+ */
+ public function test_get_items() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families' );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertCount( 2, $data, 'There should be 2 properties in the response data.' );
+ $this->assertArrayHasKey( '_links', $data[0], 'The _links property should exist in the response data 0.' );
+ $this->check_font_family_data( $data[0], self::$font_family_id2, $data[0]['_links'] );
+ $this->assertArrayHasKey( '_links', $data[1], 'The _links property should exist in the response data 1.' );
+ $this->check_font_family_data( $data[1], self::$font_family_id1, $data[1]['_links'] );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_items
+ */
+ public function test_get_items_by_slug() {
+ $font_family = get_post( self::$font_family_id2 );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families' );
+ $request->set_param( 'slug', $font_family->post_name );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertCount( 1, $data, 'There should be 2 properties in the response data.' );
+ $this->assertArrayHasKey( 'id', $data[0], 'The id property should exist in the response data.' );
+ $this->assertSame( $font_family->ID, $data[0]['id'], 'The id should match the expected ID in the response data.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_items
+ */
+ public function test_get_items_no_permission() {
+ wp_set_current_user( 0 );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families' );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response should return an error with a "rest_cannot_read" code and 401 status.' );
+
+ wp_set_current_user( self::$editor_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families' );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response should return an error with a "rest_cannot_read" code and 403 status.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_item
+ */
+ public function test_get_item() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id1 );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->check_font_family_data( $data, self::$font_family_id1, $response->get_links() );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::prepare_item_for_response
+ */
+ public function test_get_item_embedded_font_faces() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id1 );
+ $request->set_param( '_embed', true );
+ $response = rest_get_server()->dispatch( $request );
+ $data = rest_get_server()->response_to_data( $response, true );
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertArrayHasKey( '_embedded', $data, 'The _embedded property should exist in the response data.' );
+ $this->assertArrayHasKey( 'font_faces', $data['_embedded'], 'The font_faces property should exist in _embedded data.' );
+ $this->assertCount( 2, $data['_embedded']['font_faces'], 'There should be 2 font_faces in the _embedded data.' );
+
+ foreach ( $data['_embedded']['font_faces'] as $font_face ) {
+ $this->assertArrayHasKey( 'id', $font_face, 'The id property should exist in the _embedded font_face data.' );
+
+ $font_face_request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id1 . '/font-faces/' . $font_face['id'] );
+ $font_face_response = rest_get_server()->dispatch( $font_face_request );
+ $font_face_data = rest_get_server()->response_to_data( $font_face_response, true );
+
+ $this->assertSame( $font_face_data, $font_face, 'The embedded font_face data should match when the data from a single request.' );
+ }
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_item
+ */
+ public function test_get_item_removes_extra_settings() {
+ $font_family_id = self::create_font_family_post( array( 'fontFace' => array() ) );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . $font_family_id );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertArrayNotHasKey( 'fontFace', $data['font_family_settings'], 'The fontFace property should not exist in the font_family_settings data.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::prepare_item_for_response
+ */
+ public function test_get_item_malformed_post_content_returns_empty_settings() {
+ $font_family_id = wp_insert_post(
+ array(
+ 'post_type' => 'wp_font_family',
+ 'post_status' => 'publish',
+ 'post_content' => 'invalid',
+ )
+ );
+
+ static::$post_ids_to_cleanup[] = $font_family_id;
+
+ $empty_settings = array(
+ 'name' => '',
+ // Slug will default to the post id.
+ 'slug' => (string) $font_family_id,
+ 'fontFamily' => '',
+ 'preview' => '',
+ );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . $font_family_id );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertSame( $empty_settings, $data['font_family_settings'], 'The empty settings should exist in the font_family_settings data.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_item
+ */
+ public function test_get_item_invalid_font_family_id() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_item
+ */
+ public function test_get_item_no_permission() {
+ wp_set_current_user( 0 );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id1 );
+
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 401, 'The response should return an error with a "rest_cannot_read" code and 401 status.' );
+
+ wp_set_current_user( self::$editor_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_read', $response, 403, 'The response should return an error with a "rest_cannot_read" code and 403 status.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::create_item
+ */
+ public function test_create_item() {
+ $settings = array_merge( self::$default_settings, array( 'slug' => 'open-sans-2' ) );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $this->check_font_family_data( $data, $data['id'], $response->get_links() );
+
+ $reponse_settings = $data['font_family_settings'];
+ $this->assertSame( $settings, $reponse_settings, 'The expected settings should exist in the font_family_settings data.' );
+ $this->assertEmpty( $data['font_faces'], 'The font_faces should be empty or not exist in the response data.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::validate_create_font_face_request
+ */
+ public function test_create_item_default_theme_json_version() {
+ $settings = array_merge( self::$default_settings, array( 'slug' => 'open-sans-2' ) );
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ static::$post_ids_to_cleanup[] = $data['id'];
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $this->assertArrayHasKey( 'theme_json_version', $data, 'The theme_json_version property should exist in the response data.' );
+ $this->assertSame( WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED, $data['theme_json_version'], 'The default theme.json version should match the latest version supported by the controller.' );
+ }
+
+ /**
+ * @dataProvider data_create_item_invalid_theme_json_version
+ *
+ * @covers WP_REST_Font_Families_Controller::create_item
+ *
+ * @param int $theme_json_version Version to test.
+ */
+ public function test_create_item_invalid_theme_json_version( $theme_json_version ) {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param( 'theme_json_version', $theme_json_version );
+ $request->set_param( 'font_family_settings', wp_json_encode( self::$default_settings ) );
+
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_create_item_invalid_theme_json_version() {
+ return array(
+ array( 1 ),
+ array( 3 ),
+ );
+ }
+
+ /**
+ * @dataProvider data_create_item_with_default_preview
+ *
+ * @covers WP_REST_Font_Families_Controller::sanitize_font_family_settings
+ *
+ * @param array $settings Settings to test.
+ */
+ public function test_create_item_with_default_preview( $settings ) {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ static::$post_ids_to_cleanup[] = $data['id'];
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $response_settings = $data['font_family_settings'];
+ $this->assertArrayHasKey( 'preview', $response_settings, 'The preview property should exist in the font_family_settings data.' );
+ $this->assertSame( '', $response_settings['preview'], 'The preview data should be an empty string.' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_create_item_with_default_preview() {
+ $default_settings = array(
+ 'name' => 'Open Sans',
+ 'slug' => 'open-sans-2',
+ 'fontFamily' => '"Open Sans", sans-serif',
+ );
+ return array(
+ 'No preview param' => array(
+ 'settings' => $default_settings,
+ ),
+ 'Empty preview' => array(
+ 'settings' => array_merge( $default_settings, array( 'preview' => '' ) ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_sanitize_font_family_settings
+ *
+ * @covers WP_REST_Font_Families_Controller::sanitize_font_family_settings
+ *
+ * @param string $settings Font family settings to test.
+ * @param string $expected Expected settings result.
+ */
+ public function test_create_item_santize_font_family_settings( $settings, $expected ) {
+ $settings = array_merge( self::$default_settings, $settings );
+ $expected = array_merge( self::$default_settings, $expected );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ static::$post_ids_to_cleanup[] = $data['id'];
+
+ $this->assertSame( 201, $response->get_status(), 'The response status should be 201.' );
+ $this->assertSame( $expected, $data['font_family_settings'], 'The response font_family_settings should match.' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_sanitize_font_family_settings() {
+ return array(
+ 'settings with tags, extra whitespace, new lines' => array(
+ 'settings' => array(
+ 'name' => " Opening Sans\n ",
+ 'slug' => " OPENing SanS \n ",
+ 'fontFamily' => " Opening Sans\n ",
+ 'preview' => " https://example.com/ ",
+ ),
+ 'expected' => array(
+ 'name' => 'Opening Sans',
+ 'slug' => 'opening-sans-alertxss',
+ 'fontFamily' => '"Opening Sans"',
+ 'preview' => "https://example.com//stylescriptalert('XSS');/script%20%20%20%20%20%20",
+ ),
+ ),
+ 'multiword font family name with integer' => array(
+ 'settings' => array(
+ 'slug' => 'libre-barcode-128-text',
+ 'fontFamily' => 'Libre Barcode 128 Text',
+ ),
+ 'expected' => array(
+ 'slug' => 'libre-barcode-128-text',
+ 'fontFamily' => '"Libre Barcode 128 Text"',
+ ),
+ ),
+ 'multiword font family name' => array(
+ 'settings' => array(
+ 'slug' => 'b612-mono',
+ 'fontFamily' => 'B612 Mono',
+ ),
+ 'expected' => array(
+ 'slug' => 'b612-mono',
+ 'fontFamily' => '"B612 Mono"',
+ ),
+ ),
+ 'comma-separated font family names' => array(
+ 'settings' => array(
+ 'slug' => 'open-sans-noto-sans',
+ 'fontFamily' => 'Open Sans, Noto Sans, sans-serif',
+ ),
+ 'expected' => array(
+ 'slug' => 'open-sans-noto-sans',
+ 'fontFamily' => '"Open Sans", "Noto Sans", sans-serif',
+ ),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider data_create_item_invalid_settings
+ *
+ * @covers WP_REST_Font_Families_Controller::validate_create_font_face_settings
+ *
+ * @param array $settings Settings to test.
+ */
+ public function test_create_item_invalid_settings( $settings ) {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_create_item_invalid_settings() {
+ return array(
+ 'Missing name' => array(
+ 'settings' => array_diff_key( self::$default_settings, array( 'name' => '' ) ),
+ ),
+ 'Empty name' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'name' => '' ) ),
+ ),
+ 'Wrong name type' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'name' => 1234 ) ),
+ ),
+ 'Missing slug' => array(
+ 'settings' => array_diff_key( self::$default_settings, array( 'slug' => '' ) ),
+ ),
+ 'Empty slug' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'slug' => '' ) ),
+ ),
+ 'Wrong slug type' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'slug' => 1234 ) ),
+ ),
+ 'Missing fontFamily' => array(
+ 'settings' => array_diff_key( self::$default_settings, array( 'fontFamily' => '' ) ),
+ ),
+ 'Empty fontFamily' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'fontFamily' => '' ) ),
+ ),
+ 'Wrong fontFamily type' => array(
+ 'settings' => array_merge( self::$default_settings, array( 'fontFamily' => 1234 ) ),
+ ),
+ );
+ }
+
+ /**
+ * @covers WP_REST_Font_Family_Controller::validate_font_family_settings
+ */
+ public function test_create_item_invalid_settings_json() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param( 'font_family_settings', 'invalid' );
+
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' );
+ $expected_message = 'font_family_settings parameter must be a valid JSON string.';
+ $message = $response->as_error()->get_all_error_data()[0]['params']['font_family_settings'];
+ $this->assertSame( $expected_message, $message, 'The response error message should match.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Family_Controller::create_item
+ */
+ public function test_create_item_with_duplicate_slug() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param( 'theme_json_version', WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ $request->set_param( 'font_family_settings', wp_json_encode( array_merge( self::$default_settings, array( 'slug' => 'helvetica' ) ) ) );
+
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_duplicate_font_family', $response, 400, 'The response should return an error for "rest_duplicate_font_family" with 400 status.' );
+ $expected_message = 'A font family with slug "helvetica" already exists.';
+ $message = $response->as_error()->get_error_messages()[0];
+ $this->assertSame( $expected_message, $message, 'The response error message should match.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::create_item
+ */
+ public function test_create_item_no_permission() {
+ $settings = array_merge( self::$default_settings, array( 'slug' => 'open-sans-2' ) );
+ wp_set_current_user( 0 );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_create', $response, 401, 'The response should return an error for "rest_cannot_create" with 401 status.' );
+
+ wp_set_current_user( self::$editor_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families' );
+ $request->set_param(
+ 'font_family_settings',
+ wp_json_encode(
+ array(
+ 'name' => 'Open Sans',
+ 'slug' => 'open-sans',
+ 'fontFamily' => '"Open Sans", sans-serif',
+ 'preview' => 'https://s.w.org/images/fonts/16.7/previews/open-sans/open-sans-400-normal.svg',
+ )
+ )
+ );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_create', $response, 403, 'The response should return an error for "rest_cannot_create" with 403 status.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::update_item
+ */
+ public function test_update_item() {
+ wp_set_current_user( self::$admin_id );
+
+ $settings = array(
+ 'name' => 'Open Sans',
+ 'fontFamily' => '"Open Sans, "Noto Sans", sans-serif',
+ 'preview' => 'https://s.w.org/images/fonts/16.9/previews/open-sans/open-sans-400-normal.svg',
+ );
+
+ $font_family_id = self::create_font_family_post( array( 'slug' => 'open-sans-2' ) );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . $font_family_id );
+ $request->set_param(
+ 'font_family_settings',
+ wp_json_encode( $settings )
+ );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->check_font_family_data( $data, $font_family_id, $response->get_links() );
+
+ $expected_settings = array(
+ 'name' => $settings['name'],
+ 'slug' => 'open-sans-2',
+ 'fontFamily' => $settings['fontFamily'],
+ 'preview' => $settings['preview'],
+ );
+ $this->assertSame( $expected_settings, $data['font_family_settings'], 'The response font_family_settings should match expected settings.' );
+ }
+
+ /**
+ * @dataProvider data_update_item_individual_settings
+ *
+ * @covers WP_REST_Font_Families_Controller::update_item
+ *
+ * @param array $settings Settings to test.
+ */
+ public function test_update_item_individual_settings( $settings ) {
+ wp_set_current_user( self::$admin_id );
+
+ $font_family_id = self::create_font_family_post();
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . $font_family_id );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $key = key( $settings );
+ $value = current( $settings );
+ $this->assertArrayHasKey( $key, $data['font_family_settings'], 'The expected key should exist in the font_family_settings data.' );
+ $this->assertSame( $value, $data['font_family_settings'][ $key ], 'The font_family_settings data should match.' );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_update_item_individual_settings() {
+ return array(
+ array( array( 'name' => 'Opened Sans' ) ),
+ array( array( 'fontFamily' => '"Opened Sans", sans-serif' ) ),
+ array( array( 'preview' => 'https://s.w.org/images/fonts/16.7/previews/opened-sans/opened-sans-400-normal.svg' ) ),
+ // Empty preview is allowed.
+ array( array( 'preview' => '' ) ),
+ );
+ }
+
+ /**
+ * @dataProvider data_sanitize_font_family_settings
+ *
+ * @covers WP_REST_Font_Families_Controller::sanitize_font_family_settings
+ *
+ * @param string $settings Font family settings to test.
+ * @param string $expected Expected settings result.
+ */
+ public function test_update_item_santize_font_family_settings( $settings, $expected ) {
+ // Unset/modify slug from the data provider, since we're updating rather than creating.
+ unset( $settings['slug'] );
+ $initial_settings = array( 'slug' => 'open-sans-update' );
+ $expected = array_merge( self::$default_settings, $expected, $initial_settings );
+
+ wp_set_current_user( self::$admin_id );
+ $font_family_id = self::create_font_family_post( $initial_settings );
+ static::$post_ids_to_cleanup[] = $font_family_id;
+
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . $font_family_id );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertSame( $expected, $data['font_family_settings'], 'The response font_family_settings should match.' );
+ }
+
+ /**
+ * @dataProvider data_update_item_invalid_settings
+ *
+ * @covers WP_REST_Font_Families_Controller::update_item
+ *
+ * @param array $settings Settings to test.
+ */
+ public function test_update_item_empty_settings( $settings ) {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id1 );
+ $request->set_param(
+ 'font_family_settings',
+ wp_json_encode( $settings )
+ );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array
+ */
+ public function data_update_item_invalid_settings() {
+ return array(
+ 'Empty name' => array(
+ array( 'name' => '' ),
+ ),
+ 'Wrong name type' => array(
+ array( 'name' => 1234 ),
+ ),
+ 'Empty fontFamily' => array(
+ array( 'fontFamily' => '' ),
+ ),
+ 'Wrong fontFamily type' => array(
+ array( 'fontFamily' => 1234 ),
+ ),
+ );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::update_item
+ */
+ public function test_update_item_update_slug_not_allowed() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id1 );
+ $request->set_param(
+ 'font_family_settings',
+ wp_json_encode( array( 'slug' => 'new-slug' ) )
+ );
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertErrorResponse( 'rest_invalid_param', $response, 400, 'The response should return an error for "rest_invalid_param" with 400 status.' );
+ $expected_message = 'font_family_settings[slug] cannot be updated.';
+ $message = $response->as_error()->get_all_error_data()[0]['params']['font_family_settings'];
+ $this->assertSame( $expected_message, $message, 'The response error message should match.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::update_item
+ */
+ public function test_update_item_invalid_font_family_id() {
+ $settings = array_diff_key( self::$default_settings, array( 'slug' => '' ) );
+
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404, 'The response should return an error for "rest_post_invalid_id" with 404 status.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::update_item
+ */
+ public function test_update_item_no_permission() {
+ $settings = array_diff_key( self::$default_settings, array( 'slug' => '' ) );
+
+ wp_set_current_user( 0 );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id1 );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_edit', $response, 401, 'The response should return an error for "rest_cannot_edit" with 401 status for an invalid user.' );
+
+ wp_set_current_user( self::$editor_id );
+ $request = new WP_REST_Request( 'POST', '/wp/v2/font-families/' . self::$font_family_id1 );
+ $request->set_param( 'font_family_settings', wp_json_encode( $settings ) );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_edit', $response, 403, 'The response should return an error for "rest_cannot_edit" with 403 status for a user without permission.' );
+ }
+
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::delete_item
+ */
+ public function test_delete_item() {
+ wp_set_current_user( self::$admin_id );
+ $font_family_id = self::create_font_family_post();
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . $font_family_id );
+ $request['force'] = true;
+ $response = rest_get_server()->dispatch( $request );
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->assertNull( get_post( $font_family_id ), 'The post should not exist after deleting.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::delete_item
+ */
+ public function test_delete_item_no_trash() {
+ wp_set_current_user( self::$admin_id );
+ $font_family_id = self::create_font_family_post();
+
+ // Attempt trashing.
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . $font_family_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501, 'The response should return an error for "rest_trash_not_supported" with 501 status.' );
+
+ $request->set_param( 'force', 'false' );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_trash_not_supported', $response, 501, 'When "force" is false, the response should return an error for "rest_trash_not_supported" with 501 status.' );
+
+ // Ensure the post still exists.
+ $post = get_post( $font_family_id );
+ $this->assertNotEmpty( $post, 'The post should still exist.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::delete_item
+ */
+ public function test_delete_item_invalid_font_family_id() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::delete_item
+ */
+ public function test_delete_item_no_permissions() {
+ $font_family_id = self::create_font_family_post();
+
+ wp_set_current_user( 0 );
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . $font_family_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_delete', $response, 401, 'The response should return an error for "rest_cannot_delete" with 401 status for an invalid user.' );
+
+ wp_set_current_user( self::$editor_id );
+ $request = new WP_REST_Request( 'DELETE', '/wp/v2/font-families/' . $font_family_id );
+ $response = rest_get_server()->dispatch( $request );
+ $this->assertErrorResponse( 'rest_cannot_delete', $response, 403, 'The response should return an error for "rest_cannot_delete" with 403 status for a user without permission.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::prepare_item_for_response
+ */
+ public function test_prepare_item() {
+ wp_set_current_user( self::$admin_id );
+ $request = new WP_REST_Request( 'GET', '/wp/v2/font-families/' . self::$font_family_id2 );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $this->check_font_family_data( $data, self::$font_family_id2, $response->get_links() );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_item_schema
+ */
+ public function test_get_item_schema() {
+ $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/font-families' );
+ $response = rest_get_server()->dispatch( $request );
+ $data = $response->get_data();
+
+ $this->assertSame( 200, $response->get_status(), 'The response status should be 200.' );
+ $properties = $data['schema']['properties'];
+ $this->assertCount( 4, $properties, 'There should be 4 properties in the schema::properties data.' );
+ $this->assertArrayHasKey( 'id', $properties, 'The id property should exist in the schema::properties data.' );
+ $this->assertArrayHasKey( 'theme_json_version', $properties, 'The theme_json_version property should exist in the schema::properties data.' );
+ $this->assertArrayHasKey( 'font_faces', $properties, 'The font_faces property should exist in the schema::properties data.' );
+ $this->assertArrayHasKey( 'font_family_settings', $properties, 'The font_family_settings property should exist in the schema::properties data.' );
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_item_schema
+ */
+ public function test_get_item_schema_font_family_settings_should_all_have_sanitize_callbacks() {
+ $schema = ( new WP_REST_Font_Families_Controller( 'wp_font_family' ) )->get_item_schema();
+ $font_family_settings_schema = $schema['properties']['font_family_settings'];
+
+ $this->assertArrayHasKey( 'properties', $font_family_settings_schema, 'font_family_settings schema is missing properties.' );
+ $this->assertIsArray( $font_family_settings_schema['properties'], 'font_family_settings properties should be an array.' );
+
+ // arg_options should be removed for each setting property.
+ foreach ( $font_family_settings_schema['properties'] as $property ) {
+ $this->assertArrayHasKey( 'arg_options', $property, 'Setting schema should have arg_options.' );
+ $this->assertArrayHasKey( 'sanitize_callback', $property['arg_options'], 'Setting schema should have a sanitize_callback.' );
+ $this->assertIsCallable( $property['arg_options']['sanitize_callback'], 'That sanitize_callback value should be callable.' );
+ }
+ }
+
+ /**
+ * @covers WP_REST_Font_Families_Controller::get_public_item_schema
+ */
+ public function test_get_public_item_schema_should_not_have_arg_options() {
+ $schema = ( new WP_REST_Font_Families_Controller( 'wp_font_family' ) )->get_public_item_schema();
+ $font_family_settings_schema = $schema['properties']['font_family_settings'];
+
+ $this->assertArrayHasKey( 'properties', $font_family_settings_schema, 'font_family_settings schema is missing properties.' );
+ $this->assertIsArray( $font_family_settings_schema['properties'], 'font_family_settings properties should be an array.' );
+
+ // arg_options should be removed for each setting property.
+ foreach ( $font_family_settings_schema['properties'] as $property ) {
+ $this->assertArrayNotHasKey( 'arg_options', $property, 'arg_options should be removed from the schema for each setting.' );
+ }
+ }
+
+ /**
+ * If WP_Theme_JSON::LATEST_SCHEMA is changed, the controller should be updated to handle any differences
+ * in `fontFamilies` structure to ensure support for the latest theme.json schema, and backwards compatibility
+ * for existing wp_font_family posts.
+ */
+ public function test_controller_supports_latest_theme_json_version() {
+ $this->assertSame( WP_Theme_JSON::LATEST_SCHEMA, WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED );
+ }
+
+ protected function check_font_family_data( $data, $post_id, $links ) {
+ static::$post_ids_to_cleanup[] = $post_id;
+ $post = get_post( $post_id );
+
+ $this->assertArrayHasKey( 'id', $data, 'The id property should exist in response data.' );
+ $this->assertSame( $post->ID, $data['id'], 'The "id" from the response data should match the post ID.' );
+
+ $this->assertArrayHasKey( 'theme_json_version', $data, 'The theme_json_version property should exist in response data.' );
+ $this->assertSame( WP_REST_Font_Families_Controller::LATEST_THEME_JSON_VERSION_SUPPORTED, $data['theme_json_version'], 'The "theme_json_version" from the response data should match the latest version supported by the controller.' );
+
+ $font_face_ids = get_children(
+ array(
+ 'fields' => 'ids',
+ 'post_parent' => $post_id,
+ 'post_type' => 'wp_font_face',
+ 'order' => 'ASC',
+ 'orderby' => 'ID',
+ )
+ );
+ $this->assertArrayHasKey( 'font_faces', $data, 'The font_faces property should exist in the response data.' );
+
+ foreach ( $font_face_ids as $font_face_id ) {
+ $this->assertContains( $font_face_id, $data['font_faces'], 'The ID is in the font_faces data.' );
+ }
+
+ $this->assertArrayHasKey( 'font_family_settings', $data, 'The font_family_settings property should exist in the response data.' );
+ $settings = $data['font_family_settings'];
+ $expected_settings = array(
+ 'name' => $post->post_title,
+ 'slug' => $post->post_name,
+ 'fontFamily' => $settings['fontFamily'],
+ 'preview' => $settings['preview'],
+ );
+ $this->assertSame( $expected_settings, $settings, 'The font_family_settings should match.' );
+
+ $this->assertNotEmpty( $links, 'The links should not be empty in the response data.' );
+ $expected = rest_url( 'wp/v2/font-families/' . $post->ID );
+ $this->assertSame( $expected, $links['self'][0]['href'], 'The links URL from the response data should match the post\'s REST endpoint.' );
+ $expected = rest_url( 'wp/v2/font-families' );
+ $this->assertSame( $expected, $links['collection'][0]['href'], 'The links collection URL from the response data should match the REST endpoint.' );
+
+ if ( ! $font_face_ids ) {
+ return;
+ }
+
+ // Check font_face links, if present.
+ $this->assertArrayHasKey( 'font_faces', $links );
+ foreach ( $links['font_faces'] as $index => $link ) {
+ $expected = rest_url( 'wp/v2/font-families/' . $post->ID . '/font-faces/' . $font_face_ids[ $index ] );
+ $this->assertSame( $expected, $link['href'], 'The links for a font faces URL from the response data should match the REST endpoint.' );
+
+ $embeddable = isset( $link['attributes']['embeddable'] )
+ ? $link['attributes']['embeddable']
+ : $link['embeddable'];
+ $this->assertTrue( $embeddable, 'The embeddable should be true.' );
+ }
+ }
+}
diff --git a/tests/phpunit/tests/formatting/sanitizeTextField.php b/tests/phpunit/tests/formatting/sanitizeTextField.php
index d7a58486d1ba5..82cef34a382d5 100644
--- a/tests/phpunit/tests/formatting/sanitizeTextField.php
+++ b/tests/phpunit/tests/formatting/sanitizeTextField.php
@@ -143,4 +143,26 @@ public function data_sanitize_text_field() {
),
);
}
+
+ /**
+ * @ticket 60357
+ */
+ public function test_sanitize_text_field_filter() {
+ $filter = new MockAction();
+ add_filter( 'sanitize_text_field', array( $filter, 'filter' ) );
+
+ $this->assertSame( 'example', sanitize_text_field( 'example' ) );
+ $this->assertSame( 1, $filter->get_call_count(), 'The sanitize_text_field filter was not called.' );
+ }
+
+ /**
+ * @ticket 60357
+ */
+ public function test_sanitize_textarea_field_filter() {
+ $filter = new MockAction();
+ add_filter( 'sanitize_textarea_field', array( $filter, 'filter' ) );
+
+ $this->assertSame( 'example', sanitize_textarea_field( 'example' ) );
+ $this->assertSame( 1, $filter->get_call_count(), 'The sanitize_textarea_field filter was not called.' );
+ }
}
diff --git a/tests/phpunit/tests/functions.php b/tests/phpunit/tests/functions.php
index 3c2e1101ad69d..abef68f75b085 100644
--- a/tests/phpunit/tests/functions.php
+++ b/tests/phpunit/tests/functions.php
@@ -1370,6 +1370,26 @@ public function data_wp_get_image_mime() {
DIR_TESTDATA . '/uploads/dashicons.woff',
false,
),
+ // Animated AVIF.
+ array(
+ DIR_TESTDATA . '/images/avif-animated.avif',
+ 'image/avif',
+ ),
+ // Lossless AVIF.
+ array(
+ DIR_TESTDATA . '/images/avif-lossless.avif',
+ 'image/avif',
+ ),
+ // Lossy AVIF.
+ array(
+ DIR_TESTDATA . '/images/avif-lossy.avif',
+ 'image/avif',
+ ),
+ // Transparent AVIF.
+ array(
+ DIR_TESTDATA . '/images/avif-transparent.avif',
+ 'image/avif',
+ ),
);
return $data;
@@ -1496,6 +1516,50 @@ public function data_wp_getimagesize() {
DIR_TESTDATA . '/uploads/dashicons.woff',
false,
),
+ // Animated AVIF.
+ array(
+ DIR_TESTDATA . '/images/avif-animated.avif',
+ array(
+ 150,
+ 150,
+ IMAGETYPE_AVIF,
+ 'width="150" height="150"',
+ 'mime' => 'image/avif',
+ ),
+ ),
+ // Lossless AVIF.
+ array(
+ DIR_TESTDATA . '/images/avif-lossless.avif',
+ array(
+ 400,
+ 400,
+ IMAGETYPE_AVIF,
+ 'width="400" height="400"',
+ 'mime' => 'image/avif',
+ ),
+ ),
+ // Lossy AVIF.
+ array(
+ DIR_TESTDATA . '/images/avif-lossy.avif',
+ array(
+ 400,
+ 400,
+ IMAGETYPE_AVIF,
+ 'width="400" height="400"',
+ 'mime' => 'image/avif',
+ ),
+ ),
+ // Transparent AVIF.
+ array(
+ DIR_TESTDATA . '/images/avif-transparent.avif',
+ array(
+ 128,
+ 128,
+ IMAGETYPE_AVIF,
+ 'width="128" height="128"',
+ 'mime' => 'image/avif',
+ ),
+ ),
);
return $data;
diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlProcessor.php
index d9f1357b5c66f..26dc7b0bdb826 100644
--- a/tests/phpunit/tests/html-api/wpHtmlProcessor.php
+++ b/tests/phpunit/tests/html-api/wpHtmlProcessor.php
@@ -52,12 +52,12 @@ public function test_warns_that_the_static_creator_methods_should_be_called_inst
* @covers WP_HTML_Processor::get_tag
*/
public function test_get_tag_is_null_once_document_is_finished() {
- $p = WP_HTML_Processor::create_fragment( 'Test
' );
- $p->next_tag();
- $this->assertSame( 'DIV', $p->get_tag() );
+ $processor = WP_HTML_Processor::create_fragment( 'Test
' );
+ $processor->next_tag();
+ $this->assertSame( 'DIV', $processor->get_tag() );
- $this->assertFalse( $p->next_tag() );
- $this->assertNull( $p->get_tag() );
+ $this->assertFalse( $processor->next_tag() );
+ $this->assertNull( $processor->get_tag() );
}
/**
@@ -77,44 +77,44 @@ public function test_get_tag_is_null_once_document_is_finished() {
* @covers WP_HTML_Processor::seek
*/
public function test_clear_to_navigate_after_seeking() {
- $p = WP_HTML_Processor::create_fragment( '
' );
+ $processor = WP_HTML_Processor::create_fragment( '
' );
- while ( $p->next_tag() ) {
+ while ( $processor->next_tag() ) {
// Create a bookmark before entering a stack of elements and formatting elements.
- if ( null !== $p->get_attribute( 'one' ) ) {
- $this->assertTrue( $p->set_bookmark( 'one' ) );
+ if ( null !== $processor->get_attribute( 'one' ) ) {
+ $this->assertTrue( $processor->set_bookmark( 'one' ) );
continue;
}
// Create a bookmark inside of that stack.
- if ( null !== $p->get_attribute( 'two' ) ) {
- $p->set_bookmark( 'two' );
+ if ( null !== $processor->get_attribute( 'two' ) ) {
+ $processor->set_bookmark( 'two' );
break;
}
}
// Ensure that it's possible to seek back to the outside location.
- $this->assertTrue( $p->seek( 'one' ), 'Could not seek to earlier-seen location.' );
- $this->assertSame( 'DIV', $p->get_tag(), "Should have jumped back to DIV but found {$p->get_tag()} instead." );
+ $this->assertTrue( $processor->seek( 'one' ), 'Could not seek to earlier-seen location.' );
+ $this->assertSame( 'DIV', $processor->get_tag(), "Should have jumped back to DIV but found {$processor->get_tag()} instead." );
/*
* Ensure that the P element from the inner location isn't still on the stack of open elements.
* If it were, then the first STRONG element, inside the outer DIV would match the next call.
*/
- $this->assertTrue( $p->next_tag( array( 'breadcrumbs' => array( 'P', 'STRONG' ) ) ), 'Failed to find given location after seeking.' );
+ $this->assertTrue( $processor->next_tag( array( 'breadcrumbs' => array( 'P', 'STRONG' ) ) ), 'Failed to find given location after seeking.' );
// Only if the stack is properly managed will the processor advance to the inner STRONG element.
- $this->assertTrue( $p->get_attribute( 'two' ), "Found the wrong location given the breadcrumbs, at {$p->get_tag()}." );
+ $this->assertTrue( $processor->get_attribute( 'two' ), "Found the wrong location given the breadcrumbs, at {$processor->get_tag()}." );
// Ensure that in seeking backwards the processor reports the correct full set of breadcrumbs.
- $this->assertTrue( $p->seek( 'one' ), 'Failed to jump back to first bookmark.' );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV' ), $p->get_breadcrumbs(), 'Found wrong set of breadcrumbs navigating to node "one".' );
+ $this->assertTrue( $processor->seek( 'one' ), 'Failed to jump back to first bookmark.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV' ), $processor->get_breadcrumbs(), 'Found wrong set of breadcrumbs navigating to node "one".' );
// Ensure that in seeking forwards the processor reports the correct full set of breadcrumbs.
- $this->assertTrue( $p->seek( 'two' ), 'Failed to jump forward to second bookmark.' );
- $this->assertTrue( $p->get_attribute( 'two' ), "Found the wrong location given the bookmark, at {$p->get_tag()}." );
+ $this->assertTrue( $processor->seek( 'two' ), 'Failed to jump forward to second bookmark.' );
+ $this->assertTrue( $processor->get_attribute( 'two' ), "Found the wrong location given the bookmark, at {$processor->get_tag()}." );
- $this->assertSame( array( 'HTML', 'BODY', 'P', 'STRONG' ), $p->get_breadcrumbs(), 'Found wrong set of bookmarks navigating to node "two".' );
+ $this->assertSame( array( 'HTML', 'BODY', 'P', 'STRONG' ), $processor->get_breadcrumbs(), 'Found wrong set of bookmarks navigating to node "two".' );
}
/**
@@ -126,10 +126,144 @@ public function test_clear_to_navigate_after_seeking() {
* @covers WP_HTML_Processor::reconstruct_active_formatting_elements
*/
public function test_fails_to_reconstruct_formatting_elements() {
- $p = WP_HTML_Processor::create_fragment( 'OneTwoThreeFour' );
+ $processor = WP_HTML_Processor::create_fragment( 'OneTwoThreeFour' );
- $this->assertTrue( $p->next_tag( 'EM' ), 'Could not find first EM.' );
- $this->assertFalse( $p->next_tag( 'EM' ), 'Should have aborted before finding second EM as it required reconstructing the first EM.' );
+ $this->assertTrue( $processor->next_tag( 'EM' ), 'Could not find first EM.' );
+ $this->assertFalse( $processor->next_tag( 'EM' ), 'Should have aborted before finding second EM as it required reconstructing the first EM.' );
+ }
+
+ /**
+ * Ensure non-nesting tags do not nest.
+ *
+ * @ticket 60283
+ *
+ * @covers WP_HTML_Processor::step_in_body
+ * @covers WP_HTML_Processor::is_void
+ *
+ * @dataProvider data_void_tags
+ *
+ * @param string $tag_name Name of void tag under test.
+ */
+ public function test_cannot_nest_void_tags( $tag_name ) {
+ $processor = WP_HTML_Processor::create_fragment( "<{$tag_name}>" );
+
+ /*
+ * This HTML represents the same as the following HTML,
+ * assuming that it were provided `
` as the tag:
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+ $found_tag = $processor->next_tag();
+
+ if ( WP_HTML_Processor::ERROR_UNSUPPORTED === $processor->get_last_error() ) {
+ $this->markTestSkipped( "Tag {$tag_name} is not supported." );
+ }
+
+ $this->assertTrue(
+ $found_tag,
+ "Could not find first {$tag_name}."
+ );
+
+ $this->assertSame(
+ array( 'HTML', 'BODY', $tag_name ),
+ $processor->get_breadcrumbs(),
+ 'Found incorrect nesting of first element.'
+ );
+
+ $this->assertTrue(
+ $processor->next_tag(),
+ 'Should have found the DIV as the second tag.'
+ );
+
+ $this->assertSame(
+ array( 'HTML', 'BODY', 'DIV' ),
+ $processor->get_breadcrumbs(),
+ "DIV should have been a sibling of the {$tag_name}."
+ );
+ }
+
+ /**
+ * Ensure non-nesting tags do not nest when processing tokens.
+ *
+ * @ticket 60382
+ *
+ * @dataProvider data_void_tags
+ *
+ * @param string $tag_name Name of void tag under test.
+ */
+ public function test_cannot_nest_void_tags_next_token( $tag_name ) {
+ $processor = WP_HTML_Processor::create_fragment( "<{$tag_name}>
" );
+
+ /*
+ * This HTML represents the same as the following HTML,
+ * assuming that it were provided `
` as the tag:
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+
+ $found_tag = $processor->next_token();
+
+ if ( WP_HTML_Processor::ERROR_UNSUPPORTED === $processor->get_last_error() ) {
+ $this->markTestSkipped( "Tag {$tag_name} is not supported." );
+ }
+
+ $this->assertTrue(
+ $found_tag,
+ "Could not find first {$tag_name}."
+ );
+
+ $this->assertSame(
+ array( 'HTML', 'BODY', $tag_name ),
+ $processor->get_breadcrumbs(),
+ 'Found incorrect nesting of first element.'
+ );
+
+ $this->assertTrue(
+ $processor->next_token(),
+ 'Should have found the DIV as the second tag.'
+ );
+
+ $this->assertSame(
+ array( 'HTML', 'BODY', 'DIV' ),
+ $processor->get_breadcrumbs(),
+ "DIV should have been a sibling of the {$tag_name}."
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array[]
+ */
+ public static function data_void_tags() {
+ return array(
+ 'AREA' => array( 'AREA' ),
+ 'BASE' => array( 'BASE' ),
+ 'BR' => array( 'BR' ),
+ 'COL' => array( 'COL' ),
+ 'EMBED' => array( 'EMBED' ),
+ 'HR' => array( 'HR' ),
+ 'IMG' => array( 'IMG' ),
+ 'INPUT' => array( 'INPUT' ),
+ 'KEYGEN' => array( 'KEYGEN' ),
+ 'LINK' => array( 'LINK' ),
+ 'META' => array( 'META' ),
+ 'PARAM' => array( 'PARAM' ),
+ 'SOURCE' => array( 'SOURCE' ),
+ 'TRACK' => array( 'TRACK' ),
+ 'WBR' => array( 'WBR' ),
+ );
}
/**
@@ -156,30 +290,23 @@ public function test_step_in_body_fails_on_unsupported_tags( $tag_name ) {
*
* @return array[]
*/
- public function data_unsupported_special_in_body_tags() {
+ public static function data_unsupported_special_in_body_tags() {
return array(
'APPLET' => array( 'APPLET' ),
- 'AREA' => array( 'AREA' ),
'BASE' => array( 'BASE' ),
'BASEFONT' => array( 'BASEFONT' ),
'BGSOUND' => array( 'BGSOUND' ),
'BODY' => array( 'BODY' ),
- 'BR' => array( 'BR' ),
'CAPTION' => array( 'CAPTION' ),
'COL' => array( 'COL' ),
'COLGROUP' => array( 'COLGROUP' ),
- 'EMBED' => array( 'EMBED' ),
'FORM' => array( 'FORM' ),
'FRAME' => array( 'FRAME' ),
'FRAMESET' => array( 'FRAMESET' ),
'HEAD' => array( 'HEAD' ),
- 'HR' => array( 'HR' ),
'HTML' => array( 'HTML' ),
'IFRAME' => array( 'IFRAME' ),
- 'INPUT' => array( 'INPUT' ),
- 'KEYGEN' => array( 'KEYGEN' ),
'LINK' => array( 'LINK' ),
- 'LISTING' => array( 'LISTING' ),
'MARQUEE' => array( 'MARQUEE' ),
'MATH' => array( 'MATH' ),
'META' => array( 'META' ),
@@ -190,9 +317,7 @@ public function data_unsupported_special_in_body_tags() {
'OBJECT' => array( 'OBJECT' ),
'OPTGROUP' => array( 'OPTGROUP' ),
'OPTION' => array( 'OPTION' ),
- 'PARAM' => array( 'PARAM' ),
'PLAINTEXT' => array( 'PLAINTEXT' ),
- 'PRE' => array( 'PRE' ),
'RB' => array( 'RB' ),
'RP' => array( 'RP' ),
'RT' => array( 'RT' ),
@@ -200,7 +325,6 @@ public function data_unsupported_special_in_body_tags() {
'SARCASM' => array( 'SARCASM' ),
'SCRIPT' => array( 'SCRIPT' ),
'SELECT' => array( 'SELECT' ),
- 'SOURCE' => array( 'SOURCE' ),
'STYLE' => array( 'STYLE' ),
'SVG' => array( 'SVG' ),
'TABLE' => array( 'TABLE' ),
@@ -213,8 +337,6 @@ public function data_unsupported_special_in_body_tags() {
'THEAD' => array( 'THEAD' ),
'TITLE' => array( 'TITLE' ),
'TR' => array( 'TR' ),
- 'TRACK' => array( 'TRACK' ),
- 'WBR' => array( 'WBR' ),
'XMP' => array( 'XMP' ),
);
}
diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php
index 15d38d6f70c6c..1488be91654a7 100644
--- a/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php
+++ b/tests/phpunit/tests/html-api/wpHtmlProcessorBreadcrumbs.php
@@ -23,10 +23,10 @@ class Tests_HtmlApi_WpHtmlProcessorBreadcrumbs extends WP_UnitTestCase {
* @param string $tag_name Name of first tag in HTML (because HTML treats IMAGE as IMG this may not match the HTML).
*/
public function test_navigates_into_normative_html_for_supported_elements( $html, $tag_name ) {
- $p = WP_HTML_Processor::create_fragment( $html );
+ $processor = WP_HTML_Processor::create_fragment( $html );
- $this->assertTrue( $p->step(), "Failed to step into supported {$tag_name} element." );
- $this->assertSame( $tag_name, $p->get_tag(), "Misread {$tag_name} as a {$p->get_tag()} element." );
+ $this->assertTrue( $processor->step(), "Failed to step into supported {$tag_name} element." );
+ $this->assertSame( $tag_name, $processor->get_tag(), "Misread {$tag_name} as a {$processor->get_tag()} element." );
}
/**
@@ -34,12 +34,13 @@ public function test_navigates_into_normative_html_for_supported_elements( $html
*
* @return array[]
*/
- public function data_single_tag_of_supported_elements() {
+ public static function data_single_tag_of_supported_elements() {
$supported_elements = array(
'A',
'ABBR',
'ACRONYM', // Neutralized.
'ADDRESS',
+ 'AREA',
'ARTICLE',
'ASIDE',
'AUDIO',
@@ -48,6 +49,7 @@ public function data_single_tag_of_supported_elements() {
'BDO',
'BIG',
'BLINK', // Deprecated.
+ 'BR',
'BUTTON',
'CANVAS',
'CENTER', // Neutralized.
@@ -65,6 +67,7 @@ public function data_single_tag_of_supported_elements() {
'DL',
'DT',
'EM',
+ 'EMBED',
'FIELDSET',
'FIGCAPTION',
'FIGURE',
@@ -78,22 +81,25 @@ public function data_single_tag_of_supported_elements() {
'H6',
'HEADER',
'HGROUP',
+ 'HR',
'I',
'IMG',
'INS',
'LI',
- 'ISINDEX', // Deprecated
+ 'ISINDEX', // Deprecated.
'KBD',
+ 'KEYGEN', // Deprecated.
'LABEL',
'LEGEND',
+ 'LISTING', // Deprecated.
'MAIN',
'MAP',
'MARK',
'MENU',
'METER',
- 'MULTICOL', // Deprecated
+ 'MULTICOL', // Deprecated.
'NAV',
- 'NEXTID', // Deprecated
+ 'NEXTID', // Deprecated.
'OL',
'OUTPUT',
'P',
@@ -106,7 +112,7 @@ public function data_single_tag_of_supported_elements() {
'SECTION',
'SLOT',
'SMALL',
- 'SPACER', // Deprecated
+ 'SPACER', // Deprecated.
'SPAN',
'STRIKE',
'STRONG',
@@ -149,9 +155,9 @@ public function data_single_tag_of_supported_elements() {
* @param string $html HTML string containing unsupported elements.
*/
public function test_fails_when_encountering_unsupported_tag( $html ) {
- $p = WP_HTML_Processor::create_fragment( $html );
+ $processor = WP_HTML_Processor::create_fragment( $html );
- $this->assertFalse( $p->step(), "Should not have stepped into unsupported {$p->get_tag()} element." );
+ $this->assertFalse( $processor->step(), "Should not have stepped into unsupported {$processor->get_tag()} element." );
}
/**
@@ -159,29 +165,22 @@ public function test_fails_when_encountering_unsupported_tag( $html ) {
*
* @return array[]
*/
- public function data_unsupported_elements() {
+ public static function data_unsupported_elements() {
$unsupported_elements = array(
'APPLET', // Deprecated.
- 'AREA',
'BASE',
'BGSOUND', // Deprecated; self-closing if self-closing flag provided, otherwise normal.
'BODY',
- 'BR',
'CAPTION',
'COL',
'COLGROUP',
- 'EMBED',
'FORM',
'FRAME',
'FRAMESET',
'HEAD',
- 'HR',
'HTML',
'IFRAME',
- 'INPUT',
- 'KEYGEN', // Deprecated; void.
'LINK',
- 'LISTING', // Deprecated, use PRE instead.
'MARQUEE', // Deprecated.
'MATH',
'META',
@@ -193,14 +192,12 @@ public function data_unsupported_elements() {
'OPTGROUP',
'OPTION',
'PLAINTEXT', // Neutralized.
- 'PRE',
'RB', // Neutralized.
'RP',
'RT',
'RTC', // Neutralized.
'SCRIPT',
'SELECT',
- 'SOURCE',
'STYLE',
'SVG',
'TABLE',
@@ -213,8 +210,6 @@ public function data_unsupported_elements() {
'THEAD',
'TITLE',
'TR',
- 'TRACK',
- 'WBR',
'XMP', // Deprecated, use PRE instead.
);
@@ -234,14 +229,14 @@ public function data_unsupported_elements() {
* @param string $html HTML containing unsupported markup.
*/
public function test_fails_when_encountering_unsupported_markup( $html, $description ) {
- $p = WP_HTML_Processor::create_fragment( $html );
+ $processor = WP_HTML_Processor::create_fragment( $html );
- while ( $p->step() && null === $p->get_attribute( 'supported' ) ) {
+ while ( $processor->step() && null === $processor->get_attribute( 'supported' ) ) {
continue;
}
- $this->assertTrue( $p->get_attribute( 'supported' ), 'Did not find required supported element.' );
- $this->assertFalse( $p->step(), "Didn't properly reject unsupported markup: {$description}" );
+ $this->assertTrue( $processor->get_attribute( 'supported' ), 'Did not find required supported element.' );
+ $this->assertFalse( $processor->step(), "Didn't properly reject unsupported markup: {$description}" );
}
/**
@@ -249,7 +244,7 @@ public function test_fails_when_encountering_unsupported_markup( $html, $descrip
*
* @return array[]
*/
- public function data_unsupported_markup() {
+ public static function data_unsupported_markup() {
return array(
'A with formatting following unclosed A' => array(
'
Click Here ',
@@ -275,17 +270,17 @@ public function data_unsupported_markup() {
* @param int $n How many breadcrumb matches to scan through in order to find "target" element.
*/
public function test_finds_correct_tag_given_breadcrumbs( $html, $breadcrumbs, $n ) {
- $p = WP_HTML_Processor::create_fragment( $html );
+ $processor = WP_HTML_Processor::create_fragment( $html );
- $p->next_tag(
+ $processor->next_tag(
array(
'breadcrumbs' => $breadcrumbs,
'match_offset' => $n,
)
);
- $this->assertNotNull( $p->get_tag(), 'Failed to find target node.' );
- $this->assertTrue( $p->get_attribute( 'target' ), "Found {$p->get_tag()} element didn't contain the necessary 'target' attribute." );
+ $this->assertNotNull( $processor->get_tag(), 'Failed to find target node.' );
+ $this->assertTrue( $processor->get_attribute( 'target' ), "Found {$processor->get_tag()} element didn't contain the necessary 'target' attribute." );
}
/**
@@ -300,14 +295,14 @@ public function test_finds_correct_tag_given_breadcrumbs( $html, $breadcrumbs, $
* @param int $ignored_n Not used in this test but provided in the dataset for other tests.
*/
public function test_reports_correct_breadcrumbs_for_html( $html, $breadcrumbs, $ignored_n ) {
- $p = WP_HTML_Processor::create_fragment( $html );
+ $processor = WP_HTML_Processor::create_fragment( $html );
- while ( $p->next_tag() && null === $p->get_attribute( 'target' ) ) {
+ while ( $processor->next_tag() && null === $processor->get_attribute( 'target' ) ) {
continue;
}
- $this->assertNotNull( $p->get_tag(), 'Failed to find the target node.' );
- $this->assertSame( $breadcrumbs, $p->get_breadcrumbs(), 'Found the wrong path from the root of the HTML document to the target node.' );
+ $this->assertNotNull( $processor->get_tag(), 'Failed to find the target node.' );
+ $this->assertSame( $breadcrumbs, $processor->get_breadcrumbs(), 'Found the wrong path from the root of the HTML document to the target node.' );
}
/**
@@ -315,7 +310,7 @@ public function test_reports_correct_breadcrumbs_for_html( $html, $breadcrumbs,
*
* @return array[]
*/
- public function data_html_target_with_breadcrumbs() {
+ public static function data_html_target_with_breadcrumbs() {
return array(
'Simple IMG tag' => array( '
', array( 'HTML', 'BODY', 'IMG' ), 1 ),
'Two sibling IMG tags' => array( '
', array( 'HTML', 'BODY', 'IMG' ), 2 ),
@@ -398,7 +393,7 @@ public function test_reports_if_tag_matches_breadcrumbs_of_various_specificity(
*
* @return array[].
*/
- public function data_html_with_breadcrumbs_of_various_specificity() {
+ public static function data_html_with_breadcrumbs_of_various_specificity() {
return array(
// Test with void elements.
'Inner IMG' => array( '
', array( 'span', 'figure', 'img' ), true ),
@@ -438,38 +433,38 @@ public function data_html_with_breadcrumbs_of_various_specificity() {
* @covers WP_HTML_Tag_Processor::get_updated_html
*/
public function test_remains_stable_when_editing_attributes() {
- $p = WP_HTML_Processor::create_fragment( '
FirstSecond' );
- $p->next_tag( array( 'breadcrumbs' => array( 'BUTTON', 'B' ) ) );
+ $processor = WP_HTML_Processor::create_fragment( 'FirstSecond' );
+ $processor->next_tag( array( 'breadcrumbs' => array( 'BUTTON', 'B' ) ) );
$this->assertSame(
array( 'HTML', 'BODY', 'DIV', 'BUTTON', 'B' ),
- $p->get_breadcrumbs(),
+ $processor->get_breadcrumbs(),
'Found the wrong nested structure at the matched tag.'
);
- $p->set_attribute( 'a-name', 'a-value' );
+ $processor->set_attribute( 'a-name', 'a-value' );
$this->assertTrue(
- $p->get_attribute( 'here' ),
+ $processor->get_attribute( 'here' ),
'Should have found the B tag but could not find expected "here" attribute.'
);
$this->assertSame(
array( 'HTML', 'BODY', 'DIV', 'BUTTON', 'B' ),
- $p->get_breadcrumbs(),
+ $processor->get_breadcrumbs(),
'Found the wrong nested structure at the matched tag.'
);
- $p->get_updated_html();
+ $processor->get_updated_html();
$this->assertTrue(
- $p->get_attribute( 'here' ),
+ $processor->get_attribute( 'here' ),
'Should have stayed at the B tag but could not find expected "here" attribute.'
);
$this->assertSame(
array( 'HTML', 'BODY', 'DIV', 'BUTTON', 'B' ),
- $p->get_breadcrumbs(),
+ $processor->get_breadcrumbs(),
'Found the wrong nested structure at the matched tag after updating attributes.'
);
}
@@ -484,12 +479,12 @@ public function test_remains_stable_when_editing_attributes() {
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_can_modify_attributes_after_finding_tag() {
- $p = WP_HTML_Processor::create_fragment( 'test ' );
+ $processor = WP_HTML_Processor::create_fragment( '
test ' );
- $this->assertTrue( $p->next_tag( array( 'breadcrumbs' => array( 'figcaption' ) ) ), 'Unable to find given tag.' );
+ $this->assertTrue( $processor->next_tag( array( 'breadcrumbs' => array( 'figcaption' ) ) ), 'Unable to find given tag.' );
- $p->set_attribute( 'found-it', true );
- $this->assertSame( '
test ', $p->get_updated_html() );
+ $processor->set_attribute( 'found-it', true );
+ $this->assertSame( '
test ', $processor->get_updated_html() );
}
/**
@@ -502,11 +497,11 @@ public function test_can_modify_attributes_after_finding_tag() {
* @covers WP_HTML_Processor::next_tag
*/
public function test_can_query_an_element_by_tag_name() {
- $p = WP_HTML_Processor::create_fragment( '
' );
- $p->next_tag( 'IMG' );
- $p->set_attribute( 'loading', 'lazy' );
+ $processor = WP_HTML_Processor::create_fragment( '
' );
+ $processor->next_tag( 'IMG' );
+ $processor->set_attribute( 'loading', 'lazy' );
- $this->assertSame( '
', $p->get_updated_html() );
+ $this->assertSame( '
', $processor->get_updated_html() );
}
/**
@@ -519,31 +514,35 @@ public function test_can_query_an_element_by_tag_name() {
* @covers WP_HTML_Processor::seek
*/
public function test_can_seek_back_and_forth() {
- $p = WP_HTML_Processor::create_fragment( '
' );
+ $processor = WP_HTML_Processor::create_fragment(
+ <<<'HTML'
+
text
more stuff
three comes soon
' );
+HTML
+ );
// Find first tag of interest.
- while ( $p->next_tag() && null === $p->get_attribute( 'one' ) ) {
+ while ( $processor->next_tag() && null === $processor->get_attribute( 'one' ) ) {
continue;
}
- $p->set_bookmark( 'first' );
+ $processor->set_bookmark( 'first' );
// Find second tag of interest.
- while ( $p->next_tag() && null === $p->get_attribute( 'two' ) ) {
+ while ( $processor->next_tag() && null === $processor->get_attribute( 'two' ) ) {
continue;
}
- $p->set_bookmark( 'second' );
+ $processor->set_bookmark( 'second' );
// Find third tag of interest.
- while ( $p->next_tag() && null === $p->get_attribute( 'three' ) ) {
+ while ( $processor->next_tag() && null === $processor->get_attribute( 'three' ) ) {
continue;
}
- $p->set_bookmark( 'third' );
+ $processor->set_bookmark( 'third' );
// Seek backwards.
- $p->seek( 'first' );
+ $processor->seek( 'first' );
// Seek forwards. If the current token isn't also updated this could appear like a backwards seek.
- $p->seek( 'second' );
- $this->assertTrue( $p->get_attribute( 'two' ) );
+ $processor->seek( 'second' );
+ $this->assertTrue( $processor->get_attribute( 'two' ) );
}
}
diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessorSemanticRules.php b/tests/phpunit/tests/html-api/wpHtmlProcessorSemanticRules.php
index c1adf9a71a3f8..7362a588cf3f4 100644
--- a/tests/phpunit/tests/html-api/wpHtmlProcessorSemanticRules.php
+++ b/tests/phpunit/tests/html-api/wpHtmlProcessorSemanticRules.php
@@ -79,7 +79,7 @@ public function test_in_body_article_group_can_nest_inside_itself( $tag_name ) {
*
* @return array[].
*/
- public function data_article_container_group() {
+ public static function data_article_container_group() {
$group = array();
foreach (
@@ -122,19 +122,19 @@ public function data_article_container_group() {
* @ticket 58961
*/
public function test_in_body_skips_unexpected_button_closer() {
- $p = WP_HTML_Processor::create_fragment( '
Test
' );
+ $processor = WP_HTML_Processor::create_fragment( '
Test
' );
- $p->step();
- $this->assertSame( 'DIV', $p->get_tag(), 'Did not stop at initial DIV tag.' );
- $this->assertFalse( $p->is_tag_closer(), 'Did not find that initial DIV tag is an opener.' );
+ $processor->step();
+ $this->assertSame( 'DIV', $processor->get_tag(), 'Did not stop at initial DIV tag.' );
+ $this->assertFalse( $processor->is_tag_closer(), 'Did not find that initial DIV tag is an opener.' );
/*
* When encountering the BUTTON closing tag, there is no BUTTON in the stack of open elements.
* It should be ignored as there's no BUTTON to close.
*/
- $this->assertTrue( $p->step(), 'Found no further tags when it should have found the closing DIV' );
- $this->assertSame( 'DIV', $p->get_tag(), "Did not skip unexpected BUTTON; stopped at {$p->get_tag()}." );
- $this->assertTrue( $p->is_tag_closer(), 'Did not find that the terminal DIV tag is a closer.' );
+ $this->assertTrue( $processor->step(), 'Found no further tags when it should have found the closing DIV' );
+ $this->assertSame( 'DIV', $processor->get_tag(), "Did not skip unexpected BUTTON; stopped at {$processor->get_tag()}." );
+ $this->assertTrue( $processor->is_tag_closer(), 'Did not find that the terminal DIV tag is a closer.' );
}
/**
@@ -143,20 +143,20 @@ public function test_in_body_skips_unexpected_button_closer() {
* @ticket 58961
*/
public function test_in_body_button_with_no_button_in_scope() {
- $p = WP_HTML_Processor::create_fragment( '
not here ' );
+ $processor = WP_HTML_Processor::create_fragment( '
not here ' );
- $this->assertTrue( $p->next_tag( 'BUTTON' ), 'Could not find expected first button.' );
- $this->assertTrue( $p->get_attribute( 'one' ), 'Failed to match expected attribute on first button.' );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'P', 'BUTTON' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting for first button.' );
+ $this->assertTrue( $processor->next_tag( 'BUTTON' ), 'Could not find expected first button.' );
+ $this->assertTrue( $processor->get_attribute( 'one' ), 'Failed to match expected attribute on first button.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'P', 'BUTTON' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting for first button.' );
/*
* There's nothing special about this HTML construction, but it's important to verify that
* the HTML Processor can find a BUTTON under normal and normative scenarios, not just the
* malformed and unexpected ones.
*/
- $this->assertTrue( $p->next_tag( 'BUTTON' ), 'Could not find expected second button.' );
- $this->assertTrue( $p->get_attribute( 'two' ), 'Failed to match expected attribute on second button.' );
- $this->assertSame( array( 'HTML', 'BODY', 'BUTTON' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting for second button.' );
+ $this->assertTrue( $processor->next_tag( 'BUTTON' ), 'Could not find expected second button.' );
+ $this->assertTrue( $processor->get_attribute( 'two' ), 'Failed to match expected attribute on second button.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'BUTTON' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting for second button.' );
}
/**
@@ -168,27 +168,27 @@ public function test_in_body_button_with_no_button_in_scope() {
* @since 6.4.0
*/
public function test_in_body_button_with_button_in_scope_as_parent() {
- $p = WP_HTML_Processor::create_fragment( '
Click the button almosthere !
not here ' );
+ $processor = WP_HTML_Processor::create_fragment( '
Click the button almosthere !
not here ' );
- $this->assertTrue( $p->next_tag( 'BUTTON' ), 'Could not find expected first button.' );
- $this->assertTrue( $p->get_attribute( 'one' ), 'Failed to match expected attribute on first button.' );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'P', 'BUTTON' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting for first button.' );
+ $this->assertTrue( $processor->next_tag( 'BUTTON' ), 'Could not find expected first button.' );
+ $this->assertTrue( $processor->get_attribute( 'one' ), 'Failed to match expected attribute on first button.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'P', 'BUTTON' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting for first button.' );
/*
* A naive parser might skip the second BUTTON because it's looking for the close of the first one,
* or it may place it as a child of the first one, but it implicitly closes the open BUTTON.
*/
- $this->assertTrue( $p->next_tag( 'BUTTON' ), 'Could not find expected second button.' );
- $this->assertTrue( $p->get_attribute( 'two' ), 'Failed to match expected attribute on second button.' );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'P', 'BUTTON' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting for second button.' );
+ $this->assertTrue( $processor->next_tag( 'BUTTON' ), 'Could not find expected second button.' );
+ $this->assertTrue( $processor->get_attribute( 'two' ), 'Failed to match expected attribute on second button.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'P', 'BUTTON' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting for second button.' );
/*
* This is another form of the test for the second button, but from a different side. The test is
* looking for proper handling of the open and close sequence for the BUTTON tags.
*/
- $this->assertTrue( $p->next_tag( 'BUTTON' ), 'Could not find expected third button.' );
- $this->assertTrue( $p->get_attribute( 'three' ), 'Failed to match expected attribute on third button.' );
- $this->assertSame( array( 'HTML', 'BODY', 'BUTTON' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting for third button.' );
+ $this->assertTrue( $processor->next_tag( 'BUTTON' ), 'Could not find expected third button.' );
+ $this->assertTrue( $processor->get_attribute( 'three' ), 'Failed to match expected attribute on third button.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'BUTTON' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting for third button.' );
}
/**
@@ -201,12 +201,12 @@ public function test_in_body_button_with_button_in_scope_as_parent() {
* @since 6.4.0
*/
public function test_in_body_button_with_button_in_scope_as_ancestor() {
- $p = WP_HTML_Processor::create_fragment( '
not here ' );
+ $processor = WP_HTML_Processor::create_fragment( '
not here ' );
// This button finds itself normally nesting inside the DIV.
- $this->assertTrue( $p->next_tag( 'BUTTON' ), 'Could not find expected first button.' );
- $this->assertTrue( $p->get_attribute( 'one' ), 'Failed to match expected attribute on first button.' );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'BUTTON' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting for first button.' );
+ $this->assertTrue( $processor->next_tag( 'BUTTON' ), 'Could not find expected first button.' );
+ $this->assertTrue( $processor->get_attribute( 'one' ), 'Failed to match expected attribute on first button.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'BUTTON' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting for first button.' );
/*
* Because the second button appears while a BUTTON is in scope, it generates implied end tags and closes
@@ -214,14 +214,30 @@ public function test_in_body_button_with_button_in_scope_as_ancestor() {
* of an unexpected closing SPAN tag because the SPAN was closed by the second BUTTON. This element finds
* itself a child of the most-recent open element above the most-recent BUTTON, or the DIV.
*/
- $this->assertTrue( $p->next_tag( 'BUTTON' ), 'Could not find expected second button.' );
- $this->assertTrue( $p->get_attribute( 'two' ), 'Failed to match expected attribute on second button.' );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'BUTTON' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting for second button.' );
+ $this->assertTrue( $processor->next_tag( 'BUTTON' ), 'Could not find expected second button.' );
+ $this->assertTrue( $processor->get_attribute( 'two' ), 'Failed to match expected attribute on second button.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'BUTTON' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting for second button.' );
// The third button is back to normal, because everything has been implicitly or explicitly closed by now.
- $this->assertTrue( $p->next_tag( 'BUTTON' ), 'Could not find expected third button.' );
- $this->assertTrue( $p->get_attribute( 'three' ), 'Failed to match expected attribute on third button.' );
- $this->assertSame( array( 'HTML', 'BODY', 'BUTTON' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting for third button.' );
+ $this->assertTrue( $processor->next_tag( 'BUTTON' ), 'Could not find expected third button.' );
+ $this->assertTrue( $processor->get_attribute( 'three' ), 'Failed to match expected attribute on third button.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'BUTTON' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting for third button.' );
+ }
+
+ /**
+ * Verifies that HR closes an open p tag
+ *
+ * @ticket 60283
+ */
+ public function test_in_body_hr_element_closes_open_p_tag() {
+ $processor = WP_HTML_Processor::create_fragment( '
' );
+
+ $processor->next_tag( 'HR' );
+ $this->assertSame(
+ array( 'HTML', 'BODY', 'HR' ),
+ $processor->get_breadcrumbs(),
+ 'Expected HR to be a direct child of the BODY, having closed the open P element.'
+ );
}
/**
@@ -258,7 +274,7 @@ public function test_in_body_heading_element_closes_open_p_tag( $tag_name ) {
*
* @return array[].
*/
- public function data_heading_elements() {
+ public static function data_heading_elements() {
return array(
'H1' => array( 'H1' ),
'H2' => array( 'H2' ),
@@ -312,7 +328,7 @@ public function test_in_body_heading_element_closes_other_heading_elements( $fir
*
* @return array[]
*/
- public function data_heading_combinations() {
+ public static function data_heading_combinations() {
$headings = array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' );
$combinations = array();
@@ -339,15 +355,15 @@ public function data_heading_combinations() {
* @since 6.4.0
*/
public function test_in_body_any_other_end_tag_with_unclosed_special_element() {
- $p = WP_HTML_Processor::create_fragment( '
' );
+ $processor = WP_HTML_Processor::create_fragment( '
' );
- $p->next_tag( 'P' );
- $this->assertSame( 'P', $p->get_tag(), "Expected to start test on P element but found {$p->get_tag()} instead." );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'SPAN', 'P' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting.' );
+ $processor->next_tag( 'P' );
+ $this->assertSame( 'P', $processor->get_tag(), "Expected to start test on P element but found {$processor->get_tag()} instead." );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'SPAN', 'P' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting.' );
- $this->assertTrue( $p->next_tag(), 'Failed to advance past P tag to expected DIV opener.' );
- $this->assertSame( 'DIV', $p->get_tag(), "Expected to find DIV element, but found {$p->get_tag()} instead." );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'SPAN', 'DIV' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting: SPAN should still be open and DIV should be its child.' );
+ $this->assertTrue( $processor->next_tag(), 'Failed to advance past P tag to expected DIV opener.' );
+ $this->assertSame( 'DIV', $processor->get_tag(), "Expected to find DIV element, but found {$processor->get_tag()} instead." );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'SPAN', 'DIV' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting: SPAN should still be open and DIV should be its child.' );
}
/**
@@ -362,18 +378,43 @@ public function test_in_body_any_other_end_tag_with_unclosed_special_element() {
* @since 6.4.0
*/
public function test_in_body_any_other_end_tag_with_unclosed_non_special_element() {
- $p = WP_HTML_Processor::create_fragment( '
' );
+ $processor = WP_HTML_Processor::create_fragment( '
' );
+
+ $processor->next_tag( 'CODE' );
+ $this->assertSame( 'CODE', $processor->get_tag(), "Expected to start test on CODE element but found {$processor->get_tag()} instead." );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'SPAN', 'CODE' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting.' );
- $p->next_tag( 'CODE' );
- $this->assertSame( 'CODE', $p->get_tag(), "Expected to start test on CODE element but found {$p->get_tag()} instead." );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'SPAN', 'CODE' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting.' );
+ $this->assertTrue( $processor->step(), 'Failed to advance past CODE tag to expected SPAN closer.' );
+ $this->assertTrue( $processor->is_tag_closer(), 'Expected to find closing SPAN, but found opener instead.' );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV' ), $processor->get_breadcrumbs(), 'Failed to advance past CODE tag to expected DIV opener.' );
- $this->assertTrue( $p->step(), 'Failed to advance past CODE tag to expected SPAN closer.' );
- $this->assertTrue( $p->is_tag_closer(), 'Expected to find closing SPAN, but found opener instead.' );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV' ), $p->get_breadcrumbs(), 'Failed to advance past CODE tag to expected DIV opener.' );
+ $this->assertTrue( $processor->next_tag(), 'Failed to advance past SPAN closer to expected DIV opener.' );
+ $this->assertSame( 'DIV', $processor->get_tag(), "Expected to find DIV element, but found {$processor->get_tag()} instead." );
+ $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'DIV' ), $processor->get_breadcrumbs(), 'Failed to produce expected DOM nesting: SPAN should be closed and DIV should be its sibling.' );
+ }
+
+ /**
+ * Ensures that support isn't accidentally partially added for the closing BR tag ``.
+ *
+ * This tag closer has special rules and support shouldn't be added without implementing full support.
+ *
+ * > An end tag whose tag name is "br"
+ * > Parse error. Drop the attributes from the token, and act as described in the next entry;
+ * > i.e. act as if this was a "br" start tag token with no attributes, rather than the end
+ * > tag token that it actually is.
+ *
+ * When this handling is implemented, this test should be removed. It's not incorporated
+ * into the existing unsupported tag behavior test because the opening tag is supported;
+ * only the closing tag isn't.
+ *
+ * @covers WP_HTML_Processor::step_in_body
+ *
+ * @ticket 60283
+ */
+ public function test_br_end_tag_unsupported() {
+ $processor = WP_HTML_Processor::create_fragment( '' );
- $this->assertTrue( $p->next_tag(), 'Failed to advance past SPAN closer to expected DIV opener.' );
- $this->assertSame( 'DIV', $p->get_tag(), "Expected to find DIV element, but found {$p->get_tag()} instead." );
- $this->assertSame( array( 'HTML', 'BODY', 'DIV', 'DIV' ), $p->get_breadcrumbs(), 'Failed to produce expected DOM nesting: SPAN should be closed and DIV should be its sibling.' );
+ $this->assertFalse( $processor->next_tag(), 'Found a BR tag that should not be handled.' );
+ $this->assertSame( WP_HTML_Processor::ERROR_UNSUPPORTED, $processor->get_last_error() );
}
}
diff --git a/tests/phpunit/tests/html-api/wpHtmlProcessorSemanticRulesHeadingElements.php b/tests/phpunit/tests/html-api/wpHtmlProcessorSemanticRulesHeadingElements.php
index d8d70acb61e76..b33c6e072dfb1 100644
--- a/tests/phpunit/tests/html-api/wpHtmlProcessorSemanticRulesHeadingElements.php
+++ b/tests/phpunit/tests/html-api/wpHtmlProcessorSemanticRulesHeadingElements.php
@@ -53,7 +53,7 @@ public function test_in_body_heading_element_closes_open_p_tag( $tag_name ) {
*
* @return array[].
*/
- public function data_heading_elements() {
+ public static function data_heading_elements() {
return array(
'H1' => array( 'H1' ),
'H2' => array( 'H2' ),
@@ -109,7 +109,7 @@ public function test_in_body_heading_element_closes_other_heading_elements( $fir
*
* @return array[]
*/
- public function data_heading_combinations() {
+ public static function data_heading_combinations() {
$headings = array( 'H1', 'H2', 'H3', 'H4', 'H5', 'H6' );
$combinations = array();
diff --git a/tests/phpunit/tests/html-api/wpHtmlSupportRequiredHtmlProcessor.php b/tests/phpunit/tests/html-api/wpHtmlSupportRequiredHtmlProcessor.php
index 2770acb7360df..2d3cd21ce461b 100644
--- a/tests/phpunit/tests/html-api/wpHtmlSupportRequiredHtmlProcessor.php
+++ b/tests/phpunit/tests/html-api/wpHtmlSupportRequiredHtmlProcessor.php
@@ -42,9 +42,9 @@ class Tests_HtmlApi_WpHtmlSupportRequiredHtmlProcessor extends WP_UnitTestCase {
* @param string $tag_name the HTML Processor should abort when encountering this tag, e.g. "BUTTON".
*/
private function ensure_support_is_added_everywhere( $tag_name ) {
- $p = WP_HTML_Processor::create_fragment( "<$tag_name>" );
+ $processor = WP_HTML_Processor::create_fragment( "<$tag_name>" );
- $this->assertFalse( $p->step(), "Must support terminating elements in specific scope check before adding support for the {$tag_name} element." );
+ $this->assertFalse( $processor->step(), "Must support terminating elements in specific scope check before adding support for the {$tag_name} element." );
}
/**
diff --git a/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php b/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php
index 0a05629e024bd..c2e8c697e8156 100644
--- a/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php
+++ b/tests/phpunit/tests/html-api/wpHtmlSupportRequiredOpenElements.php
@@ -44,9 +44,9 @@ class Tests_HtmlApi_WpHtmlSupportRequiredOpenElements extends WP_UnitTestCase {
* @param string $tag_name the HTML Processor should abort when encountering this tag, e.g. "BUTTON".
*/
private function ensure_support_is_added_everywhere( $tag_name ) {
- $p = WP_HTML_Processor::create_fragment( "<$tag_name>" );
+ $processor = WP_HTML_Processor::create_fragment( "<$tag_name>" );
- $this->assertFalse( $p->step(), "Must support terminating elements in specific scope check before adding support for the {$tag_name} element." );
+ $this->assertFalse( $processor->step(), "Must support terminating elements in specific scope check before adding support for the {$tag_name} element." );
}
/**
diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor-bookmark.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor-bookmark.php
index 90adfb20be955..a0a3b2aa44b4b 100644
--- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor-bookmark.php
+++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor-bookmark.php
@@ -19,12 +19,12 @@ class Tests_HtmlApi_WpHtmlTagProcessor_Bookmark extends WP_UnitTestCase {
* @covers WP_HTML_Tag_Processor::set_bookmark
*/
public function test_set_bookmark() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag( 'li' );
- $this->assertTrue( $p->set_bookmark( 'first li' ), 'Could not allocate a "first li" bookmark' );
- $p->next_tag( 'li' );
- $this->assertTrue( $p->set_bookmark( 'second li' ), 'Could not allocate a "second li" bookmark' );
- $this->assertTrue( $p->set_bookmark( 'first li' ), 'Could not move the "first li" bookmark' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag( 'li' );
+ $this->assertTrue( $processor->set_bookmark( 'first li' ), 'Could not allocate a "first li" bookmark' );
+ $processor->next_tag( 'li' );
+ $this->assertTrue( $processor->set_bookmark( 'second li' ), 'Could not allocate a "second li" bookmark' );
+ $this->assertTrue( $processor->set_bookmark( 'first li' ), 'Could not move the "first li" bookmark' );
}
/**
@@ -33,11 +33,11 @@ public function test_set_bookmark() {
* @covers WP_HTML_Tag_Processor::release_bookmark
*/
public function test_release_bookmark() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag( 'li' );
- $this->assertFalse( $p->release_bookmark( 'first li' ), 'Released a non-existing bookmark' );
- $p->set_bookmark( 'first li' );
- $this->assertTrue( $p->release_bookmark( 'first li' ), 'Could not release a bookmark' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag( 'li' );
+ $this->assertFalse( $processor->release_bookmark( 'first li' ), 'Released a non-existing bookmark' );
+ $processor->set_bookmark( 'first li' );
+ $this->assertTrue( $processor->release_bookmark( 'first li' ), 'Could not release a bookmark' );
}
/**
@@ -46,8 +46,8 @@ public function test_release_bookmark() {
* @covers WP_HTML_Tag_Processor::has_bookmark
*/
public function test_has_bookmark_returns_false_if_bookmark_does_not_exist() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertFalse( $p->has_bookmark( 'my-bookmark' ) );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $this->assertFalse( $processor->has_bookmark( 'my-bookmark' ) );
}
/**
@@ -56,10 +56,10 @@ public function test_has_bookmark_returns_false_if_bookmark_does_not_exist() {
* @covers WP_HTML_Tag_Processor::has_bookmark
*/
public function test_has_bookmark_returns_true_if_bookmark_exists() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
- $p->set_bookmark( 'my-bookmark' );
- $this->assertTrue( $p->has_bookmark( 'my-bookmark' ) );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
+ $processor->set_bookmark( 'my-bookmark' );
+ $this->assertTrue( $processor->has_bookmark( 'my-bookmark' ) );
}
/**
@@ -68,11 +68,11 @@ public function test_has_bookmark_returns_true_if_bookmark_exists() {
* @covers WP_HTML_Tag_Processor::has_bookmark
*/
public function test_has_bookmark_returns_false_if_bookmark_has_been_released() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
- $p->set_bookmark( 'my-bookmark' );
- $p->release_bookmark( 'my-bookmark' );
- $this->assertFalse( $p->has_bookmark( 'my-bookmark' ) );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
+ $processor->set_bookmark( 'my-bookmark' );
+ $processor->release_bookmark( 'my-bookmark' );
+ $this->assertFalse( $processor->has_bookmark( 'my-bookmark' ) );
}
/**
@@ -81,19 +81,19 @@ public function test_has_bookmark_returns_false_if_bookmark_has_been_released()
* @covers WP_HTML_Tag_Processor::seek
*/
public function test_seek() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag( 'li' );
- $p->set_bookmark( 'first li' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag( 'li' );
+ $processor->set_bookmark( 'first li' );
- $p->next_tag( 'li' );
- $p->set_attribute( 'foo-2', 'bar-2' );
+ $processor->next_tag( 'li' );
+ $processor->set_attribute( 'foo-2', 'bar-2' );
- $p->seek( 'first li' );
- $p->set_attribute( 'foo-1', 'bar-1' );
+ $processor->seek( 'first li' );
+ $processor->set_attribute( 'foo-1', 'bar-1' );
$this->assertSame(
'
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Did not seek to the intended bookmark locations'
);
}
@@ -104,18 +104,18 @@ public function test_seek() {
* @covers WP_HTML_Tag_Processor::seek
*/
public function test_seeks_to_tag_closer_bookmark() {
- $p = new WP_HTML_Tag_Processor( '
First
Second ' );
- $p->next_tag( array( 'tag_closers' => 'visit' ) );
- $p->set_bookmark( 'first' );
- $p->next_tag( array( 'tag_closers' => 'visit' ) );
- $p->set_bookmark( 'second' );
+ $processor = new WP_HTML_Tag_Processor( '
First
Second ' );
+ $processor->next_tag( array( 'tag_closers' => 'visit' ) );
+ $processor->set_bookmark( 'first' );
+ $processor->next_tag( array( 'tag_closers' => 'visit' ) );
+ $processor->set_bookmark( 'second' );
- $p->seek( 'first' );
- $p->seek( 'second' );
+ $processor->seek( 'first' );
+ $processor->seek( 'second' );
$this->assertSame(
'DIV',
- $p->get_tag(),
+ $processor->get_tag(),
'Did not seek to the intended bookmark location'
);
}
@@ -159,24 +159,24 @@ public function test_seeks_to_tag_closer_bookmark() {
* @covers WP_HTML_Tag_Processor::set_bookmark
*/
public function test_removing_long_attributes_doesnt_break_seek() {
- $input = <<
HTML;
- $p = new WP_HTML_Tag_Processor( $input );
- $p->next_tag( 'button' );
- $p->set_bookmark( 'first' );
- $p->next_tag( 'button' );
- $p->set_bookmark( 'second' );
+ $processor = new WP_HTML_Tag_Processor( $input );
+ $processor->next_tag( 'button' );
+ $processor->set_bookmark( 'first' );
+ $processor->next_tag( 'button' );
+ $processor->set_bookmark( 'second' );
$this->assertTrue(
- $p->seek( 'first' ),
+ $processor->seek( 'first' ),
'Seek() to the first button has failed'
);
- $p->remove_attribute( 'twenty_one_characters' );
- $p->remove_attribute( '7_chars' );
+ $processor->remove_attribute( 'twenty_one_characters' );
+ $processor->remove_attribute( '7_chars' );
$this->assertTrue(
- $p->seek( 'second' ),
+ $processor->seek( 'second' ),
'Seek() to the second button has failed'
);
}
@@ -232,61 +232,61 @@ public function test_bookmarks_complex_use_case() {
HTML;
- $p = new WP_HTML_Tag_Processor( $input );
- $p->next_tag( 'div' );
- $p->next_tag( 'div' );
- $p->next_tag( 'div' );
- $p->set_bookmark( 'first div' );
- $p->next_tag( 'button' );
- $p->set_bookmark( 'first button' );
- $p->next_tag( 'button' );
- $p->set_bookmark( 'second button' );
- $p->next_tag( 'button' );
- $p->set_bookmark( 'third button' );
- $p->next_tag( 'button' );
- $p->set_bookmark( 'fourth button' );
-
- $p->seek( 'first button' );
- $p->set_attribute( 'type', 'submit' );
+ $processor = new WP_HTML_Tag_Processor( $input );
+ $processor->next_tag( 'div' );
+ $processor->next_tag( 'div' );
+ $processor->next_tag( 'div' );
+ $processor->set_bookmark( 'first div' );
+ $processor->next_tag( 'button' );
+ $processor->set_bookmark( 'first button' );
+ $processor->next_tag( 'button' );
+ $processor->set_bookmark( 'second button' );
+ $processor->next_tag( 'button' );
+ $processor->set_bookmark( 'third button' );
+ $processor->next_tag( 'button' );
+ $processor->set_bookmark( 'fourth button' );
+
+ $processor->seek( 'first button' );
+ $processor->set_attribute( 'type', 'submit' );
$this->assertTrue(
- $p->seek( 'third button' ),
+ $processor->seek( 'third button' ),
'Seek() to the third button failed'
);
- $p->remove_attribute( 'class' );
- $p->remove_attribute( 'type' );
- $p->remove_attribute( 'aria-expanded' );
- $p->set_attribute( 'id', 'rebase-and-merge' );
- $p->remove_attribute( 'data-details-container' );
+ $processor->remove_attribute( 'class' );
+ $processor->remove_attribute( 'type' );
+ $processor->remove_attribute( 'aria-expanded' );
+ $processor->set_attribute( 'id', 'rebase-and-merge' );
+ $processor->remove_attribute( 'data-details-container' );
$this->assertTrue(
- $p->seek( 'first div' ),
+ $processor->seek( 'first div' ),
'Seek() to the first div failed'
);
- $p->set_attribute( 'checked', false );
+ $processor->set_attribute( 'checked', false );
$this->assertTrue(
- $p->seek( 'fourth button' ),
+ $processor->seek( 'fourth button' ),
'Seek() to the fourth button failed'
);
- $p->set_attribute( 'id', 'last-button' );
- $p->remove_attribute( 'class' );
- $p->remove_attribute( 'type' );
- $p->remove_attribute( 'checked' );
- $p->remove_attribute( 'aria-label' );
- $p->remove_attribute( 'disabled' );
- $p->remove_attribute( 'data-view-component' );
+ $processor->set_attribute( 'id', 'last-button' );
+ $processor->remove_attribute( 'class' );
+ $processor->remove_attribute( 'type' );
+ $processor->remove_attribute( 'checked' );
+ $processor->remove_attribute( 'aria-label' );
+ $processor->remove_attribute( 'disabled' );
+ $processor->remove_attribute( 'data-view-component' );
$this->assertTrue(
- $p->seek( 'second button' ),
+ $processor->seek( 'second button' ),
'Seek() to the second button failed'
);
- $p->remove_attribute( 'type' );
- $p->set_attribute( 'class', 'hx_create-pr-button' );
+ $processor->remove_attribute( 'type' );
+ $processor->set_attribute( 'class', 'hx_create-pr-button' );
$this->assertSame(
$expected_output,
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Performing several attribute updates on different tags does not produce the expected HTML snippet'
);
}
@@ -297,18 +297,18 @@ public function test_bookmarks_complex_use_case() {
* @covers WP_HTML_Tag_Processor::seek
*/
public function test_updates_bookmark_for_additions_after_both_sides() {
- $p = new WP_HTML_Tag_Processor( '
First
Second
' );
- $p->next_tag();
- $p->set_bookmark( 'first' );
- $p->next_tag();
- $p->add_class( 'second' );
+ $processor = new WP_HTML_Tag_Processor( '
First
Second
' );
+ $processor->next_tag();
+ $processor->set_bookmark( 'first' );
+ $processor->next_tag();
+ $processor->add_class( 'second' );
- $p->seek( 'first' );
- $p->add_class( 'first' );
+ $processor->seek( 'first' );
+ $processor->add_class( 'first' );
$this->assertSame(
'
First
Second
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'The bookmark was updated incorrectly in response to HTML markup updates'
);
}
@@ -319,21 +319,21 @@ public function test_updates_bookmark_for_additions_after_both_sides() {
* @covers WP_HTML_Tag_Processor::seek
*/
public function test_updates_bookmark_for_additions_before_both_sides() {
- $p = new WP_HTML_Tag_Processor( '
First
Second
' );
- $p->next_tag();
- $p->set_bookmark( 'first' );
- $p->next_tag();
- $p->set_bookmark( 'second' );
+ $processor = new WP_HTML_Tag_Processor( '
First
Second
' );
+ $processor->next_tag();
+ $processor->set_bookmark( 'first' );
+ $processor->next_tag();
+ $processor->set_bookmark( 'second' );
- $p->seek( 'first' );
- $p->add_class( 'first' );
+ $processor->seek( 'first' );
+ $processor->add_class( 'first' );
- $p->seek( 'second' );
- $p->add_class( 'second' );
+ $processor->seek( 'second' );
+ $processor->add_class( 'second' );
$this->assertSame(
'
First
Second
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'The bookmark was updated incorrectly in response to HTML markup updates'
);
}
@@ -344,14 +344,14 @@ public function test_updates_bookmark_for_additions_before_both_sides() {
* @covers WP_HTML_Tag_Processor::seek
*/
public function test_updates_bookmark_for_deletions_after_both_sides() {
- $p = new WP_HTML_Tag_Processor( '
First
Second
' );
- $p->next_tag();
- $p->set_bookmark( 'first' );
- $p->next_tag();
- $p->remove_attribute( 'disabled' );
+ $processor = new WP_HTML_Tag_Processor( '
First
Second
' );
+ $processor->next_tag();
+ $processor->set_bookmark( 'first' );
+ $processor->next_tag();
+ $processor->remove_attribute( 'disabled' );
- $p->seek( 'first' );
- $p->set_attribute( 'untouched', true );
+ $processor->seek( 'first' );
+ $processor->set_attribute( 'untouched', true );
$this->assertSame(
/*
@@ -363,7 +363,7 @@ public function test_updates_bookmark_for_deletions_after_both_sides() {
* is not required.
*/
'
First
Second
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'The bookmark was incorrectly in response to HTML markup updates'
);
}
@@ -374,17 +374,17 @@ public function test_updates_bookmark_for_deletions_after_both_sides() {
* @covers WP_HTML_Tag_Processor::seek
*/
public function test_updates_bookmark_for_deletions_before_both_sides() {
- $p = new WP_HTML_Tag_Processor( '
First
Second
' );
- $p->next_tag();
- $p->set_bookmark( 'first' );
- $p->next_tag();
- $p->set_bookmark( 'second' );
+ $processor = new WP_HTML_Tag_Processor( '
First
Second
' );
+ $processor->next_tag();
+ $processor->set_bookmark( 'first' );
+ $processor->next_tag();
+ $processor->set_bookmark( 'second' );
- $p->seek( 'first' );
- $p->remove_attribute( 'disabled' );
+ $processor->seek( 'first' );
+ $processor->remove_attribute( 'disabled' );
- $p->seek( 'second' );
- $p->set_attribute( 'safe', true );
+ $processor->seek( 'second' );
+ $processor->set_attribute( 'safe', true );
$this->assertSame(
/*
@@ -396,7 +396,7 @@ public function test_updates_bookmark_for_deletions_before_both_sides() {
* is not required.
*/
'
First
Second
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'The bookmark was updated incorrectly in response to HTML markup updates'
);
}
@@ -407,15 +407,15 @@ public function test_updates_bookmark_for_deletions_before_both_sides() {
* @covers WP_HTML_Tag_Processor::set_bookmark
*/
public function test_limits_the_number_of_bookmarks() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag( 'li' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag( 'li' );
for ( $i = 0; $i < WP_HTML_Tag_Processor::MAX_BOOKMARKS; $i++ ) {
- $this->assertTrue( $p->set_bookmark( "bookmark $i" ), "Could not allocate the bookmark #$i" );
+ $this->assertTrue( $processor->set_bookmark( "bookmark $i" ), "Could not allocate the bookmark #$i" );
}
$this->setExpectedIncorrectUsage( 'WP_HTML_Tag_Processor::set_bookmark' );
- $this->assertFalse( $p->set_bookmark( 'final bookmark' ), "Allocated $i bookmarks, which is one above the limit" );
+ $this->assertFalse( $processor->set_bookmark( 'final bookmark' ), "Allocated $i bookmarks, which is one above the limit" );
}
/**
@@ -424,15 +424,60 @@ public function test_limits_the_number_of_bookmarks() {
* @covers WP_HTML_Tag_Processor::seek
*/
public function test_limits_the_number_of_seek_calls() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag( 'li' );
- $p->set_bookmark( 'bookmark' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag( 'li' );
+ $processor->set_bookmark( 'bookmark' );
for ( $i = 0; $i < WP_HTML_Tag_Processor::MAX_SEEK_OPS; $i++ ) {
- $this->assertTrue( $p->seek( 'bookmark' ), 'Could not seek to the "bookmark"' );
+ $this->assertTrue( $processor->seek( 'bookmark' ), 'Could not seek to the "bookmark"' );
}
$this->setExpectedIncorrectUsage( 'WP_HTML_Tag_Processor::seek' );
- $this->assertFalse( $p->seek( 'bookmark' ), "$i-th seek() to the bookmark succeeded, even though it should exceed the allowed limit" );
+ $this->assertFalse( $processor->seek( 'bookmark' ), "$i-th seek() to the bookmark succeeded, even though it should exceed the allowed limit" );
+ }
+
+ /**
+ * Ensures that it's possible to seek to an earlier location in a document even
+ * after reaching the end of a document, when most functionality shuts down.
+ *
+ * @ticket 60428
+ *
+ * @dataProvider data_incomplete_html_with_target_nodes_for_seeking
+ *
+ * @param string $html_with_target_element HTML string containing a tag with a `target` attribute.
+ */
+ public function test_can_seek_after_document_ends( $html_with_target_element ) {
+ $processor = new WP_HTML_Tag_Processor( $html_with_target_element );
+
+ $sought_tag_name = null;
+ while ( $processor->next_tag() ) {
+ if ( null !== $processor->get_attribute( 'target' ) ) {
+ $processor->set_bookmark( 'target' );
+ $sought_tag_name = $processor->get_tag();
+ }
+ }
+
+ $this->assertTrue(
+ $processor->seek( 'target' ),
+ 'Should have been able to seek to the target bookmark after reaching the end of the document.'
+ );
+
+ $this->assertSame(
+ $sought_tag_name,
+ $processor->get_tag(),
+ "Should have found original target node instead of {$processor->get_tag()}."
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array[].
+ */
+ public static function data_incomplete_html_with_target_nodes_for_seeking() {
+ return array(
+ 'Compete document' => array( '
' ),
+ 'Incomplete document' => array( '
assertFalse(
+ $processor->next_token(),
+ "Should not have found any tokens but found {$processor->get_token_type()}."
+ );
+ }
+
+ /**
+ * Ensures that normative text nodes are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_text_node() {
+ $processor = new WP_HTML_Tag_Processor( 'Hello, World!' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#text',
+ $processor->get_token_type(),
+ "Should have found #text token type but found {$processor->get_token_type()} instead."
+ );
+
+ $this->assertSame(
+ 'Hello, World!',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that normative Elements are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_element() {
+ $processor = new WP_HTML_Tag_Processor( '
Hello, World!
' );
+ $processor->next_token();
+
+ $this->assertSame(
+ 'DIV',
+ $processor->get_token_name(),
+ "Should have found DIV tag name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ 'test',
+ $processor->get_attribute( 'id' ),
+ "Should have found id attribute value 'test' but found {$processor->get_attribute( 'id' )} instead."
+ );
+
+ $this->assertTrue(
+ $processor->get_attribute( 'inert' ),
+ "Should have found boolean attribute 'inert' but didn't."
+ );
+
+ $attributes = $processor->get_attribute_names_with_prefix( '' );
+ $attribute_list = array_map( 'Tests_HtmlApi_WpHtmlProcessor_Token_Scanning::quoted', $attributes );
+ $this->assertSame(
+ array( 'id', 'inert' ),
+ $attributes,
+ 'Should have found only two attributes but found ' . implode( ', ', $attribute_list ) . ' instead.'
+ );
+
+ $this->assertSame(
+ '',
+ $processor->get_modifiable_text(),
+ "Should have found empty modifiable text but found '{$processor->get_modifiable_text()}' instead."
+ );
+ }
+
+ /**
+ * Ensures that normative SCRIPT elements are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_script_element() {
+ $processor = new WP_HTML_Tag_Processor( '' );
+ $processor->next_token();
+
+ $this->assertSame(
+ 'SCRIPT',
+ $processor->get_token_name(),
+ "Should have found SCRIPT tag name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ 'module',
+ $processor->get_attribute( 'type' ),
+ "Should have found type attribute value 'module' but found {$processor->get_attribute( 'type' )} instead."
+ );
+
+ $attributes = $processor->get_attribute_names_with_prefix( '' );
+ $attribute_list = array_map( 'Tests_HtmlApi_WpHtmlProcessor_Token_Scanning::quoted', $attributes );
+ $this->assertSame(
+ array( 'type' ),
+ $attributes,
+ "Should have found single 'type' attribute but found " . implode( ', ', $attribute_list ) . ' instead.'
+ );
+
+ $this->assertSame(
+ 'console.log( "Hello, World!" );',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that normative TEXTAREA elements are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_textarea_element() {
+ $processor = new WP_HTML_Tag_Processor(
+ <<
+Is > XHTML?
+
+HTML
+ );
+ $processor->next_token();
+
+ $this->assertSame(
+ 'TEXTAREA',
+ $processor->get_token_name(),
+ "Should have found TEXTAREA tag name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ '30',
+ $processor->get_attribute( 'rows' ),
+ "Should have found rows attribute value 'module' but found {$processor->get_attribute( 'rows' )} instead."
+ );
+
+ $this->assertSame(
+ '80',
+ $processor->get_attribute( 'cols' ),
+ "Should have found cols attribute value 'module' but found {$processor->get_attribute( 'cols' )} instead."
+ );
+
+ $attributes = $processor->get_attribute_names_with_prefix( '' );
+ $attribute_list = array_map( 'Tests_HtmlApi_WpHtmlProcessor_Token_Scanning::quoted', $attributes );
+ $this->assertSame(
+ array( 'rows', 'cols' ),
+ $attributes,
+ 'Should have found only two attributes but found ' . implode( ', ', $attribute_list ) . ' instead.'
+ );
+
+ // Note that the leading newline should be removed from the TEXTAREA contents.
+ $this->assertSame(
+ "Is > XHTML?\n",
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that normative TITLE elements are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_title_element() {
+ $processor = new WP_HTML_Tag_Processor(
+ <<
+Is > XHTML?
+
+HTML
+ );
+ $processor->next_token();
+
+ $this->assertSame(
+ 'TITLE',
+ $processor->get_token_name(),
+ "Should have found TITLE tag name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ 'multi-line-title',
+ $processor->get_attribute( 'class' ),
+ "Should have found class attribute value 'multi-line-title' but found {$processor->get_attribute( 'rows' )} instead."
+ );
+
+ $attributes = $processor->get_attribute_names_with_prefix( '' );
+ $attribute_list = array_map( 'Tests_HtmlApi_WpHtmlProcessor_Token_Scanning::quoted', $attributes );
+ $this->assertSame(
+ array( 'class' ),
+ $attributes,
+ 'Should have found only one attribute but found ' . implode( ', ', $attribute_list ) . ' instead.'
+ );
+
+ $this->assertSame(
+ "\nIs > XHTML?\n",
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that normative RAWTEXT elements are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ *
+ * @dataProvider data_rawtext_elements
+ *
+ * @param string $tag_name The name of the RAWTEXT tag to test.
+ */
+ public function test_basic_assertion_rawtext_elements( $tag_name ) {
+ $processor = new WP_HTML_Tag_Processor(
+ <<
+Is > XHTML?
+{$tag_name}>
+HTML
+ );
+ $processor->next_token();
+
+ $this->assertSame(
+ $tag_name,
+ $processor->get_token_name(),
+ "Should have found {$tag_name} tag name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ 'multi-line-title',
+ $processor->get_attribute( 'class' ),
+ "Should have found class attribute value 'multi-line-title' but found {$processor->get_attribute( 'rows' )} instead."
+ );
+
+ $attributes = $processor->get_attribute_names_with_prefix( '' );
+ $attribute_list = array_map( 'Tests_HtmlApi_WpHtmlProcessor_Token_Scanning::quoted', $attributes );
+ $this->assertSame(
+ array( 'class' ),
+ $attributes,
+ 'Should have found only one attribute but found ' . implode( ', ', $attribute_list ) . ' instead.'
+ );
+
+ $this->assertSame(
+ "\nIs > XHTML?\n",
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array[].
+ */
+ public static function data_rawtext_elements() {
+ return array(
+ 'IFRAME' => array( 'IFRAME' ),
+ 'NOEMBED' => array( 'NOEMBED' ),
+ 'NOFRAMES' => array( 'NOFRAMES' ),
+ 'STYLE' => array( 'STYLE' ),
+ 'XMP' => array( 'XMP' ),
+ );
+ }
+
+ /**
+ * Ensures that normative CDATA sections are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_cdata_section() {
+ $processor = new WP_HTML_Tag_Processor( '' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_name(),
+ "Should have found comment token but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ WP_HTML_Processor::COMMENT_AS_CDATA_LOOKALIKE,
+ $processor->get_comment_type(),
+ 'Should have detected a CDATA-like invalid comment.'
+ );
+
+ $this->assertNull(
+ $processor->get_tag(),
+ 'Should not have been able to query tag name on non-element token.'
+ );
+
+ $this->assertNull(
+ $processor->get_attribute( 'type' ),
+ 'Should not have been able to query attributes on non-element token.'
+ );
+
+ $this->assertSame(
+ 'this is a comment',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that normative CDATA sections are properly parsed.
+ *
+ * @ticket 60406
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_cdata_comment_with_incorrect_closer() {
+ $processor = new WP_HTML_Tag_Processor( '' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_name(),
+ "Should have found comment token but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ WP_HTML_Processor::COMMENT_AS_INVALID_HTML,
+ $processor->get_comment_type(),
+ 'Should have detected invalid HTML comment.'
+ );
+
+ $this->assertSame(
+ '[CDATA[this is missing a closing square bracket]',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that abruptly-closed CDATA sections are properly parsed as comments.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_abruptly_closed_cdata_section() {
+ $processor = new WP_HTML_Tag_Processor( ' a comment]]>' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_name(),
+ "Should have found a bogus comment but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ WP_HTML_Processor::COMMENT_AS_INVALID_HTML,
+ $processor->get_comment_type(),
+ 'Should have detected invalid HTML comment.'
+ );
+
+ $this->assertNull(
+ $processor->get_tag(),
+ 'Should not have been able to query tag name on non-element token.'
+ );
+
+ $this->assertNull(
+ $processor->get_attribute( 'type' ),
+ 'Should not have been able to query attributes on non-element token.'
+ );
+
+ $this->assertSame(
+ '[CDATA[this is ',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+
+ $processor->next_token();
+
+ $this->assertSame(
+ '#text',
+ $processor->get_token_name(),
+ "Should have found text node but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ ' a comment]]>',
+ $processor->get_modifiable_text(),
+ 'Should have found remaining syntax from abruptly-closed CDATA section.'
+ );
+ }
+
+ /**
+ * Ensures that normative Processing Instruction nodes are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_processing_instruction() {
+ $processor = new WP_HTML_Tag_Processor( '' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_name(),
+ "Should have found comment token but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertSame(
+ WP_HTML_Processor::COMMENT_AS_PI_NODE_LOOKALIKE,
+ $processor->get_comment_type(),
+ 'Should have detected a Processing Instruction-like invalid comment.'
+ );
+
+ $this->assertSame(
+ 'wp-bit',
+ $processor->get_tag(),
+ "Should have found PI target as tag name but found {$processor->get_tag()} instead."
+ );
+
+ $this->assertNull(
+ $processor->get_attribute( 'type' ),
+ 'Should not have been able to query attributes on non-element token.'
+ );
+
+ $this->assertSame(
+ ' {"just": "kidding"}',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that abruptly-closed Processing Instruction nodes are properly parsed as comments.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_abruptly_closed_processing_instruction() {
+ $processor = new WP_HTML_Tag_Processor( '=5.3.6"?>' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_type(),
+ "Should have found bogus comment but found {$processor->get_token_type()} instead."
+ );
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_name(),
+ "Should have found #comment as name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertNull(
+ $processor->get_tag(),
+ 'Should not have been able to query tag name on non-element token.'
+ );
+
+ $this->assertNull(
+ $processor->get_attribute( 'type' ),
+ 'Should not have been able to query attributes on non-element token.'
+ );
+
+ $this->assertSame(
+ 'version="',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+
+ $processor->next_token();
+
+ $this->assertSame(
+ '=5.3.6"?>',
+ $processor->get_modifiable_text(),
+ 'Should have found remaining syntax from abruptly-closed Processing Instruction.'
+ );
+ }
+
+ /**
+ * Ensures that common comments are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @dataProvider data_common_comments
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ *
+ * @param string $html Contains the comment in full.
+ * @param string $text Contains the appropriate modifiable text.
+ */
+ public function test_basic_assertion_common_comments( $html, $text ) {
+ $processor = new WP_HTML_Tag_Processor( $html );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_type(),
+ "Should have found comment but found {$processor->get_token_type()} instead."
+ );
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_name(),
+ "Should have found #comment as name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertNull(
+ $processor->get_tag(),
+ 'Should not have been able to query tag name on non-element token.'
+ );
+
+ $this->assertNull(
+ $processor->get_attribute( 'type' ),
+ 'Should not have been able to query attributes on non-element token.'
+ );
+
+ $this->assertSame(
+ $text,
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Data provider.
+ *
+ * @return array[].
+ */
+ public static function data_common_comments() {
+ return array(
+ 'Shortest comment' => array( '', '' ),
+ 'Short comment' => array( '', '' ),
+ 'Short comment w/o text' => array( '', '' ),
+ 'Short comment with text' => array( '', '-' ),
+ 'PI node without target' => array( ' missing?>', ' missing?' ),
+ 'Invalid PI node' => array( '/missing/>', '/missing/' ),
+ 'Invalid ! directive' => array( '', 'something else' ),
+ );
+ }
+
+ /**
+ * Ensures that normative HTML comments are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_html_comment() {
+ $processor = new WP_HTML_Tag_Processor( '' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_type(),
+ "Should have found comment but found {$processor->get_token_type()} instead."
+ );
+
+ $this->assertSame(
+ '#comment',
+ $processor->get_token_name(),
+ "Should have found #comment as name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertNull(
+ $processor->get_tag(),
+ 'Should not have been able to query tag name on non-element token.'
+ );
+
+ $this->assertNull(
+ $processor->get_attribute( 'type' ),
+ 'Should not have been able to query attributes on non-element token.'
+ );
+
+ $this->assertSame(
+ ' wp:paragraph ',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that normative DOCTYPE elements are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_doctype() {
+ $processor = new WP_HTML_Tag_Processor( '' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#doctype',
+ $processor->get_token_type(),
+ "Should have found DOCTYPE but found {$processor->get_token_type()} instead."
+ );
+
+ $this->assertSame(
+ 'html',
+ $processor->get_token_name(),
+ "Should have found 'html' as name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertNull(
+ $processor->get_tag(),
+ 'Should not have been able to query tag name on non-element token.'
+ );
+
+ $this->assertNull(
+ $processor->get_attribute( 'type' ),
+ 'Should not have been able to query attributes on non-element token.'
+ );
+
+ $this->assertSame(
+ ' html',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that normative presumptuous tag closers (empty closers) are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_presumptuous_tag() {
+ $processor = new WP_HTML_Tag_Processor( '>' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#presumptuous-tag',
+ $processor->get_token_type(),
+ "Should have found presumptuous tag but found {$processor->get_token_type()} instead."
+ );
+
+ $this->assertSame(
+ '#presumptuous-tag',
+ $processor->get_token_name(),
+ "Should have found #presumptuous-tag as name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertNull(
+ $processor->get_tag(),
+ 'Should not have been able to query tag name on non-element token.'
+ );
+
+ $this->assertNull(
+ $processor->get_attribute( 'type' ),
+ 'Should not have been able to query attributes on non-element token.'
+ );
+
+ $this->assertSame(
+ '',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Ensures that normative funky comments are properly parsed.
+ *
+ * @ticket 60170
+ *
+ * @since 6.5.0
+ *
+ * @covers WP_HTML_Tag_Processor::next_token
+ */
+ public function test_basic_assertion_funky_comment() {
+ $processor = new WP_HTML_Tag_Processor( '%url>' );
+ $processor->next_token();
+
+ $this->assertSame(
+ '#funky-comment',
+ $processor->get_token_type(),
+ "Should have found funky comment but found {$processor->get_token_type()} instead."
+ );
+
+ $this->assertSame(
+ '#funky-comment',
+ $processor->get_token_name(),
+ "Should have found #funky-comment as name but found {$processor->get_token_name()} instead."
+ );
+
+ $this->assertNull(
+ $processor->get_tag(),
+ 'Should not have been able to query tag name on non-element token.'
+ );
+
+ $this->assertNull(
+ $processor->get_attribute( 'type' ),
+ 'Should not have been able to query attributes on non-element token.'
+ );
+
+ $this->assertSame(
+ '%url',
+ $processor->get_modifiable_text(),
+ 'Found incorrect modifiable text.'
+ );
+ }
+
+ /**
+ * Test helper that wraps a string in double quotes.
+ *
+ * @param string $s The string to wrap in double-quotes.
+ * @return string The string wrapped in double-quotes.
+ */
+ private static function quoted( $s ) {
+ return "\"$s\"";
+ }
+}
diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php
index 8a681d2cb0042..5375a2fca0ebf 100644
--- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php
+++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php
@@ -22,9 +22,9 @@ class Tests_HtmlApi_WpHtmlTagProcessor extends WP_UnitTestCase {
* @covers WP_HTML_Tag_Processor::get_tag
*/
public function test_get_tag_returns_null_before_finding_tags() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertNull( $p->get_tag(), 'Calling get_tag() without selecting a tag did not return null' );
+ $this->assertNull( $processor->get_tag(), 'Calling get_tag() without selecting a tag did not return null' );
}
/**
@@ -33,10 +33,10 @@ public function test_get_tag_returns_null_before_finding_tags() {
* @covers WP_HTML_Tag_Processor::get_tag
*/
public function test_get_tag_returns_null_when_not_in_open_tag() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertFalse( $p->next_tag( 'p' ), 'Querying a non-existing tag did not return false' );
- $this->assertNull( $p->get_tag(), 'Accessing a non-existing tag did not return null' );
+ $this->assertFalse( $processor->next_tag( 'p' ), 'Querying a non-existing tag did not return false' );
+ $this->assertNull( $processor->get_tag(), 'Accessing a non-existing tag did not return null' );
}
/**
@@ -45,10 +45,10 @@ public function test_get_tag_returns_null_when_not_in_open_tag() {
* @covers WP_HTML_Tag_Processor::get_tag
*/
public function test_get_tag_returns_open_tag_name() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertTrue( $p->next_tag( 'div' ), 'Querying an existing tag did not return true' );
- $this->assertSame( 'DIV', $p->get_tag(), 'Accessing an existing tag name did not return "div"' );
+ $this->assertTrue( $processor->next_tag( 'div' ), 'Querying an existing tag did not return true' );
+ $this->assertSame( 'DIV', $processor->get_tag(), 'Accessing an existing tag name did not return "div"' );
}
/**
@@ -62,13 +62,13 @@ public function test_get_tag_returns_open_tag_name() {
* @param bool $flag_is_set Whether the input HTML's first tag contains the self-closing flag.
*/
public function test_has_self_closing_flag_matches_input_html( $html, $flag_is_set ) {
- $p = new WP_HTML_Tag_Processor( $html );
- $p->next_tag( array( 'tag_closers' => 'visit' ) );
+ $processor = new WP_HTML_Tag_Processor( $html );
+ $processor->next_tag( array( 'tag_closers' => 'visit' ) );
if ( $flag_is_set ) {
- $this->assertTrue( $p->has_self_closing_flag(), 'Did not find the self-closing tag when it was present.' );
+ $this->assertTrue( $processor->has_self_closing_flag(), 'Did not find the self-closing tag when it was present.' );
} else {
- $this->assertFalse( $p->has_self_closing_flag(), 'Found the self-closing tag when it was absent.' );
+ $this->assertFalse( $processor->has_self_closing_flag(), 'Found the self-closing tag when it was absent.' );
}
}
@@ -77,7 +77,7 @@ public function test_has_self_closing_flag_matches_input_html( $html, $flag_is_s
*
* @return array[]
*/
- public function data_has_self_closing_flag() {
+ public static function data_has_self_closing_flag() {
return array(
// These should not have a self-closer, and will leave an element un-closed if it's assumed they are self-closing.
'Self-closing flag on non-void HTML element' => array( '
', true ),
@@ -107,9 +107,9 @@ public function data_has_self_closing_flag() {
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_returns_null_before_finding_tags() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertNull( $p->get_attribute( 'class' ), 'Accessing an attribute without selecting a tag did not return null' );
+ $this->assertNull( $processor->get_attribute( 'class' ), 'Accessing an attribute without selecting a tag did not return null' );
}
/**
@@ -118,10 +118,10 @@ public function test_get_attribute_returns_null_before_finding_tags() {
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_returns_null_when_not_in_open_tag() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertFalse( $p->next_tag( 'p' ), 'Querying a non-existing tag did not return false' );
- $this->assertNull( $p->get_attribute( 'class' ), 'Accessing an attribute of a non-existing tag did not return null' );
+ $this->assertFalse( $processor->next_tag( 'p' ), 'Querying a non-existing tag did not return false' );
+ $this->assertNull( $processor->get_attribute( 'class' ), 'Accessing an attribute of a non-existing tag did not return null' );
}
/**
@@ -130,11 +130,11 @@ public function test_get_attribute_returns_null_when_not_in_open_tag() {
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_returns_null_when_in_closing_tag() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertTrue( $p->next_tag( 'div' ), 'Querying an existing tag did not return true' );
- $this->assertTrue( $p->next_tag( array( 'tag_closers' => 'visit' ) ), 'Querying an existing closing tag did not return true' );
- $this->assertNull( $p->get_attribute( 'class' ), 'Accessing an attribute of a closing tag did not return null' );
+ $this->assertTrue( $processor->next_tag( 'div' ), 'Querying an existing tag did not return true' );
+ $this->assertTrue( $processor->next_tag( array( 'tag_closers' => 'visit' ) ), 'Querying an existing closing tag did not return true' );
+ $this->assertNull( $processor->get_attribute( 'class' ), 'Accessing an attribute of a closing tag did not return null' );
}
/**
@@ -143,10 +143,10 @@ public function test_get_attribute_returns_null_when_in_closing_tag() {
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_returns_null_when_attribute_missing() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertTrue( $p->next_tag( 'div' ), 'Querying an existing tag did not return true' );
- $this->assertNull( $p->get_attribute( 'test-id' ), 'Accessing a non-existing attribute did not return null' );
+ $this->assertTrue( $processor->next_tag( 'div' ), 'Querying an existing tag did not return true' );
+ $this->assertNull( $processor->get_attribute( 'test-id' ), 'Accessing a non-existing attribute did not return null' );
}
/**
@@ -155,10 +155,10 @@ public function test_get_attribute_returns_null_when_attribute_missing() {
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_returns_attribute_value() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertTrue( $p->next_tag( 'div' ), 'Querying an existing tag did not return true' );
- $this->assertSame( 'test', $p->get_attribute( 'class' ), 'Accessing a class="test" attribute value did not return "test"' );
+ $this->assertTrue( $processor->next_tag( 'div' ), 'Querying an existing tag did not return true' );
+ $this->assertSame( 'test', $processor->get_attribute( 'class' ), 'Accessing a class="test" attribute value did not return "test"' );
}
/**
@@ -167,10 +167,10 @@ public function test_get_attribute_returns_attribute_value() {
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_returns_true_for_boolean_attribute() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertTrue( $p->next_tag( array( 'class_name' => 'test' ) ), 'Querying an existing tag did not return true' );
- $this->assertTrue( $p->get_attribute( 'enabled' ), 'Accessing a boolean "enabled" attribute value did not return true' );
+ $this->assertTrue( $processor->next_tag( array( 'class_name' => 'test' ) ), 'Querying an existing tag did not return true' );
+ $this->assertTrue( $processor->get_attribute( 'enabled' ), 'Accessing a boolean "enabled" attribute value did not return true' );
}
/**
@@ -179,12 +179,12 @@ public function test_get_attribute_returns_true_for_boolean_attribute() {
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_returns_string_for_truthy_attributes() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertTrue( $p->next_tag(), 'Querying an existing tag did not return true' );
- $this->assertSame( 'enabled', $p->get_attribute( 'enabled' ), 'Accessing a boolean "enabled" attribute value did not return true' );
- $this->assertSame( '1', $p->get_attribute( 'checked' ), 'Accessing a checked=1 attribute value did not return "1"' );
- $this->assertSame( 'true', $p->get_attribute( 'hidden' ), 'Accessing a hidden="true" attribute value did not return "true"' );
+ $this->assertTrue( $processor->next_tag(), 'Querying an existing tag did not return true' );
+ $this->assertSame( 'enabled', $processor->get_attribute( 'enabled' ), 'Accessing a boolean "enabled" attribute value did not return true' );
+ $this->assertSame( '1', $processor->get_attribute( 'checked' ), 'Accessing a checked=1 attribute value did not return "1"' );
+ $this->assertSame( 'true', $processor->get_attribute( 'hidden' ), 'Accessing a hidden="true" attribute value did not return "true"' );
}
/**
@@ -193,10 +193,10 @@ public function test_get_attribute_returns_string_for_truthy_attributes() {
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_decodes_html_character_references() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag();
- $this->assertSame( 'the "grande" is < 32oz†', $p->get_attribute( 'id' ), 'HTML Attribute value was returned without decoding character references' );
+ $this->assertSame( 'the "grande" is < 32oz†', $processor->get_attribute( 'id' ), 'HTML Attribute value was returned without decoding character references' );
}
/**
@@ -205,14 +205,14 @@ public function test_get_attribute_decodes_html_character_references() {
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_attributes_parser_treats_slash_as_attribute_separator() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
- $this->assertTrue( $p->next_tag(), 'Querying an existing tag did not return true' );
- $this->assertTrue( $p->get_attribute( 'a' ), 'Accessing an existing attribute did not return true' );
- $this->assertTrue( $p->get_attribute( 'b' ), 'Accessing an existing attribute did not return true' );
- $this->assertTrue( $p->get_attribute( 'c' ), 'Accessing an existing attribute did not return true' );
- $this->assertTrue( $p->get_attribute( 'd' ), 'Accessing an existing attribute did not return true' );
- $this->assertSame( 'test', $p->get_attribute( 'e' ), 'Accessing an existing e="test" did not return "test"' );
+ $this->assertTrue( $processor->next_tag(), 'Querying an existing tag did not return true' );
+ $this->assertTrue( $processor->get_attribute( 'a' ), 'Accessing an existing attribute did not return true' );
+ $this->assertTrue( $processor->get_attribute( 'b' ), 'Accessing an existing attribute did not return true' );
+ $this->assertTrue( $processor->get_attribute( 'c' ), 'Accessing an existing attribute did not return true' );
+ $this->assertTrue( $processor->get_attribute( 'd' ), 'Accessing an existing attribute did not return true' );
+ $this->assertSame( 'test', $processor->get_attribute( 'e' ), 'Accessing an existing e="test" did not return "test"' );
}
/**
@@ -225,12 +225,12 @@ public function test_attributes_parser_treats_slash_as_attribute_separator() {
* @param string $attribute_name Name of data-enabled attribute with case variations.
*/
public function test_get_attribute_is_case_insensitive_for_attributes_with_values( $attribute_name ) {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
$this->assertSame(
'true',
- $p->get_attribute( $attribute_name ),
+ $processor->get_attribute( $attribute_name ),
'Accessing an attribute by a differently-cased name did not return its value'
);
}
@@ -245,11 +245,11 @@ public function test_get_attribute_is_case_insensitive_for_attributes_with_value
* @param string $attribute_name Name of data-enabled attribute with case variations.
*/
public function test_attributes_parser_is_case_insensitive_for_attributes_without_values( $attribute_name ) {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
$this->assertTrue(
- $p->get_attribute( $attribute_name ),
+ $processor->get_attribute( $attribute_name ),
'Accessing an attribute by a differently-cased name did not return its value'
);
}
@@ -259,7 +259,7 @@ public function test_attributes_parser_is_case_insensitive_for_attributes_withou
*
* @return array[].
*/
- public function data_attribute_name_case_variants() {
+ public static function data_attribute_name_case_variants() {
return array(
array( 'DATA-enabled' ),
array( 'data-enabled' ),
@@ -274,11 +274,11 @@ public function data_attribute_name_case_variants() {
* @covers WP_HTML_Tag_Processor::remove_attribute
*/
public function test_remove_attribute_is_case_insensitive() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
- $p->remove_attribute( 'data-enabled' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
+ $processor->remove_attribute( 'data-enabled' );
- $this->assertSame( '
Test
', $p->get_updated_html(), 'A case-insensitive remove_attribute call did not remove the attribute' );
+ $this->assertSame( '
Test
', $processor->get_updated_html(), 'A case-insensitive remove_attribute call did not remove the attribute' );
}
/**
@@ -287,11 +287,11 @@ public function test_remove_attribute_is_case_insensitive() {
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_set_attribute_is_case_insensitive() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
- $p->set_attribute( 'data-enabled', 'abc' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
+ $processor->set_attribute( 'data-enabled', 'abc' );
- $this->assertSame( '
Test
', $p->get_updated_html(), 'A case-insensitive set_attribute call did not update the existing attribute' );
+ $this->assertSame( '
Test
', $processor->get_updated_html(), 'A case-insensitive set_attribute call did not update the existing attribute' );
}
/**
@@ -300,9 +300,9 @@ public function test_set_attribute_is_case_insensitive() {
* @covers WP_HTML_Tag_Processor::get_attribute_names_with_prefix
*/
public function test_get_attribute_names_with_prefix_returns_null_before_finding_tags() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
$this->assertNull(
- $p->get_attribute_names_with_prefix( 'data-' ),
+ $processor->get_attribute_names_with_prefix( 'data-' ),
'Accessing attributes by their prefix did not return null when no tag was selected'
);
}
@@ -313,9 +313,9 @@ public function test_get_attribute_names_with_prefix_returns_null_before_finding
* @covers WP_HTML_Tag_Processor::get_attribute_names_with_prefix
*/
public function test_get_attribute_names_with_prefix_returns_null_when_not_in_open_tag() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag( 'p' );
- $this->assertNull( $p->get_attribute_names_with_prefix( 'data-' ), 'Accessing attributes of a non-existing tag did not return null' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag( 'p' );
+ $this->assertNull( $processor->get_attribute_names_with_prefix( 'data-' ), 'Accessing attributes of a non-existing tag did not return null' );
}
/**
@@ -324,11 +324,11 @@ public function test_get_attribute_names_with_prefix_returns_null_when_not_in_op
* @covers WP_HTML_Tag_Processor::get_attribute_names_with_prefix
*/
public function test_get_attribute_names_with_prefix_returns_null_when_in_closing_tag() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag( 'div' );
- $p->next_tag( array( 'tag_closers' => 'visit' ) );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag( 'div' );
+ $processor->next_tag( array( 'tag_closers' => 'visit' ) );
- $this->assertNull( $p->get_attribute_names_with_prefix( 'data-' ), 'Accessing attributes of a closing tag did not return null' );
+ $this->assertNull( $processor->get_attribute_names_with_prefix( 'data-' ), 'Accessing attributes of a closing tag did not return null' );
}
/**
@@ -337,10 +337,10 @@ public function test_get_attribute_names_with_prefix_returns_null_when_in_closin
* @covers WP_HTML_Tag_Processor::get_attribute_names_with_prefix
*/
public function test_get_attribute_names_with_prefix_returns_empty_array_when_no_attributes_present() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag( 'div' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag( 'div' );
- $this->assertSame( array(), $p->get_attribute_names_with_prefix( 'data-' ), 'Accessing the attributes on a tag without any did not return an empty array' );
+ $this->assertSame( array(), $processor->get_attribute_names_with_prefix( 'data-' ), 'Accessing the attributes on a tag without any did not return an empty array' );
}
/**
@@ -349,12 +349,12 @@ public function test_get_attribute_names_with_prefix_returns_empty_array_when_no
* @covers WP_HTML_Tag_Processor::get_attribute_names_with_prefix
*/
public function test_get_attribute_names_with_prefix_returns_matching_attribute_names_in_lowercase() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
$this->assertSame(
array( 'data-enabled', 'data-test-id' ),
- $p->get_attribute_names_with_prefix( 'data-' ),
+ $processor->get_attribute_names_with_prefix( 'data-' ),
'Accessing attributes by their prefix did not return their lowercase names'
);
}
@@ -365,18 +365,18 @@ public function test_get_attribute_names_with_prefix_returns_matching_attribute_
* @covers WP_HTML_Tag_Processor::get_attribute_names_with_prefix
*/
public function test_get_attribute_names_with_prefix_returns_attribute_added_by_set_attribute() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
- $p->set_attribute( 'data-test-id', '14' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
+ $processor->set_attribute( 'data-test-id', '14' );
$this->assertSame(
'
Test
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
"Updated HTML doesn't include attribute added via set_attribute"
);
$this->assertSame(
array( 'data-test-id', 'data-foo' ),
- $p->get_attribute_names_with_prefix( 'data-' ),
+ $processor->get_attribute_names_with_prefix( 'data-' ),
"Accessing attribute names doesn't find attribute added via set_attribute"
);
}
@@ -387,17 +387,17 @@ public function test_get_attribute_names_with_prefix_returns_attribute_added_by_
* @covers WP_HTML_Tag_Processor::__toString
*/
public function test_to_string_returns_updated_html() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
- $p->remove_attribute( 'id' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
+ $processor->remove_attribute( 'id' );
- $p->next_tag();
- $p->set_attribute( 'id', 'div-id-1' );
- $p->add_class( 'new_class_1' );
+ $processor->next_tag();
+ $processor->set_attribute( 'id', 'div-id-1' );
+ $processor->add_class( 'new_class_1' );
$this->assertSame(
- $p->get_updated_html(),
- (string) $p,
+ $processor->get_updated_html(),
+ (string) $processor,
'get_updated_html() returned a different value than __toString()'
);
}
@@ -408,35 +408,35 @@ public function test_to_string_returns_updated_html() {
* @covers WP_HTML_Tag_Processor::get_updated_html
*/
public function test_get_updated_html_applies_the_updates_so_far_and_keeps_the_processor_on_the_current_tag() {
- $p = new WP_HTML_Tag_Processor( '
Test
' );
- $p->next_tag();
- $p->remove_attribute( 'id' );
+ $processor = new WP_HTML_Tag_Processor( '
Test
' );
+ $processor->next_tag();
+ $processor->remove_attribute( 'id' );
- $p->next_tag();
- $p->set_attribute( 'id', 'div-id-1' );
- $p->add_class( 'new_class_1' );
+ $processor->next_tag();
+ $processor->set_attribute( 'id', 'div-id-1' );
+ $processor->add_class( 'new_class_1' );
$this->assertSame(
'
Test
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Calling get_updated_html after updating the attributes of the second tag returned different HTML than expected'
);
- $p->set_attribute( 'id', 'div-id-2' );
- $p->add_class( 'new_class_2' );
+ $processor->set_attribute( 'id', 'div-id-2' );
+ $processor->add_class( 'new_class_2' );
$this->assertSame(
'
Test
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Calling get_updated_html after updating the attributes of the second tag for the second time returned different HTML than expected'
);
- $p->next_tag();
- $p->remove_attribute( 'id' );
+ $processor->next_tag();
+ $processor->remove_attribute( 'id' );
$this->assertSame(
'
Test
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Calling get_updated_html after removing the id attribute of the third tag returned different HTML than expected'
);
}
@@ -447,11 +447,11 @@ public function test_get_updated_html_applies_the_updates_so_far_and_keeps_the_p
* @covers WP_HTML_Tag_Processor::get_updated_html
*/
public function test_get_updated_html_without_updating_any_attributes_returns_the_original_html() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
$this->assertSame(
self::HTML_SIMPLE,
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Casting WP_HTML_Tag_Processor to a string without performing any updates did not return the initial HTML snippet'
);
}
@@ -463,17 +463,17 @@ public function test_get_updated_html_without_updating_any_attributes_returns_th
* @ticket 58160
*/
public function test_get_updated_html_applies_updates_to_content_after_seeking_to_before_parsed_bytes() {
- $p = new WP_HTML_Tag_Processor( '
' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
- $p->set_attribute( 'wonky', true );
- $p->next_tag();
- $p->set_bookmark( 'here' );
+ $processor->next_tag();
+ $processor->set_attribute( 'wonky', true );
+ $processor->next_tag();
+ $processor->set_bookmark( 'here' );
- $p->next_tag( array( 'tag_closers' => 'visit' ) );
- $p->seek( 'here' );
+ $processor->next_tag( array( 'tag_closers' => 'visit' ) );
+ $processor->seek( 'here' );
- $this->assertSame( '
', $p->get_updated_html() );
+ $this->assertSame( '
', $processor->get_updated_html() );
}
/**
@@ -482,9 +482,9 @@ public function test_get_updated_html_applies_updates_to_content_after_seeking_t
* @covers WP_HTML_Tag_Processor::next_tag
*/
public function test_next_tag_with_no_arguments_should_find_the_next_existing_tag() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $this->assertTrue( $p->next_tag(), 'Querying an existing tag did not return true' );
+ $this->assertTrue( $processor->next_tag(), 'Querying an existing tag did not return true' );
}
/**
@@ -493,9 +493,9 @@ public function test_next_tag_with_no_arguments_should_find_the_next_existing_ta
* @covers WP_HTML_Tag_Processor::next_tag
*/
public function test_next_tag_should_return_false_for_a_non_existing_tag() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $this->assertFalse( $p->next_tag( 'p' ), 'Querying a non-existing tag did not return false' );
+ $this->assertFalse( $processor->next_tag( 'p' ), 'Querying a non-existing tag did not return false' );
}
/**
@@ -504,9 +504,9 @@ public function test_next_tag_should_return_false_for_a_non_existing_tag() {
* @covers WP_HTML_Tag_Processor::next_tag
*/
public function test_next_tag_matches_decoded_class_names() {
- $p = new WP_HTML_Tag_Processor( '
' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
- $this->assertTrue( $p->next_tag( array( 'class_name' => '
' ) ), 'Failed to find tag with HTML-encoded class name.' );
+ $this->assertTrue( $processor->next_tag( array( 'class_name' => '' ) ), 'Failed to find tag with HTML-encoded class name.' );
}
/**
@@ -517,22 +517,22 @@ public function test_next_tag_matches_decoded_class_names() {
* @covers WP_HTML_Tag_Processor::is_tag_closer
*/
public function test_next_tag_should_stop_on_closers_only_when_requested() {
- $p = new WP_HTML_Tag_Processor( ' ' );
+ $processor = new WP_HTML_Tag_Processor( ' ' );
- $this->assertTrue( $p->next_tag( array( 'tag_name' => 'div' ) ), 'Did not find desired tag opener' );
- $this->assertFalse( $p->next_tag( array( 'tag_name' => 'div' ) ), 'Visited an unwanted tag, a tag closer' );
+ $this->assertTrue( $processor->next_tag( array( 'tag_name' => 'div' ) ), 'Did not find desired tag opener' );
+ $this->assertFalse( $processor->next_tag( array( 'tag_name' => 'div' ) ), 'Visited an unwanted tag, a tag closer' );
- $p = new WP_HTML_Tag_Processor( ' ' );
- $p->next_tag(
+ $processor = new WP_HTML_Tag_Processor( ' ' );
+ $processor->next_tag(
array(
'tag_name' => 'div',
'tag_closers' => 'visit',
)
);
- $this->assertFalse( $p->is_tag_closer(), 'Indicated a tag opener is a tag closer' );
+ $this->assertFalse( $processor->is_tag_closer(), 'Indicated a tag opener is a tag closer' );
$this->assertTrue(
- $p->next_tag(
+ $processor->next_tag(
array(
'tag_name' => 'div',
'tag_closers' => 'visit',
@@ -540,11 +540,11 @@ public function test_next_tag_should_stop_on_closers_only_when_requested() {
),
'Did not stop at desired tag closer'
);
- $this->assertTrue( $p->is_tag_closer(), 'Indicated a tag closer is a tag opener' );
+ $this->assertTrue( $processor->is_tag_closer(), 'Indicated a tag closer is a tag opener' );
- $p = new WP_HTML_Tag_Processor( '' );
- $this->assertTrue( $p->next_tag( array( 'tag_closers' => 'visit' ) ), "Did not find a tag opener when tag_closers was set to 'visit'" );
- $this->assertFalse( $p->next_tag( array( 'tag_closers' => 'visit' ) ), "Found a closer where there wasn't one" );
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $this->assertTrue( $processor->next_tag( array( 'tag_closers' => 'visit' ) ), "Did not find a tag opener when tag_closers was set to 'visit'" );
+ $this->assertFalse( $processor->next_tag( array( 'tag_closers' => 'visit' ) ), "Found a closer where there wasn't one" );
}
/**
@@ -554,32 +554,38 @@ public function test_next_tag_should_stop_on_closers_only_when_requested() {
* @covers WP_HTML_Tag_Processor::is_tag_closer
*/
public function test_next_tag_should_stop_on_rcdata_and_script_tag_closers_when_requested() {
- $p = new WP_HTML_Tag_Processor( '' );
+ $processor = new WP_HTML_Tag_Processor( '' );
- $p->next_tag();
- $this->assertTrue( $p->next_tag( array( 'tag_closers' => 'visit' ) ), 'Did not find the tag closer' );
- $this->assertTrue( $p->is_tag_closer(), 'Indicated a ' );
- $this->assertTrue( $p->next_tag( array( 'tag_closers' => 'visit' ) ), 'Did not find the tag closer when there was no tag opener' );
+ $processor = new WP_HTML_Tag_Processor( 'abc' );
+ $this->assertTrue( $processor->next_tag( array( 'tag_closers' => 'visit' ) ), 'Did not find the tag closer when there was no tag opener' );
- $p = new WP_HTML_Tag_Processor( '
' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
- $this->assertTrue( $p->next_tag( array( 'tag_closers' => 'visit' ) ), 'Did not find the tag closer' );
- $this->assertTrue( $p->is_tag_closer(), 'Indicated a
' );
- $this->assertTrue( $p->next_tag( array( 'tag_closers' => 'visit' ) ), 'Did not find the tag closer when there was no tag opener' );
+ $processor = new WP_HTML_Tag_Processor( 'abc' );
+ $this->assertTrue( $processor->next_tag( array( 'tag_closers' => 'visit' ) ), 'Did not find the tag closer when there was no tag opener' );
- $p = new WP_HTML_Tag_Processor( '
abc ' );
+ $processor = new WP_HTML_Tag_Processor( '
abc ' );
- $p->next_tag();
- $this->assertTrue( $p->next_tag( array( 'tag_closers' => 'visit' ) ), 'Did not find the tag closer' );
- $this->assertTrue( $p->is_tag_closer(), 'Indicated a
tag opener is a tag closer' );
+ $processor->next_tag();
+ $this->assertFalse(
+ $processor->next_tag( array( 'tag_closers' => 'visit' ) ),
+ 'Should not have found closing TITLE when closing an opener.'
+ );
- $p = new WP_HTML_Tag_Processor( 'abc ' );
- $this->assertTrue( $p->next_tag( array( 'tag_closers' => 'visit' ) ), 'Did not find the tag closer when there was no tag opener' );
+ $processor = new WP_HTML_Tag_Processor( 'abc' );
+ $this->assertTrue( $processor->next_tag( array( 'tag_closers' => 'visit' ) ), 'Did not find the tag closer when there was no tag opener' );
}
/**
@@ -614,16 +620,16 @@ public function test_internal_pointer_returns_to_original_spot_after_inserting_c
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_set_attribute_on_a_non_existing_tag_does_not_change_the_markup() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $this->assertFalse( $p->next_tag( 'p' ), 'Querying a non-existing tag did not return false' );
- $this->assertFalse( $p->next_tag( 'div' ), 'Querying a non-existing tag did not return false' );
+ $this->assertFalse( $processor->next_tag( 'p' ), 'Querying a non-existing tag did not return false' );
+ $this->assertFalse( $processor->next_tag( 'div' ), 'Querying a non-existing tag did not return false' );
- $p->set_attribute( 'id', 'primary' );
+ $processor->set_attribute( 'id', 'primary' );
$this->assertSame(
self::HTML_SIMPLE,
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Calling get_updated_html after updating a non-existing tag returned an HTML that was different from the original HTML'
);
}
@@ -637,31 +643,31 @@ public function test_set_attribute_on_a_non_existing_tag_does_not_change_the_mar
* @covers WP_HTML_Tag_Processor::remove_class
*/
public function test_attribute_ops_on_tag_closer_do_not_change_the_markup() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag(
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag(
array(
'tag_name' => 'div',
'tag_closers' => 'visit',
)
);
- $this->assertFalse( $p->is_tag_closer(), 'Skipped tag opener' );
+ $this->assertFalse( $processor->is_tag_closer(), 'Skipped tag opener' );
- $p->next_tag(
+ $processor->next_tag(
array(
'tag_name' => 'div',
'tag_closers' => 'visit',
)
);
- $this->assertTrue( $p->is_tag_closer(), 'Skipped tag closer' );
- $this->assertFalse( $p->set_attribute( 'id', 'test' ), "Allowed setting an attribute on a tag closer when it shouldn't have" );
- $this->assertFalse( $p->remove_attribute( 'invalid-id' ), "Allowed removing an attribute on a tag closer when it shouldn't have" );
- $this->assertFalse( $p->add_class( 'sneaky' ), "Allowed adding a class on a tag closer when it shouldn't have" );
- $this->assertFalse( $p->remove_class( 'not-appearing-in-this-test' ), "Allowed removing a class on a tag closer when it shouldn't have" );
+ $this->assertTrue( $processor->is_tag_closer(), 'Skipped tag closer' );
+ $this->assertFalse( $processor->set_attribute( 'id', 'test' ), "Allowed setting an attribute on a tag closer when it shouldn't have" );
+ $this->assertFalse( $processor->remove_attribute( 'invalid-id' ), "Allowed removing an attribute on a tag closer when it shouldn't have" );
+ $this->assertFalse( $processor->add_class( 'sneaky' ), "Allowed adding a class on a tag closer when it shouldn't have" );
+ $this->assertFalse( $processor->remove_class( 'not-appearing-in-this-test' ), "Allowed removing a class on a tag closer when it shouldn't have" );
$this->assertSame(
'
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Calling get_updated_html after updating a non-existing tag returned an HTML that was different from the original HTML'
);
}
@@ -670,9 +676,9 @@ public function test_attribute_ops_on_tag_closer_do_not_change_the_markup() {
* Passing a double quote inside of an attribute value could lead to an XSS attack as follows:
*
* ```php
- * $p = new WP_HTML_Tag_Processor( '' );
- * $p->next_tag();
- * $p->set_attribute('class', '" onclick="alert');
+ * $processor = new WP_HTML_Tag_Processor( '' );
+ * $processor->next_tag();
+ * $processor->set_attribute('class', '" onclick="alert');
* echo $p;
* //
* ```
@@ -691,9 +697,9 @@ public function test_attribute_ops_on_tag_closer_do_not_change_the_markup() {
* @param string $attribute_value A value with potential XSS exploit.
*/
public function test_set_attribute_prevents_xss( $attribute_value ) {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
- $p->set_attribute( 'test', $attribute_value );
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag();
+ $processor->set_attribute( 'test', $attribute_value );
/*
* Testing the escaping is hard using tools that properly parse
@@ -707,7 +713,7 @@ public function test_set_attribute_prevents_xss( $attribute_value ) {
* content and (b) looks at the raw values.
*/
$match = null;
- preg_match( '~^
$~', $p->get_updated_html(), $match );
+ preg_match( '~^
$~', $processor->get_updated_html(), $match );
list( , $actual_value ) = $match;
$this->assertSame( '"' . esc_attr( $attribute_value ) . '"', $actual_value, 'Entities were not properly escaped in the attribute value' );
@@ -718,7 +724,7 @@ public function test_set_attribute_prevents_xss( $attribute_value ) {
*
* @return string[][].
*/
- public function data_set_attribute_prevents_xss() {
+ public static function data_set_attribute_prevents_xss() {
return array(
array( '"' ),
array( '"' ),
@@ -738,18 +744,18 @@ public function data_set_attribute_prevents_xss() {
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_set_attribute_with_a_non_existing_attribute_adds_a_new_attribute_to_the_markup() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->set_attribute( 'test-attribute', 'test-value' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->set_attribute( 'test-attribute', 'test-value' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not include attribute added via set_attribute()'
);
$this->assertSame(
'test-value',
- $p->get_attribute( 'test-attribute' ),
+ $processor->get_attribute( 'test-attribute' ),
'get_attribute() (called after get_updated_html()) did not return attribute added via set_attribute()'
);
}
@@ -760,18 +766,18 @@ public function test_set_attribute_with_a_non_existing_attribute_adds_a_new_attr
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_returns_updated_values_before_they_are_applied() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->set_attribute( 'test-attribute', 'test-value' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->set_attribute( 'test-attribute', 'test-value' );
$this->assertSame(
'test-value',
- $p->get_attribute( 'test-attribute' ),
+ $processor->get_attribute( 'test-attribute' ),
'get_attribute() (called before get_updated_html()) did not return attribute added via set_attribute()'
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not include attribute added via set_attribute()'
);
}
@@ -782,18 +788,18 @@ public function test_get_attribute_returns_updated_values_before_they_are_applie
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_returns_updated_values_before_they_are_applied_with_different_name_casing() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->set_attribute( 'test-ATTribute', 'test-value' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->set_attribute( 'test-ATTribute', 'test-value' );
$this->assertSame(
'test-value',
- $p->get_attribute( 'test-attribute' ),
+ $processor->get_attribute( 'test-attribute' ),
'get_attribute() (called before get_updated_html()) did not return attribute added via set_attribute()'
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not include attribute added via set_attribute()'
);
}
@@ -804,18 +810,18 @@ public function test_get_attribute_returns_updated_values_before_they_are_applie
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_reflects_added_class_names_before_they_are_applied() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->add_class( 'my-class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->add_class( 'my-class' );
$this->assertSame(
'my-class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
'get_attribute() (called before get_updated_html()) did not return class name added via add_class()'
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not include class name added via add_class()'
);
}
@@ -826,26 +832,26 @@ public function test_get_attribute_reflects_added_class_names_before_they_are_ap
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_reflects_added_class_names_before_they_are_applied_and_retains_classes_from_previous_add_class_calls() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->add_class( 'my-class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->add_class( 'my-class' );
$this->assertSame(
'my-class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
'get_attribute() (called before get_updated_html()) did not return class name added via add_class()'
);
- $p->add_class( 'my-other-class' );
+ $processor->add_class( 'my-other-class' );
$this->assertSame(
'my-class my-other-class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
'get_attribute() (called before get_updated_html()) did not return class names added via subsequent add_class() calls'
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not include class names added via subsequent add_class() calls'
);
}
@@ -856,17 +862,17 @@ public function test_get_attribute_reflects_added_class_names_before_they_are_ap
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_reflects_removed_attribute_before_it_is_applied() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->remove_attribute( 'id' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->remove_attribute( 'id' );
$this->assertNull(
- $p->get_attribute( 'id' ),
+ $processor->get_attribute( 'id' ),
'get_attribute() (called before get_updated_html()) returned attribute that was removed by remove_attribute()'
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML includes attribute that was removed by remove_attribute()'
);
}
@@ -877,18 +883,18 @@ public function test_get_attribute_reflects_removed_attribute_before_it_is_appli
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_reflects_adding_and_then_removing_an_attribute_before_those_updates_are_applied() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->set_attribute( 'test-attribute', 'test-value' );
- $p->remove_attribute( 'test-attribute' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->set_attribute( 'test-attribute', 'test-value' );
+ $processor->remove_attribute( 'test-attribute' );
$this->assertNull(
- $p->get_attribute( 'test-attribute' ),
+ $processor->get_attribute( 'test-attribute' ),
'get_attribute() (called before get_updated_html()) returned attribute that was added via set_attribute() and then removed by remove_attribute()'
);
$this->assertSame(
self::HTML_SIMPLE,
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML includes attribute that was added via set_attribute() and then removed by remove_attribute()'
);
}
@@ -899,18 +905,18 @@ public function test_get_attribute_reflects_adding_and_then_removing_an_attribut
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_reflects_setting_and_then_removing_an_existing_attribute_before_those_updates_are_applied() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->set_attribute( 'id', 'test-value' );
- $p->remove_attribute( 'id' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->set_attribute( 'id', 'test-value' );
+ $processor->remove_attribute( 'id' );
$this->assertNull(
- $p->get_attribute( 'id' ),
+ $processor->get_attribute( 'id' ),
'get_attribute() (called before get_updated_html()) returned attribute that was overwritten by set_attribute() and then removed by remove_attribute()'
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML includes attribute that was overwritten by set_attribute() and then removed by remove_attribute()'
);
}
@@ -921,18 +927,18 @@ public function test_get_attribute_reflects_setting_and_then_removing_an_existin
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_reflects_removed_class_names_before_they_are_applied() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->remove_class( 'with-border' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->remove_class( 'with-border' );
$this->assertSame(
'main',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
'get_attribute() (called before get_updated_html()) returned the wrong attribute after calling remove_attribute()'
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML includes wrong attribute after calling remove_attribute()'
);
}
@@ -943,19 +949,19 @@ public function test_get_attribute_reflects_removed_class_names_before_they_are_
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_reflects_setting_and_then_removing_a_class_name_before_those_updates_are_applied() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->add_class( 'foo-class' );
- $p->remove_class( 'foo-class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->add_class( 'foo-class' );
+ $processor->remove_class( 'foo-class' );
$this->assertSame(
'main with-border',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
'get_attribute() (called before get_updated_html()) returned class name that was added via add_class() and then removed by remove_class()'
);
$this->assertSame(
self::HTML_WITH_CLASSES,
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML includes class that was added via add_class() and then removed by remove_class()'
);
}
@@ -966,19 +972,19 @@ public function test_get_attribute_reflects_setting_and_then_removing_a_class_na
* @covers WP_HTML_Tag_Processor::get_attribute
*/
public function test_get_attribute_reflects_duplicating_and_then_removing_an_existing_class_name_before_those_updates_are_applied() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->add_class( 'with-border' );
- $p->remove_class( 'with-border' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->add_class( 'with-border' );
+ $processor->remove_class( 'with-border' );
$this->assertSame(
'main',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
'get_attribute() (called before get_updated_html()) returned class name that was duplicated via add_class() and then removed by remove_class()'
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML includes class that was duplicated via add_class() and then removed by remove_class()'
);
}
@@ -992,13 +998,13 @@ public function test_get_attribute_reflects_duplicating_and_then_removing_an_exi
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_update_first_attribute_when_duplicated_attributes_exist() {
- $p = new WP_HTML_Tag_Processor( '
Text
' );
- $p->next_tag();
- $p->set_attribute( 'id', 'updated-id' );
+ $processor = new WP_HTML_Tag_Processor( '
Text
' );
+ $processor->next_tag();
+ $processor->set_attribute( 'id', 'updated-id' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Proper (first) appearance of attribute was not updated when duplicates exist'
);
}
@@ -1009,12 +1015,12 @@ public function test_update_first_attribute_when_duplicated_attributes_exist() {
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_set_attribute_with_an_existing_attribute_name_updates_its_value_in_the_markup() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->set_attribute( 'id', 'new-id' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->set_attribute( 'id', 'new-id' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Existing attribute was not updated'
);
}
@@ -1028,13 +1034,13 @@ public function test_set_attribute_with_an_existing_attribute_name_updates_its_v
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_set_attribute_with_case_variants_updates_only_the_original_first_copy() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
- $p->set_attribute( 'DATA-ENABLED', 'canary' );
- $p->set_attribute( 'Data-Enabled', 'canary' );
- $p->set_attribute( 'dATa-EnABled', 'canary' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag();
+ $processor->set_attribute( 'DATA-ENABLED', 'canary' );
+ $processor->set_attribute( 'Data-Enabled', 'canary' );
+ $processor->set_attribute( 'dATa-EnABled', 'canary' );
- $this->assertSame( '
', strtolower( $p->get_updated_html() ) );
+ $this->assertSame( '
', strtolower( $processor->get_updated_html() ) );
}
/**
@@ -1044,14 +1050,14 @@ public function test_set_attribute_with_case_variants_updates_only_the_original_
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_next_tag_and_set_attribute_in_a_loop_update_all_tags_in_the_markup() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- while ( $p->next_tag() ) {
- $p->set_attribute( 'data-foo', 'bar' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ while ( $processor->next_tag() ) {
+ $processor->set_attribute( 'data-foo', 'bar' );
}
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Not all tags were updated when looping with next_tag() and set_attribute()'
);
}
@@ -1067,13 +1073,13 @@ public function test_next_tag_and_set_attribute_in_a_loop_update_all_tags_in_the
* @covers WP_HTML_Tag_Processor::remove_attribute
*/
public function test_remove_first_when_duplicated_attribute() {
- $p = new WP_HTML_Tag_Processor( '
Text
' );
- $p->next_tag();
- $p->remove_attribute( 'id' );
+ $processor = new WP_HTML_Tag_Processor( '
Text
' );
+ $processor->next_tag();
+ $processor->remove_attribute( 'id' );
$this->assertStringNotContainsString(
'update-me',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'First attribute (when duplicates exist) was not removed'
);
}
@@ -1084,13 +1090,13 @@ public function test_remove_first_when_duplicated_attribute() {
* @covers WP_HTML_Tag_Processor::remove_attribute
*/
public function test_remove_attribute_with_an_existing_attribute_name_removes_it_from_the_markup() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->remove_attribute( 'id' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->remove_attribute( 'id' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Attribute was not removed'
);
}
@@ -1105,16 +1111,16 @@ public function test_remove_attribute_with_an_existing_attribute_name_removes_it
* @dataProvider data_html_with_duplicated_attributes
*/
public function test_remove_attribute_with_duplicated_attributes_removes_all_of_them( $html_with_duplicate_attributes, $attribute_to_remove ) {
- $p = new WP_HTML_Tag_Processor( $html_with_duplicate_attributes );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( $html_with_duplicate_attributes );
+ $processor->next_tag();
- $p->remove_attribute( $attribute_to_remove );
- $this->assertNull( $p->get_attribute( $attribute_to_remove ), 'Failed to remove all copies of an attribute when duplicated in modified source.' );
+ $processor->remove_attribute( $attribute_to_remove );
+ $this->assertNull( $processor->get_attribute( $attribute_to_remove ), 'Failed to remove all copies of an attribute when duplicated in modified source.' );
// Recreate a tag processor with the updated HTML after removing the attribute.
- $p = new WP_HTML_Tag_Processor( $p->get_updated_html() );
- $p->next_tag();
- $this->assertNull( $p->get_attribute( $attribute_to_remove ), 'Failed to remove all copies of duplicated attributes when getting updated HTML.' );
+ $processor = new WP_HTML_Tag_Processor( $processor->get_updated_html() );
+ $processor->next_tag();
+ $this->assertNull( $processor->get_attribute( $attribute_to_remove ), 'Failed to remove all copies of duplicated attributes when getting updated HTML.' );
}
/**
@@ -1125,12 +1131,12 @@ public function test_remove_attribute_with_duplicated_attributes_removes_all_of_
* @covers WP_HTML_Tag_Processor::remove_attribute
*/
public function test_previous_duplicated_attributes_are_not_removed_on_successive_tag_removal() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
- $p->next_tag();
- $p->remove_attribute( 'id' );
+ $processor = new WP_HTML_Tag_Processor( '' );
+ $processor->next_tag();
+ $processor->next_tag();
+ $processor->remove_attribute( 'id' );
- $this->assertSame( '', $p->get_updated_html() );
+ $this->assertSame( '', $processor->get_updated_html() );
}
/**
@@ -1140,7 +1146,7 @@ public function test_previous_duplicated_attributes_are_not_removed_on_successiv
*
* @return array[].
*/
- public function data_html_with_duplicated_attributes() {
+ public static function data_html_with_duplicated_attributes() {
return array(
'Double attributes' => array( '', 'id' ),
'Triple attributes' => array( '
', 'id' ),
@@ -1156,13 +1162,13 @@ public function data_html_with_duplicated_attributes() {
* @covers WP_HTML_Tag_Processor::remove_attribute
*/
public function test_remove_attribute_with_a_non_existing_attribute_name_does_not_change_the_markup() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->remove_attribute( 'no-such-attribute' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->remove_attribute( 'no-such-attribute' );
$this->assertSame(
self::HTML_SIMPLE,
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Content was changed when attempting to remove an attribute that did not exist'
);
}
@@ -1173,18 +1179,18 @@ public function test_remove_attribute_with_a_non_existing_attribute_name_does_no
* @covers WP_HTML_Tag_Processor::add_class
*/
public function test_add_class_creates_a_class_attribute_when_there_is_none() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->add_class( 'foo-class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->add_class( 'foo-class' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not include class name added via add_class()'
);
$this->assertSame(
'foo-class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) did not return class name added via add_class()"
);
}
@@ -1195,19 +1201,19 @@ public function test_add_class_creates_a_class_attribute_when_there_is_none() {
* @covers WP_HTML_Tag_Processor::add_class
*/
public function test_calling_add_class_twice_creates_a_class_attribute_with_both_class_names_when_there_is_no_class_attribute() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->add_class( 'foo-class' );
- $p->add_class( 'bar-class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->add_class( 'foo-class' );
+ $processor->add_class( 'bar-class' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not include class names added via subsequent add_class() calls'
);
$this->assertSame(
'foo-class bar-class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) did not return class names added via subsequent add_class() calls"
);
}
@@ -1218,17 +1224,17 @@ public function test_calling_add_class_twice_creates_a_class_attribute_with_both
* @covers WP_HTML_Tag_Processor::remove_class
*/
public function test_remove_class_does_not_change_the_markup_when_there_is_no_class_attribute() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->remove_class( 'foo-class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->remove_class( 'foo-class' );
$this->assertSame(
self::HTML_SIMPLE,
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML includes class name that was removed by remove_class()'
);
$this->assertNull(
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) did not return null for class name that was removed by remove_class()"
);
}
@@ -1239,19 +1245,19 @@ public function test_remove_class_does_not_change_the_markup_when_there_is_no_cl
* @covers WP_HTML_Tag_Processor::add_class
*/
public function test_add_class_appends_class_names_to_the_existing_class_attribute_when_one_already_exists() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->add_class( 'foo-class' );
- $p->add_class( 'bar-class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->add_class( 'foo-class' );
+ $processor->add_class( 'bar-class' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not reflect class names added to existing class attribute via subsequent add_class() calls'
);
$this->assertSame(
'main with-border foo-class bar-class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) does not reflect class names added to existing class attribute via subsequent add_class() calls"
);
}
@@ -1262,18 +1268,18 @@ public function test_add_class_appends_class_names_to_the_existing_class_attribu
* @covers WP_HTML_Tag_Processor::remove_class
*/
public function test_remove_class_removes_a_single_class_from_the_class_attribute_when_one_exists() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->remove_class( 'main' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->remove_class( 'main' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not reflect class name removed from existing class attribute via remove_class()'
);
$this->assertSame(
' with-border',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) does not reflect class name removed from existing class attribute via remove_class()"
);
}
@@ -1284,18 +1290,18 @@ public function test_remove_class_removes_a_single_class_from_the_class_attribut
* @covers WP_HTML_Tag_Processor::remove_class
*/
public function test_calling_remove_class_with_all_listed_class_names_removes_the_existing_class_attribute_from_the_markup() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->remove_class( 'main' );
- $p->remove_class( 'with-border' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->remove_class( 'main' );
+ $processor->remove_class( 'with-border' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not reflect class attribute removed via subesequent remove_class() calls'
);
$this->assertNull(
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) did not return null for class attribute removed via subesequent remove_class() calls"
);
}
@@ -1306,18 +1312,18 @@ public function test_calling_remove_class_with_all_listed_class_names_removes_th
* @covers WP_HTML_Tag_Processor::add_class
*/
public function test_add_class_does_not_add_duplicate_class_names() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->add_class( 'with-border' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->add_class( 'with-border' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not reflect deduplicated class name added via add_class()'
);
$this->assertSame(
'main with-border',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) does not reflect deduplicated class name added via add_class()"
);
}
@@ -1328,18 +1334,18 @@ public function test_add_class_does_not_add_duplicate_class_names() {
* @covers WP_HTML_Tag_Processor::add_class
*/
public function test_add_class_preserves_class_name_order_when_a_duplicate_class_name_is_added() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->add_class( 'main' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->add_class( 'main' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not reflect class name order after adding duplicated class name via add_class()'
);
$this->assertSame(
'main with-border',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) does not reflect class name order after adding duplicated class name added via add_class()"
);
}
@@ -1350,20 +1356,20 @@ public function test_add_class_preserves_class_name_order_when_a_duplicate_class
* @covers WP_HTML_Tag_Processor::add_class
*/
public function test_add_class_when_there_is_a_class_attribute_with_excessive_whitespaces() {
- $p = new WP_HTML_Tag_Processor(
+ $processor = new WP_HTML_Tag_Processor(
'
Text
'
);
- $p->next_tag();
- $p->add_class( 'foo-class' );
+ $processor->next_tag();
+ $processor->add_class( 'foo-class' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not reflect existing excessive whitespace after adding class name via add_class()'
);
$this->assertSame(
' main with-border foo-class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) does not reflect existing excessive whitespace after adding class name via add_class()"
);
}
@@ -1374,20 +1380,20 @@ public function test_add_class_when_there_is_a_class_attribute_with_excessive_wh
* @covers WP_HTML_Tag_Processor::remove_class
*/
public function test_remove_class_preserves_whitespaces_when_there_is_a_class_attribute_with_excessive_whitespaces() {
- $p = new WP_HTML_Tag_Processor(
+ $processor = new WP_HTML_Tag_Processor(
'
Text
'
);
- $p->next_tag();
- $p->remove_class( 'with-border' );
+ $processor->next_tag();
+ $processor->remove_class( 'with-border' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not reflect existing excessive whitespace after removing class name via remove_class()'
);
$this->assertSame(
' main',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) does not reflect existing excessive whitespace after removing class name via removing_class()"
);
}
@@ -1398,19 +1404,19 @@ public function test_remove_class_preserves_whitespaces_when_there_is_a_class_at
* @covers WP_HTML_Tag_Processor::remove_class
*/
public function test_removing_all_classes_removes_the_existing_class_attribute_from_the_markup_even_when_excessive_whitespaces_are_present() {
- $p = new WP_HTML_Tag_Processor(
+ $processor = new WP_HTML_Tag_Processor(
'
Text
'
);
- $p->next_tag();
- $p->remove_class( 'main' );
- $p->remove_class( 'with-border' );
+ $processor->next_tag();
+ $processor->remove_class( 'main' );
+ $processor->remove_class( 'with-border' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Updated HTML does not reflect removed class attribute after removing all class names via remove_class()'
);
$this->assertNull(
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute( 'class' ) did not return null after removing all class names via remove_class()"
);
}
@@ -1429,33 +1435,33 @@ public function test_removing_all_classes_removes_the_existing_class_attribute_f
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_set_attribute_takes_priority_over_add_class() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->add_class( 'add_class' );
- $p->set_attribute( 'class', 'set_attribute' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->add_class( 'add_class' );
+ $processor->set_attribute( 'class', 'set_attribute' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
"Calling get_updated_html after updating first tag's attributes did not return the expected HTML"
);
$this->assertSame(
'set_attribute',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"Calling get_attribute after updating first tag's attributes did not return the expected class name"
);
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->set_attribute( 'class', 'set_attribute' );
- $p->add_class( 'add_class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->set_attribute( 'class', 'set_attribute' );
+ $processor->add_class( 'add_class' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
"Calling get_updated_html after updating first tag's attributes did not return the expected HTML"
);
$this->assertSame(
'set_attribute add_class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"Calling get_attribute after updating first tag's attributes did not return the expected class name"
);
}
@@ -1476,33 +1482,33 @@ public function test_set_attribute_takes_priority_over_add_class() {
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_set_attribute_takes_priority_over_add_class_even_before_updating() {
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->add_class( 'add_class' );
- $p->set_attribute( 'class', 'set_attribute' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->add_class( 'add_class' );
+ $processor->set_attribute( 'class', 'set_attribute' );
$this->assertSame(
'set_attribute',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"Calling get_attribute after updating first tag's attributes did not return the expected class name"
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
"Calling get_updated_html after updating first tag's attributes did not return the expected HTML"
);
- $p = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
- $p->next_tag();
- $p->set_attribute( 'class', 'set_attribute' );
- $p->add_class( 'add_class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_WITH_CLASSES );
+ $processor->next_tag();
+ $processor->set_attribute( 'class', 'set_attribute' );
+ $processor->add_class( 'add_class' );
$this->assertSame(
'set_attribute add_class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"Calling get_attribute after updating first tag's attributes did not return the expected class name"
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
"Calling get_updated_html after updating first tag's attributes did not return the expected HTML"
);
}
@@ -1513,18 +1519,18 @@ public function test_set_attribute_takes_priority_over_add_class_even_before_upd
* @covers WP_HTML_Tag_Processor::add_class
*/
public function test_add_class_overrides_boolean_class_attribute() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->set_attribute( 'class', true );
- $p->add_class( 'add_class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->set_attribute( 'class', true );
+ $processor->add_class( 'add_class' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
"Updated HTML doesn't reflect class added via add_class that was originally set as boolean attribute"
);
$this->assertSame(
'add_class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute (called after get_updated_html()) doesn't reflect class added via add_class that was originally set as boolean attribute"
);
}
@@ -1535,18 +1541,18 @@ public function test_add_class_overrides_boolean_class_attribute() {
* @covers WP_HTML_Tag_Processor::add_class
*/
public function test_add_class_overrides_boolean_class_attribute_even_before_updating() {
- $p = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
- $p->next_tag();
- $p->set_attribute( 'class', true );
- $p->add_class( 'add_class' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_SIMPLE );
+ $processor->next_tag();
+ $processor->set_attribute( 'class', true );
+ $processor->add_class( 'add_class' );
$this->assertSame(
'add_class',
- $p->get_attribute( 'class' ),
+ $processor->get_attribute( 'class' ),
"get_attribute (called before get_updated_html()) doesn't reflect class added via add_class that was originally set as boolean attribute"
);
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
"Updated HTML doesn't reflect class added via add_class that was originally set as boolean attribute"
);
}
@@ -1607,12 +1613,12 @@ public function test_advanced_use_case() {
HTML;
- $p = new WP_HTML_Tag_Processor( $input );
- $this->assertTrue( $p->next_tag( 'div' ), 'Did not find first DIV tag in input.' );
- $p->set_attribute( 'data-details', '{ "key": "value" }' );
- $p->add_class( 'is-processed' );
+ $processor = new WP_HTML_Tag_Processor( $input );
+ $this->assertTrue( $processor->next_tag( 'div' ), 'Did not find first DIV tag in input.' );
+ $processor->set_attribute( 'data-details', '{ "key": "value" }' );
+ $processor->add_class( 'is-processed' );
$this->assertTrue(
- $p->next_tag(
+ $processor->next_tag(
array(
'tag_name' => 'div',
'class_name' => 'BtnGroup',
@@ -1620,11 +1626,11 @@ public function test_advanced_use_case() {
),
'Did not find the first BtnGroup DIV tag'
);
- $p->remove_class( 'BtnGroup' );
- $p->add_class( 'button-group' );
- $p->add_class( 'Another-Mixed-Case' );
+ $processor->remove_class( 'BtnGroup' );
+ $processor->add_class( 'button-group' );
+ $processor->add_class( 'Another-Mixed-Case' );
$this->assertTrue(
- $p->next_tag(
+ $processor->next_tag(
array(
'tag_name' => 'div',
'class_name' => 'BtnGroup',
@@ -1632,11 +1638,11 @@ public function test_advanced_use_case() {
),
'Did not find the second BtnGroup DIV tag'
);
- $p->remove_class( 'BtnGroup' );
- $p->add_class( 'button-group' );
- $p->add_class( 'Another-Mixed-Case' );
+ $processor->remove_class( 'BtnGroup' );
+ $processor->add_class( 'button-group' );
+ $processor->add_class( 'Another-Mixed-Case' );
$this->assertTrue(
- $p->next_tag(
+ $processor->next_tag(
array(
'tag_name' => 'button',
'class_name' => 'btn',
@@ -1645,10 +1651,10 @@ public function test_advanced_use_case() {
),
'Did not find third BUTTON tag with "btn" CSS class'
);
- $p->remove_attribute( 'class' );
- $this->assertFalse( $p->next_tag( 'non-existent' ), "Found a {$p->get_tag()} tag when none should have been found." );
- $p->set_attribute( 'class', 'test' );
- $this->assertSame( $expected_output, $p->get_updated_html(), 'Calling get_updated_html after updating the attributes did not return the expected HTML' );
+ $processor->remove_attribute( 'class' );
+ $this->assertFalse( $processor->next_tag( 'non-existent' ), "Found a {$processor->get_tag()} tag when none should have been found." );
+ $processor->set_attribute( 'class', 'test' );
+ $this->assertSame( $expected_output, $processor->get_updated_html(), 'Calling get_updated_html after updating the attributes did not return the expected HTML' );
}
/**
@@ -1657,26 +1663,26 @@ public function test_advanced_use_case() {
* @covers WP_HTML_Tag_Processor::next_tag
*/
public function test_correctly_parses_html_attributes_wrapped_in_single_quotation_marks() {
- $p = new WP_HTML_Tag_Processor(
+ $processor = new WP_HTML_Tag_Processor(
'
Text
'
);
- $p->next_tag(
+ $processor->next_tag(
array(
'tag_name' => 'div',
'id' => 'first',
)
);
- $p->remove_attribute( 'id' );
- $p->next_tag(
+ $processor->remove_attribute( 'id' );
+ $processor->next_tag(
array(
'tag_name' => 'span',
'id' => 'second',
)
);
- $p->set_attribute( 'id', 'single-quote' );
+ $processor->set_attribute( 'id', 'single-quote' );
$this->assertSame(
'
Text
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Did not remove single-quoted attribute'
);
}
@@ -1687,14 +1693,14 @@ public function test_correctly_parses_html_attributes_wrapped_in_single_quotatio
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_set_attribute_with_value_equal_to_true_adds_a_boolean_html_attribute_with_implicit_value() {
- $p = new WP_HTML_Tag_Processor(
+ $processor = new WP_HTML_Tag_Processor(
'
'
);
- $p->next_tag( 'input' );
- $p->set_attribute( 'checked', true );
+ $processor->next_tag( 'input' );
+ $processor->set_attribute( 'checked', true );
$this->assertSame(
'
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Did not add "checked" as an expected boolean attribute'
);
}
@@ -1705,14 +1711,14 @@ public function test_set_attribute_with_value_equal_to_true_adds_a_boolean_html_
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_setting_a_boolean_attribute_to_false_removes_it_from_the_markup() {
- $p = new WP_HTML_Tag_Processor(
+ $processor = new WP_HTML_Tag_Processor(
'
'
);
- $p->next_tag( 'input' );
- $p->set_attribute( 'checked', false );
+ $processor->next_tag( 'input' );
+ $processor->set_attribute( 'checked', false );
$this->assertSame(
'
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Did not remove boolean attribute when set to false'
);
}
@@ -1724,12 +1730,12 @@ public function test_setting_a_boolean_attribute_to_false_removes_it_from_the_ma
*/
public function test_setting_a_missing_attribute_to_false_does_not_change_the_markup() {
$html_input = '
';
- $p = new WP_HTML_Tag_Processor( $html_input );
- $p->next_tag( 'input' );
- $p->set_attribute( 'checked', false );
+ $processor = new WP_HTML_Tag_Processor( $html_input );
+ $processor->next_tag( 'input' );
+ $processor->set_attribute( 'checked', false );
$this->assertSame(
$html_input,
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Changed the markup unexpectedly when setting a non-existing attribute to false'
);
}
@@ -1740,14 +1746,14 @@ public function test_setting_a_missing_attribute_to_false_does_not_change_the_ma
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_setting_a_boolean_attribute_to_a_string_value_adds_explicit_value_to_the_markup() {
- $p = new WP_HTML_Tag_Processor(
+ $processor = new WP_HTML_Tag_Processor(
'
'
);
- $p->next_tag( 'input' );
- $p->set_attribute( 'checked', 'checked' );
+ $processor->next_tag( 'input' );
+ $processor->set_attribute( 'checked', 'checked' );
$this->assertSame(
'
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Did not add string value to existing boolean attribute'
);
}
@@ -1759,18 +1765,18 @@ public function test_setting_a_boolean_attribute_to_a_string_value_adds_explicit
* @covers WP_HTML_Tag_Processor::paused_at_incomplete_token
*/
public function test_unclosed_script_tag_should_not_cause_an_infinite_loop() {
- $p = new WP_HTML_Tag_Processor( '
',
@@ -1860,11 +1866,11 @@ public function data_next_tag_ignores_script_tag_contents() {
* element after contain the "start" and "end" CSS classes.
*/
public function test_next_tag_ignores_invalid_first_character_of_tag_name_comments( $html_with_markers ) {
- $p = new WP_HTML_Tag_Processor( $html_with_markers );
- $p->next_tag( array( 'class_name' => 'start' ) );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( $html_with_markers );
+ $processor->next_tag( array( 'class_name' => 'start' ) );
+ $processor->next_tag();
- $this->assertSame( 'end', $p->get_attribute( 'class' ) );
+ $this->assertSame( 'end', $processor->get_attribute( 'class' ) );
}
/**
@@ -1872,7 +1878,7 @@ public function test_next_tag_ignores_invalid_first_character_of_tag_name_commen
*
* @return array[]
*/
- public function data_next_tag_ignores_invalid_first_character_of_tag_name_comments() {
+ public static function data_next_tag_ignores_invalid_first_character_of_tag_name_comments() {
return array(
'Invalid tag openers as normal text' => array(
'
',
@@ -1899,11 +1905,11 @@ public function data_next_tag_ignores_invalid_first_character_of_tag_name_commen
* @param string $rcdata_tag RCDATA tag.
*/
public function test_next_tag_ignores_contents_of_rcdata_tag( $rcdata_then_div, $rcdata_tag ) {
- $p = new WP_HTML_Tag_Processor( $rcdata_then_div );
- $p->next_tag();
- $this->assertSame( $rcdata_tag, $p->get_tag(), "The first found tag was not '$rcdata_tag'" );
- $p->next_tag();
- $this->assertSame( 'DIV', $p->get_tag(), "The second found tag was not 'div'" );
+ $processor = new WP_HTML_Tag_Processor( $rcdata_then_div );
+ $processor->next_tag();
+ $this->assertSame( $rcdata_tag, $processor->get_tag(), "The first found tag was not '$rcdata_tag'" );
+ $processor->next_tag();
+ $this->assertSame( 'DIV', $processor->get_tag(), "The second found tag was not 'div'" );
}
/**
@@ -1911,7 +1917,7 @@ public function test_next_tag_ignores_contents_of_rcdata_tag( $rcdata_then_div,
*
* @return array[]
*/
- public function data_next_tag_ignores_contents_of_rcdata_tag() {
+ public static function data_next_tag_ignores_contents_of_rcdata_tag() {
return array(
'simple textarea' => array(
'rcdata_then_div' => '
',
@@ -1958,10 +1964,10 @@ public function data_next_tag_ignores_contents_of_rcdata_tag() {
* @covers WP_HTML_Tag_Processor::next_tag
*/
public function test_processes_inside_of_noscript_elements() {
- $p = new WP_HTML_Tag_Processor( '
' );
+ $processor = new WP_HTML_Tag_Processor( '
' );
- $this->assertTrue( $p->next_tag( 'INPUT' ), 'Failed to find INPUT element inside NOSCRIPT element.' );
- $this->assertTrue( $p->next_tag( 'DIV' ), 'Failed to find DIV element after NOSCRIPT element.' );
+ $this->assertTrue( $processor->next_tag( 'INPUT' ), 'Failed to find INPUT element inside NOSCRIPT element.' );
+ $this->assertTrue( $processor->next_tag( 'DIV' ), 'Failed to find DIV element after NOSCRIPT element.' );
}
/**
@@ -1990,7 +1996,7 @@ public function test_next_tag_ignores_contents_of_rawtext_tags( $rawtext_element
*
* @return array[].
*/
- public function data_next_tag_ignores_contents_of_rawtext_tags() {
+ public static function data_next_tag_ignores_contents_of_rawtext_tags() {
return array(
'IFRAME' => array( '
' ),
'NOEMBED' => array( '
' ),
@@ -2006,11 +2012,11 @@ public function data_next_tag_ignores_contents_of_rawtext_tags() {
* @covers WP_HTML_Tag_Processor::class_list
*/
public function test_class_list_empty_when_missing_class() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag();
$found_classes = false;
- foreach ( $p->class_list() as $class ) {
+ foreach ( $processor->class_list() as $class ) {
$found_classes = true;
}
@@ -2023,11 +2029,11 @@ public function test_class_list_empty_when_missing_class() {
* @covers WP_HTML_Tag_Processor::class_list
*/
public function test_class_list_empty_when_class_is_boolean() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag();
$found_classes = false;
- foreach ( $p->class_list() as $class ) {
+ foreach ( $processor->class_list() as $class ) {
$found_classes = true;
}
@@ -2040,11 +2046,11 @@ public function test_class_list_empty_when_class_is_boolean() {
* @covers WP_HTML_Tag_Processor::class_list
*/
public function test_class_list_empty_when_class_is_empty() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag();
$found_classes = false;
- foreach ( $p->class_list() as $class ) {
+ foreach ( $processor->class_list() as $class ) {
$found_classes = true;
}
@@ -2057,11 +2063,11 @@ public function test_class_list_empty_when_class_is_empty() {
* @covers WP_HTML_Tag_Processor::class_list
*/
public function test_class_list_visits_each_class_in_order() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag();
$found_classes = array();
- foreach ( $p->class_list() as $class ) {
+ foreach ( $processor->class_list() as $class ) {
$found_classes[] = $class;
}
@@ -2074,11 +2080,11 @@ public function test_class_list_visits_each_class_in_order() {
* @covers WP_HTML_Tag_Processor::class_list
*/
public function test_class_list_decodes_class_names() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag();
$found_classes = array();
- foreach ( $p->class_list() as $class ) {
+ foreach ( $processor->class_list() as $class ) {
$found_classes[] = $class;
}
@@ -2091,11 +2097,11 @@ public function test_class_list_decodes_class_names() {
* @covers WP_HTML_Tag_Processor::class_list
*/
public function test_class_list_visits_unique_class_names_only_once() {
- $p = new WP_HTML_Tag_Processor( '
' );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( '
' );
+ $processor->next_tag();
$found_classes = array();
- foreach ( $p->class_list() as $class ) {
+ foreach ( $processor->class_list() as $class ) {
$found_classes[] = $class;
}
@@ -2114,13 +2120,13 @@ public function test_class_list_visits_unique_class_names_only_once() {
* @param bool $has_class Whether the sought class exists in the given HTML.
*/
public function test_has_class_handles_expected_class_name_variations( $html, $sought_class, $has_class ) {
- $p = new WP_HTML_Tag_Processor( $html );
- $p->next_tag();
+ $processor = new WP_HTML_Tag_Processor( $html );
+ $processor->next_tag();
if ( $has_class ) {
- $this->assertTrue( $p->has_class( $sought_class ), "Failed to find expected class {$sought_class}." );
+ $this->assertTrue( $processor->has_class( $sought_class ), "Failed to find expected class {$sought_class}." );
} else {
- $this->assertFalse( $p->has_class( $sought_class ), "Found class {$sought_class} when it doesn't exist." );
+ $this->assertFalse( $processor->has_class( $sought_class ), "Found class {$sought_class} when it doesn't exist." );
}
}
@@ -2129,7 +2135,7 @@ public function test_has_class_handles_expected_class_name_variations( $html, $s
*
* @return array[]
*/
- public function data_html_with_variations_of_class_values_and_sought_class_names() {
+ public static function data_html_with_variations_of_class_values_and_sought_class_names() {
return array(
'Tag without any classes' => array( '
', 'foo', false ),
'Tag with boolean class' => array( '
', 'foo', false ),
@@ -2153,16 +2159,16 @@ public function data_html_with_variations_of_class_values_and_sought_class_names
*
*/
public function test_allows_incorrectly_closed_comments() {
- $p = new WP_HTML_Tag_Processor( '
-->
' );
+ $processor = new WP_HTML_Tag_Processor( '
-->
' );
- $p->next_tag();
- $this->assertSame( 'before', $p->get_attribute( 'id' ), 'Did not find starting tag.' );
+ $processor->next_tag();
+ $this->assertSame( 'before', $processor->get_attribute( 'id' ), 'Did not find starting tag.' );
- $p->next_tag();
- $this->assertSame( 'after', $p->get_attribute( 'id' ), 'Did not properly close improperly-closed comment.' );
+ $processor->next_tag();
+ $this->assertSame( 'after', $processor->get_attribute( 'id' ), 'Did not properly close improperly-closed comment.' );
- $p->next_tag();
- $this->assertSame( 'final', $p->get_attribute( 'id' ), 'Did not skip over unopened comment-closer.' );
+ $processor->next_tag();
+ $this->assertSame( 'final', $processor->get_attribute( 'id' ), 'Did not skip over unopened comment-closer.' );
}
/**
@@ -2178,15 +2184,15 @@ public function test_allows_incorrectly_closed_comments() {
* @param string $html_ending_before_comment_close HTML with opened comments that aren't closed.
*/
public function test_documents_may_end_with_unclosed_comment( $html_ending_before_comment_close ) {
- $p = new WP_HTML_Tag_Processor( $html_ending_before_comment_close );
+ $processor = new WP_HTML_Tag_Processor( $html_ending_before_comment_close );
$this->assertFalse(
- $p->next_tag(),
- "Should not have found any tag, but found {$p->get_tag()}."
+ $processor->next_tag(),
+ "Should not have found any tag, but found {$processor->get_tag()}."
);
$this->assertTrue(
- $p->paused_at_incomplete_token(),
+ $processor->paused_at_incomplete_token(),
"Should have indicated that the parser found an incomplete token but didn't."
);
}
@@ -2196,7 +2202,7 @@ public function test_documents_may_end_with_unclosed_comment( $html_ending_befor
*
* @return array[]
*/
- public function data_html_with_unclosed_comments() {
+ public static function data_html_with_unclosed_comments() {
return array(
'Shortest open valid comment' => array( '
' ),
'Empty comment with two dashes only, improperly closed' => array( '
' ),
@@ -2256,11 +2262,11 @@ public function data_abruptly_closed_empty_comments() {
* @param $input_html HTML with multiple divs, one of which carries the "target" attribute.
*/
public function test_skips_contents_of_script_and_rcdata_regions( $input_html ) {
- $p = new WP_HTML_Tag_Processor( $input_html );
- $p->next_tag( 'div' );
+ $processor = new WP_HTML_Tag_Processor( $input_html );
+ $processor->next_tag( 'div' );
$this->assertTrue(
- $p->get_attribute( 'target' ),
+ $processor->get_attribute( 'target' ),
'Did not properly skip over script and rcdata regions; incorrectly found tags inside'
);
}
@@ -2270,7 +2276,7 @@ public function test_skips_contents_of_script_and_rcdata_regions( $input_html )
*
* @return array[]
*/
- public function data_skips_contents_of_script_and_rcdata_regions() {
+ public static function data_skips_contents_of_script_and_rcdata_regions() {
return array(
'Balanced SCRIPT tags' => array( '
' ),
'Unexpected SCRIPT closer after DIV' => array( 'console.log("
")
' ),
@@ -2289,16 +2295,16 @@ public function data_skips_contents_of_script_and_rcdata_regions() {
* @covers WP_HTML_Tag_Processor::set_attribute
*/
public function test_can_query_and_update_wrongly_nested_tags() {
- $p = new WP_HTML_Tag_Processor(
+ $processor = new WP_HTML_Tag_Processor(
'
123456
789'
);
- $p->next_tag( 'span' );
- $p->set_attribute( 'class', 'span-class' );
- $p->next_tag( 'p' );
- $p->set_attribute( 'class', 'p-class' );
+ $processor->next_tag( 'span' );
+ $processor->set_attribute( 'class', 'span-class' );
+ $processor->next_tag( 'p' );
+ $processor->set_attribute( 'class', 'p-class' );
$this->assertSame(
'
123456
789',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Did not find overlapping p tag'
);
}
@@ -2310,12 +2316,12 @@ public function test_can_query_and_update_wrongly_nested_tags() {
* @covers WP_HTML_Tag_Processor::remove_attribute
*/
public function test_removing_specific_attributes_in_malformed_html() {
- $p = new WP_HTML_Tag_Processor( self::HTML_MALFORMED );
- $p->next_tag( 'span' );
- $p->remove_attribute( 'Notifications<' );
+ $processor = new WP_HTML_Tag_Processor( self::HTML_MALFORMED );
+ $processor->next_tag( 'span' );
+ $processor->remove_attribute( 'Notifications<' );
$this->assertSame(
'
Back to notifications
',
- $p->get_updated_html(),
+ $processor->get_updated_html(),
'Did not remove "Notifications<" attribute in malformed input'
);
}
@@ -2351,12 +2357,13 @@ public function test_next_tag_returns_false_when_there_are_no_tags( $html_withou
*
* @return array[]
*/
- public function data_html_without_tags() {
+ public static function data_html_without_tags() {
return array(
'DOCTYPE declaration' => array( 'Just some HTML' ),
'No tags' => array( 'this is nothing more than a text node' ),
'Text with comments' => array( 'One comment.' ),
'Empty tag closer' => array( '>' ),
+ 'CDATA as HTML comment' => array( '' ),
'Processing instruction' => array( '' ),
'Combination XML-like' => array( '' ),
);
@@ -2375,15 +2382,15 @@ public function data_html_without_tags() {
* @param string $incomplete_html HTML text containing some kind of incomplete syntax.
*/
public function test_next_tag_returns_false_for_incomplete_syntax_elements( $incomplete_html ) {
- $p = new WP_HTML_Tag_Processor( $incomplete_html );
+ $processor = new WP_HTML_Tag_Processor( $incomplete_html );
$this->assertFalse(
- $p->next_tag(),
- "Shouldn't have found any tags but found {$p->get_tag()}."
+ $processor->next_tag(),
+ "Shouldn't have found any tags but found {$processor->get_tag()}."
);
$this->assertTrue(
- $p->paused_at_incomplete_token(),
+ $processor->paused_at_incomplete_token(),
"Should have indicated that the parser found an incomplete token but didn't."
);
}
@@ -2393,7 +2400,7 @@ public function test_next_tag_returns_false_for_incomplete_syntax_elements( $inc
*
* @return array[]
*/
- public function data_incomplete_syntax_elements() {
+ public static function data_incomplete_syntax_elements() {
return array(
'Incomplete tag name' => array( '
array( ' array( ' array( ' array( '' => array( '' ),
'Unclosed IFRAME' => array( '