diff --git a/.github/workflows/coding-standards.yml b/.github/workflows/coding-standards.yml index 0709194d35eab..79ebf67416e34 100644 --- a/.github/workflows/coding-standards.yml +++ b/.github/workflows/coding-standards.yml @@ -142,8 +142,6 @@ jobs: contents: read timeout-minutes: 20 if: ${{ github.repository == 'WordPress/wordpress-develop' || github.event_name == 'pull_request' }} - env: - PUPPETEER_SKIP_DOWNLOAD: ${{ true }} steps: - name: Checkout repository diff --git a/.github/workflows/end-to-end-tests.yml b/.github/workflows/end-to-end-tests.yml index 42eab6ff447da..64001ad5cafd5 100644 --- a/.github/workflows/end-to-end-tests.yml +++ b/.github/workflows/end-to-end-tests.yml @@ -42,11 +42,13 @@ jobs: # - Sets up Node.js. # - Logs debug information about the GitHub Action runner. # - Installs npm dependencies. + # - Install Playwright browsers. # - Builds WordPress to run from the `build` directory. # - Starts the WordPress Docker container. # - Logs the running Docker containers. # - Logs Docker debug information (about both the Docker installation within the runner and the WordPress container). # - Install WordPress within the Docker container. + # - Install Gutenberg. # - Run the E2E tests. # - Ensures version-controlled files are not modified or deleted. e2e-tests: @@ -90,6 +92,9 @@ jobs: - name: Install npm Dependencies run: npm ci + - name: Install Playwright browsers + run: npx playwright install --with-deps + - name: Build WordPress run: npm run build @@ -115,6 +120,9 @@ jobs: LOCAL_SCRIPT_DEBUG: ${{ matrix.LOCAL_SCRIPT_DEBUG }} run: npm run env:install + - name: Install Gutenberg + run: npm run env:cli -- plugin install gutenberg --path=/var/www/${{ env.LOCAL_DIR }} + - name: Run E2E tests run: npm run test:e2e @@ -129,6 +137,22 @@ jobs: - name: Ensure version-controlled files are not modified or deleted run: git diff --exit-code + slack-notifications: + name: Slack Notifications + uses: WordPress/wordpress-develop/.github/workflows/slack-notifications.yml@trunk + permissions: + actions: read + contents: read + needs: [ e2e-tests ] + if: ${{ github.repository == 'WordPress/wordpress-develop' && github.event_name != 'pull_request' && always() }} + with: + calling_status: ${{ contains( needs.*.result, 'cancelled' ) && 'cancelled' || contains( needs.*.result, 'failure' ) && 'failure' || 'success' }} + secrets: + SLACK_GHA_SUCCESS_WEBHOOK: ${{ secrets.SLACK_GHA_SUCCESS_WEBHOOK }} + SLACK_GHA_CANCELLED_WEBHOOK: ${{ secrets.SLACK_GHA_CANCELLED_WEBHOOK }} + SLACK_GHA_FIXED_WEBHOOK: ${{ secrets.SLACK_GHA_FIXED_WEBHOOK }} + SLACK_GHA_FAILURE_WEBHOOK: ${{ secrets.SLACK_GHA_FAILURE_WEBHOOK }} + failed-workflow: name: Failed workflow tasks runs-on: ubuntu-latest @@ -141,7 +165,8 @@ jobs: github.event_name != 'pull_request' && github.run_attempt < 2 && ( - needs.e2e-tests.result == 'cancelled' || needs.e2e-tests.result == 'failure' + contains( needs.*.result, 'cancelled' ) || + contains( needs.*.result, 'failure' ) ) steps: - name: Dispatch workflow run diff --git a/.github/workflows/failed-workflow.yml b/.github/workflows/failed-workflow.yml index ebc305568ccad..f92d4b8102e9f 100644 --- a/.github/workflows/failed-workflow.yml +++ b/.github/workflows/failed-workflow.yml @@ -26,13 +26,13 @@ jobs: runs-on: ubuntu-latest permissions: actions: write - timeout-minutes: 5 + timeout-minutes: 20 steps: - name: Rerun a workflow uses: actions/github-script@d7906e4ad0b1822421a7e6a35d5ca353c962f410 # v6.4.1 with: - retries: 2 + retries: 10 retry-exempt-status-codes: 418 script: | const workflow_run = await github.rest.actions.getWorkflowRun({ diff --git a/.github/workflows/install-testing.yml b/.github/workflows/install-testing.yml index bd8dccc0b8b65..d83f56b3792a6 100644 --- a/.github/workflows/install-testing.yml +++ b/.github/workflows/install-testing.yml @@ -39,7 +39,7 @@ jobs: # - Creates a `wp-config.php` file. # - Installs WordPress. install-tests-mysql: - name: WP ${{ inputs.new-version || 'latest' }} / PHP ${{ matrix.php }} / ${{ 'mariadb' == matrix.db-type && 'MariaDB' || 'MySQL' }} ${{ matrix.db-version }}${{ matrix.multisite && ' multisite' || '' }} + name: WP ${{ inputs.wp-version || 'latest' }} / PHP ${{ matrix.php }} / ${{ 'mariadb' == matrix.db-type && 'MariaDB' || 'MySQL' }} ${{ matrix.db-version }}${{ matrix.multisite && ' multisite' || '' }} permissions: contents: read runs-on: ubuntu-latest diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 4ec15b95913af..d936c62d19ae4 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -31,10 +31,10 @@ permissions: {} env: # Performance testing should be performed in an environment reflecting a standard production environment. - WP_DEBUG: false - SCRIPT_DEBUG: false - SAVEQUERIES : false - WP_DEVELOPMENT_MODE: '' + LOCAL_WP_DEBUG: false + LOCAL_SCRIPT_DEBUG: false + LOCAL_SAVEQUERIES: false + LOCAL_WP_DEVELOPMENT_MODE: "''" # This workflow takes two sets of measurements — one for the current commit, # and another against a consistent version that is used as a baseline measurement. @@ -56,6 +56,7 @@ jobs: # - Set up Node.js. # - Log debug information. # - Install npm dependencies. + # - Install Playwright browsers. # - Build WordPress. # - Start Docker environment. # - Log running Docker containers. @@ -73,6 +74,7 @@ jobs: # - Run performance tests (previous/target commit). # - Print target performance tests results. # - Reset to original commit. + # - Install npm dependencies. # - Set the environment to the baseline version. # - Run baseline performance tests. # - Print baseline performance tests results. @@ -119,6 +121,9 @@ jobs: - name: Install npm dependencies run: npm ci + - name: Install Playwright browsers + run: npx playwright install --with-deps + - name: Build WordPress run: npm run build @@ -182,24 +187,35 @@ jobs: run: npm run build - name: Run target performance tests (base/previous commit) - run: npm run test:performance -- --prefix=before + env: + TEST_RESULTS_PREFIX: before + run: npm run test:performance - name: Print target performance tests results - run: node ./tests/performance/results.js --prefix=before + env: + TEST_RESULTS_PREFIX: before + run: node ./tests/performance/results.js - name: Reset to original commit run: git reset --hard $GITHUB_SHA + - name: Install npm dependencies + run: npm ci + - name: Set the environment to the baseline version run: | npm run env:cli -- core update --version=${{ env.BASE_TAG }} --force --path=/var/www/${{ env.LOCAL_DIR }} npm run env:cli -- core version --path=/var/www/${{ env.LOCAL_DIR }} - name: Run baseline performance tests - run: npm run test:performance -- --prefix=base + env: + TEST_RESULTS_PREFIX: base + run: npm run test:performance - name: Print baseline performance tests results - run: node ./tests/performance/results.js --prefix=base + env: + TEST_RESULTS_PREFIX: base + run: node ./tests/performance/results.js - name: Compare results with base run: node ./tests/performance/compare-results.js ${{ runner.temp }}/summary.md diff --git a/.github/workflows/phpunit-tests-run.yml b/.github/workflows/phpunit-tests-run.yml index 54c34c6511e00..eb3eab76e7617 100644 --- a/.github/workflows/phpunit-tests-run.yml +++ b/.github/workflows/phpunit-tests-run.yml @@ -51,7 +51,6 @@ env: LOCAL_DB_VERSION: ${{ inputs.db-version }} LOCAL_PHP_MEMCACHED: ${{ inputs.memcached }} PHPUNIT_CONFIG: ${{ inputs.phpunit-config }} - PUPPETEER_SKIP_DOWNLOAD: ${{ true }} jobs: # Runs the PHPUnit tests for WordPress. @@ -159,11 +158,11 @@ jobs: - name: Run ms-files tests as a multisite install if: ${{ inputs.multisite }} - run: node ./tools/local-env/scripts/docker.js run php ./vendor/bin/phpunit --verbose -c tests/phpunit/multisite.xml --group ms-files + run: node ./tools/local-env/scripts/docker.js run php ./vendor/bin/phpunit --verbose -c ${{ env.PHPUNIT_CONFIG }} --group ms-files - name: Run external HTTP tests if: ${{ ! inputs.multisite }} - run: node ./tools/local-env/scripts/docker.js run php ./vendor/bin/phpunit --verbose -c phpunit.xml.dist --group external-http + run: node ./tools/local-env/scripts/docker.js run php ./vendor/bin/phpunit --verbose -c ${{ env.PHPUNIT_CONFIG }} --group external-http # __fakegroup__ is excluded to force PHPUnit to ignore the settings in phpunit.xml.dist. - name: Run (Xdebug) tests diff --git a/.github/workflows/slack-notifications.yml b/.github/workflows/slack-notifications.yml index b3d8ef663f2ae..f9b0f04723495 100644 --- a/.github/workflows/slack-notifications.yml +++ b/.github/workflows/slack-notifications.yml @@ -75,8 +75,10 @@ jobs: return 'first-failure'; } - // When a workflow has been restarted to fix a failure, check the previous run attempt. - if ( workflow_run.data.run_attempt > 1 ) { + // When a workflow has been restarted, check the previous run attempt. Because workflows are automatically + // restarted once and a failure on the first run is not reported, failures on the second run should not be + // considered. + if ( workflow_run.data.run_attempt > 2 ) { const previous_run = await github.rest.actions.getWorkflowRunAttempt({ owner: context.repo.owner, repo: context.repo.repo, diff --git a/.github/workflows/test-coverage.yml b/.github/workflows/test-coverage.yml index cd00e9b7f0359..5e963900fb08f 100644 --- a/.github/workflows/test-coverage.yml +++ b/.github/workflows/test-coverage.yml @@ -29,7 +29,6 @@ on: permissions: {} env: - PUPPETEER_SKIP_DOWNLOAD: ${{ true }} LOCAL_PHP: '7.4-fpm' LOCAL_PHP_XDEBUG: true LOCAL_PHP_XDEBUG_MODE: 'coverage' diff --git a/.github/workflows/test-npm.yml b/.github/workflows/test-npm.yml index d53c8ec825690..185908f7943db 100644 --- a/.github/workflows/test-npm.yml +++ b/.github/workflows/test-npm.yml @@ -37,9 +37,6 @@ concurrency: # Any needed permissions should be configured at the job level. permissions: {} -env: - PUPPETEER_SKIP_DOWNLOAD: ${{ true }} - jobs: # Verifies that installing npm dependencies and building WordPress works as expected. # diff --git a/.gitignore b/.gitignore index 596abbaa6432d..0a02b30a1548d 100644 --- a/.gitignore +++ b/.gitignore @@ -100,4 +100,4 @@ wp-tests-config.php /docker-compose.override.yml # Visual regression test diffs -tests/visual-regression/specs/__image_snapshots__ +tests/visual-regression/specs/__snapshots__ diff --git a/package-lock.json b/package-lock.json index 1b877660d304e..eba4628e2b018 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,70 +11,70 @@ "dependencies": { "@emotion/is-prop-valid": "0.8.8", "@emotion/memoize": "0.7.4", - "@wordpress/a11y": "3.42.4", - "@wordpress/annotations": "2.42.4", - "@wordpress/api-fetch": "6.39.4", - "@wordpress/autop": "3.42.4", - "@wordpress/blob": "3.42.4", - "@wordpress/block-directory": "4.19.4", - "@wordpress/block-editor": "12.10.4", - "@wordpress/block-library": "8.19.4", - "@wordpress/block-serialization-default-parser": "4.42.4", - "@wordpress/blocks": "12.19.4", - "@wordpress/commands": "0.13.4", - "@wordpress/components": "25.8.4", - "@wordpress/compose": "6.19.4", - "@wordpress/core-commands": "0.11.4", - "@wordpress/core-data": "6.19.4", - "@wordpress/customize-widgets": "4.19.4", - "@wordpress/data": "9.12.4", - "@wordpress/data-controls": "3.11.4", - "@wordpress/date": "4.42.4", - "@wordpress/deprecated": "3.42.4", - "@wordpress/dom": "3.42.4", - "@wordpress/dom-ready": "3.42.4", - "@wordpress/edit-post": "7.19.4", - "@wordpress/edit-site": "5.19.4", - "@wordpress/edit-widgets": "5.19.4", - "@wordpress/editor": "13.19.4", - "@wordpress/element": "5.19.4", - "@wordpress/escape-html": "2.42.4", - "@wordpress/format-library": "4.19.4", - "@wordpress/hooks": "3.42.4", - "@wordpress/html-entities": "3.42.4", - "@wordpress/i18n": "4.42.4", - "@wordpress/icons": "9.33.4", - "@wordpress/interactivity": "2.3.4", - "@wordpress/interface": "5.19.4", - "@wordpress/is-shallow-equal": "4.42.4", - "@wordpress/keyboard-shortcuts": "4.19.4", - "@wordpress/keycodes": "3.42.4", - "@wordpress/list-reusable-blocks": "4.19.4", - "@wordpress/media-utils": "4.33.4", - "@wordpress/notices": "4.10.4", - "@wordpress/nux": "8.4.4", - "@wordpress/patterns": "1.3.4", - "@wordpress/plugins": "6.10.4", - "@wordpress/preferences": "3.19.4", - "@wordpress/preferences-persistence": "1.34.4", - "@wordpress/primitives": "3.40.4", - "@wordpress/priority-queue": "2.42.4", - "@wordpress/private-apis": "0.24.4", - "@wordpress/redux-routine": "4.42.4", - "@wordpress/reusable-blocks": "4.19.4", - "@wordpress/rich-text": "6.19.4", - "@wordpress/router": "0.11.4", - "@wordpress/server-side-render": "4.19.4", - "@wordpress/shortcode": "3.42.4", - "@wordpress/style-engine": "1.25.4", - "@wordpress/sync": "0.4.4", - "@wordpress/token-list": "2.42.4", - "@wordpress/undo-manager": "0.2.4", - "@wordpress/url": "3.43.4", - "@wordpress/viewport": "5.19.4", - "@wordpress/warning": "2.42.4", - "@wordpress/widgets": "3.19.4", - "@wordpress/wordcount": "3.42.4", + "@wordpress/a11y": "3.42.6", + "@wordpress/annotations": "2.42.6", + "@wordpress/api-fetch": "6.39.6", + "@wordpress/autop": "3.42.6", + "@wordpress/blob": "3.42.6", + "@wordpress/block-directory": "4.19.6", + "@wordpress/block-editor": "12.10.6", + "@wordpress/block-library": "8.19.6", + "@wordpress/block-serialization-default-parser": "4.42.6", + "@wordpress/blocks": "12.19.6", + "@wordpress/commands": "0.13.6", + "@wordpress/components": "25.8.6", + "@wordpress/compose": "6.19.6", + "@wordpress/core-commands": "0.11.6", + "@wordpress/core-data": "6.19.6", + "@wordpress/customize-widgets": "4.19.6", + "@wordpress/data": "9.12.6", + "@wordpress/data-controls": "3.11.6", + "@wordpress/date": "4.42.6", + "@wordpress/deprecated": "3.42.6", + "@wordpress/dom": "3.42.6", + "@wordpress/dom-ready": "3.42.6", + "@wordpress/edit-post": "7.19.6", + "@wordpress/edit-site": "5.19.6", + "@wordpress/edit-widgets": "5.19.6", + "@wordpress/editor": "13.19.6", + "@wordpress/element": "5.19.6", + "@wordpress/escape-html": "2.42.6", + "@wordpress/format-library": "4.19.6", + "@wordpress/hooks": "3.42.6", + "@wordpress/html-entities": "3.42.6", + "@wordpress/i18n": "4.42.6", + "@wordpress/icons": "9.33.6", + "@wordpress/interactivity": "2.3.6", + "@wordpress/interface": "5.19.6", + "@wordpress/is-shallow-equal": "4.42.6", + "@wordpress/keyboard-shortcuts": "4.19.6", + "@wordpress/keycodes": "3.42.6", + "@wordpress/list-reusable-blocks": "4.19.6", + "@wordpress/media-utils": "4.33.6", + "@wordpress/notices": "4.10.6", + "@wordpress/nux": "8.4.6", + "@wordpress/patterns": "1.3.6", + "@wordpress/plugins": "6.10.6", + "@wordpress/preferences": "3.19.6", + "@wordpress/preferences-persistence": "1.34.6", + "@wordpress/primitives": "3.40.6", + "@wordpress/priority-queue": "2.42.6", + "@wordpress/private-apis": "0.24.6", + "@wordpress/redux-routine": "4.42.6", + "@wordpress/reusable-blocks": "4.19.6", + "@wordpress/rich-text": "6.19.6", + "@wordpress/router": "0.11.6", + "@wordpress/server-side-render": "4.19.6", + "@wordpress/shortcode": "3.42.6", + "@wordpress/style-engine": "1.25.6", + "@wordpress/sync": "0.4.6", + "@wordpress/token-list": "2.42.6", + "@wordpress/undo-manager": "0.2.6", + "@wordpress/url": "3.43.6", + "@wordpress/viewport": "5.19.6", + "@wordpress/warning": "2.42.6", + "@wordpress/widgets": "3.19.6", + "@wordpress/wordcount": "3.42.6", "backbone": "1.5.0", "clipboard": "2.0.11", "core-js-url-browser": "3.6.4", @@ -106,11 +106,13 @@ }, "devDependencies": { "@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.4", - "@wordpress/dependency-extraction-webpack-plugin": "4.25.4", - "@wordpress/e2e-test-utils": "10.13.4", - "@wordpress/scripts": "26.13.4", + "@wordpress/babel-preset-default": "7.26.6", + "@wordpress/dependency-extraction-webpack-plugin": "4.25.6", + "@wordpress/e2e-test-utils": "10.13.6", + "@wordpress/e2e-test-utils-playwright": "0.11.0", + "@wordpress/scripts": "26.13.6", "autoprefixer": "10.4.16", "chalk": "5.3.0", "check-node-version": "4.2.1", @@ -3743,6 +3745,25 @@ "node": ">=8" } }, + "node_modules/@playwright/test": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.0.tgz", + "integrity": "sha512-zOdGloaF0jeec7hqoLqM5S3L2rR4WxMJs6lgiAeR70JlH7Ml54ZPoIIf3X7cvnKde3Q9jJ/gaxkFh8fYI9s1rg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "playwright-core": "1.32.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.5.tgz", @@ -5950,16 +5971,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz", - "integrity": "sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", + "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/type-utils": "6.7.4", - "@typescript-eslint/utils": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -5985,15 +6006,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.4.tgz", - "integrity": "sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.5.tgz", + "integrity": "sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4" }, "engines": { @@ -6013,13 +6034,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz", - "integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", + "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -6030,13 +6051,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz", - "integrity": "sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz", + "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/utils": "6.7.4", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -6057,9 +6078,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz", - "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", + "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -6070,13 +6091,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz", - "integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", + "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6097,17 +6118,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.4.tgz", - "integrity": "sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz", + "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==", "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.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", "semver": "^7.5.4" }, "engines": { @@ -6122,12 +6143,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz", - "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", + "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/types": "6.7.5", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -6349,28 +6370,28 @@ } }, "node_modules/@wordpress/a11y": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-3.42.4.tgz", - "integrity": "sha512-kJdsWkqQ5iBaFnpEUXKRydfZBfY3zDNbIia8gLxGqallW84wSsSvajLe+EewxNs32KzJADaIcJ3zTMHqUnSo3Q==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-3.42.6.tgz", + "integrity": "sha512-jvSXfOauAZfhDG9RdsyIWYtSBEeR3VBH4ar80gk3xgbEdp14GdJ9NzZBel42KmmIjKJFpKagj5VIaD5EgQMziw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/dom-ready": "^3.42.4", - "@wordpress/i18n": "^4.42.4" + "@wordpress/dom-ready": "^3.42.6", + "@wordpress/i18n": "^4.42.6" }, "engines": { "node": ">=12" } }, "node_modules/@wordpress/annotations": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/annotations/-/annotations-2.42.4.tgz", - "integrity": "sha512-qlo1mN+oYgP6qJRYaHwotmUzcJo4RaGG24ZRegItgw/jztcoZej2dPf0IrcN8WyokAk0YHeMNfGumNm7YywANA==", + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/annotations/-/annotations-2.42.6.tgz", + "integrity": "sha512-G+gzWVOeJ6EV00ZZZRfM95+gzBwWxe9jcn6Ql5sZTe90/H9iUSC5bYvlhGfK62glfwTmmTJjSZL/BJR0zrEuow==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/data": "^9.12.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/rich-text": "^6.19.4", + "@wordpress/data": "^9.12.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/rich-text": "^6.19.6", "rememo": "^4.0.2", "uuid": "^9.0.1" }, @@ -6382,22 +6403,22 @@ } }, "node_modules/@wordpress/api-fetch": { - "version": "6.39.4", - "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.39.4.tgz", - "integrity": "sha512-yILvK5Qng58Dj0+o76Zhs4dgRajHib/1u+b2vSKhPCF/BKqjb0tvD3t/dff9IyhYGC1jIWVG77sA1L+AkIa6zg==", + "version": "6.39.6", + "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.39.6.tgz", + "integrity": "sha512-JVMNy4MlDXxz3CwXbr+vRkKfHYAXYMirUxfB9Vmj3hC7bCbtVGMbNdZrjJW9L7UlRH8zZGiKbdZ+9HESnq+bpw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/i18n": "^4.42.4", - "@wordpress/url": "^3.43.4" + "@wordpress/i18n": "^4.42.6", + "@wordpress/url": "^3.43.6" }, "engines": { "node": ">=12" } }, "node_modules/@wordpress/autop": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-3.42.4.tgz", - "integrity": "sha512-9SzLSSSSZkvEZ4eDyWFmD0/BvxpdlhboGUJqGXew1zeDD3VrUf8tKHaNg8V1pnrPdFdMTPzPi9mf98bggtqIbQ==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-3.42.6.tgz", + "integrity": "sha512-q2vTd3IYZBsbYOlWpa8KLlhEDERepgsiPv8BdkS9Aj7HZ6XtbxtwnnYu0gYZoDFb223g6IdASJs7ic3Rj4oP0Q==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -6418,9 +6439,9 @@ } }, "node_modules/@wordpress/babel-preset-default": { - "version": "7.26.4", - "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-7.26.4.tgz", - "integrity": "sha512-7YKnSFVmg/8CgtcXh6v4C2L+H6/MOH6lLLu7rBLY0p3bGX+EnFDb3jzaWMtoPLvyIBjD8cUln09JtPrIfsRrNA==", + "version": "7.26.6", + "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-7.26.6.tgz", + "integrity": "sha512-Np6az/l4er+463PR4Bg5DJTYceNf4JUKJcMYogFaW+2NZARtQggjiqdjrKlWijHSzGq1tIMMGWUHiFKP1nub8A==", "dev": true, "dependencies": { "@babel/core": "^7.16.0", @@ -6429,10 +6450,10 @@ "@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.4", - "@wordpress/browserslist-config": "^5.25.4", - "@wordpress/element": "^5.19.4", - "@wordpress/warning": "^2.42.4", + "@wordpress/babel-plugin-import-jsx-pragma": "^4.25.6", + "@wordpress/browserslist-config": "^5.25.6", + "@wordpress/element": "^5.19.6", + "@wordpress/warning": "^2.42.6", "browserslist": "^4.21.9", "core-js": "^3.31.0" }, @@ -6447,9 +6468,9 @@ "dev": true }, "node_modules/@wordpress/blob": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-3.42.4.tgz", - "integrity": "sha512-Mg/2TaXbYwRE77DNwDrjhKQpyfB6NbGu+YtZrI5a7Nu6Y/VpLBAUrekTOXnn1kGZfX5LITaUonZxyyFFBcPiow==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-3.42.6.tgz", + "integrity": "sha512-8mb0ghOqaHgOGmbamy/SE9+mLx/vqdAdPR1olxLLcwD4OROM2vSMK/GSpRD8EPM3A3dCxqvK/W7zhCUhj/y6Rg==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -6458,29 +6479,29 @@ } }, "node_modules/@wordpress/block-directory": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-4.19.4.tgz", - "integrity": "sha512-/NTVS9eSur56HWM1SN4VIgWb26QSPmZIYMvd7T0BFpko+jL0YdqhZ0DI0BbXVxGPc/tDZ+k5kFN9FvZVNKU01w==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-4.19.6.tgz", + "integrity": "sha512-V2sh5pEjrFL/AOMnkb+C91mhiL6dhi79zlmiBxpsnEoCsDeN6SehkximdZqba+jiqpX/rwtgYn8ny2q18/IKpQ==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/edit-post": "^7.19.4", - "@wordpress/editor": "^13.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/url": "^3.43.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/edit-post": "^7.19.6", + "@wordpress/editor": "^13.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/url": "^3.43.6", "change-case": "^4.1.2" }, "engines": { @@ -6492,44 +6513,44 @@ } }, "node_modules/@wordpress/block-editor": { - "version": "12.10.4", - "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-12.10.4.tgz", - "integrity": "sha512-ADxKedK9ZqyebdD216gCfPX6Fe6xWN0VMABwiYMlOC4sE3QYVk/kKX55IabAi40+N0GtVSh6r9sJjXJ9yX59hw==", + "version": "12.10.6", + "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-12.10.6.tgz", + "integrity": "sha512-2ONGkwu3hM1hyWB1hHj5xggi14SjB81qE2TXkbdVaABFORoIFKX0TfcBiyEvF+vUTnFxInKteR9JPDjmzQDfhg==", "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.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/commands": "^0.13.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/shortcode": "^3.42.4", - "@wordpress/style-engine": "^1.25.4", - "@wordpress/token-list": "^2.42.4", - "@wordpress/url": "^3.43.4", - "@wordpress/warning": "^2.42.4", - "@wordpress/wordcount": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/commands": "^0.13.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/shortcode": "^3.42.6", + "@wordpress/style-engine": "^1.25.6", + "@wordpress/token-list": "^2.42.6", + "@wordpress/url": "^3.43.6", + "@wordpress/warning": "^2.42.6", + "@wordpress/wordcount": "^3.42.6", "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", @@ -6553,41 +6574,41 @@ } }, "node_modules/@wordpress/block-library": { - "version": "8.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-8.19.4.tgz", - "integrity": "sha512-U5s0T/aRT/sk7cRomkjYj62hgKqNtKHzOzm3T7lwZi+1BXPq/zDGXl3jE8M1H1yermUuTffLk6BSC+n9c03JYA==", + "version": "8.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-8.19.6.tgz", + "integrity": "sha512-xZRgLebqmDvRaBMP5wsBl2qdzB/HhfCJbGy7YabnCSgZQKYEj4Y11mC5vl27zr8u4aAftsp07bKLJaDGs30IyA==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/autop": "^3.42.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interactivity": "^2.3.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/primitives": "^3.40.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/reusable-blocks": "^4.19.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/server-side-render": "^4.19.4", - "@wordpress/url": "^3.43.4", - "@wordpress/viewport": "^5.19.4", - "@wordpress/wordcount": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/autop": "^3.42.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interactivity": "^2.3.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/primitives": "^3.40.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/reusable-blocks": "^4.19.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/server-side-render": "^4.19.6", + "@wordpress/url": "^3.43.6", + "@wordpress/viewport": "^5.19.6", + "@wordpress/wordcount": "^3.42.6", "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", @@ -6607,9 +6628,9 @@ } }, "node_modules/@wordpress/block-serialization-default-parser": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-4.42.4.tgz", - "integrity": "sha512-+BW7gTWjcGj3DVtAzQsX7bT8OKsFpq6B9FjS0Oc+6M9bCJd5IW5XNHu+NOKLJFX80Ao1x2eN4a9IWs0xZl0Z5g==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-4.42.6.tgz", + "integrity": "sha512-Tto25U4xB+WV2elReEbgIyQ/6S6papc320O1BqGrTvrlMsmz+DJRu8sgHti5geNL7EkSd2fFaoiH1wlqdSVGBg==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -6618,25 +6639,25 @@ } }, "node_modules/@wordpress/blocks": { - "version": "12.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-12.19.4.tgz", - "integrity": "sha512-JD7vbdow1RZ3SHsJTn8Opg7fdic7brG7P6YI0pvtZhmixWk1uMWyFzu3aoj9SooB0aQzWIhQy324O351+Gy2vA==", + "version": "12.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-12.19.6.tgz", + "integrity": "sha512-He6ItxlBRRO3mNkiMkZerORb716nyNyNCah7MhKqaepqwfKiuQNb1lBNpBv6DwD2urmXpQXYmVQ2hRv8vHDJ2w==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/autop": "^3.42.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/block-serialization-default-parser": "^4.42.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/shortcode": "^3.42.4", + "@wordpress/autop": "^3.42.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/block-serialization-default-parser": "^4.42.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/shortcode": "^3.42.6", "change-case": "^4.1.2", "colord": "^2.7.0", "deepmerge": "^4.3.0", @@ -6667,18 +6688,18 @@ } }, "node_modules/@wordpress/commands": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-0.13.4.tgz", - "integrity": "sha512-FIByPkwOB3urKDcQbLM1WJcnNPEd8OQCyT4lpSyk11FeUg6ANVJRZrEJtx8vr7ZHxTc+wIkROYIjcOUa5e1mvw==", + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-0.13.6.tgz", + "integrity": "sha512-nWilSFfNgdz6atKanRDZMLUyHM/PqJmK/k5edoQ+4ytllITfy2kGfKYGNPcfGEJ8degFZtRm4Zdl8zf/XJVucw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/components": "^25.8.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/private-apis": "^0.24.4", + "@wordpress/components": "^25.8.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/private-apis": "^0.24.6", "classnames": "^2.3.1", "cmdk": "^0.2.0", "rememo": "^4.0.2" @@ -6692,9 +6713,9 @@ } }, "node_modules/@wordpress/components": { - "version": "25.8.4", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-25.8.4.tgz", - "integrity": "sha512-/JYvxesKoflXhNNkEaSmGUrs02dQY13E5tldUnHiIKmHQTlv9ZdfsxSib50CVG5s3cCzde570ibZLZhnW6hPTQ==", + "version": "25.8.6", + "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-25.8.6.tgz", + "integrity": "sha512-gi5A3jhd1KesL1e9Qh36m6IhuBs8GMlJa66PVIA84pL+L22bugpIkmv2ZUiSnS4F0Uwrc8a8b+4vkhZpIHXNng==", "dependencies": { "@ariakit/react": "^0.2.12", "@babel/runtime": "^7.16.0", @@ -6707,23 +6728,23 @@ "@floating-ui/react-dom": "^2.0.1", "@radix-ui/react-dropdown-menu": "2.0.4", "@use-gesture/react": "^10.2.24", - "@wordpress/a11y": "^3.42.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/primitives": "^3.40.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/warning": "^2.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/primitives": "^3.40.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/warning": "^2.42.6", "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", @@ -6755,19 +6776,19 @@ } }, "node_modules/@wordpress/compose": { - "version": "6.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-6.19.4.tgz", - "integrity": "sha512-Sjo1vvGvtb++cOdaTBUyft7TPQ4/aLKSdl3PiAVARN/YKXZrPuTA6c4QKyisnrGAhKRJf4XWblR7eF2+5Gnz4Q==", + "version": "6.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-6.19.6.tgz", + "integrity": "sha512-O/ah1LEGnetk0TcsgI2ZFnAvqI1hJ0XJ8nzFWYgw4irFy4io2JML1ACOPnCBLvCdfiaiJPyep/b5sfQa701LvQ==", "dependencies": { "@babel/runtime": "^7.16.0", "@types/mousetrap": "^1.6.8", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/priority-queue": "^2.42.4", - "@wordpress/undo-manager": "^0.2.4", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/priority-queue": "^2.42.6", + "@wordpress/undo-manager": "^0.2.6", "change-case": "^4.1.2", "clipboard": "^2.0.8", "mousetrap": "^1.6.5", @@ -6781,21 +6802,21 @@ } }, "node_modules/@wordpress/core-commands": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/@wordpress/core-commands/-/core-commands-0.11.4.tgz", - "integrity": "sha512-tSqARe5fR/xk6sbz0ZGMSNfhXi975TkraSBWjiffGZufQNm6Mp+w9AwJOC2fr6XYwLDQR5jo0ZAQpjlfko6Z9g==", + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@wordpress/core-commands/-/core-commands-0.11.6.tgz", + "integrity": "sha512-l3F8ZufPULbVN1StaQUDIQFL/RfH4sQkOsb/43YLvfS+kp6GPhJtgYvoiqze1gWNCLrMu5HcqVCiPcwEB59T/w==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/commands": "^0.13.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/router": "^0.11.4", - "@wordpress/url": "^3.43.4" + "@wordpress/block-editor": "^12.10.6", + "@wordpress/commands": "^0.13.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/router": "^0.11.6", + "@wordpress/url": "^3.43.6" }, "engines": { "node": ">=12" @@ -6806,25 +6827,25 @@ } }, "node_modules/@wordpress/core-data": { - "version": "6.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-6.19.4.tgz", - "integrity": "sha512-LxR0VdALzfaEUPviDQoTgpVrdfyWv9nd0CqcsiqiDLM14m/2zw15Be/OBicZgivfvWPTIN3oj7GhKnLP+2rxOg==", + "version": "6.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-6.19.6.tgz", + "integrity": "sha512-0dSgwipsY0UzwdnaDqMk2D2QnjSH8LDiqrTeHm8PLmxBEOJy0Uruf1cXxfV+4vVCMeI/w+CS0mW9jKNKj5Q9kA==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/sync": "^0.4.4", - "@wordpress/undo-manager": "^0.2.4", - "@wordpress/url": "^3.43.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/sync": "^0.4.6", + "@wordpress/undo-manager": "^0.2.6", + "@wordpress/url": "^3.43.6", "change-case": "^4.1.2", "equivalent-key-map": "^0.2.2", "fast-deep-equal": "^3.1.3", @@ -6841,31 +6862,31 @@ } }, "node_modules/@wordpress/customize-widgets": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/customize-widgets/-/customize-widgets-4.19.4.tgz", - "integrity": "sha512-ocJIYYhpYPdKOa/0QgJIeRiFyrRzx5eDTgve1jt1XC3MBEctUcRNNWSR6flCFaG0Mt3xUeFhV/yo54yRyHhTjQ==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/customize-widgets/-/customize-widgets-4.19.6.tgz", + "integrity": "sha512-eP7ZYBDH19pp+3Sk1IBDFkdhXgVPknvJIOvmsZGtUpdEtOStusM3SDZwn/iomQvaCtrSjM4VQg4qUQ/Wn21Ncg==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/block-library": "^8.19.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interface": "^5.19.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/widgets": "^3.19.4", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/block-library": "^8.19.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interface": "^5.19.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/widgets": "^3.19.6", "classnames": "^2.3.1", "fast-deep-equal": "^3.1.3" }, @@ -6878,18 +6899,18 @@ } }, "node_modules/@wordpress/data": { - "version": "9.12.4", - "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-9.12.4.tgz", - "integrity": "sha512-EjywfvoI4VEslYQWICNDrp/8YIs7sLNMN7yPtpnOH41SQ9cAackFD6ipqa80HGvq3AzNZejxeLHV+mfOjkk1ZQ==", + "version": "9.12.6", + "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-9.12.6.tgz", + "integrity": "sha512-Fr+felS8t92Opj/MFANho/0bkqJVZyyVoDvI30oZkgFXM+nHGtHj51vu/tsfveON8Dy8AFMz5wgABpQBLqmybg==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/compose": "^6.19.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/priority-queue": "^2.42.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/redux-routine": "^4.42.4", + "@wordpress/compose": "^6.19.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/priority-queue": "^2.42.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/redux-routine": "^4.42.6", "deepmerge": "^4.3.0", "equivalent-key-map": "^0.2.2", "is-plain-object": "^5.0.0", @@ -6907,14 +6928,14 @@ } }, "node_modules/@wordpress/data-controls": { - "version": "3.11.4", - "resolved": "https://registry.npmjs.org/@wordpress/data-controls/-/data-controls-3.11.4.tgz", - "integrity": "sha512-Xp4zZcTPqEp1V8sxmuo8PlUtus6PqW7NDzy+xydzevt1uAAN4c5In02qgy1dJGpY+6g8xJlCvVpuyt9TMbeCKg==", + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/@wordpress/data-controls/-/data-controls-3.11.6.tgz", + "integrity": "sha512-pEbA3HeH6czq7trPhNd1hdWjHttqSLOBSMKW6YFI4Qm/r0IDZm+fmK9jEz9cqrwiH9ttJLT6Us+WubAOjMdq2w==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4" + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6" }, "engines": { "node": ">=12" @@ -6924,12 +6945,12 @@ } }, "node_modules/@wordpress/date": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-4.42.4.tgz", - "integrity": "sha512-HqYEONVFPZSnSvFE/w2wB7gfM++ZHdLYxHE4LwKBxhGrJKb2JIHUvC9q47tAfbvF8uxK1TPxMVp8NwkY6w4/zQ==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-4.42.6.tgz", + "integrity": "sha512-lQJKn1e/T1tocCyoJzk7HG/deu/nxhUsmjw7vFnhrMhHTFVFC0N7aW79YMQoKFwn7Q2/yWON3r8NFENET9oWQw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/deprecated": "^3.42.4", + "@wordpress/deprecated": "^3.42.6", "moment": "^2.29.4", "moment-timezone": "^0.5.40" }, @@ -6938,9 +6959,9 @@ } }, "node_modules/@wordpress/dependency-extraction-webpack-plugin": { - "version": "4.25.4", - "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-4.25.4.tgz", - "integrity": "sha512-J34PNW4ZVH8Z6TQ6Bi+3/J2BjPzWal/IseMO+q9MwGl1felPPKtkKH9WWAHuZcJOGwfMroYgu47XanP+iHZj1w==", + "version": "4.25.6", + "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-4.25.6.tgz", + "integrity": "sha512-XspAnFqK8gIt+xbnIYLdAlD/u308lPUUrmApxf+NOG1Ln/eeVSTR6f8D8f4l0fpyQmz9c5v7HIvryLhiktZT1w==", "dev": true, "dependencies": { "json2php": "^0.0.7", @@ -6954,33 +6975,33 @@ } }, "node_modules/@wordpress/deprecated": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-3.42.4.tgz", - "integrity": "sha512-1sohYQHq+bRFpjoYMPf6u5+dBrhu+6v8CmfO+emQFCf6xh+qn/nBiOJNCAzWqRFGBvSckDv04LG6Vnks0mAIQw==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-3.42.6.tgz", + "integrity": "sha512-GfnhIrXqjlKTH4Z7SdTbzToxg5UnJAj6bS8OuO7fb7LYtS9XAEkYsF6ck2vXW524LgFw0uNS5O74LRCqu19YEA==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/hooks": "^3.42.4" + "@wordpress/hooks": "^3.42.6" }, "engines": { "node": ">=12" } }, "node_modules/@wordpress/dom": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-3.42.4.tgz", - "integrity": "sha512-fU6yskF7BNnTPUriCjDGhx3w+PqSZTt+VSmiTcFhaGKDmMNi+5u/cWRXRluljrZj5PG7NIohfYUQQ4p5akT9Bg==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-3.42.6.tgz", + "integrity": "sha512-zWuS3JVFUQRKBWtraa93OxLYl7q/Rg4tBj8q0S4a/DTh/xIaSEZCxs2zeeLupeqpWrdtySZYKBHLTIMkQueWkw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/deprecated": "^3.42.4" + "@wordpress/deprecated": "^3.42.6" }, "engines": { "node": ">=12" } }, "node_modules/@wordpress/dom-ready": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.42.4.tgz", - "integrity": "sha512-c5vPCU932RFBQZgCmX62AHt75OaefGf4B9CWigBQD6oCDqXNOHeCrSJgEmU+YPKclloazpl+JOb3Nnlv8ky8dg==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.42.6.tgz", + "integrity": "sha512-0qYKm+zLD+E/opSd8o2I70LCr/N7p/B36FDrZoIRXpZIT6+soS3khTFu9Rd655Aneqqu53eh/KcBQcAoLoQQSg==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -6989,15 +7010,15 @@ } }, "node_modules/@wordpress/e2e-test-utils": { - "version": "10.13.4", - "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-10.13.4.tgz", - "integrity": "sha512-eEXlOiOvq2PKERPrplybrueWxcDDtbd+hzopfibOzXWOMIHXrgvs+oookasYdANlVu5MDEWT0/g+E7vlG8qgew==", + "version": "10.13.6", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-10.13.6.tgz", + "integrity": "sha512-FHHmTMgXF5guQeJ+oO/0HZnwuGoc+mymBOHORnJMZe50EuiNxwQ70ZeSGE0LE99dOqNOWGgN3vxf2B5F64QE/g==", "dev": true, "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/url": "^3.43.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/url": "^3.43.6", "change-case": "^4.1.2", "form-data": "^4.0.0", "node-fetch": "^2.6.0" @@ -7011,14 +7032,14 @@ } }, "node_modules/@wordpress/e2e-test-utils-playwright": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.10.4.tgz", - "integrity": "sha512-JVJZsft/idcOrm67OBOa+h0+vcP/KisybIXhWgbTvWKaedLYqzVKqvOBIm2nRpki9u3k2b0iy6uOPf9BNdIfnQ==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.11.0.tgz", + "integrity": "sha512-UxDkVvm24FJdi4nkn5+n9XirYxdJ1QDZgnHotdrgGRel8NOvlEOlhmT/xpuAPQrVwo+yynxEKeb1Y2AT6jX9og==", "dev": true, "dependencies": { - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/url": "^3.43.4", + "@wordpress/api-fetch": "^6.40.0", + "@wordpress/keycodes": "^3.43.0", + "@wordpress/url": "^3.44.0", "change-case": "^4.1.2", "form-data": "^4.0.0", "get-port": "^5.1.1", @@ -7032,6 +7053,79 @@ "@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", @@ -7073,41 +7167,41 @@ } }, "node_modules/@wordpress/edit-post": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-7.19.4.tgz", - "integrity": "sha512-h5QprgDiEzTFFKqyou4BU5KeqydM+xItPhbM5ktE6p2Or65aHctNMXSMMHNc1oeu/9t94Bu9Wj0YxUpESBv74Q==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-7.19.6.tgz", + "integrity": "sha512-ifer5vVUa89zFxahxtGQT9SxbvDqnSAmbuGv0MUPOmuFsKREjwVSQVpuCo/V501wwzHXcoBwjXx2RTn2a5CIIg==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/block-library": "^8.19.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/commands": "^0.13.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-commands": "^0.11.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/editor": "^13.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interface": "^5.19.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/url": "^3.43.4", - "@wordpress/viewport": "^5.19.4", - "@wordpress/warning": "^2.42.4", - "@wordpress/widgets": "^3.19.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/block-library": "^8.19.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/commands": "^0.13.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-commands": "^0.11.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/editor": "^13.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interface": "^5.19.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/url": "^3.43.6", + "@wordpress/viewport": "^5.19.6", + "@wordpress/warning": "^2.42.6", + "@wordpress/widgets": "^3.19.6", "classnames": "^2.3.1", "memize": "^2.1.0", "rememo": "^4.0.2" @@ -7121,49 +7215,49 @@ } }, "node_modules/@wordpress/edit-site": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/edit-site/-/edit-site-5.19.4.tgz", - "integrity": "sha512-9WyOLHwqp9U9EOnjEJC5fznbsQG8fQufT6evP/jL46ErqLy0PKwthZxqiydToMoaZY8xpzq9IlWCW89GKFN3og==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/edit-site/-/edit-site-5.19.6.tgz", + "integrity": "sha512-LVxG7M9vRy8Nt9qTSB8wYla+lnMsoocszlrEWxiSDfXAbcnrase+UyjxaFYFmSLYWZYCDJsLXBipb0QdnsyNtg==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/block-library": "^8.19.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/commands": "^0.13.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-commands": "^0.11.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/editor": "^13.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interface": "^5.19.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/patterns": "^1.3.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/primitives": "^3.40.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/reusable-blocks": "^4.19.4", - "@wordpress/router": "^0.11.4", - "@wordpress/style-engine": "^1.25.4", - "@wordpress/url": "^3.43.4", - "@wordpress/viewport": "^5.19.4", - "@wordpress/widgets": "^3.19.4", - "@wordpress/wordcount": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/block-library": "^8.19.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/commands": "^0.13.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-commands": "^0.11.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/editor": "^13.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interface": "^5.19.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/patterns": "^1.3.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/primitives": "^3.40.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/reusable-blocks": "^4.19.6", + "@wordpress/router": "^0.11.6", + "@wordpress/style-engine": "^1.25.6", + "@wordpress/url": "^3.43.6", + "@wordpress/viewport": "^5.19.6", + "@wordpress/widgets": "^3.19.6", + "@wordpress/wordcount": "^3.42.6", "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.9.2", @@ -7185,37 +7279,37 @@ } }, "node_modules/@wordpress/edit-widgets": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/edit-widgets/-/edit-widgets-5.19.4.tgz", - "integrity": "sha512-jxWhnSLumrnpeGnuwYdDscze2zsuiqZiCZFQSq6VxkKLjfdI6LZwww5AY0W3aBD0qGGTxB4YO78imgLm56ZFkQ==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/edit-widgets/-/edit-widgets-5.19.6.tgz", + "integrity": "sha512-975yw6gIuHsl9Ize4dPVUMs2NwaOeH9AMTweumDNI3NRzdKeOCsKZ55lSXjn7Jp6+j11oOyP7D+220VWds16lA==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/block-library": "^8.19.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interface": "^5.19.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/patterns": "^1.3.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/reusable-blocks": "^4.19.4", - "@wordpress/url": "^3.43.4", - "@wordpress/widgets": "^3.19.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/block-library": "^8.19.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interface": "^5.19.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/patterns": "^1.3.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/reusable-blocks": "^4.19.6", + "@wordpress/url": "^3.43.6", + "@wordpress/widgets": "^3.19.6", "classnames": "^2.3.1" }, "engines": { @@ -7227,40 +7321,40 @@ } }, "node_modules/@wordpress/editor": { - "version": "13.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-13.19.4.tgz", - "integrity": "sha512-W7j9Im7ajQqia0rNrnoBkKm5WOj9cQOA5qQNqoWFf3VXLk23CTTiGVz3U9TEyIjQlMIeD8T6G8VHbYBXYBSDGQ==", + "version": "13.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-13.19.6.tgz", + "integrity": "sha512-5cay+921/4qCGHiZ/qS7QEgGE4F09gIisaR9/NxpV6Nptp2Orqfjh/czCrg2vTQWWb0heechr3ii10ubRLoiFg==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/patterns": "^1.3.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/reusable-blocks": "^4.19.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/server-side-render": "^4.19.4", - "@wordpress/url": "^3.43.4", - "@wordpress/wordcount": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/patterns": "^1.3.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/reusable-blocks": "^4.19.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/server-side-render": "^4.19.6", + "@wordpress/url": "^3.43.6", + "@wordpress/wordcount": "^3.42.6", "classnames": "^2.3.1", "date-fns": "^2.28.0", "memize": "^2.1.0", @@ -7277,14 +7371,14 @@ } }, "node_modules/@wordpress/element": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.19.4.tgz", - "integrity": "sha512-96WJOiPDlnt+Jq1uteEYo/CNhTKd3/eeEEl1dPpg+oJZy36Vp4NsrDiJptVwMXVUwSX38YLWIm62xSdR99Pq8A==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.19.6.tgz", + "integrity": "sha512-KhKJ2b2PUKuuE41a3tJKDG5YHPBo2VTCziW69ePkOsXWt/z9z0lq5+iSiZvmpMmRO8JWmhqEJGcauy6NhpZA2Q==", "dependencies": { "@babel/runtime": "^7.16.0", "@types/react": "^18.0.21", "@types/react-dom": "^18.0.6", - "@wordpress/escape-html": "^2.42.4", + "@wordpress/escape-html": "^2.42.6", "change-case": "^4.1.2", "is-plain-object": "^5.0.0", "react": "^18.2.0", @@ -7295,9 +7389,9 @@ } }, "node_modules/@wordpress/escape-html": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.42.4.tgz", - "integrity": "sha512-fjNxU4nn5nTJ6PUXs0BmTft+WuIoezI0L62yPXF42IVfDdkG5lFNMsgmjOOp0FW1PEalCh2YjchoH84Z08nw2g==", + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.42.6.tgz", + "integrity": "sha512-rYIQ38V65Lind4wpALW4ggvw/zbVKwswDEfHw16L1f611/HLmVALb1gsydpJ/nldvECMNIi7bDRQhrrgDmHKzw==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -7306,16 +7400,16 @@ } }, "node_modules/@wordpress/eslint-plugin": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-16.0.4.tgz", - "integrity": "sha512-NeFw9PR60+YBuq/jGKTRtQGUg0k9XzR/6KhiwwpY33GZgukepljUSs2oYP90r0KbkIvoWxt/AuP7LsuM/bqIew==", + "version": "16.0.6", + "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-16.0.6.tgz", + "integrity": "sha512-7MOJobRhXZOvqKBhd3cU6NR9wIOvXuDYnVWEicDaef6/KnrcH+8nPR1Y5aYlwkxW8gSgYeITsCCN3kTLJJIBPQ==", "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.4", - "@wordpress/prettier-config": "^2.25.4", + "@wordpress/babel-preset-default": "^7.26.6", + "@wordpress/prettier-config": "^2.25.6", "cosmiconfig": "^7.0.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.25.2", @@ -7364,22 +7458,22 @@ } }, "node_modules/@wordpress/format-library": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/format-library/-/format-library-4.19.4.tgz", - "integrity": "sha512-mViKxEoEdNogAcBNX7Ww/eF8XRMPbPZ5ZunWbW3S0vvNU4KGQrbEnMPlQquZpLxhmETzDzQFzReRzrzDvdd6kQ==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/format-library/-/format-library-4.19.6.tgz", + "integrity": "sha512-QfBJzycsxsvPXx6W9TR51b7idAW84CB23d0inB/CqMtq4ifb/ILssMSQ57TaixT5rALIrnSXyOsIhWe7kOVcFw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/url": "^3.43.4" + "@wordpress/a11y": "^3.42.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/url": "^3.43.6" }, "engines": { "node": ">=12" @@ -7390,9 +7484,9 @@ } }, "node_modules/@wordpress/hooks": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.42.4.tgz", - "integrity": "sha512-Be2xGwuQR90pksU5u1Pgsko2zm4Z0OHd+A4/FUc5s+Dz92zGolxYj9g7/JGPQZlmT3qTobstUxgXzUUxqjx7pA==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.42.6.tgz", + "integrity": "sha512-lG9iQs/eUjLVYL6ADoUKil5gaRwBjebZGKR1VPZaTmZnroXJP/dGy5YlKCUAwpWikgW68mtakaqJCjkjIrOAPQ==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -7401,9 +7495,9 @@ } }, "node_modules/@wordpress/html-entities": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.42.4.tgz", - "integrity": "sha512-7kdzkZkXpj0Brwz9MmElQowC9tACBZ8sIeIL3DmYzbLo8Labzo39qPsUONl8ko12yFslCPfo91FUC59r+39NzA==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.42.6.tgz", + "integrity": "sha512-LoGIBjY9KZI4UqkyLRewm2c3I0J691R/oi7aLZdqeakLdzo4RgyN+t36oy8Xn0HzCvR2/Jn8kgkRzWvQtagk0w==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -7412,12 +7506,12 @@ } }, "node_modules/@wordpress/i18n": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.42.4.tgz", - "integrity": "sha512-EdgpL5QiPmLYwyAJNAofJF9jxMk+qXUoJvyZ7IA03a/W0e9ZU0z3k1J1UlnBveS8frl8IZGFk+7Ex5iFEaZaFg==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.42.6.tgz", + "integrity": "sha512-z4It7blrz2GJAfHlwSXBmdfCKJSzNEnOIMw9kccK6V81n3GMP7m7kh+Yrol5swJnTSdAmx2hkZguMjtEoIhdvg==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/hooks": "^3.42.4", + "@wordpress/hooks": "^3.42.6", "gettext-parser": "^1.3.1", "memize": "^2.1.0", "sprintf-js": "^1.1.1", @@ -7431,22 +7525,22 @@ } }, "node_modules/@wordpress/icons": { - "version": "9.33.4", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.33.4.tgz", - "integrity": "sha512-KGPUhEQdA6pA/gGj/JL4BSA1aIPyypgzFhQtrLEkZxUEOAyWZxoOn/QKrEx3uAYVsPrbjLEDMfyEMViQTkQB3w==", + "version": "9.33.6", + "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.33.6.tgz", + "integrity": "sha512-TEwuga9Nukyec4Z1nzsDolBneC8GGC4QpyPO8RD8NuiuyHj4pmis1sbmDPIxvtVOkcDOYQU3be16Vy+4VeSgbQ==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/element": "^5.19.4", - "@wordpress/primitives": "^3.40.4" + "@wordpress/element": "^5.19.6", + "@wordpress/primitives": "^3.40.6" }, "engines": { "node": ">=12" } }, "node_modules/@wordpress/interactivity": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-2.3.4.tgz", - "integrity": "sha512-rVHgi5D3jzEZtwJsc7ON3vqlUQUQJz7BztmVYUZIcqYA8I7e7bxby8Wp9a+9y5ZD+b5vNV+lmUxaRXCS6EjBrQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-2.3.6.tgz", + "integrity": "sha512-duZIob6rPv9FDSi3G0FXn8OOwejUFOaxEGnLQD0pYYg0lRJQQGUxgLRPNIbL8wJ5mb0/LDRAAee8XT+LHWOq6g==", "dependencies": { "@preact/signals": "^1.1.3", "deepsignal": "^1.3.6", @@ -7457,22 +7551,22 @@ } }, "node_modules/@wordpress/interface": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-5.19.4.tgz", - "integrity": "sha512-+WddMz+wIM7P4XYlQRlhxC2o8FJMtpxbvxbNVpjhDklAoLfYC/3Yu3tENO1MTZjhXR5Du+rWoOwr2S+gnPHiqw==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-5.19.6.tgz", + "integrity": "sha512-f3hj0TyTsAfBwvVkBeI4DBGZfSVfobIvkklgIIeJ9Rkxk3a71Bubwk0QfefK0/kH8BNy8o4YK4LNCGPxl//fGg==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/viewport": "^5.19.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/viewport": "^5.19.6", "classnames": "^2.3.1" }, "engines": { @@ -7484,9 +7578,9 @@ } }, "node_modules/@wordpress/is-shallow-equal": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-4.42.4.tgz", - "integrity": "sha512-cb1mOrgz1agMulmGGPvKhVhpThkhgPPn2JqYJTlcfo1G8BwpQP5U/w2g8vu/4gCYS5OyuTilXbMa4RTpx61WsA==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-4.42.6.tgz", + "integrity": "sha512-gJEoqRE9jMvHMT39PLrd2QQc2qfa3PnDfcmz6R+TYsrbK09/uN9ZIFfKK1o9d1FoVBBTfbGfn358spEaQLAXfQ==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -7528,14 +7622,14 @@ } }, "node_modules/@wordpress/keyboard-shortcuts": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-4.19.4.tgz", - "integrity": "sha512-cMWMFr7b1QJhNulpd4E76QmFhPYshmR445dNeXfmHZBobsAxr3U6wJfl144uMJ4PNjNpS9bGpQ2s0zaz3N+B5Q==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-4.19.6.tgz", + "integrity": "sha512-mvzS5bSePRj6h7Wau6o6Jznpxj0zGvWVMF9JQf7pCYHVEOIYS15yNpJoU1FiMnMT3afbB2pN/5NmuDXpw9DFmw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/keycodes": "^3.42.4", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/keycodes": "^3.42.6", "rememo": "^4.0.2" }, "engines": { @@ -7546,12 +7640,12 @@ } }, "node_modules/@wordpress/keycodes": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.42.4.tgz", - "integrity": "sha512-RPV9eLBGTuFXPwRBRuujX9fb9BPrY6DojByS0O/G/sk/Dh+ncCyudQ9T0hCkRErelxma8WqigVAeOkcNzVNoLg==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.42.6.tgz", + "integrity": "sha512-VTvLQxqmGuziPsdDLRXV5mirY9PiTXR/+B5EA/cYExPeFUgfS7B3u8+vjvHUujlbGwrivU8jZjLrgbwEjC2bcw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/i18n": "^4.42.4", + "@wordpress/i18n": "^4.42.6", "change-case": "^4.1.2" }, "engines": { @@ -7559,16 +7653,16 @@ } }, "node_modules/@wordpress/list-reusable-blocks": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/list-reusable-blocks/-/list-reusable-blocks-4.19.4.tgz", - "integrity": "sha512-kfl/lkKQ3T1++dHA4dXEwaoHU188tmbioo6T06Vy86p91AhBqq3wOaIZ2qrgExSB4o+c+8Dc66AzmwfOj/hieg==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/list-reusable-blocks/-/list-reusable-blocks-4.19.6.tgz", + "integrity": "sha512-9T+HX03lq9P0OUvovZQUFJL/M1MM07IL4+AUMu+UNA8HKOz3ASbOXFNXNoMmVJSEoQcvIYnSTSDUPzMJ5Eszxg==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", "change-case": "^4.1.2" }, "engines": { @@ -7580,28 +7674,28 @@ } }, "node_modules/@wordpress/media-utils": { - "version": "4.33.4", - "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-4.33.4.tgz", - "integrity": "sha512-WIQVJKXA9zp/CZEh/mun420y8GxJtyLQWUar0AyZcD73hmNdaDzfe7MYzhp3kVQ7E4OcIcq5yxoVhHViun9FUg==", + "version": "4.33.6", + "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-4.33.6.tgz", + "integrity": "sha512-FGjlcfpFmHQmwCQycPlijwwsoO4bWn6ap0VgGLU59V+3cWmfO2dmwaquPoFAgFcQt6LFcaqaeen72JlG7G0CHA==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4" + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6" }, "engines": { "node": ">=12" } }, "node_modules/@wordpress/notices": { - "version": "4.10.4", - "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-4.10.4.tgz", - "integrity": "sha512-7OxkoFy6pKHkvsflJR3fsP5ngHbciN9BBguhqgTj9lLVclVFhfrPDlkcdzfXk3DC5vixze3atJM3JKmue9DA6g==", + "version": "4.10.6", + "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-4.10.6.tgz", + "integrity": "sha512-g1uyL0zguU0s6EiYyKpZEu97FNK5j+4uXCAITQhpaOJDSUBF9TflPFaXrBKkBCwKvfgE9P7FtYDrVEnceF+z/g==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/data": "^9.12.4" + "@wordpress/a11y": "^3.42.6", + "@wordpress/data": "^9.12.6" }, "engines": { "node": ">=12" @@ -7623,18 +7717,18 @@ } }, "node_modules/@wordpress/nux": { - "version": "8.4.4", - "resolved": "https://registry.npmjs.org/@wordpress/nux/-/nux-8.4.4.tgz", - "integrity": "sha512-CWsm9BfBY3PjtPcy1+kga5GC/J4D3du5YacgxkVkwuRcnino0PvHxdnz2YcbUjyXHWGcFlz/x4eto278Pqa5ug==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/@wordpress/nux/-/nux-8.4.6.tgz", + "integrity": "sha512-v54z9qXa1kk9+cG4GlxmUghAmI47prA8uUWR28s7pZzeaD/eFZEQ8X8HTUE9tm35NS7dK+qWcNSUwsfLH4kuww==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", "rememo": "^4.0.2" }, "engines": { @@ -7646,28 +7740,27 @@ } }, "node_modules/@wordpress/patterns": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-1.3.4.tgz", - "integrity": "sha512-TKyR0FN1JQ2xPHIxzXuayo3NRYCuDgIpTj4803LITqm1y6Ypw0U/H1Pooi4epvgiLd+Oa0sNbTkBRfCEbH075w==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-1.3.6.tgz", + "integrity": "sha512-ji5O7NfJIixIxJoF9K7VfS++BRcI3yuQ7fWJsDPq2vd7xR+n3uHJGGouxi7OcvmQ4blYM6is+RZyXDm+F1O4pQ==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/url": "^3.43.4" + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/url": "^3.43.6" }, "engines": { - "node": ">=16.0.0", - "npm": ">=8 <9" + "node": ">=16.0.0" }, "peerDependencies": { "react": "^18.0.0", @@ -7675,17 +7768,17 @@ } }, "node_modules/@wordpress/plugins": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-6.10.4.tgz", - "integrity": "sha512-MACIKd4WhUZ5nuvFPiBaB6bOGw/EceCzpbuN1JXZe3i1CgXxuS4NIZmfkpX5F5pRsfcVeyTQUDmqAB3UQQDB7Q==", + "version": "6.10.6", + "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-6.10.6.tgz", + "integrity": "sha512-3eCZouQ/Z5wmORsoVOKqKNdlxU5UNgsoOiljpwypYmZCqpS2+HdPlVHx6juV7B6KysU77rrAOOoGJqqEt/RPfQ==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/is-shallow-equal": "^4.42.4", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/is-shallow-equal": "^4.42.6", "memize": "^2.0.1" }, "engines": { @@ -7713,17 +7806,17 @@ } }, "node_modules/@wordpress/preferences": { - "version": "3.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-3.19.4.tgz", - "integrity": "sha512-rCvRfJD/lA7yaAPczhVjawvypRCTzUCeInndkatGegn8u9wkFg6wJU52ZyqYdjV80ihvq5o8VsLIBXjYzp/+Rw==", + "version": "3.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-3.19.6.tgz", + "integrity": "sha512-OGVWwha+v86cFCrrxow4n8a585IumGUvmJPGMRzLdvLRcinvHX9xNevYw+SV/ecrsHtOhSRSrAM9Yn9t9V1HzA==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/components": "^25.8.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/components": "^25.8.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", "classnames": "^2.3.1" }, "engines": { @@ -7735,21 +7828,21 @@ } }, "node_modules/@wordpress/preferences-persistence": { - "version": "1.34.4", - "resolved": "https://registry.npmjs.org/@wordpress/preferences-persistence/-/preferences-persistence-1.34.4.tgz", - "integrity": "sha512-+ka04qSy/HoOoQmm0vttlwLJ+Lgw0sPSjy7/QzT+kp46PhGMVXmpdxmETKldHBUpKXa0N/9JO7566XILWLBQCA==", + "version": "1.34.6", + "resolved": "https://registry.npmjs.org/@wordpress/preferences-persistence/-/preferences-persistence-1.34.6.tgz", + "integrity": "sha512-sWZUSOejx5HNCOJBisv60Kqe0hHfwlQL6K6VNL5U0oGO3QTtww7EPz2wi9Is3JKnhk9SKgI3F7+Ey9cqyARlXw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4" + "@wordpress/api-fetch": "^6.39.6" }, "engines": { "node": ">=12" } }, "node_modules/@wordpress/prettier-config": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-2.25.4.tgz", - "integrity": "sha512-ns7MFZ0DZyLcU0efjdwgP9pRpnDZbuC6wgD+nfJVYc5EOt1FiQGHnjRkoOZYCqCJosQCka0+sjiylcW2PD6cYA==", + "version": "2.25.6", + "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-2.25.6.tgz", + "integrity": "sha512-huMWGCr4Dy9/rYoJVtoQUKIp/CgPy+Cd7tQ6WZzuhPXZ9Pkd4Omkuu70QOji3k1b+qkXMFpS2fVxiD6rAsmtRQ==", "dev": true, "engines": { "node": ">=14" @@ -7759,12 +7852,12 @@ } }, "node_modules/@wordpress/primitives": { - "version": "3.40.4", - "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.40.4.tgz", - "integrity": "sha512-990RKWcIQB236FsBMXGuIwWblhoOPi2N8xWTzqYnge7UY8hg8um8+pSxXppAnP5mmObovQGzenTYhCMiEnC48w==", + "version": "3.40.6", + "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.40.6.tgz", + "integrity": "sha512-PnAZlx5FfhN3m03es+vEK3brqtp5Z4PggeGEeGSNXdxq9/A2YMsK4yno1jVQczFwN48AAA6WkV/Dp5LmRgh/iA==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/element": "^5.19.4", + "@wordpress/element": "^5.19.6", "classnames": "^2.3.1" }, "engines": { @@ -7772,9 +7865,9 @@ } }, "node_modules/@wordpress/priority-queue": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-2.42.4.tgz", - "integrity": "sha512-MmaWSCJr5tgUJFqPZwiC+MBwY+fSsoudA5iCDqlQwvwCmG092pzH3bhI6vryS83bbowC/UvTZTw/cNVaazxAKQ==", + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-2.42.6.tgz", + "integrity": "sha512-y9JbhHUdChKXGQIS67Z6z4BWrqEIO3COZoBlQLScvCNdgzGYMoZfyqN1AMy1DiFJ3eIoZGLWDaKqLnA9I6p+1w==", "dependencies": { "@babel/runtime": "^7.16.0", "requestidlecallback": "^0.3.0" @@ -7784,9 +7877,9 @@ } }, "node_modules/@wordpress/private-apis": { - "version": "0.24.4", - "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.24.4.tgz", - "integrity": "sha512-2DJnBVa1ZnM6HoqPbtVYjIhdf08oQbmhK6Amwkp/ZXe+rnpkN989JuLJnw70qnsIXZwK1YcUj1ndWVUxi2ZkEQ==", + "version": "0.24.6", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.24.6.tgz", + "integrity": "sha512-f1kNlPgVTk+DjzOJh3nRUSZam6BshD6VAquYP7pukFfHlA4eQViUHL4TVvAc8EC48J5tRl2GqsdYeXG3oOscmQ==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -7795,9 +7888,9 @@ } }, "node_modules/@wordpress/redux-routine": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-4.42.4.tgz", - "integrity": "sha512-GrTeL3PNHObUh+hT0M7QfkKou6s8LbczNpIT6eOALhPJYL28e+UK6XxBccTT59DmZdNDI8Ycn5/6IYyDGk5psA==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-4.42.6.tgz", + "integrity": "sha512-LHdyocfwj5EMITN4i7siwkX1gKI8O4z/IX+Z6Ex+RV7MXb0Cpfyqi5aGXs+uGdUInJhNa+fh/vjYqBaiXfwbRw==", "dependencies": { "@babel/runtime": "^7.16.0", "is-plain-object": "^5.0.0", @@ -7812,22 +7905,22 @@ } }, "node_modules/@wordpress/reusable-blocks": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-4.19.4.tgz", - "integrity": "sha512-wPgzMugNbmfUuUtAA9koCaD5CWjf1dxsUrxmq6kx+alOJeEGEmSxdNfJCws21kFXi/gQwijPonQFW4oxMxLoFQ==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-4.19.6.tgz", + "integrity": "sha512-AxU3gkfFOPuDG06GDg/OScr2trWzW6LBqUK4TgTv30tAVOZi8TisoIloxx7gWSpsTP9oBbOY0ilhQQH10e/Vgw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/url": "^3.43.4" + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/url": "^3.43.6" }, "engines": { "node": ">=12" @@ -7838,19 +7931,19 @@ } }, "node_modules/@wordpress/rich-text": { - "version": "6.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-6.19.4.tgz", - "integrity": "sha512-ecf18dQRYwDSABvhiZ0lQJUK5Ui4XTHq8sxP908DPvtOcuUszyXPPoghT9L/MgR6chi1d8PtFS4wAOfm474zWA==", + "version": "6.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-6.19.6.tgz", + "integrity": "sha512-8W49w3scw0njSN9Z+z9S/EVfc83wvaMuk3WqY2GFvUDfWQayetAMK9LoYfVZECGoO0Cy/cL0Ru4xv989DBuWYw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/keycodes": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/keycodes": "^3.42.6", "memize": "^2.1.0", "rememo": "^4.0.2" }, @@ -7862,14 +7955,14 @@ } }, "node_modules/@wordpress/router": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/@wordpress/router/-/router-0.11.4.tgz", - "integrity": "sha512-2I7HxlT/N/pdHGvJ2iQjXsHnu5cSLnr/yciD6U+nMFHu9AiL0o0z28HCF/E/NKb4BLTzRc+RUjlDEKd74rroWQ==", + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@wordpress/router/-/router-0.11.6.tgz", + "integrity": "sha512-WVY5A91joF4vNP75n/RjqCy/PyGUbL0m6UGR2G0q/da3XgABXi4pGlZKU6DhpE46gTInzfokHOxNwtbggopHcw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/element": "^5.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/url": "^3.43.4", + "@wordpress/element": "^5.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/url": "^3.43.6", "history": "^5.1.0" }, "engines": { @@ -7880,24 +7973,24 @@ } }, "node_modules/@wordpress/scripts": { - "version": "26.13.4", - "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-26.13.4.tgz", - "integrity": "sha512-9dNSM4v9DN1pdBsnDMxhggMS3aMBqsIxFDvWzLx6mlmOTA5mI74XATYNKroONfPXCiUUubRmil+raT3UhTP2jQ==", + "version": "26.13.6", + "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-26.13.6.tgz", + "integrity": "sha512-ROzfZpf8OL4k+r5GCU1DaE3gBFbjVMwDGdhseRaoQj0LIsDrDYJr6RimoWgl4TP8YWAH+T/YbZWHImMc0J+0Rw==", "dev": true, "dependencies": { "@babel/core": "^7.16.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.2", "@svgr/webpack": "^8.0.1", - "@wordpress/babel-preset-default": "^7.26.4", - "@wordpress/browserslist-config": "^5.25.4", - "@wordpress/dependency-extraction-webpack-plugin": "^4.25.4", - "@wordpress/e2e-test-utils-playwright": "^0.10.4", - "@wordpress/eslint-plugin": "^16.0.4", - "@wordpress/jest-preset-default": "^11.13.4", - "@wordpress/npm-package-json-lint-config": "^4.27.4", - "@wordpress/postcss-plugins-preset": "^4.26.4", - "@wordpress/prettier-config": "^2.25.4", - "@wordpress/stylelint-config": "^21.25.4", + "@wordpress/babel-preset-default": "^7.26.6", + "@wordpress/browserslist-config": "^5.25.6", + "@wordpress/dependency-extraction-webpack-plugin": "^4.25.6", + "@wordpress/e2e-test-utils-playwright": "^0.10.6", + "@wordpress/eslint-plugin": "^16.0.6", + "@wordpress/jest-preset-default": "^11.13.6", + "@wordpress/npm-package-json-lint-config": "^4.27.6", + "@wordpress/postcss-plugins-preset": "^4.26.6", + "@wordpress/prettier-config": "^2.25.6", + "@wordpress/stylelint-config": "^21.25.6", "adm-zip": "^0.5.9", "babel-jest": "^29.6.2", "babel-loader": "^8.2.3", @@ -7957,6 +8050,28 @@ "react-dom": "^18.0.0" } }, + "node_modules/@wordpress/scripts/node_modules/@wordpress/e2e-test-utils-playwright": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.10.6.tgz", + "integrity": "sha512-qUIcQTB4lFG6BUVCPtzs4gDeO/9Pzz1Knq3Uvt1QIYojy9Yr6G6c3f3Mudql+HFfiXoj3B3BxGbA4oLSb7bI6w==", + "dev": true, + "dependencies": { + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/url": "^3.43.6", + "change-case": "^4.1.2", + "form-data": "^4.0.0", + "get-port": "^5.1.1", + "lighthouse": "^10.4.0", + "mime": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "@playwright/test": ">=1" + } + }, "node_modules/@wordpress/scripts/node_modules/ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -8100,6 +8215,20 @@ "node": ">=8" } }, + "node_modules/@wordpress/scripts/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": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/@wordpress/scripts/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -8159,6 +8288,18 @@ "node": ">=8" } }, + "node_modules/@wordpress/scripts/node_modules/mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/@wordpress/scripts/node_modules/p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", @@ -8296,20 +8437,20 @@ } }, "node_modules/@wordpress/server-side-render": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-4.19.4.tgz", - "integrity": "sha512-EtOnXb8tZ2bltpR8mHAK2uoaF+4a0X2tyBmT0iam4LpL+csMnQkUaDR5WeugxFQ47iLDK679AGblDy8gOlomOg==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-4.19.6.tgz", + "integrity": "sha512-mrRQDdpqsSW3Qfd8LSITMGY+Zazt1vKUSLc1DjSZksIMmOb/HUnNs4VKlhhcA638tjmBuWrTtPbTGG/kroWO+A==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/url": "^3.43.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/url": "^3.43.6", "fast-deep-equal": "^3.1.3" }, "engines": { @@ -8321,9 +8462,9 @@ } }, "node_modules/@wordpress/shortcode": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-3.42.4.tgz", - "integrity": "sha512-P0d9OHi9g+O78PTtN34lunNi21bPyaRMjPPxtyCtMgSRfSB9dQjFGfA2HZ9cq4clRae8tpUMRQtksNWMszQhsA==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-3.42.6.tgz", + "integrity": "sha512-3uW65IppB9Gs8bAhClZYWDxy9Rl3iqOuMH2mwEU02wdvCNlr47YLLo/2QiqNpjtyyyTJFNrhaiQjZhFyulCygA==", "dependencies": { "@babel/runtime": "^7.16.0", "memize": "^2.0.1" @@ -8333,9 +8474,9 @@ } }, "node_modules/@wordpress/style-engine": { - "version": "1.25.4", - "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-1.25.4.tgz", - "integrity": "sha512-p3GUdsOibw59ajKAr+dxK8zB/3HAGWj4lmL2gPqU2EqnoWkomKEd9lWWSTLzNxHHMJPgpPCUd5WeMifUJow1sg==", + "version": "1.25.6", + "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-1.25.6.tgz", + "integrity": "sha512-7GuFhRAd51A602i8uyytBbFPcEifXV5WH2UVAeiDN5sju/6f+OF2pAHG0lN799ricNE7i2idRIIUbl7CJsmQEQ==", "dependencies": { "@babel/runtime": "^7.16.0", "change-case": "^4.1.2" @@ -8361,9 +8502,9 @@ } }, "node_modules/@wordpress/sync": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-0.4.4.tgz", - "integrity": "sha512-Sdzgp6LPrgli6cAGJSssB2HE/6SrM1zKimyiiVjue0/Sui2NB5OepEbf43s43JSddgtqDUDuTq2xC6XnNelfGw==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-0.4.6.tgz", + "integrity": "sha512-incrgWQOlngpM4dceEzASvbZ+OxlkitsDvBOlj1VGe5mhKBrYDsdoYNvF760+l3QQ+5FE2w3d5ilHaSnIkpE6w==", "dependencies": { "@babel/runtime": "^7.16.0", "y-indexeddb": "~9.0.11", @@ -8375,9 +8516,9 @@ } }, "node_modules/@wordpress/token-list": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-2.42.4.tgz", - "integrity": "sha512-w/7cS3OCCaqZRbRXzXl1o2GbVmLXdBPknvm8NuYsNLnA0n8aNzeOcH3gB0/DETzJ4UL2htu/ukkSSQ69JGb/Ow==", + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-2.42.6.tgz", + "integrity": "sha512-Z02kJIfSbE/d35wvF89b4iZTPQA1/rK5MGIIb5JkrO2mQZE9ZnUDagN4Ci0Lrq5pvw0L+p1cCLFz/X26vguOtA==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -8386,21 +8527,21 @@ } }, "node_modules/@wordpress/undo-manager": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-0.2.4.tgz", - "integrity": "sha512-dXvWdFEKmwj/h+bTvL4xcTyD49srTxVhAoUZxN7J3baoKMqU71Vl8AEntboVUdgF7DdgvPkABQxSF29i47tbpQ==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-0.2.6.tgz", + "integrity": "sha512-0u28awvzIAU78d24xw8wkzmDGFBPzVbKorylrW/d+6QRL31v0/4Sv9mlLlmHr0G/wgcKPA53t34HQ9i0IMkaEQ==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/is-shallow-equal": "^4.42.4" + "@wordpress/is-shallow-equal": "^4.42.6" }, "engines": { "node": ">=12" } }, "node_modules/@wordpress/url": { - "version": "3.43.4", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.43.4.tgz", - "integrity": "sha512-flnQ8AMNWyOoeojq1VdH/INS0BCJJprSMz33it8v7LMvb0p8Dju80LHM9H2I9sn2ljO0hWx8hA9AuI7jqEWnng==", + "version": "3.43.6", + "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.43.6.tgz", + "integrity": "sha512-1Rz9N8gQD4cFcM1JO0Nrn91c8EMmb0z49KoX8wKrq2SvwSUs0fEvPj2XwRVk7VMItR9ieg9B4XxSNBLynfviLg==", "dependencies": { "@babel/runtime": "^7.16.0", "remove-accents": "^0.5.0" @@ -8410,14 +8551,14 @@ } }, "node_modules/@wordpress/viewport": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-5.19.4.tgz", - "integrity": "sha512-uazIYyL0vmHOXsQQzh4tVFtrL+ReCYPBIpQaJStcLoyAzn5WAPQRmjfcpYK/TpMZxT/wLVrHUUBXnTumBVkmHA==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-5.19.6.tgz", + "integrity": "sha512-n5u0kRr66tg7nLRyaWPLi5Fzs0ZRYfYkUlazkszMWJ+V4tNtC683IBy9jgQE/SPFBAn5Vf5yRJT7ov/xAgltkQ==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4" + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6" }, "engines": { "node": ">=12" @@ -8427,30 +8568,30 @@ } }, "node_modules/@wordpress/warning": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.42.4.tgz", - "integrity": "sha512-q2YzFYDjFD7FuthRGag4yIsOylCl1KN8mDSPaxYuSpkxNSYgpW9SCrBTMxGxrHfSx48Q/FZwvRGRJFgH4DFpoA==", + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.42.6.tgz", + "integrity": "sha512-QN9NAiiJvBVwLzzi1IQlkAmoKENGRTmx7OqI1w+qbzGdKRguwPd7ek0nNQg95ktDE0PzgRlILfXwDJTJM7y9Tg==", "engines": { "node": ">=12" } }, "node_modules/@wordpress/widgets": { - "version": "3.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/widgets/-/widgets-3.19.4.tgz", - "integrity": "sha512-HeLFh9OrIS4svnEEscS0HInlQ9/FwgG0lta/rcTZbn6jq09dfziEhtEhcT+eMm/OEQbW2A2jyU9WLf91REGB/g==", + "version": "3.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/widgets/-/widgets-3.19.6.tgz", + "integrity": "sha512-607mGNC3bj+xOVHWQl9FHB78aQmbNJDp3vaplw09jcI/rs6Us+AR9WqKkeA9Bv/1xPENPSruFNrcuuIbNN7EXw==", "dependencies": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/notices": "^4.10.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/notices": "^4.10.6", "classnames": "^2.3.1" }, "peerDependencies": { @@ -8459,9 +8600,9 @@ } }, "node_modules/@wordpress/wordcount": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-3.42.4.tgz", - "integrity": "sha512-8jP0hpZ++IXPnIWA8RJbHzJi9cXh40rrzGLR90P+Nm88BakA/OZhl5wavWcniiPtXn/hMhg2GyJa24IdV3NdLw==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-3.42.6.tgz", + "integrity": "sha512-eyAuwgV9c3P0HxBx0qY0JlV42sBm0vMmRKkCgfUZBNqW+1dzBXy1esOYCOJASSwUoGkV7USOHZQm1iMu/2WjoQ==", "dependencies": { "@babel/runtime": "^7.16.0" }, @@ -13838,9 +13979,9 @@ } }, "node_modules/eslint-import-resolver-node/node_modules/resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -14174,9 +14315,9 @@ } }, "node_modules/eslint-plugin-prettier": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", - "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", "dev": true, "dependencies": { "prettier-linter-helpers": "^1.0.0", @@ -14266,12 +14407,12 @@ } }, "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -36730,6 +36871,17 @@ } } }, + "@playwright/test": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.32.0.tgz", + "integrity": "sha512-zOdGloaF0jeec7hqoLqM5S3L2rR4WxMJs6lgiAeR70JlH7Ml54ZPoIIf3X7cvnKde3Q9jJ/gaxkFh8fYI9s1rg==", + "dev": true, + "requires": { + "@types/node": "*", + "fsevents": "2.3.2", + "playwright-core": "1.32.0" + } + }, "@pmmmwh/react-refresh-webpack-plugin": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.5.tgz", @@ -38439,16 +38591,16 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz", - "integrity": "sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", + "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/type-utils": "6.7.4", - "@typescript-eslint/utils": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -38458,54 +38610,54 @@ } }, "@typescript-eslint/parser": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.4.tgz", - "integrity": "sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.5.tgz", + "integrity": "sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "6.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz", - "integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", + "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", "dev": true, "requires": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5" } }, "@typescript-eslint/type-utils": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz", - "integrity": "sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz", + "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "6.7.4", - "@typescript-eslint/utils": "6.7.4", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/types": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz", - "integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", + "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz", - "integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", + "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", "dev": true, "requires": { - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/visitor-keys": "6.7.4", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -38514,27 +38666,27 @@ } }, "@typescript-eslint/utils": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.4.tgz", - "integrity": "sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz", + "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==", "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.7.4", - "@typescript-eslint/types": "6.7.4", - "@typescript-eslint/typescript-estree": "6.7.4", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz", - "integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", + "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", "dev": true, "requires": { - "@typescript-eslint/types": "6.7.4", + "@typescript-eslint/types": "6.7.5", "eslint-visitor-keys": "^3.4.1" }, "dependencies": { @@ -38727,43 +38879,43 @@ "dev": true }, "@wordpress/a11y": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-3.42.4.tgz", - "integrity": "sha512-kJdsWkqQ5iBaFnpEUXKRydfZBfY3zDNbIia8gLxGqallW84wSsSvajLe+EewxNs32KzJADaIcJ3zTMHqUnSo3Q==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/a11y/-/a11y-3.42.6.tgz", + "integrity": "sha512-jvSXfOauAZfhDG9RdsyIWYtSBEeR3VBH4ar80gk3xgbEdp14GdJ9NzZBel42KmmIjKJFpKagj5VIaD5EgQMziw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/dom-ready": "^3.42.4", - "@wordpress/i18n": "^4.42.4" + "@wordpress/dom-ready": "^3.42.6", + "@wordpress/i18n": "^4.42.6" } }, "@wordpress/annotations": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/annotations/-/annotations-2.42.4.tgz", - "integrity": "sha512-qlo1mN+oYgP6qJRYaHwotmUzcJo4RaGG24ZRegItgw/jztcoZej2dPf0IrcN8WyokAk0YHeMNfGumNm7YywANA==", + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/annotations/-/annotations-2.42.6.tgz", + "integrity": "sha512-G+gzWVOeJ6EV00ZZZRfM95+gzBwWxe9jcn6Ql5sZTe90/H9iUSC5bYvlhGfK62glfwTmmTJjSZL/BJR0zrEuow==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/data": "^9.12.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/rich-text": "^6.19.4", + "@wordpress/data": "^9.12.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/rich-text": "^6.19.6", "rememo": "^4.0.2", "uuid": "^9.0.1" } }, "@wordpress/api-fetch": { - "version": "6.39.4", - "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.39.4.tgz", - "integrity": "sha512-yILvK5Qng58Dj0+o76Zhs4dgRajHib/1u+b2vSKhPCF/BKqjb0tvD3t/dff9IyhYGC1jIWVG77sA1L+AkIa6zg==", + "version": "6.39.6", + "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.39.6.tgz", + "integrity": "sha512-JVMNy4MlDXxz3CwXbr+vRkKfHYAXYMirUxfB9Vmj3hC7bCbtVGMbNdZrjJW9L7UlRH8zZGiKbdZ+9HESnq+bpw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/i18n": "^4.42.4", - "@wordpress/url": "^3.43.4" + "@wordpress/i18n": "^4.42.6", + "@wordpress/url": "^3.43.6" } }, "@wordpress/autop": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-3.42.4.tgz", - "integrity": "sha512-9SzLSSSSZkvEZ4eDyWFmD0/BvxpdlhboGUJqGXew1zeDD3VrUf8tKHaNg8V1pnrPdFdMTPzPi9mf98bggtqIbQ==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/autop/-/autop-3.42.6.tgz", + "integrity": "sha512-q2vTd3IYZBsbYOlWpa8KLlhEDERepgsiPv8BdkS9Aj7HZ6XtbxtwnnYu0gYZoDFb223g6IdASJs7ic3Rj4oP0Q==", "requires": { "@babel/runtime": "^7.16.0" } @@ -38775,9 +38927,9 @@ "dev": true }, "@wordpress/babel-preset-default": { - "version": "7.26.4", - "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-7.26.4.tgz", - "integrity": "sha512-7YKnSFVmg/8CgtcXh6v4C2L+H6/MOH6lLLu7rBLY0p3bGX+EnFDb3jzaWMtoPLvyIBjD8cUln09JtPrIfsRrNA==", + "version": "7.26.6", + "resolved": "https://registry.npmjs.org/@wordpress/babel-preset-default/-/babel-preset-default-7.26.6.tgz", + "integrity": "sha512-Np6az/l4er+463PR4Bg5DJTYceNf4JUKJcMYogFaW+2NZARtQggjiqdjrKlWijHSzGq1tIMMGWUHiFKP1nub8A==", "dev": true, "requires": { "@babel/core": "^7.16.0", @@ -38786,10 +38938,10 @@ "@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.4", - "@wordpress/browserslist-config": "^5.25.4", - "@wordpress/element": "^5.19.4", - "@wordpress/warning": "^2.42.4", + "@wordpress/babel-plugin-import-jsx-pragma": "^4.25.6", + "@wordpress/browserslist-config": "^5.25.6", + "@wordpress/element": "^5.19.6", + "@wordpress/warning": "^2.42.6", "browserslist": "^4.21.9", "core-js": "^3.31.0" } @@ -38801,79 +38953,79 @@ "dev": true }, "@wordpress/blob": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-3.42.4.tgz", - "integrity": "sha512-Mg/2TaXbYwRE77DNwDrjhKQpyfB6NbGu+YtZrI5a7Nu6Y/VpLBAUrekTOXnn1kGZfX5LITaUonZxyyFFBcPiow==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/blob/-/blob-3.42.6.tgz", + "integrity": "sha512-8mb0ghOqaHgOGmbamy/SE9+mLx/vqdAdPR1olxLLcwD4OROM2vSMK/GSpRD8EPM3A3dCxqvK/W7zhCUhj/y6Rg==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/block-directory": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-4.19.4.tgz", - "integrity": "sha512-/NTVS9eSur56HWM1SN4VIgWb26QSPmZIYMvd7T0BFpko+jL0YdqhZ0DI0BbXVxGPc/tDZ+k5kFN9FvZVNKU01w==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/block-directory/-/block-directory-4.19.6.tgz", + "integrity": "sha512-V2sh5pEjrFL/AOMnkb+C91mhiL6dhi79zlmiBxpsnEoCsDeN6SehkximdZqba+jiqpX/rwtgYn8ny2q18/IKpQ==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/edit-post": "^7.19.4", - "@wordpress/editor": "^13.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/url": "^3.43.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/edit-post": "^7.19.6", + "@wordpress/editor": "^13.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/url": "^3.43.6", "change-case": "^4.1.2" } }, "@wordpress/block-editor": { - "version": "12.10.4", - "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-12.10.4.tgz", - "integrity": "sha512-ADxKedK9ZqyebdD216gCfPX6Fe6xWN0VMABwiYMlOC4sE3QYVk/kKX55IabAi40+N0GtVSh6r9sJjXJ9yX59hw==", + "version": "12.10.6", + "resolved": "https://registry.npmjs.org/@wordpress/block-editor/-/block-editor-12.10.6.tgz", + "integrity": "sha512-2ONGkwu3hM1hyWB1hHj5xggi14SjB81qE2TXkbdVaABFORoIFKX0TfcBiyEvF+vUTnFxInKteR9JPDjmzQDfhg==", "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.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/commands": "^0.13.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/shortcode": "^3.42.4", - "@wordpress/style-engine": "^1.25.4", - "@wordpress/token-list": "^2.42.4", - "@wordpress/url": "^3.43.4", - "@wordpress/warning": "^2.42.4", - "@wordpress/wordcount": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/commands": "^0.13.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/shortcode": "^3.42.6", + "@wordpress/style-engine": "^1.25.6", + "@wordpress/token-list": "^2.42.6", + "@wordpress/url": "^3.43.6", + "@wordpress/warning": "^2.42.6", + "@wordpress/wordcount": "^3.42.6", "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", @@ -38890,41 +39042,41 @@ } }, "@wordpress/block-library": { - "version": "8.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-8.19.4.tgz", - "integrity": "sha512-U5s0T/aRT/sk7cRomkjYj62hgKqNtKHzOzm3T7lwZi+1BXPq/zDGXl3jE8M1H1yermUuTffLk6BSC+n9c03JYA==", + "version": "8.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/block-library/-/block-library-8.19.6.tgz", + "integrity": "sha512-xZRgLebqmDvRaBMP5wsBl2qdzB/HhfCJbGy7YabnCSgZQKYEj4Y11mC5vl27zr8u4aAftsp07bKLJaDGs30IyA==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/autop": "^3.42.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interactivity": "^2.3.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/primitives": "^3.40.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/reusable-blocks": "^4.19.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/server-side-render": "^4.19.4", - "@wordpress/url": "^3.43.4", - "@wordpress/viewport": "^5.19.4", - "@wordpress/wordcount": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/autop": "^3.42.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interactivity": "^2.3.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/primitives": "^3.40.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/reusable-blocks": "^4.19.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/server-side-render": "^4.19.6", + "@wordpress/url": "^3.43.6", + "@wordpress/viewport": "^5.19.6", + "@wordpress/wordcount": "^3.42.6", "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", @@ -38937,33 +39089,33 @@ } }, "@wordpress/block-serialization-default-parser": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-4.42.4.tgz", - "integrity": "sha512-+BW7gTWjcGj3DVtAzQsX7bT8OKsFpq6B9FjS0Oc+6M9bCJd5IW5XNHu+NOKLJFX80Ao1x2eN4a9IWs0xZl0Z5g==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/block-serialization-default-parser/-/block-serialization-default-parser-4.42.6.tgz", + "integrity": "sha512-Tto25U4xB+WV2elReEbgIyQ/6S6papc320O1BqGrTvrlMsmz+DJRu8sgHti5geNL7EkSd2fFaoiH1wlqdSVGBg==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/blocks": { - "version": "12.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-12.19.4.tgz", - "integrity": "sha512-JD7vbdow1RZ3SHsJTn8Opg7fdic7brG7P6YI0pvtZhmixWk1uMWyFzu3aoj9SooB0aQzWIhQy324O351+Gy2vA==", + "version": "12.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/blocks/-/blocks-12.19.6.tgz", + "integrity": "sha512-He6ItxlBRRO3mNkiMkZerORb716nyNyNCah7MhKqaepqwfKiuQNb1lBNpBv6DwD2urmXpQXYmVQ2hRv8vHDJ2w==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/autop": "^3.42.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/block-serialization-default-parser": "^4.42.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/shortcode": "^3.42.4", + "@wordpress/autop": "^3.42.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/block-serialization-default-parser": "^4.42.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/shortcode": "^3.42.6", "change-case": "^4.1.2", "colord": "^2.7.0", "deepmerge": "^4.3.0", @@ -38985,27 +39137,27 @@ "dev": true }, "@wordpress/commands": { - "version": "0.13.4", - "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-0.13.4.tgz", - "integrity": "sha512-FIByPkwOB3urKDcQbLM1WJcnNPEd8OQCyT4lpSyk11FeUg6ANVJRZrEJtx8vr7ZHxTc+wIkROYIjcOUa5e1mvw==", + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/@wordpress/commands/-/commands-0.13.6.tgz", + "integrity": "sha512-nWilSFfNgdz6atKanRDZMLUyHM/PqJmK/k5edoQ+4ytllITfy2kGfKYGNPcfGEJ8degFZtRm4Zdl8zf/XJVucw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/components": "^25.8.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/private-apis": "^0.24.4", + "@wordpress/components": "^25.8.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/private-apis": "^0.24.6", "classnames": "^2.3.1", "cmdk": "^0.2.0", "rememo": "^4.0.2" } }, "@wordpress/components": { - "version": "25.8.4", - "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-25.8.4.tgz", - "integrity": "sha512-/JYvxesKoflXhNNkEaSmGUrs02dQY13E5tldUnHiIKmHQTlv9ZdfsxSib50CVG5s3cCzde570ibZLZhnW6hPTQ==", + "version": "25.8.6", + "resolved": "https://registry.npmjs.org/@wordpress/components/-/components-25.8.6.tgz", + "integrity": "sha512-gi5A3jhd1KesL1e9Qh36m6IhuBs8GMlJa66PVIA84pL+L22bugpIkmv2ZUiSnS4F0Uwrc8a8b+4vkhZpIHXNng==", "requires": { "@ariakit/react": "^0.2.12", "@babel/runtime": "^7.16.0", @@ -39018,23 +39170,23 @@ "@floating-ui/react-dom": "^2.0.1", "@radix-ui/react-dropdown-menu": "2.0.4", "@use-gesture/react": "^10.2.24", - "@wordpress/a11y": "^3.42.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/primitives": "^3.40.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/warning": "^2.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/primitives": "^3.40.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/warning": "^2.42.6", "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.7.0", @@ -39059,19 +39211,19 @@ } }, "@wordpress/compose": { - "version": "6.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-6.19.4.tgz", - "integrity": "sha512-Sjo1vvGvtb++cOdaTBUyft7TPQ4/aLKSdl3PiAVARN/YKXZrPuTA6c4QKyisnrGAhKRJf4XWblR7eF2+5Gnz4Q==", + "version": "6.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/compose/-/compose-6.19.6.tgz", + "integrity": "sha512-O/ah1LEGnetk0TcsgI2ZFnAvqI1hJ0XJ8nzFWYgw4irFy4io2JML1ACOPnCBLvCdfiaiJPyep/b5sfQa701LvQ==", "requires": { "@babel/runtime": "^7.16.0", "@types/mousetrap": "^1.6.8", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/priority-queue": "^2.42.4", - "@wordpress/undo-manager": "^0.2.4", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/priority-queue": "^2.42.6", + "@wordpress/undo-manager": "^0.2.6", "change-case": "^4.1.2", "clipboard": "^2.0.8", "mousetrap": "^1.6.5", @@ -39079,43 +39231,43 @@ } }, "@wordpress/core-commands": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/@wordpress/core-commands/-/core-commands-0.11.4.tgz", - "integrity": "sha512-tSqARe5fR/xk6sbz0ZGMSNfhXi975TkraSBWjiffGZufQNm6Mp+w9AwJOC2fr6XYwLDQR5jo0ZAQpjlfko6Z9g==", + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@wordpress/core-commands/-/core-commands-0.11.6.tgz", + "integrity": "sha512-l3F8ZufPULbVN1StaQUDIQFL/RfH4sQkOsb/43YLvfS+kp6GPhJtgYvoiqze1gWNCLrMu5HcqVCiPcwEB59T/w==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/commands": "^0.13.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/router": "^0.11.4", - "@wordpress/url": "^3.43.4" + "@wordpress/block-editor": "^12.10.6", + "@wordpress/commands": "^0.13.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/router": "^0.11.6", + "@wordpress/url": "^3.43.6" } }, "@wordpress/core-data": { - "version": "6.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-6.19.4.tgz", - "integrity": "sha512-LxR0VdALzfaEUPviDQoTgpVrdfyWv9nd0CqcsiqiDLM14m/2zw15Be/OBicZgivfvWPTIN3oj7GhKnLP+2rxOg==", + "version": "6.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/core-data/-/core-data-6.19.6.tgz", + "integrity": "sha512-0dSgwipsY0UzwdnaDqMk2D2QnjSH8LDiqrTeHm8PLmxBEOJy0Uruf1cXxfV+4vVCMeI/w+CS0mW9jKNKj5Q9kA==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/sync": "^0.4.4", - "@wordpress/undo-manager": "^0.2.4", - "@wordpress/url": "^3.43.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/sync": "^0.4.6", + "@wordpress/undo-manager": "^0.2.6", + "@wordpress/url": "^3.43.6", "change-case": "^4.1.2", "equivalent-key-map": "^0.2.2", "fast-deep-equal": "^3.1.3", @@ -39125,48 +39277,48 @@ } }, "@wordpress/customize-widgets": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/customize-widgets/-/customize-widgets-4.19.4.tgz", - "integrity": "sha512-ocJIYYhpYPdKOa/0QgJIeRiFyrRzx5eDTgve1jt1XC3MBEctUcRNNWSR6flCFaG0Mt3xUeFhV/yo54yRyHhTjQ==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/customize-widgets/-/customize-widgets-4.19.6.tgz", + "integrity": "sha512-eP7ZYBDH19pp+3Sk1IBDFkdhXgVPknvJIOvmsZGtUpdEtOStusM3SDZwn/iomQvaCtrSjM4VQg4qUQ/Wn21Ncg==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/block-library": "^8.19.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interface": "^5.19.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/widgets": "^3.19.4", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/block-library": "^8.19.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interface": "^5.19.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/widgets": "^3.19.6", "classnames": "^2.3.1", "fast-deep-equal": "^3.1.3" } }, "@wordpress/data": { - "version": "9.12.4", - "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-9.12.4.tgz", - "integrity": "sha512-EjywfvoI4VEslYQWICNDrp/8YIs7sLNMN7yPtpnOH41SQ9cAackFD6ipqa80HGvq3AzNZejxeLHV+mfOjkk1ZQ==", + "version": "9.12.6", + "resolved": "https://registry.npmjs.org/@wordpress/data/-/data-9.12.6.tgz", + "integrity": "sha512-Fr+felS8t92Opj/MFANho/0bkqJVZyyVoDvI30oZkgFXM+nHGtHj51vu/tsfveON8Dy8AFMz5wgABpQBLqmybg==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/compose": "^6.19.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/is-shallow-equal": "^4.42.4", - "@wordpress/priority-queue": "^2.42.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/redux-routine": "^4.42.4", + "@wordpress/compose": "^6.19.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/is-shallow-equal": "^4.42.6", + "@wordpress/priority-queue": "^2.42.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/redux-routine": "^4.42.6", "deepmerge": "^4.3.0", "equivalent-key-map": "^0.2.2", "is-plain-object": "^5.0.0", @@ -39178,31 +39330,31 @@ } }, "@wordpress/data-controls": { - "version": "3.11.4", - "resolved": "https://registry.npmjs.org/@wordpress/data-controls/-/data-controls-3.11.4.tgz", - "integrity": "sha512-Xp4zZcTPqEp1V8sxmuo8PlUtus6PqW7NDzy+xydzevt1uAAN4c5In02qgy1dJGpY+6g8xJlCvVpuyt9TMbeCKg==", + "version": "3.11.6", + "resolved": "https://registry.npmjs.org/@wordpress/data-controls/-/data-controls-3.11.6.tgz", + "integrity": "sha512-pEbA3HeH6czq7trPhNd1hdWjHttqSLOBSMKW6YFI4Qm/r0IDZm+fmK9jEz9cqrwiH9ttJLT6Us+WubAOjMdq2w==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4" + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6" } }, "@wordpress/date": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-4.42.4.tgz", - "integrity": "sha512-HqYEONVFPZSnSvFE/w2wB7gfM++ZHdLYxHE4LwKBxhGrJKb2JIHUvC9q47tAfbvF8uxK1TPxMVp8NwkY6w4/zQ==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/date/-/date-4.42.6.tgz", + "integrity": "sha512-lQJKn1e/T1tocCyoJzk7HG/deu/nxhUsmjw7vFnhrMhHTFVFC0N7aW79YMQoKFwn7Q2/yWON3r8NFENET9oWQw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/deprecated": "^3.42.4", + "@wordpress/deprecated": "^3.42.6", "moment": "^2.29.4", "moment-timezone": "^0.5.40" } }, "@wordpress/dependency-extraction-webpack-plugin": { - "version": "4.25.4", - "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-4.25.4.tgz", - "integrity": "sha512-J34PNW4ZVH8Z6TQ6Bi+3/J2BjPzWal/IseMO+q9MwGl1felPPKtkKH9WWAHuZcJOGwfMroYgu47XanP+iHZj1w==", + "version": "4.25.6", + "resolved": "https://registry.npmjs.org/@wordpress/dependency-extraction-webpack-plugin/-/dependency-extraction-webpack-plugin-4.25.6.tgz", + "integrity": "sha512-XspAnFqK8gIt+xbnIYLdAlD/u308lPUUrmApxf+NOG1Ln/eeVSTR6f8D8f4l0fpyQmz9c5v7HIvryLhiktZT1w==", "dev": true, "requires": { "json2php": "^0.0.7", @@ -39210,41 +39362,41 @@ } }, "@wordpress/deprecated": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-3.42.4.tgz", - "integrity": "sha512-1sohYQHq+bRFpjoYMPf6u5+dBrhu+6v8CmfO+emQFCf6xh+qn/nBiOJNCAzWqRFGBvSckDv04LG6Vnks0mAIQw==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/deprecated/-/deprecated-3.42.6.tgz", + "integrity": "sha512-GfnhIrXqjlKTH4Z7SdTbzToxg5UnJAj6bS8OuO7fb7LYtS9XAEkYsF6ck2vXW524LgFw0uNS5O74LRCqu19YEA==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/hooks": "^3.42.4" + "@wordpress/hooks": "^3.42.6" } }, "@wordpress/dom": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-3.42.4.tgz", - "integrity": "sha512-fU6yskF7BNnTPUriCjDGhx3w+PqSZTt+VSmiTcFhaGKDmMNi+5u/cWRXRluljrZj5PG7NIohfYUQQ4p5akT9Bg==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/dom/-/dom-3.42.6.tgz", + "integrity": "sha512-zWuS3JVFUQRKBWtraa93OxLYl7q/Rg4tBj8q0S4a/DTh/xIaSEZCxs2zeeLupeqpWrdtySZYKBHLTIMkQueWkw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/deprecated": "^3.42.4" + "@wordpress/deprecated": "^3.42.6" } }, "@wordpress/dom-ready": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.42.4.tgz", - "integrity": "sha512-c5vPCU932RFBQZgCmX62AHt75OaefGf4B9CWigBQD6oCDqXNOHeCrSJgEmU+YPKclloazpl+JOb3Nnlv8ky8dg==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/dom-ready/-/dom-ready-3.42.6.tgz", + "integrity": "sha512-0qYKm+zLD+E/opSd8o2I70LCr/N7p/B36FDrZoIRXpZIT6+soS3khTFu9Rd655Aneqqu53eh/KcBQcAoLoQQSg==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/e2e-test-utils": { - "version": "10.13.4", - "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-10.13.4.tgz", - "integrity": "sha512-eEXlOiOvq2PKERPrplybrueWxcDDtbd+hzopfibOzXWOMIHXrgvs+oookasYdANlVu5MDEWT0/g+E7vlG8qgew==", + "version": "10.13.6", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-10.13.6.tgz", + "integrity": "sha512-FHHmTMgXF5guQeJ+oO/0HZnwuGoc+mymBOHORnJMZe50EuiNxwQ70ZeSGE0LE99dOqNOWGgN3vxf2B5F64QE/g==", "dev": true, "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/url": "^3.43.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/url": "^3.43.6", "change-case": "^4.1.2", "form-data": "^4.0.0", "node-fetch": "^2.6.0" @@ -39264,14 +39416,14 @@ } }, "@wordpress/e2e-test-utils-playwright": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.10.4.tgz", - "integrity": "sha512-JVJZsft/idcOrm67OBOa+h0+vcP/KisybIXhWgbTvWKaedLYqzVKqvOBIm2nRpki9u3k2b0iy6uOPf9BNdIfnQ==", + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.11.0.tgz", + "integrity": "sha512-UxDkVvm24FJdi4nkn5+n9XirYxdJ1QDZgnHotdrgGRel8NOvlEOlhmT/xpuAPQrVwo+yynxEKeb1Y2AT6jX9og==", "dev": true, "requires": { - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/url": "^3.43.4", + "@wordpress/api-fetch": "^6.40.0", + "@wordpress/keycodes": "^3.43.0", + "@wordpress/url": "^3.44.0", "change-case": "^4.1.2", "form-data": "^4.0.0", "get-port": "^5.1.1", @@ -39279,6 +39431,61 @@ "mime": "^3.0.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", @@ -39299,90 +39506,90 @@ } }, "@wordpress/edit-post": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-7.19.4.tgz", - "integrity": "sha512-h5QprgDiEzTFFKqyou4BU5KeqydM+xItPhbM5ktE6p2Or65aHctNMXSMMHNc1oeu/9t94Bu9Wj0YxUpESBv74Q==", + "version": "7.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/edit-post/-/edit-post-7.19.6.tgz", + "integrity": "sha512-ifer5vVUa89zFxahxtGQT9SxbvDqnSAmbuGv0MUPOmuFsKREjwVSQVpuCo/V501wwzHXcoBwjXx2RTn2a5CIIg==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/block-library": "^8.19.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/commands": "^0.13.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-commands": "^0.11.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/editor": "^13.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interface": "^5.19.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/url": "^3.43.4", - "@wordpress/viewport": "^5.19.4", - "@wordpress/warning": "^2.42.4", - "@wordpress/widgets": "^3.19.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/block-library": "^8.19.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/commands": "^0.13.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-commands": "^0.11.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/editor": "^13.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interface": "^5.19.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/url": "^3.43.6", + "@wordpress/viewport": "^5.19.6", + "@wordpress/warning": "^2.42.6", + "@wordpress/widgets": "^3.19.6", "classnames": "^2.3.1", "memize": "^2.1.0", "rememo": "^4.0.2" } }, "@wordpress/edit-site": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/edit-site/-/edit-site-5.19.4.tgz", - "integrity": "sha512-9WyOLHwqp9U9EOnjEJC5fznbsQG8fQufT6evP/jL46ErqLy0PKwthZxqiydToMoaZY8xpzq9IlWCW89GKFN3og==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/edit-site/-/edit-site-5.19.6.tgz", + "integrity": "sha512-LVxG7M9vRy8Nt9qTSB8wYla+lnMsoocszlrEWxiSDfXAbcnrase+UyjxaFYFmSLYWZYCDJsLXBipb0QdnsyNtg==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/block-library": "^8.19.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/commands": "^0.13.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-commands": "^0.11.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/editor": "^13.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interface": "^5.19.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/patterns": "^1.3.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/primitives": "^3.40.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/reusable-blocks": "^4.19.4", - "@wordpress/router": "^0.11.4", - "@wordpress/style-engine": "^1.25.4", - "@wordpress/url": "^3.43.4", - "@wordpress/viewport": "^5.19.4", - "@wordpress/widgets": "^3.19.4", - "@wordpress/wordcount": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/block-library": "^8.19.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/commands": "^0.13.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-commands": "^0.11.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/editor": "^13.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interface": "^5.19.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/patterns": "^1.3.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/primitives": "^3.40.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/reusable-blocks": "^4.19.6", + "@wordpress/router": "^0.11.6", + "@wordpress/style-engine": "^1.25.6", + "@wordpress/url": "^3.43.6", + "@wordpress/viewport": "^5.19.6", + "@wordpress/widgets": "^3.19.6", + "@wordpress/wordcount": "^3.42.6", "change-case": "^4.1.2", "classnames": "^2.3.1", "colord": "^2.9.2", @@ -39397,75 +39604,75 @@ } }, "@wordpress/edit-widgets": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/edit-widgets/-/edit-widgets-5.19.4.tgz", - "integrity": "sha512-jxWhnSLumrnpeGnuwYdDscze2zsuiqZiCZFQSq6VxkKLjfdI6LZwww5AY0W3aBD0qGGTxB4YO78imgLm56ZFkQ==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/edit-widgets/-/edit-widgets-5.19.6.tgz", + "integrity": "sha512-975yw6gIuHsl9Ize4dPVUMs2NwaOeH9AMTweumDNI3NRzdKeOCsKZ55lSXjn7Jp6+j11oOyP7D+220VWds16lA==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/block-library": "^8.19.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/interface": "^5.19.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/patterns": "^1.3.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/reusable-blocks": "^4.19.4", - "@wordpress/url": "^3.43.4", - "@wordpress/widgets": "^3.19.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/block-library": "^8.19.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/interface": "^5.19.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/patterns": "^1.3.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/reusable-blocks": "^4.19.6", + "@wordpress/url": "^3.43.6", + "@wordpress/widgets": "^3.19.6", "classnames": "^2.3.1" } }, "@wordpress/editor": { - "version": "13.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-13.19.4.tgz", - "integrity": "sha512-W7j9Im7ajQqia0rNrnoBkKm5WOj9cQOA5qQNqoWFf3VXLk23CTTiGVz3U9TEyIjQlMIeD8T6G8VHbYBXYBSDGQ==", + "version": "13.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/editor/-/editor-13.19.6.tgz", + "integrity": "sha512-5cay+921/4qCGHiZ/qS7QEgGE4F09gIisaR9/NxpV6Nptp2Orqfjh/czCrg2vTQWWb0heechr3ii10ubRLoiFg==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/date": "^4.42.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/dom": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/keyboard-shortcuts": "^4.19.4", - "@wordpress/keycodes": "^3.42.4", - "@wordpress/media-utils": "^4.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/patterns": "^1.3.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/reusable-blocks": "^4.19.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/server-side-render": "^4.19.4", - "@wordpress/url": "^3.43.4", - "@wordpress/wordcount": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/date": "^4.42.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/dom": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/keyboard-shortcuts": "^4.19.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/media-utils": "^4.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/patterns": "^1.3.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/reusable-blocks": "^4.19.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/server-side-render": "^4.19.6", + "@wordpress/url": "^3.43.6", + "@wordpress/wordcount": "^3.42.6", "classnames": "^2.3.1", "date-fns": "^2.28.0", "memize": "^2.1.0", @@ -39475,14 +39682,14 @@ } }, "@wordpress/element": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.19.4.tgz", - "integrity": "sha512-96WJOiPDlnt+Jq1uteEYo/CNhTKd3/eeEEl1dPpg+oJZy36Vp4NsrDiJptVwMXVUwSX38YLWIm62xSdR99Pq8A==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-5.19.6.tgz", + "integrity": "sha512-KhKJ2b2PUKuuE41a3tJKDG5YHPBo2VTCziW69ePkOsXWt/z9z0lq5+iSiZvmpMmRO8JWmhqEJGcauy6NhpZA2Q==", "requires": { "@babel/runtime": "^7.16.0", "@types/react": "^18.0.21", "@types/react-dom": "^18.0.6", - "@wordpress/escape-html": "^2.42.4", + "@wordpress/escape-html": "^2.42.6", "change-case": "^4.1.2", "is-plain-object": "^5.0.0", "react": "^18.2.0", @@ -39490,24 +39697,24 @@ } }, "@wordpress/escape-html": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.42.4.tgz", - "integrity": "sha512-fjNxU4nn5nTJ6PUXs0BmTft+WuIoezI0L62yPXF42IVfDdkG5lFNMsgmjOOp0FW1PEalCh2YjchoH84Z08nw2g==", + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/escape-html/-/escape-html-2.42.6.tgz", + "integrity": "sha512-rYIQ38V65Lind4wpALW4ggvw/zbVKwswDEfHw16L1f611/HLmVALb1gsydpJ/nldvECMNIi7bDRQhrrgDmHKzw==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/eslint-plugin": { - "version": "16.0.4", - "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-16.0.4.tgz", - "integrity": "sha512-NeFw9PR60+YBuq/jGKTRtQGUg0k9XzR/6KhiwwpY33GZgukepljUSs2oYP90r0KbkIvoWxt/AuP7LsuM/bqIew==", + "version": "16.0.6", + "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-16.0.6.tgz", + "integrity": "sha512-7MOJobRhXZOvqKBhd3cU6NR9wIOvXuDYnVWEicDaef6/KnrcH+8nPR1Y5aYlwkxW8gSgYeITsCCN3kTLJJIBPQ==", "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.4", - "@wordpress/prettier-config": "^2.25.4", + "@wordpress/babel-preset-default": "^7.26.6", + "@wordpress/prettier-config": "^2.25.6", "cosmiconfig": "^7.0.0", "eslint-config-prettier": "^8.3.0", "eslint-plugin-import": "^2.25.2", @@ -39534,47 +39741,47 @@ } }, "@wordpress/format-library": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/format-library/-/format-library-4.19.4.tgz", - "integrity": "sha512-mViKxEoEdNogAcBNX7Ww/eF8XRMPbPZ5ZunWbW3S0vvNU4KGQrbEnMPlQquZpLxhmETzDzQFzReRzrzDvdd6kQ==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/format-library/-/format-library-4.19.6.tgz", + "integrity": "sha512-QfBJzycsxsvPXx6W9TR51b7idAW84CB23d0inB/CqMtq4ifb/ILssMSQ57TaixT5rALIrnSXyOsIhWe7kOVcFw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/rich-text": "^6.19.4", - "@wordpress/url": "^3.43.4" + "@wordpress/a11y": "^3.42.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/rich-text": "^6.19.6", + "@wordpress/url": "^3.43.6" } }, "@wordpress/hooks": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.42.4.tgz", - "integrity": "sha512-Be2xGwuQR90pksU5u1Pgsko2zm4Z0OHd+A4/FUc5s+Dz92zGolxYj9g7/JGPQZlmT3qTobstUxgXzUUxqjx7pA==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.42.6.tgz", + "integrity": "sha512-lG9iQs/eUjLVYL6ADoUKil5gaRwBjebZGKR1VPZaTmZnroXJP/dGy5YlKCUAwpWikgW68mtakaqJCjkjIrOAPQ==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/html-entities": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.42.4.tgz", - "integrity": "sha512-7kdzkZkXpj0Brwz9MmElQowC9tACBZ8sIeIL3DmYzbLo8Labzo39qPsUONl8ko12yFslCPfo91FUC59r+39NzA==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/html-entities/-/html-entities-3.42.6.tgz", + "integrity": "sha512-LoGIBjY9KZI4UqkyLRewm2c3I0J691R/oi7aLZdqeakLdzo4RgyN+t36oy8Xn0HzCvR2/Jn8kgkRzWvQtagk0w==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/i18n": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.42.4.tgz", - "integrity": "sha512-EdgpL5QiPmLYwyAJNAofJF9jxMk+qXUoJvyZ7IA03a/W0e9ZU0z3k1J1UlnBveS8frl8IZGFk+7Ex5iFEaZaFg==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.42.6.tgz", + "integrity": "sha512-z4It7blrz2GJAfHlwSXBmdfCKJSzNEnOIMw9kccK6V81n3GMP7m7kh+Yrol5swJnTSdAmx2hkZguMjtEoIhdvg==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/hooks": "^3.42.4", + "@wordpress/hooks": "^3.42.6", "gettext-parser": "^1.3.1", "memize": "^2.1.0", "sprintf-js": "^1.1.1", @@ -39582,19 +39789,19 @@ } }, "@wordpress/icons": { - "version": "9.33.4", - "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.33.4.tgz", - "integrity": "sha512-KGPUhEQdA6pA/gGj/JL4BSA1aIPyypgzFhQtrLEkZxUEOAyWZxoOn/QKrEx3uAYVsPrbjLEDMfyEMViQTkQB3w==", + "version": "9.33.6", + "resolved": "https://registry.npmjs.org/@wordpress/icons/-/icons-9.33.6.tgz", + "integrity": "sha512-TEwuga9Nukyec4Z1nzsDolBneC8GGC4QpyPO8RD8NuiuyHj4pmis1sbmDPIxvtVOkcDOYQU3be16Vy+4VeSgbQ==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/element": "^5.19.4", - "@wordpress/primitives": "^3.40.4" + "@wordpress/element": "^5.19.6", + "@wordpress/primitives": "^3.40.6" } }, "@wordpress/interactivity": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-2.3.4.tgz", - "integrity": "sha512-rVHgi5D3jzEZtwJsc7ON3vqlUQUQJz7BztmVYUZIcqYA8I7e7bxby8Wp9a+9y5ZD+b5vNV+lmUxaRXCS6EjBrQ==", + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@wordpress/interactivity/-/interactivity-2.3.6.tgz", + "integrity": "sha512-duZIob6rPv9FDSi3G0FXn8OOwejUFOaxEGnLQD0pYYg0lRJQQGUxgLRPNIbL8wJ5mb0/LDRAAee8XT+LHWOq6g==", "requires": { "@preact/signals": "^1.1.3", "deepsignal": "^1.3.6", @@ -39602,29 +39809,29 @@ } }, "@wordpress/interface": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-5.19.4.tgz", - "integrity": "sha512-+WddMz+wIM7P4XYlQRlhxC2o8FJMtpxbvxbNVpjhDklAoLfYC/3Yu3tENO1MTZjhXR5Du+rWoOwr2S+gnPHiqw==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/interface/-/interface-5.19.6.tgz", + "integrity": "sha512-f3hj0TyTsAfBwvVkBeI4DBGZfSVfobIvkklgIIeJ9Rkxk3a71Bubwk0QfefK0/kH8BNy8o4YK4LNCGPxl//fGg==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/plugins": "^6.10.4", - "@wordpress/preferences": "^3.19.4", - "@wordpress/viewport": "^5.19.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/plugins": "^6.10.6", + "@wordpress/preferences": "^3.19.6", + "@wordpress/viewport": "^5.19.6", "classnames": "^2.3.1" } }, "@wordpress/is-shallow-equal": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-4.42.4.tgz", - "integrity": "sha512-cb1mOrgz1agMulmGGPvKhVhpThkhgPPn2JqYJTlcfo1G8BwpQP5U/w2g8vu/4gCYS5OyuTilXbMa4RTpx61WsA==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/is-shallow-equal/-/is-shallow-equal-4.42.6.tgz", + "integrity": "sha512-gJEoqRE9jMvHMT39PLrd2QQc2qfa3PnDfcmz6R+TYsrbK09/uN9ZIFfKK1o9d1FoVBBTfbGfn358spEaQLAXfQ==", "requires": { "@babel/runtime": "^7.16.0" } @@ -39650,61 +39857,61 @@ } }, "@wordpress/keyboard-shortcuts": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-4.19.4.tgz", - "integrity": "sha512-cMWMFr7b1QJhNulpd4E76QmFhPYshmR445dNeXfmHZBobsAxr3U6wJfl144uMJ4PNjNpS9bGpQ2s0zaz3N+B5Q==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/keyboard-shortcuts/-/keyboard-shortcuts-4.19.6.tgz", + "integrity": "sha512-mvzS5bSePRj6h7Wau6o6Jznpxj0zGvWVMF9JQf7pCYHVEOIYS15yNpJoU1FiMnMT3afbB2pN/5NmuDXpw9DFmw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/keycodes": "^3.42.4", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/keycodes": "^3.42.6", "rememo": "^4.0.2" } }, "@wordpress/keycodes": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.42.4.tgz", - "integrity": "sha512-RPV9eLBGTuFXPwRBRuujX9fb9BPrY6DojByS0O/G/sk/Dh+ncCyudQ9T0hCkRErelxma8WqigVAeOkcNzVNoLg==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-3.42.6.tgz", + "integrity": "sha512-VTvLQxqmGuziPsdDLRXV5mirY9PiTXR/+B5EA/cYExPeFUgfS7B3u8+vjvHUujlbGwrivU8jZjLrgbwEjC2bcw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/i18n": "^4.42.4", + "@wordpress/i18n": "^4.42.6", "change-case": "^4.1.2" } }, "@wordpress/list-reusable-blocks": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/list-reusable-blocks/-/list-reusable-blocks-4.19.4.tgz", - "integrity": "sha512-kfl/lkKQ3T1++dHA4dXEwaoHU188tmbioo6T06Vy86p91AhBqq3wOaIZ2qrgExSB4o+c+8Dc66AzmwfOj/hieg==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/list-reusable-blocks/-/list-reusable-blocks-4.19.6.tgz", + "integrity": "sha512-9T+HX03lq9P0OUvovZQUFJL/M1MM07IL4+AUMu+UNA8HKOz3ASbOXFNXNoMmVJSEoQcvIYnSTSDUPzMJ5Eszxg==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", "change-case": "^4.1.2" } }, "@wordpress/media-utils": { - "version": "4.33.4", - "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-4.33.4.tgz", - "integrity": "sha512-WIQVJKXA9zp/CZEh/mun420y8GxJtyLQWUar0AyZcD73hmNdaDzfe7MYzhp3kVQ7E4OcIcq5yxoVhHViun9FUg==", + "version": "4.33.6", + "resolved": "https://registry.npmjs.org/@wordpress/media-utils/-/media-utils-4.33.6.tgz", + "integrity": "sha512-FGjlcfpFmHQmwCQycPlijwwsoO4bWn6ap0VgGLU59V+3cWmfO2dmwaquPoFAgFcQt6LFcaqaeen72JlG7G0CHA==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/blob": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4" + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/blob": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6" } }, "@wordpress/notices": { - "version": "4.10.4", - "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-4.10.4.tgz", - "integrity": "sha512-7OxkoFy6pKHkvsflJR3fsP5ngHbciN9BBguhqgTj9lLVclVFhfrPDlkcdzfXk3DC5vixze3atJM3JKmue9DA6g==", + "version": "4.10.6", + "resolved": "https://registry.npmjs.org/@wordpress/notices/-/notices-4.10.6.tgz", + "integrity": "sha512-g1uyL0zguU0s6EiYyKpZEu97FNK5j+4uXCAITQhpaOJDSUBF9TflPFaXrBKkBCwKvfgE9P7FtYDrVEnceF+z/g==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/data": "^9.12.4" + "@wordpress/a11y": "^3.42.6", + "@wordpress/data": "^9.12.6" } }, "@wordpress/npm-package-json-lint-config": { @@ -39714,54 +39921,54 @@ "dev": true }, "@wordpress/nux": { - "version": "8.4.4", - "resolved": "https://registry.npmjs.org/@wordpress/nux/-/nux-8.4.4.tgz", - "integrity": "sha512-CWsm9BfBY3PjtPcy1+kga5GC/J4D3du5YacgxkVkwuRcnino0PvHxdnz2YcbUjyXHWGcFlz/x4eto278Pqa5ug==", + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/@wordpress/nux/-/nux-8.4.6.tgz", + "integrity": "sha512-v54z9qXa1kk9+cG4GlxmUghAmI47prA8uUWR28s7pZzeaD/eFZEQ8X8HTUE9tm35NS7dK+qWcNSUwsfLH4kuww==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", "rememo": "^4.0.2" } }, "@wordpress/patterns": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-1.3.4.tgz", - "integrity": "sha512-TKyR0FN1JQ2xPHIxzXuayo3NRYCuDgIpTj4803LITqm1y6Ypw0U/H1Pooi4epvgiLd+Oa0sNbTkBRfCEbH075w==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@wordpress/patterns/-/patterns-1.3.6.tgz", + "integrity": "sha512-ji5O7NfJIixIxJoF9K7VfS++BRcI3yuQ7fWJsDPq2vd7xR+n3uHJGGouxi7OcvmQ4blYM6is+RZyXDm+F1O4pQ==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/html-entities": "^3.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/url": "^3.43.4" + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/html-entities": "^3.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/url": "^3.43.6" } }, "@wordpress/plugins": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-6.10.4.tgz", - "integrity": "sha512-MACIKd4WhUZ5nuvFPiBaB6bOGw/EceCzpbuN1JXZe3i1CgXxuS4NIZmfkpX5F5pRsfcVeyTQUDmqAB3UQQDB7Q==", + "version": "6.10.6", + "resolved": "https://registry.npmjs.org/@wordpress/plugins/-/plugins-6.10.6.tgz", + "integrity": "sha512-3eCZouQ/Z5wmORsoVOKqKNdlxU5UNgsoOiljpwypYmZCqpS2+HdPlVHx6juV7B6KysU77rrAOOoGJqqEt/RPfQ==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/element": "^5.19.4", - "@wordpress/hooks": "^3.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/is-shallow-equal": "^4.42.4", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/element": "^5.19.6", + "@wordpress/hooks": "^3.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/is-shallow-equal": "^4.42.6", "memize": "^2.0.1" } }, @@ -39776,66 +39983,66 @@ } }, "@wordpress/preferences": { - "version": "3.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-3.19.4.tgz", - "integrity": "sha512-rCvRfJD/lA7yaAPczhVjawvypRCTzUCeInndkatGegn8u9wkFg6wJU52ZyqYdjV80ihvq5o8VsLIBXjYzp/+Rw==", + "version": "3.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/preferences/-/preferences-3.19.6.tgz", + "integrity": "sha512-OGVWwha+v86cFCrrxow4n8a585IumGUvmJPGMRzLdvLRcinvHX9xNevYw+SV/ecrsHtOhSRSrAM9Yn9t9V1HzA==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/components": "^25.8.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/components": "^25.8.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", "classnames": "^2.3.1" } }, "@wordpress/preferences-persistence": { - "version": "1.34.4", - "resolved": "https://registry.npmjs.org/@wordpress/preferences-persistence/-/preferences-persistence-1.34.4.tgz", - "integrity": "sha512-+ka04qSy/HoOoQmm0vttlwLJ+Lgw0sPSjy7/QzT+kp46PhGMVXmpdxmETKldHBUpKXa0N/9JO7566XILWLBQCA==", + "version": "1.34.6", + "resolved": "https://registry.npmjs.org/@wordpress/preferences-persistence/-/preferences-persistence-1.34.6.tgz", + "integrity": "sha512-sWZUSOejx5HNCOJBisv60Kqe0hHfwlQL6K6VNL5U0oGO3QTtww7EPz2wi9Is3JKnhk9SKgI3F7+Ey9cqyARlXw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4" + "@wordpress/api-fetch": "^6.39.6" } }, "@wordpress/prettier-config": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-2.25.4.tgz", - "integrity": "sha512-ns7MFZ0DZyLcU0efjdwgP9pRpnDZbuC6wgD+nfJVYc5EOt1FiQGHnjRkoOZYCqCJosQCka0+sjiylcW2PD6cYA==", + "version": "2.25.6", + "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-2.25.6.tgz", + "integrity": "sha512-huMWGCr4Dy9/rYoJVtoQUKIp/CgPy+Cd7tQ6WZzuhPXZ9Pkd4Omkuu70QOji3k1b+qkXMFpS2fVxiD6rAsmtRQ==", "dev": true }, "@wordpress/primitives": { - "version": "3.40.4", - "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.40.4.tgz", - "integrity": "sha512-990RKWcIQB236FsBMXGuIwWblhoOPi2N8xWTzqYnge7UY8hg8um8+pSxXppAnP5mmObovQGzenTYhCMiEnC48w==", + "version": "3.40.6", + "resolved": "https://registry.npmjs.org/@wordpress/primitives/-/primitives-3.40.6.tgz", + "integrity": "sha512-PnAZlx5FfhN3m03es+vEK3brqtp5Z4PggeGEeGSNXdxq9/A2YMsK4yno1jVQczFwN48AAA6WkV/Dp5LmRgh/iA==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/element": "^5.19.4", + "@wordpress/element": "^5.19.6", "classnames": "^2.3.1" } }, "@wordpress/priority-queue": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-2.42.4.tgz", - "integrity": "sha512-MmaWSCJr5tgUJFqPZwiC+MBwY+fSsoudA5iCDqlQwvwCmG092pzH3bhI6vryS83bbowC/UvTZTw/cNVaazxAKQ==", + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/priority-queue/-/priority-queue-2.42.6.tgz", + "integrity": "sha512-y9JbhHUdChKXGQIS67Z6z4BWrqEIO3COZoBlQLScvCNdgzGYMoZfyqN1AMy1DiFJ3eIoZGLWDaKqLnA9I6p+1w==", "requires": { "@babel/runtime": "^7.16.0", "requestidlecallback": "^0.3.0" } }, "@wordpress/private-apis": { - "version": "0.24.4", - "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.24.4.tgz", - "integrity": "sha512-2DJnBVa1ZnM6HoqPbtVYjIhdf08oQbmhK6Amwkp/ZXe+rnpkN989JuLJnw70qnsIXZwK1YcUj1ndWVUxi2ZkEQ==", + "version": "0.24.6", + "resolved": "https://registry.npmjs.org/@wordpress/private-apis/-/private-apis-0.24.6.tgz", + "integrity": "sha512-f1kNlPgVTk+DjzOJh3nRUSZam6BshD6VAquYP7pukFfHlA4eQViUHL4TVvAc8EC48J5tRl2GqsdYeXG3oOscmQ==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/redux-routine": { - "version": "4.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-4.42.4.tgz", - "integrity": "sha512-GrTeL3PNHObUh+hT0M7QfkKou6s8LbczNpIT6eOALhPJYL28e+UK6XxBccTT59DmZdNDI8Ycn5/6IYyDGk5psA==", + "version": "4.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/redux-routine/-/redux-routine-4.42.6.tgz", + "integrity": "sha512-LHdyocfwj5EMITN4i7siwkX1gKI8O4z/IX+Z6Ex+RV7MXb0Cpfyqi5aGXs+uGdUInJhNa+fh/vjYqBaiXfwbRw==", "requires": { "@babel/runtime": "^7.16.0", "is-plain-object": "^5.0.0", @@ -39844,73 +40051,73 @@ } }, "@wordpress/reusable-blocks": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-4.19.4.tgz", - "integrity": "sha512-wPgzMugNbmfUuUtAA9koCaD5CWjf1dxsUrxmq6kx+alOJeEGEmSxdNfJCws21kFXi/gQwijPonQFW4oxMxLoFQ==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/reusable-blocks/-/reusable-blocks-4.19.6.tgz", + "integrity": "sha512-AxU3gkfFOPuDG06GDg/OScr2trWzW6LBqUK4TgTv30tAVOZi8TisoIloxx7gWSpsTP9oBbOY0ilhQQH10e/Vgw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/notices": "^4.10.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/url": "^3.43.4" + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/notices": "^4.10.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/url": "^3.43.6" } }, "@wordpress/rich-text": { - "version": "6.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-6.19.4.tgz", - "integrity": "sha512-ecf18dQRYwDSABvhiZ0lQJUK5Ui4XTHq8sxP908DPvtOcuUszyXPPoghT9L/MgR6chi1d8PtFS4wAOfm474zWA==", + "version": "6.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/rich-text/-/rich-text-6.19.6.tgz", + "integrity": "sha512-8W49w3scw0njSN9Z+z9S/EVfc83wvaMuk3WqY2GFvUDfWQayetAMK9LoYfVZECGoO0Cy/cL0Ru4xv989DBuWYw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/a11y": "^3.42.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/escape-html": "^2.42.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/keycodes": "^3.42.4", + "@wordpress/a11y": "^3.42.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/escape-html": "^2.42.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/keycodes": "^3.42.6", "memize": "^2.1.0", "rememo": "^4.0.2" } }, "@wordpress/router": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/@wordpress/router/-/router-0.11.4.tgz", - "integrity": "sha512-2I7HxlT/N/pdHGvJ2iQjXsHnu5cSLnr/yciD6U+nMFHu9AiL0o0z28HCF/E/NKb4BLTzRc+RUjlDEKd74rroWQ==", + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@wordpress/router/-/router-0.11.6.tgz", + "integrity": "sha512-WVY5A91joF4vNP75n/RjqCy/PyGUbL0m6UGR2G0q/da3XgABXi4pGlZKU6DhpE46gTInzfokHOxNwtbggopHcw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/element": "^5.19.4", - "@wordpress/private-apis": "^0.24.4", - "@wordpress/url": "^3.43.4", + "@wordpress/element": "^5.19.6", + "@wordpress/private-apis": "^0.24.6", + "@wordpress/url": "^3.43.6", "history": "^5.1.0" } }, "@wordpress/scripts": { - "version": "26.13.4", - "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-26.13.4.tgz", - "integrity": "sha512-9dNSM4v9DN1pdBsnDMxhggMS3aMBqsIxFDvWzLx6mlmOTA5mI74XATYNKroONfPXCiUUubRmil+raT3UhTP2jQ==", + "version": "26.13.6", + "resolved": "https://registry.npmjs.org/@wordpress/scripts/-/scripts-26.13.6.tgz", + "integrity": "sha512-ROzfZpf8OL4k+r5GCU1DaE3gBFbjVMwDGdhseRaoQj0LIsDrDYJr6RimoWgl4TP8YWAH+T/YbZWHImMc0J+0Rw==", "dev": true, "requires": { "@babel/core": "^7.16.0", "@pmmmwh/react-refresh-webpack-plugin": "^0.5.2", "@svgr/webpack": "^8.0.1", - "@wordpress/babel-preset-default": "^7.26.4", - "@wordpress/browserslist-config": "^5.25.4", - "@wordpress/dependency-extraction-webpack-plugin": "^4.25.4", - "@wordpress/e2e-test-utils-playwright": "^0.10.4", - "@wordpress/eslint-plugin": "^16.0.4", - "@wordpress/jest-preset-default": "^11.13.4", - "@wordpress/npm-package-json-lint-config": "^4.27.4", - "@wordpress/postcss-plugins-preset": "^4.26.4", - "@wordpress/prettier-config": "^2.25.4", - "@wordpress/stylelint-config": "^21.25.4", + "@wordpress/babel-preset-default": "^7.26.6", + "@wordpress/browserslist-config": "^5.25.6", + "@wordpress/dependency-extraction-webpack-plugin": "^4.25.6", + "@wordpress/e2e-test-utils-playwright": "^0.10.6", + "@wordpress/eslint-plugin": "^16.0.6", + "@wordpress/jest-preset-default": "^11.13.6", + "@wordpress/npm-package-json-lint-config": "^4.27.6", + "@wordpress/postcss-plugins-preset": "^4.26.6", + "@wordpress/prettier-config": "^2.25.6", + "@wordpress/stylelint-config": "^21.25.6", "adm-zip": "^0.5.9", "babel-jest": "^29.6.2", "babel-loader": "^8.2.3", @@ -39958,6 +40165,22 @@ "webpack-dev-server": "^4.4.0" }, "dependencies": { + "@wordpress/e2e-test-utils-playwright": { + "version": "0.10.6", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.10.6.tgz", + "integrity": "sha512-qUIcQTB4lFG6BUVCPtzs4gDeO/9Pzz1Knq3Uvt1QIYojy9Yr6G6c3f3Mudql+HFfiXoj3B3BxGbA4oLSb7bI6w==", + "dev": true, + "requires": { + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/keycodes": "^3.42.6", + "@wordpress/url": "^3.43.6", + "change-case": "^4.1.2", + "form-data": "^4.0.0", + "get-port": "^5.1.1", + "lighthouse": "^10.4.0", + "mime": "^3.0.0" + } + }, "ajv": { "version": "8.12.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", @@ -40054,6 +40277,17 @@ "path-exists": "^4.0.0" } }, + "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" + } + }, "glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -40098,6 +40332,12 @@ "p-locate": "^4.1.0" } }, + "mime": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz", + "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==", + "dev": true + }, "p-locate": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", @@ -40183,36 +40423,36 @@ } }, "@wordpress/server-side-render": { - "version": "4.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-4.19.4.tgz", - "integrity": "sha512-EtOnXb8tZ2bltpR8mHAK2uoaF+4a0X2tyBmT0iam4LpL+csMnQkUaDR5WeugxFQ47iLDK679AGblDy8gOlomOg==", + "version": "4.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/server-side-render/-/server-side-render-4.19.6.tgz", + "integrity": "sha512-mrRQDdpqsSW3Qfd8LSITMGY+Zazt1vKUSLc1DjSZksIMmOb/HUnNs4VKlhhcA638tjmBuWrTtPbTGG/kroWO+A==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/deprecated": "^3.42.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/url": "^3.43.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/deprecated": "^3.42.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/url": "^3.43.6", "fast-deep-equal": "^3.1.3" } }, "@wordpress/shortcode": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-3.42.4.tgz", - "integrity": "sha512-P0d9OHi9g+O78PTtN34lunNi21bPyaRMjPPxtyCtMgSRfSB9dQjFGfA2HZ9cq4clRae8tpUMRQtksNWMszQhsA==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/shortcode/-/shortcode-3.42.6.tgz", + "integrity": "sha512-3uW65IppB9Gs8bAhClZYWDxy9Rl3iqOuMH2mwEU02wdvCNlr47YLLo/2QiqNpjtyyyTJFNrhaiQjZhFyulCygA==", "requires": { "@babel/runtime": "^7.16.0", "memize": "^2.0.1" } }, "@wordpress/style-engine": { - "version": "1.25.4", - "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-1.25.4.tgz", - "integrity": "sha512-p3GUdsOibw59ajKAr+dxK8zB/3HAGWj4lmL2gPqU2EqnoWkomKEd9lWWSTLzNxHHMJPgpPCUd5WeMifUJow1sg==", + "version": "1.25.6", + "resolved": "https://registry.npmjs.org/@wordpress/style-engine/-/style-engine-1.25.6.tgz", + "integrity": "sha512-7GuFhRAd51A602i8uyytBbFPcEifXV5WH2UVAeiDN5sju/6f+OF2pAHG0lN799ricNE7i2idRIIUbl7CJsmQEQ==", "requires": { "@babel/runtime": "^7.16.0", "change-case": "^4.1.2" @@ -40229,9 +40469,9 @@ } }, "@wordpress/sync": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-0.4.4.tgz", - "integrity": "sha512-Sdzgp6LPrgli6cAGJSssB2HE/6SrM1zKimyiiVjue0/Sui2NB5OepEbf43s43JSddgtqDUDuTq2xC6XnNelfGw==", + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@wordpress/sync/-/sync-0.4.6.tgz", + "integrity": "sha512-incrgWQOlngpM4dceEzASvbZ+OxlkitsDvBOlj1VGe5mhKBrYDsdoYNvF760+l3QQ+5FE2w3d5ilHaSnIkpE6w==", "requires": { "@babel/runtime": "^7.16.0", "y-indexeddb": "~9.0.11", @@ -40240,71 +40480,71 @@ } }, "@wordpress/token-list": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-2.42.4.tgz", - "integrity": "sha512-w/7cS3OCCaqZRbRXzXl1o2GbVmLXdBPknvm8NuYsNLnA0n8aNzeOcH3gB0/DETzJ4UL2htu/ukkSSQ69JGb/Ow==", + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/token-list/-/token-list-2.42.6.tgz", + "integrity": "sha512-Z02kJIfSbE/d35wvF89b4iZTPQA1/rK5MGIIb5JkrO2mQZE9ZnUDagN4Ci0Lrq5pvw0L+p1cCLFz/X26vguOtA==", "requires": { "@babel/runtime": "^7.16.0" } }, "@wordpress/undo-manager": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-0.2.4.tgz", - "integrity": "sha512-dXvWdFEKmwj/h+bTvL4xcTyD49srTxVhAoUZxN7J3baoKMqU71Vl8AEntboVUdgF7DdgvPkABQxSF29i47tbpQ==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@wordpress/undo-manager/-/undo-manager-0.2.6.tgz", + "integrity": "sha512-0u28awvzIAU78d24xw8wkzmDGFBPzVbKorylrW/d+6QRL31v0/4Sv9mlLlmHr0G/wgcKPA53t34HQ9i0IMkaEQ==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/is-shallow-equal": "^4.42.4" + "@wordpress/is-shallow-equal": "^4.42.6" } }, "@wordpress/url": { - "version": "3.43.4", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.43.4.tgz", - "integrity": "sha512-flnQ8AMNWyOoeojq1VdH/INS0BCJJprSMz33it8v7LMvb0p8Dju80LHM9H2I9sn2ljO0hWx8hA9AuI7jqEWnng==", + "version": "3.43.6", + "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.43.6.tgz", + "integrity": "sha512-1Rz9N8gQD4cFcM1JO0Nrn91c8EMmb0z49KoX8wKrq2SvwSUs0fEvPj2XwRVk7VMItR9ieg9B4XxSNBLynfviLg==", "requires": { "@babel/runtime": "^7.16.0", "remove-accents": "^0.5.0" } }, "@wordpress/viewport": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-5.19.4.tgz", - "integrity": "sha512-uazIYyL0vmHOXsQQzh4tVFtrL+ReCYPBIpQaJStcLoyAzn5WAPQRmjfcpYK/TpMZxT/wLVrHUUBXnTumBVkmHA==", + "version": "5.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/viewport/-/viewport-5.19.6.tgz", + "integrity": "sha512-n5u0kRr66tg7nLRyaWPLi5Fzs0ZRYfYkUlazkszMWJ+V4tNtC683IBy9jgQE/SPFBAn5Vf5yRJT7ov/xAgltkQ==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/compose": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4" + "@wordpress/compose": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6" } }, "@wordpress/warning": { - "version": "2.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.42.4.tgz", - "integrity": "sha512-q2YzFYDjFD7FuthRGag4yIsOylCl1KN8mDSPaxYuSpkxNSYgpW9SCrBTMxGxrHfSx48Q/FZwvRGRJFgH4DFpoA==" + "version": "2.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/warning/-/warning-2.42.6.tgz", + "integrity": "sha512-QN9NAiiJvBVwLzzi1IQlkAmoKENGRTmx7OqI1w+qbzGdKRguwPd7ek0nNQg95ktDE0PzgRlILfXwDJTJM7y9Tg==" }, "@wordpress/widgets": { - "version": "3.19.4", - "resolved": "https://registry.npmjs.org/@wordpress/widgets/-/widgets-3.19.4.tgz", - "integrity": "sha512-HeLFh9OrIS4svnEEscS0HInlQ9/FwgG0lta/rcTZbn6jq09dfziEhtEhcT+eMm/OEQbW2A2jyU9WLf91REGB/g==", + "version": "3.19.6", + "resolved": "https://registry.npmjs.org/@wordpress/widgets/-/widgets-3.19.6.tgz", + "integrity": "sha512-607mGNC3bj+xOVHWQl9FHB78aQmbNJDp3vaplw09jcI/rs6Us+AR9WqKkeA9Bv/1xPENPSruFNrcuuIbNN7EXw==", "requires": { "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.39.4", - "@wordpress/block-editor": "^12.10.4", - "@wordpress/blocks": "^12.19.4", - "@wordpress/components": "^25.8.4", - "@wordpress/compose": "^6.19.4", - "@wordpress/core-data": "^6.19.4", - "@wordpress/data": "^9.12.4", - "@wordpress/element": "^5.19.4", - "@wordpress/i18n": "^4.42.4", - "@wordpress/icons": "^9.33.4", - "@wordpress/notices": "^4.10.4", + "@wordpress/api-fetch": "^6.39.6", + "@wordpress/block-editor": "^12.10.6", + "@wordpress/blocks": "^12.19.6", + "@wordpress/components": "^25.8.6", + "@wordpress/compose": "^6.19.6", + "@wordpress/core-data": "^6.19.6", + "@wordpress/data": "^9.12.6", + "@wordpress/element": "^5.19.6", + "@wordpress/i18n": "^4.42.6", + "@wordpress/icons": "^9.33.6", + "@wordpress/notices": "^4.10.6", "classnames": "^2.3.1" } }, "@wordpress/wordcount": { - "version": "3.42.4", - "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-3.42.4.tgz", - "integrity": "sha512-8jP0hpZ++IXPnIWA8RJbHzJi9cXh40rrzGLR90P+Nm88BakA/OZhl5wavWcniiPtXn/hMhg2GyJa24IdV3NdLw==", + "version": "3.42.6", + "resolved": "https://registry.npmjs.org/@wordpress/wordcount/-/wordcount-3.42.6.tgz", + "integrity": "sha512-eyAuwgV9c3P0HxBx0qY0JlV42sBm0vMmRKkCgfUZBNqW+1dzBXy1esOYCOJASSwUoGkV7USOHZQm1iMu/2WjoQ==", "requires": { "@babel/runtime": "^7.16.0" } @@ -44660,9 +44900,9 @@ } }, "resolve": { - "version": "1.22.6", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", - "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "requires": { "is-core-module": "^2.13.0", @@ -44887,9 +45127,9 @@ "dev": true }, "eslint-plugin-prettier": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", - "integrity": "sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", + "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0", @@ -44936,12 +45176,12 @@ "dev": true }, "resolve": { - "version": "2.0.0-next.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", - "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", "dev": true, "requires": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } diff --git a/package.json b/package.json index bdebf39fb4403..4587765dad018 100644 --- a/package.json +++ b/package.json @@ -25,11 +25,13 @@ ], "devDependencies": { "@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.4", - "@wordpress/dependency-extraction-webpack-plugin": "4.25.4", - "@wordpress/e2e-test-utils": "10.13.4", - "@wordpress/scripts": "26.13.4", + "@wordpress/babel-preset-default": "7.26.6", + "@wordpress/dependency-extraction-webpack-plugin": "4.25.6", + "@wordpress/e2e-test-utils": "10.13.6", + "@wordpress/e2e-test-utils-playwright": "0.11.0", + "@wordpress/scripts": "26.13.6", "autoprefixer": "10.4.16", "chalk": "5.3.0", "check-node-version": "4.2.1", @@ -78,70 +80,70 @@ "dependencies": { "@emotion/is-prop-valid": "0.8.8", "@emotion/memoize": "0.7.4", - "@wordpress/a11y": "3.42.4", - "@wordpress/annotations": "2.42.4", - "@wordpress/api-fetch": "6.39.4", - "@wordpress/autop": "3.42.4", - "@wordpress/blob": "3.42.4", - "@wordpress/block-directory": "4.19.4", - "@wordpress/block-editor": "12.10.4", - "@wordpress/block-library": "8.19.4", - "@wordpress/block-serialization-default-parser": "4.42.4", - "@wordpress/blocks": "12.19.4", - "@wordpress/commands": "0.13.4", - "@wordpress/components": "25.8.4", - "@wordpress/compose": "6.19.4", - "@wordpress/core-commands": "0.11.4", - "@wordpress/core-data": "6.19.4", - "@wordpress/customize-widgets": "4.19.4", - "@wordpress/data": "9.12.4", - "@wordpress/data-controls": "3.11.4", - "@wordpress/date": "4.42.4", - "@wordpress/deprecated": "3.42.4", - "@wordpress/dom": "3.42.4", - "@wordpress/dom-ready": "3.42.4", - "@wordpress/edit-post": "7.19.4", - "@wordpress/edit-site": "5.19.4", - "@wordpress/edit-widgets": "5.19.4", - "@wordpress/editor": "13.19.4", - "@wordpress/element": "5.19.4", - "@wordpress/escape-html": "2.42.4", - "@wordpress/format-library": "4.19.4", - "@wordpress/hooks": "3.42.4", - "@wordpress/html-entities": "3.42.4", - "@wordpress/i18n": "4.42.4", - "@wordpress/icons": "9.33.4", - "@wordpress/interactivity": "2.3.4", - "@wordpress/interface": "5.19.4", - "@wordpress/is-shallow-equal": "4.42.4", - "@wordpress/keyboard-shortcuts": "4.19.4", - "@wordpress/keycodes": "3.42.4", - "@wordpress/list-reusable-blocks": "4.19.4", - "@wordpress/media-utils": "4.33.4", - "@wordpress/notices": "4.10.4", - "@wordpress/nux": "8.4.4", - "@wordpress/patterns": "1.3.4", - "@wordpress/plugins": "6.10.4", - "@wordpress/preferences": "3.19.4", - "@wordpress/preferences-persistence": "1.34.4", - "@wordpress/primitives": "3.40.4", - "@wordpress/priority-queue": "2.42.4", - "@wordpress/private-apis": "0.24.4", - "@wordpress/redux-routine": "4.42.4", - "@wordpress/reusable-blocks": "4.19.4", - "@wordpress/rich-text": "6.19.4", - "@wordpress/router": "0.11.4", - "@wordpress/server-side-render": "4.19.4", - "@wordpress/shortcode": "3.42.4", - "@wordpress/style-engine": "1.25.4", - "@wordpress/sync": "0.4.4", - "@wordpress/token-list": "2.42.4", - "@wordpress/undo-manager": "0.2.4", - "@wordpress/url": "3.43.4", - "@wordpress/viewport": "5.19.4", - "@wordpress/warning": "2.42.4", - "@wordpress/widgets": "3.19.4", - "@wordpress/wordcount": "3.42.4", + "@wordpress/a11y": "3.42.6", + "@wordpress/annotations": "2.42.6", + "@wordpress/api-fetch": "6.39.6", + "@wordpress/autop": "3.42.6", + "@wordpress/blob": "3.42.6", + "@wordpress/block-directory": "4.19.6", + "@wordpress/block-editor": "12.10.6", + "@wordpress/block-library": "8.19.6", + "@wordpress/block-serialization-default-parser": "4.42.6", + "@wordpress/blocks": "12.19.6", + "@wordpress/commands": "0.13.6", + "@wordpress/components": "25.8.6", + "@wordpress/compose": "6.19.6", + "@wordpress/core-commands": "0.11.6", + "@wordpress/core-data": "6.19.6", + "@wordpress/customize-widgets": "4.19.6", + "@wordpress/data": "9.12.6", + "@wordpress/data-controls": "3.11.6", + "@wordpress/date": "4.42.6", + "@wordpress/deprecated": "3.42.6", + "@wordpress/dom": "3.42.6", + "@wordpress/dom-ready": "3.42.6", + "@wordpress/edit-post": "7.19.6", + "@wordpress/edit-site": "5.19.6", + "@wordpress/edit-widgets": "5.19.6", + "@wordpress/editor": "13.19.6", + "@wordpress/element": "5.19.6", + "@wordpress/escape-html": "2.42.6", + "@wordpress/format-library": "4.19.6", + "@wordpress/hooks": "3.42.6", + "@wordpress/html-entities": "3.42.6", + "@wordpress/i18n": "4.42.6", + "@wordpress/icons": "9.33.6", + "@wordpress/interactivity": "2.3.6", + "@wordpress/interface": "5.19.6", + "@wordpress/is-shallow-equal": "4.42.6", + "@wordpress/keyboard-shortcuts": "4.19.6", + "@wordpress/keycodes": "3.42.6", + "@wordpress/list-reusable-blocks": "4.19.6", + "@wordpress/media-utils": "4.33.6", + "@wordpress/notices": "4.10.6", + "@wordpress/nux": "8.4.6", + "@wordpress/patterns": "1.3.6", + "@wordpress/plugins": "6.10.6", + "@wordpress/preferences": "3.19.6", + "@wordpress/preferences-persistence": "1.34.6", + "@wordpress/primitives": "3.40.6", + "@wordpress/priority-queue": "2.42.6", + "@wordpress/private-apis": "0.24.6", + "@wordpress/redux-routine": "4.42.6", + "@wordpress/reusable-blocks": "4.19.6", + "@wordpress/rich-text": "6.19.6", + "@wordpress/router": "0.11.6", + "@wordpress/server-side-render": "4.19.6", + "@wordpress/shortcode": "3.42.6", + "@wordpress/style-engine": "1.25.6", + "@wordpress/sync": "0.4.6", + "@wordpress/token-list": "2.42.6", + "@wordpress/undo-manager": "0.2.6", + "@wordpress/url": "3.43.6", + "@wordpress/viewport": "5.19.6", + "@wordpress/warning": "2.42.6", + "@wordpress/widgets": "3.19.6", + "@wordpress/wordcount": "3.42.6", "backbone": "1.5.0", "clipboard": "2.0.11", "core-js-url-browser": "3.6.4", @@ -189,10 +191,10 @@ "env:cli": "node ./tools/local-env/scripts/docker.js run cli", "env:logs": "node ./tools/local-env/scripts/docker.js logs", "env:pull": "node ./tools/local-env/scripts/docker.js pull", - "test:performance": "node ./tests/performance/run-tests.js", + "test:performance": "wp-scripts test-playwright --config tests/performance/playwright.config.js", "test:php": "node ./tools/local-env/scripts/docker.js run -T php composer update -W && node ./tools/local-env/scripts/docker.js run php ./vendor/bin/phpunit", - "test:e2e": "node ./tests/e2e/run-tests.js", - "test:visual": "node ./tests/visual-regression/run-tests.js", + "test:e2e": "wp-scripts test-playwright --config tests/e2e/playwright.config.js", + "test:visual": "wp-scripts test-playwright --config tests/visual-regression/playwright.config.js", "sync-gutenberg-packages": "grunt sync-gutenberg-packages", "postsync-gutenberg-packages": "grunt wp-packages:sync-stable-blocks && grunt build --dev && grunt build" } diff --git a/src/js/_enqueues/admin/common.js b/src/js/_enqueues/admin/common.js index 0984ac2dfe93a..e3daa8c4d1c6f 100644 --- a/src/js/_enqueues/admin/common.js +++ b/src/js/_enqueues/admin/common.js @@ -1702,24 +1702,45 @@ $( function() { } } ); - // Close sidebar when focus moves outside of toggle and sidebar. - $( '#wp-admin-bar-menu-toggle, #adminmenumain' ).on( 'focusout', function() { - var focusIsInToggle, focusIsInSidebar; - + // Close sidebar when target moves outside of toggle and sidebar. + $( document ).on( 'click', function( event ) { if ( ! $wpwrap.hasClass( 'wp-responsive-open' ) || ! document.hasFocus() ) { return; } - // A brief delay is required to allow focus to switch to another element. - setTimeout( function() { - focusIsInToggle = $.contains( $( '#wp-admin-bar-menu-toggle' )[0], $( ':focus' )[0] ); - focusIsInSidebar = $.contains( $( '#adminmenumain' )[0], $( ':focus' )[0] ); - if ( ! focusIsInToggle && ! focusIsInSidebar ) { - $( '#wp-admin-bar-menu-toggle' ).trigger( 'click.wp-responsive' ); - } - }, 10 ); + var focusIsInToggle = $.contains( $( '#wp-admin-bar-menu-toggle' )[0], event.target ); + var focusIsInSidebar = $.contains( $( '#adminmenuwrap' )[0], event.target ); + + if ( ! focusIsInToggle && ! focusIsInSidebar ) { + $( '#wp-admin-bar-menu-toggle' ).trigger( 'click.wp-responsive' ); + } } ); + // Close sidebar when a keypress completes outside of toggle and sidebar. + $( document ).on( 'keyup', function( event ) { + var toggleButton = $( '#wp-admin-bar-menu-toggle' )[0]; + if ( ! $wpwrap.hasClass( 'wp-responsive-open' ) ) { + return; + } + if ( 27 === event.keyCode ) { + $( toggleButton ).trigger( 'click.wp-responsive' ); + $( toggleButton ).find( 'a' ).trigger( 'focus' ); + } else { + if ( 9 === event.keyCode ) { + var sidebar = $( '#adminmenuwrap' )[0]; + var focusedElement = event.relatedTarget || document.activeElement; + // A brief delay is required to allow focus to switch to another element. + setTimeout( function() { + var focusIsInToggle = $.contains( toggleButton, focusedElement ); + var focusIsInSidebar = $.contains( sidebar, focusedElement ); + + if ( ! focusIsInToggle && ! focusIsInSidebar ) { + $( toggleButton ).trigger( 'click.wp-responsive' ); + } + }, 10 ); + } + } + }); // Add menu events. $adminmenu.on( 'click.wp-responsive', 'li.wp-has-submenu > a', function( event ) { diff --git a/src/js/_enqueues/admin/post.js b/src/js/_enqueues/admin/post.js index 6b96ad25f2af1..a86ea4c84bf38 100644 --- a/src/js/_enqueues/admin/post.js +++ b/src/js/_enqueues/admin/post.js @@ -511,7 +511,7 @@ jQuery( function($) { // See https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event. return __( 'The changes you made will be lost if you navigate away from this page.' ); } - }).on( 'unload.edit-post', function( event ) { + }).on( 'pagehide.edit-post', function( event ) { if ( ! releaseLock ) { return; } diff --git a/src/js/_enqueues/lib/gallery.js b/src/js/_enqueues/lib/gallery.js index d493946c5b0f5..761b36db97a00 100644 --- a/src/js/_enqueues/lib/gallery.js +++ b/src/js/_enqueues/lib/gallery.js @@ -88,8 +88,6 @@ jQuery( function($) { } }); -jQuery(window).on( 'unload', function () { window.tinymce = window.tinyMCE = window.wpgallery = null; } ); // Cleanup. - /* gallery settings */ window.tinymce = null; diff --git a/src/js/_enqueues/wp/heartbeat.js b/src/js/_enqueues/wp/heartbeat.js index c6950ef7df065..f3a92b0a1f78e 100644 --- a/src/js/_enqueues/wp/heartbeat.js +++ b/src/js/_enqueues/wp/heartbeat.js @@ -223,9 +223,9 @@ settings.checkFocusTimer = window.setInterval( checkFocus, 10000 ); } - $(window).on( 'unload.wp-heartbeat', function() { + $(window).on( 'pagehide.wp-heartbeat', function() { // Don't connect anymore. - settings.suspend = true; + suspend(); // Abort the last request if not completed. if ( settings.xhr && settings.xhr.readyState !== 4 ) { @@ -233,6 +233,25 @@ } }); + $(window).on( + 'pageshow.wp-heartbeat', + /** + * Handles pageshow event, specifically when page navigation is restored from back/forward cache. + * + * @param {jQuery.Event} event + * @param {PageTransitionEvent} event.originalEvent + */ + function ( event ) { + if ( event.originalEvent.persisted ) { + /* + * When page navigation is stored via bfcache (Back/Forward Cache), consider this the same as + * if the user had just switched to the tab since the behavior is similar. + */ + focused(); + } + } + ); + // Check for user activity every 30 seconds. window.setInterval( checkUserActivity, 30000 ); @@ -541,7 +560,7 @@ settings.userActivity = time(); // Resume if suspended. - settings.suspend = false; + resume(); if ( ! settings.hasFocus ) { settings.hasFocus = true; @@ -549,6 +568,20 @@ } } + /** + * Suspends connecting. + */ + function suspend() { + settings.suspend = true; + } + + /** + * Resumes connecting. + */ + function resume() { + settings.suspend = false; + } + /** * Runs when the user becomes active after a period of inactivity. * @@ -593,7 +626,7 @@ // Suspend after 10 minutes of inactivity when suspending is enabled. // Always suspend after 60 minutes of inactivity. This will release the post lock, etc. if ( ( settings.suspendEnabled && lastActive > 600000 ) || lastActive > 3600000 ) { - settings.suspend = true; + suspend(); } if ( ! settings.userActivityEvents ) { diff --git a/src/js/_enqueues/wp/mce-view.js b/src/js/_enqueues/wp/mce-view.js index a9b57b601d11e..863803f614816 100644 --- a/src/js/_enqueues/wp/mce-view.js +++ b/src/js/_enqueues/wp/mce-view.js @@ -643,16 +643,6 @@ }, 3000 ); } - function reload() { - if ( ! editor.isHidden() ) { - $( node ).data( 'rendered', null ); - - setTimeout( function() { - wp.mce.views.render(); - } ); - } - } - function addObserver() { observer = new MutationObserver( _.debounce( resize, 100 ) ); @@ -663,7 +653,7 @@ } ); } - $( iframeWin ).on( 'load', resize ).on( 'unload', reload ); + $( iframeWin ).on( 'load', resize ); MutationObserver = iframeWin.MutationObserver || iframeWin.WebKitMutationObserver || iframeWin.MozMutationObserver; diff --git a/src/js/_enqueues/wp/media/models.js b/src/js/_enqueues/wp/media/models.js index 5ff0552cbff38..edca0a14f2113 100644 --- a/src/js/_enqueues/wp/media/models.js +++ b/src/js/_enqueues/wp/media/models.js @@ -2,8 +2,7 @@ * @output wp-includes/js/media-models.js */ -var $ = jQuery, - Attachment, Attachments, l10n, media; +var Attachment, Attachments, l10n, media; /** @namespace wp */ window.wp = window.wp || {}; @@ -237,8 +236,3 @@ media.query = function( props ) { props: _.extend( _.defaults( props || {}, { orderby: 'date' } ), { query: true } ) }); }; - -// Clean up. Prevents mobile browsers caching. -$(window).on('unload', function(){ - window.wp = null; -}); diff --git a/src/js/_enqueues/wp/widgets/text.js b/src/js/_enqueues/wp/widgets/text.js index ee4dbb9529161..48d72475eebe3 100644 --- a/src/js/_enqueues/wp/widgets/text.js +++ b/src/js/_enqueues/wp/widgets/text.js @@ -291,7 +291,7 @@ wp.textWidgets = ( function( $ ) { onInit = function() { // When a widget is moved in the DOM the dynamically-created TinyMCE iframe will be destroyed and has to be re-built. - $( editor.getWin() ).on( 'unload', function() { + $( editor.getWin() ).on( 'pagehide', function() { _.defer( buildEditor ); }); diff --git a/src/wp-admin/css/about.css b/src/wp-admin/css/about.css index f4eec067e2bee..607e7676485a4 100644 --- a/src/wp-admin/css/about.css +++ b/src/wp-admin/css/about.css @@ -733,7 +733,7 @@ ------------------------------------------------------------------------------*/ .about__section .wp-people-group-title { - margin-bottom: calc(var(--gap) * 2); + margin-bottom: calc(var(--gap) * 2 - 10px); text-align: center; } @@ -748,7 +748,7 @@ display: inline-block; vertical-align: top; box-sizing: border-box; - margin-bottom: var(--gap); + margin-bottom: calc(var(--gap) - 10px); width: 25%; text-align: center; } @@ -780,8 +780,10 @@ } .about__section .wp-person .web { + display: block; font-size: 1.4em; font-weight: 600; + padding: 10px 10px 0; text-decoration: none; } diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php index 8aada30959372..69f5fd469ca94 100644 --- a/src/wp-admin/includes/ajax-actions.php +++ b/src/wp-admin/includes/ajax-actions.php @@ -3882,13 +3882,29 @@ function wp_ajax_parse_media_shortcode() { $shortcode = wp_unslash( $_POST['shortcode'] ); + // Only process previews for media related shortcodes: + $found_shortcodes = get_shortcode_tags_in_content( $shortcode ); + $media_shortcodes = array( + 'audio', + 'embed', + 'playlist', + 'video', + 'gallery', + ); + + $other_shortcodes = array_diff( $found_shortcodes, $media_shortcodes ); + + if ( ! empty( $other_shortcodes ) ) { + wp_send_json_error(); + } + if ( ! empty( $_POST['post_ID'] ) ) { $post = get_post( (int) $_POST['post_ID'] ); } // The embed shortcode requires a post. if ( ! $post || ! current_user_can( 'edit_post', $post->ID ) ) { - if ( 'embed' === $shortcode ) { + if ( in_array( 'embed', $found_shortcodes, true ) ) { wp_send_json_error(); } } else { diff --git a/src/wp-admin/includes/class-custom-background.php b/src/wp-admin/includes/class-custom-background.php index b818016b28931..2eb3ccfd64bab 100644 --- a/src/wp-admin/includes/class-custom-background.php +++ b/src/wp-admin/includes/class-custom-background.php @@ -571,8 +571,9 @@ public function handle_upload() { $thumbnail = wp_get_attachment_image_src( $id, 'thumbnail' ); set_theme_mod( 'background_image_thumb', sanitize_url( $thumbnail[0] ) ); - /** This action is documented in wp-admin/includes/class-custom-image-header.php */ - do_action( 'wp_create_file_in_uploads', $file, $id ); // For replication. + /** This filter is documented in wp-admin/includes/class-custom-image-header.php */ + $file = apply_filters( 'wp_create_file_in_uploads', $file, $id ); // For replication. + $this->updated = true; } diff --git a/src/wp-admin/includes/class-custom-image-header.php b/src/wp-admin/includes/class-custom-image-header.php index 9df725af0cb06..ee3bcb12ecb7e 100644 --- a/src/wp-admin/includes/class-custom-image-header.php +++ b/src/wp-admin/includes/class-custom-image-header.php @@ -882,14 +882,16 @@ public function step_2() { $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) ); /** - * Fires after the header image is set or an error is returned. + * Filters the attachment file path after the custom header or background image is set. + * + * Used for file replication. * * @since 2.1.0 * * @param string $file Path to the file. * @param int $attachment_id Attachment ID. */ - do_action( 'wp_create_file_in_uploads', $file, $attachment_id ); // For replication. + $file = apply_filters( 'wp_create_file_in_uploads', $file, $attachment_id ); // For replication. return $this->finished(); } elseif ( $width > $max_width ) { diff --git a/src/wp-admin/includes/class-wp-comments-list-table.php b/src/wp-admin/includes/class-wp-comments-list-table.php index b9eb0c2052090..1433818ccfb4f 100644 --- a/src/wp-admin/includes/class-wp-comments-list-table.php +++ b/src/wp-admin/includes/class-wp-comments-list-table.php @@ -654,6 +654,19 @@ public function single_row( $item ) { $this->user_can = current_user_can( 'edit_comment', $comment->comment_ID ); + $edit_post_cap = $post ? 'edit_post' : 'edit_posts'; + if ( + current_user_can( $edit_post_cap, $comment->comment_post_ID ) || + ( + empty( $post->post_password ) && + current_user_can( 'read_post', $comment->comment_post_ID ) + ) + ) { + // The user has access to the post + } else { + return false; + } + echo ""; $this->single_row_columns( $comment ); echo "\n"; diff --git a/src/wp-admin/includes/class-wp-filesystem-base.php b/src/wp-admin/includes/class-wp-filesystem-base.php index b20a4b99e4a97..8b291279e172e 100644 --- a/src/wp-admin/includes/class-wp-filesystem-base.php +++ b/src/wp-admin/includes/class-wp-filesystem-base.php @@ -216,13 +216,13 @@ public function find_folder( $folder ) { } } } elseif ( 'direct' === $this->method ) { - $folder = str_replace( '\\', '/', $folder ); // Windows path sanitisation. + $folder = str_replace( '\\', '/', $folder ); // Windows path sanitization. return trailingslashit( $folder ); } $folder = preg_replace( '|^([a-z]{1}):|i', '', $folder ); // Strip out Windows drive letter if it's there. - $folder = str_replace( '\\', '/', $folder ); // Windows path sanitisation. + $folder = str_replace( '\\', '/', $folder ); // Windows path sanitization. if ( isset( $this->cache[ $folder ] ) ) { return $this->cache[ $folder ]; diff --git a/src/wp-admin/includes/class-wp-list-table.php b/src/wp-admin/includes/class-wp-list-table.php index fefb69380e121..b3aebd9643cdf 100644 --- a/src/wp-admin/includes/class-wp-list-table.php +++ b/src/wp-admin/includes/class-wp-list-table.php @@ -851,6 +851,20 @@ protected function comments_bubble( $post_id, $pending_comments ) { $pending_comments_number ); + $post_object = get_post( $post_id ); + $edit_post_cap = $post_object ? 'edit_post' : 'edit_posts'; + if ( + current_user_can( $edit_post_cap, $post_id ) || + ( + empty( $post_object->post_password ) && + current_user_can( 'read_post', $post_id ) + ) + ) { + // The user has access to the post and thus can see comments + } else { + return false; + } + if ( ! $approved_comments && ! $pending_comments ) { // No comments at all. printf( 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 d16349928dabb..5c92fba7aad1c 100644 --- a/src/wp-admin/includes/class-wp-plugins-list-table.php +++ b/src/wp-admin/includes/class-wp-plugins-list-table.php @@ -1280,8 +1280,7 @@ public function single_row( $item ) { if ( ! $compatible_php || ! $compatible_wp ) { printf( - '' . - '' . + '', esc_attr( $this->get_column_count() ) ); diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php index 31eba07a2dc63..5b5042394965c 100644 --- a/src/wp-admin/includes/dashboard.php +++ b/src/wp-admin/includes/dashboard.php @@ -1109,7 +1109,16 @@ function wp_dashboard_recent_comments( $total_items = 5 ) { echo ''; diff --git a/src/wp-admin/includes/file.php b/src/wp-admin/includes/file.php index 7ea3619e077b0..600ddc27dfd6e 100644 --- a/src/wp-admin/includes/file.php +++ b/src/wp-admin/includes/file.php @@ -1266,7 +1266,7 @@ function download_url( $url, $timeout = 300, $signature_verification = false ) { $signature_verification = in_array( parse_url( $url, PHP_URL_HOST ), $signed_hostnames, true ); } - // Perform signature valiation if supported. + // Perform signature validation if supported. if ( $signature_verification ) { $signature = wp_remote_retrieve_header( $response, 'X-Content-Signature' ); diff --git a/src/wp-admin/includes/update-core.php b/src/wp-admin/includes/update-core.php index 51d786fa6d795..2214b1b66852b 100644 --- a/src/wp-admin/includes/update-core.php +++ b/src/wp-admin/includes/update-core.php @@ -1845,13 +1845,14 @@ function _upgrade_440_force_deactivate_incompatible_plugins() { * @since 5.8.0 * @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. */ function _upgrade_core_deactivate_incompatible_plugins() { - if ( defined( 'GUTENBERG_VERSION' ) && version_compare( GUTENBERG_VERSION, '14.1', '<' ) ) { + if ( defined( 'GUTENBERG_VERSION' ) && version_compare( GUTENBERG_VERSION, '16.5', '<' ) ) { $deactivated_gutenberg['gutenberg'] = array( 'plugin_name' => 'Gutenberg', 'version_deactivated' => GUTENBERG_VERSION, - 'version_compatible' => '14.1', + 'version_compatible' => '16.5', ); 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/includes/user.php b/src/wp-admin/includes/user.php index e19727401d89d..423c13ad15ccd 100644 --- a/src/wp-admin/includes/user.php +++ b/src/wp-admin/includes/user.php @@ -638,6 +638,7 @@ function admin_created_user_email( $text ) { * * @since 5.6.0 * @since 6.2.0 Allow insecure HTTP connections for the local environment. + * @since 6.3.2 Validates the success and reject URLs to prevent javascript pseudo protocol being executed. * * @param array $request { * The array of request data. All arguments are optional and may be empty. @@ -651,27 +652,24 @@ function admin_created_user_email( $text ) { * @return true|WP_Error True if the request is valid, a WP_Error object contains errors if not. */ function wp_is_authorize_application_password_request_valid( $request, $user ) { - $error = new WP_Error(); - $is_local = 'local' === wp_get_environment_type(); - - if ( ! empty( $request['success_url'] ) ) { - $scheme = wp_parse_url( $request['success_url'], PHP_URL_SCHEME ); + $error = new WP_Error(); - if ( 'http' === $scheme && ! $is_local ) { + if ( isset( $request['success_url'] ) ) { + $validated_success_url = wp_is_authorize_application_redirect_url_valid( $request['success_url'] ); + if ( is_wp_error( $validated_success_url ) ) { $error->add( - 'invalid_redirect_scheme', - __( 'The success URL must be served over a secure connection.' ) + $validated_success_url->get_error_code(), + $validated_success_url->get_error_message() ); } } - if ( ! empty( $request['reject_url'] ) ) { - $scheme = wp_parse_url( $request['reject_url'], PHP_URL_SCHEME ); - - if ( 'http' === $scheme && ! $is_local ) { + if ( isset( $request['reject_url'] ) ) { + $validated_reject_url = wp_is_authorize_application_redirect_url_valid( $request['reject_url'] ); + if ( is_wp_error( $validated_reject_url ) ) { $error->add( - 'invalid_redirect_scheme', - __( 'The rejection URL must be served over a secure connection.' ) + $validated_reject_url->get_error_code(), + $validated_reject_url->get_error_message() ); } } @@ -700,3 +698,59 @@ function wp_is_authorize_application_password_request_valid( $request, $user ) { return true; } + +/** + * Validates the redirect URL protocol scheme. The protocol can be anything except http and javascript. + * + * @since 6.3.2 + * + * @param string $url - The redirect URL to be validated. + * + * @return true|WP_Error True if the redirect URL is valid, a WP_Error object otherwise. + */ +function wp_is_authorize_application_redirect_url_valid( $url ) { + $bad_protocols = array( 'javascript', 'data' ); + if ( empty( $url ) ) { + return true; + } + + // Based on https://www.rfc-editor.org/rfc/rfc2396#section-3.1 + $valid_scheme_regex = '/^[a-zA-Z][a-zA-Z0-9+.-]*:/'; + if ( ! preg_match( $valid_scheme_regex, $url ) ) { + return new WP_Error( + 'invalid_redirect_url_format', + __( 'Invalid URL format.' ) + ); + } + + /** + * Filters the list of invalid protocols used in applications redirect URLs. + * + * @since 6.3.2 + * + * @param string[] $bad_protocols Array of invalid protocols. + * @param string $url The redirect URL to be validated. + */ + $invalid_protocols = array_map( 'strtolower', apply_filters( 'wp_authorize_application_redirect_url_invalid_protocols', $bad_protocols, $url ) ); + + $scheme = wp_parse_url( $url, PHP_URL_SCHEME ); + $host = wp_parse_url( $url, PHP_URL_HOST ); + $is_local = 'local' === wp_get_environment_type(); + + // validates if the proper URI format is applied to the $url + if ( empty( $host ) || empty( $scheme ) || in_array( strtolower( $scheme ), $invalid_protocols, true ) ) { + return new WP_Error( + 'invalid_redirect_url_format', + __( 'Invalid URL format.' ) + ); + } + + if ( 'http' === $scheme && ! $is_local ) { + return new WP_Error( + 'invalid_redirect_scheme', + __( 'The URL must be served over a secure connection.' ) + ); + } + + return true; +} diff --git a/src/wp-content/themes/twentynineteen/style-editor.css b/src/wp-content/themes/twentynineteen/style-editor.css index 3dd9c1eb8ae40..54487026e231a 100644 --- a/src/wp-content/themes/twentynineteen/style-editor.css +++ b/src/wp-content/themes/twentynineteen/style-editor.css @@ -605,7 +605,7 @@ body .wp-block.aligncenter { } @media only screen and (min-width: 768px) { - body.block-editor-writing-flow, + body.block-editor-iframe__body, body.block-editor-writing-flow, body .block-editor-writing-flow { max-width: 80%; margin: 0 10%; diff --git a/src/wp-content/themes/twentynineteen/style-editor.scss b/src/wp-content/themes/twentynineteen/style-editor.scss index 2c129c809ad28..ce8a2883f8318 100644 --- a/src/wp-content/themes/twentynineteen/style-editor.scss +++ b/src/wp-content/themes/twentynineteen/style-editor.scss @@ -36,6 +36,7 @@ body { @include media(tablet) { + &.block-editor-iframe__body, &.block-editor-writing-flow, .block-editor-writing-flow { max-width: 80%; diff --git a/src/wp-content/themes/twentytwentyfour/assets/css/button-outline.css b/src/wp-content/themes/twentytwentyfour/assets/css/button-outline.css index 92ae175986319..26032360fde89 100644 --- a/src/wp-content/themes/twentytwentyfour/assets/css/button-outline.css +++ b/src/wp-content/themes/twentytwentyfour/assets/css/button-outline.css @@ -1,6 +1,6 @@ .wp-block-button.is-style-outline - > .wp-block-button__link:not(.has-background):hover { - background-color: var(--wp--preset--color--contrast-2); + > .wp-block-button__link:not(.has-text-color, .has-background):hover { + background-color: var(--wp--preset--color--contrast-2, var(--wp--preset--color--contrast, transparent)); color: var(--wp--preset--color--base); - border-color: var(--wp--preset--color--contrast-2); + border-color: var(--wp--preset--color--contrast-2, var(--wp--preset--color--contrast, currentColor)); } diff --git a/src/wp-content/themes/twentytwentyfour/functions.php b/src/wp-content/themes/twentytwentyfour/functions.php index cffc4dc01d895..e569d5b8e9f5d 100644 --- a/src/wp-content/themes/twentytwentyfour/functions.php +++ b/src/wp-content/themes/twentytwentyfour/functions.php @@ -52,7 +52,7 @@ function twentytwentyfour_block_styles() { .is-style-arrow-icon-details { padding-top: var(--wp--preset--spacing--10); padding-bottom: var(--wp--preset--spacing--10); - border-bottom: 1px solid rgba(255, 255, 255, 0.20); + border-bottom: 1px solid var(--wp--preset--color--contrast-2, currentColor); } .is-style-arrow-icon-details summary { diff --git a/src/wp-content/themes/twentytwentyfour/parts/header.html b/src/wp-content/themes/twentytwentyfour/parts/header.html index 8c069b4d4226f..422ad31d7f52a 100644 --- a/src/wp-content/themes/twentytwentyfour/parts/header.html +++ b/src/wp-content/themes/twentytwentyfour/parts/header.html @@ -8,6 +8,6 @@ - + diff --git a/src/wp-content/themes/twentytwentyfour/patterns/centered-statement.php b/src/wp-content/themes/twentytwentyfour/patterns/centered-statement.php index 1384759f3c35d..5637bdf14d79f 100644 --- a/src/wp-content/themes/twentytwentyfour/patterns/centered-statement.php +++ b/src/wp-content/themes/twentytwentyfour/patterns/centered-statement.php @@ -3,6 +3,7 @@ * Title: Centered Statement * Slug: twentytwentyfour/centered-statement * Categories: text, about, featured + * Keywords: statement, centered * Viewport width: 1400 */ ?> diff --git a/src/wp-content/themes/twentytwentyfour/patterns/clients.php b/src/wp-content/themes/twentytwentyfour/patterns/clients.php index 9d38f3eb699aa..e24572710b4dc 100644 --- a/src/wp-content/themes/twentytwentyfour/patterns/clients.php +++ b/src/wp-content/themes/twentytwentyfour/patterns/clients.php @@ -20,27 +20,27 @@ - +
- -
+ +
- -
+ +
- -
+ +
- -
+ +
- -
+ +
diff --git a/src/wp-content/themes/twentytwentyfour/patterns/columns.php b/src/wp-content/themes/twentytwentyfour/patterns/columns.php index ec5d1c1053306..913a467dc31d8 100644 --- a/src/wp-content/themes/twentytwentyfour/patterns/columns.php +++ b/src/wp-content/themes/twentytwentyfour/patterns/columns.php @@ -1,6 +1,6 @@ - - diff --git a/src/wp-content/themes/twentytwentyfour/theme.json b/src/wp-content/themes/twentytwentyfour/theme.json index f3b637dd186a4..a8790a9b3eae5 100644 --- a/src/wp-content/themes/twentytwentyfour/theme.json +++ b/src/wp-content/themes/twentytwentyfour/theme.json @@ -162,7 +162,7 @@ "spacingSizes": [ { "name": "1", - "size": "min(1rem, 1vw)", + "size": "1rem", "slug": "10" }, { @@ -331,20 +331,25 @@ "core/code": { "border": { "color": "var(--wp--preset--color--contrast)", - "radius": "0.25rem", - "style": "solid", - "width": "2px" + "radius": "var(--wp--preset--spacing--20)" + }, + "color": { + "background": "var(--wp--preset--color--base-2)", + "text": "var(--wp--preset--color--contrast-2)" }, "spacing": { "padding": { - "bottom": "var(--wp--preset--spacing--50)", - "left": "var(--wp--preset--spacing--50)", - "right": "var(--wp--preset--spacing--50)", - "top": "var(--wp--preset--spacing--50)" + "bottom": "calc(var(--wp--preset--spacing--30) + 0.75rem)", + "left": "calc(var(--wp--preset--spacing--30) + 0.75rem)", + "right": "calc(var(--wp--preset--spacing--30) + 0.75rem)", + "top": "calc(var(--wp--preset--spacing--30) + 0.75rem)" } }, "typography": { - "fontFamily": "monospace" + "fontSize": "var(--wp--preset--font-size--medium)", + "fontStyle": "normal", + "fontWeight": "400", + "lineHeight": "1.6" } }, "core/comment-author-name": { @@ -612,23 +617,7 @@ }, "core/pullquote": { "border": { - "bottom": { - "style": "none", - "width": "0px" - }, - "left": { - "style": "none", - "width": "0px" - }, - "radius": "var(--wp--preset--spacing--20)", - "right": { - "style": "none", - "width": "0px" - }, - "top": { - "style": "none", - "width": "0px" - } + "radius": "var(--wp--preset--spacing--20)" }, "elements": { "cite": { @@ -657,6 +646,13 @@ "core/query-title": { "css": "& span {font-style: italic;}" }, + "core/query-no-results": { + "spacing": { + "padding": { + "top": "var(--wp--preset--spacing--30)" + } + } + }, "core/quote": { "border": { "radius": "var(--wp--preset--spacing--20)" diff --git a/src/wp-includes/Requests/src/Hooks.php b/src/wp-includes/Requests/src/Hooks.php index 74fba0b3e135a..d8023ed0bb688 100644 --- a/src/wp-includes/Requests/src/Hooks.php +++ b/src/wp-includes/Requests/src/Hooks.php @@ -96,4 +96,8 @@ public function dispatch($hook, $parameters = []) { return true; } + + public function __wakeup() { + throw new \LogicException( __CLASS__ . ' should never be unserialized' ); + } } diff --git a/src/wp-includes/Requests/src/Iri.php b/src/wp-includes/Requests/src/Iri.php index c452c7365b0f7..41ea7a8a8c81c 100644 --- a/src/wp-includes/Requests/src/Iri.php +++ b/src/wp-includes/Requests/src/Iri.php @@ -717,6 +717,20 @@ public function is_valid() { return true; } + public function __wakeup() { + $class_props = get_class_vars( __CLASS__ ); + $string_props = array( 'scheme', 'iuserinfo', 'ihost', 'port', 'ipath', 'iquery', 'ifragment' ); + $array_props = array( 'normalization' ); + foreach ( $class_props as $prop => $default_value ) { + if ( in_array( $prop, $string_props, true ) && ! is_string( $this->$prop ) ) { + throw new UnexpectedValueException(); + } elseif ( in_array( $prop, $array_props, true ) && ! is_array( $this->$prop ) ) { + throw new UnexpectedValueException(); + } + $this->$prop = null; + } + } + /** * Set the entire IRI. Returns true on success, false on failure (if there * are any invalid characters). diff --git a/src/wp-includes/Requests/src/Session.php b/src/wp-includes/Requests/src/Session.php index 000d2526d40de..0a63279022e74 100644 --- a/src/wp-includes/Requests/src/Session.php +++ b/src/wp-includes/Requests/src/Session.php @@ -265,6 +265,10 @@ public function request_multiple($requests, $options = []) { return Requests::request_multiple($requests, $options); } + public function __wakeup() { + throw new \LogicException( __CLASS__ . ' should never be unserialized' ); + } + /** * Merge a request's data with the default data * diff --git a/src/wp-includes/assets/script-loader-packages.min.php b/src/wp-includes/assets/script-loader-packages.min.php index c4141f8386974..4c47d84e69626 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' => 'fed54818bfbd86e592c4'), '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' => 'a02c62404dd229f97dc8'), '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' => '46b0c70e2ad17e4594d9'), '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' => '36c9df2cbb8c204ab6a9'), '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' => '374dd88ea463111ee0d3'), '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' => 'bf91befd670fe5777d90'), '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' => 'b83e6291371827f645e0'), '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' => '8fd668a21c0e6cb6e7c9'), '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' => '666fe9658758d0bbe7e4'), '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' => '8e3be75e41f7ecd1c59b'), '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' => 'a234b790ef3bf2e642aa'), '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' => 'e77a47fd9d438c2c79a7'), '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' => '4c4cca5c8337c47c30be'), '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' => '5be8725e45378af75600'), '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' => '947e922b7ef984c21416'), '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' => 'f13ebfe5e07847a1f4b3'), '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' => 'bc3f04a9045626928db0'), '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' => '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' => '3a7c7924f855839011fb'), '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' => '4a4e1bddf0705bf8837e'), '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' => 'ab8337e4d25b39f67261'), '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' => 'ac1f0efce014968a3716'), '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' => 'ac94d42fa1999bcf3722'), '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' => 'd4c3059140e082ba39f9'), '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' => '3f5791ae786456067a27'), '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' => 'e1f251d36e08fc03cc75'), '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' => '5ac513f0f58c78e7f084'), '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')); diff --git a/src/wp-includes/block-patterns.php b/src/wp-includes/block-patterns.php index dd70d2b589fd6..a1a7a67d818e2 100644 --- a/src/wp-includes/block-patterns.php +++ b/src/wp-includes/block-patterns.php @@ -350,9 +350,25 @@ function _register_theme_block_patterns() { continue; } + $file_path = $dirpath . $file; + + if ( ! file_exists( $file_path ) ) { + _doing_it_wrong( + __FUNCTION__, + sprintf( + /* translators: %s: file name. */ + __( 'Could not register file "%s" as a block pattern as the file does not exist.' ), + $file + ), + '6.4.0' + ); + $theme->delete_pattern_cache(); + continue; + } + // The actual pattern content is the output of the file. ob_start(); - include $dirpath . $file; + include $file_path; $pattern_data['content'] = ob_get_clean(); if ( ! $pattern_data['content'] ) { continue; @@ -408,11 +424,13 @@ function _register_theme_block_patterns() { function _wp_get_block_patterns( WP_Theme $theme ) { $can_use_cached = ! wp_is_development_mode( 'theme' ); - if ( $can_use_cached ) { - $pattern_data = $theme->get_pattern_cache(); - if ( is_array( $pattern_data ) ) { + $pattern_data = $theme->get_pattern_cache(); + if ( is_array( $pattern_data ) ) { + if ( $can_use_cached ) { return $pattern_data; } + // If in development mode, clear pattern cache. + $theme->delete_pattern_cache(); } $dirpath = $theme->get_stylesheet_directory() . '/patterns/'; diff --git a/src/wp-includes/block-supports/elements.php b/src/wp-includes/block-supports/elements.php index 770e3e95c30e1..4f3de8c5b863e 100644 --- a/src/wp-includes/block-supports/elements.php +++ b/src/wp-includes/block-supports/elements.php @@ -36,6 +36,9 @@ function wp_render_elements_support( $block_content, $block ) { } $block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] ); + if ( ! $block_type ) { + return $block_content; + } $element_color_properties = array( 'button' => array( diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 0ce64a659d6a6..94934599a8751 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -549,15 +549,18 @@ function _build_block_template_result_from_file( $template_file, $template_type $template->area = $template_file['area']; } - $before_block_visitor = '_inject_theme_attribute_in_template_part_block'; + $before_block_visitor = ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ? '_inject_theme_attribute_in_template_part_block' : null; $after_block_visitor = null; $hooked_blocks = get_hooked_blocks(); if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) { $before_block_visitor = make_before_block_visitor( $hooked_blocks, $template ); $after_block_visitor = make_after_block_visitor( $hooked_blocks, $template ); } - $blocks = parse_blocks( $template_content ); - $template->content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor ); + if ( null !== $before_block_visitor || null !== $after_block_visitor ) { + $blocks = parse_blocks( $template_content ); + $template_content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor ); + } + $template->content = $template_content; return $template; } @@ -724,6 +727,7 @@ function _wp_build_title_and_description_for_taxonomy_block_template( $taxonomy, * * @since 5.9.0 * @since 6.3.0 Added `modified` property to template objects. + * @since 6.4.0 Added support for a revision post to be passed to this function. * @access private * * @param WP_Post $post Template post. @@ -731,7 +735,14 @@ function _wp_build_title_and_description_for_taxonomy_block_template( $taxonomy, */ function _build_block_template_result_from_post( $post ) { $default_template_types = get_default_block_template_types(); - $terms = get_the_terms( $post, 'wp_theme' ); + + $post_id = wp_is_post_revision( $post ); + if ( ! $post_id ) { + $post_id = $post; + } + $parent_post = get_post( $post_id ); + + $terms = get_the_terms( $parent_post, 'wp_theme' ); if ( is_wp_error( $terms ) ) { return $terms; @@ -745,12 +756,12 @@ function _build_block_template_result_from_post( $post ) { $template_file = _get_block_template_file( $post->post_type, $post->post_name ); $has_theme_file = get_stylesheet() === $theme && null !== $template_file; - $origin = get_post_meta( $post->ID, 'origin', true ); - $is_wp_suggestion = get_post_meta( $post->ID, 'is_wp_suggestion', true ); + $origin = get_post_meta( $parent_post->ID, 'origin', true ); + $is_wp_suggestion = get_post_meta( $parent_post->ID, 'is_wp_suggestion', true ); $template = new WP_Block_Template(); $template->wp_id = $post->ID; - $template->id = $theme . '//' . $post->post_name; + $template->id = $theme . '//' . $parent_post->post_name; $template->theme = $theme; $template->content = $post->post_content; $template->slug = $post->post_name; @@ -765,23 +776,23 @@ function _build_block_template_result_from_post( $post ) { $template->author = $post->post_author; $template->modified = $post->post_modified; - if ( 'wp_template' === $post->post_type && $has_theme_file && isset( $template_file['postTypes'] ) ) { + if ( 'wp_template' === $parent_post->post_type && $has_theme_file && isset( $template_file['postTypes'] ) ) { $template->post_types = $template_file['postTypes']; } - if ( 'wp_template' === $post->post_type && isset( $default_template_types[ $template->slug ] ) ) { + if ( 'wp_template' === $parent_post->post_type && isset( $default_template_types[ $template->slug ] ) ) { $template->is_custom = false; } - if ( 'wp_template_part' === $post->post_type ) { - $type_terms = get_the_terms( $post, 'wp_template_part_area' ); + if ( 'wp_template_part' === $parent_post->post_type ) { + $type_terms = get_the_terms( $parent_post, 'wp_template_part_area' ); if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) { $template->area = $type_terms[0]->name; } } // Check for a block template without a description and title or with a title equal to the slug. - if ( 'wp_template' === $post->post_type && empty( $template->description ) && ( empty( $template->title ) || $template->title === $template->slug ) ) { + if ( 'wp_template' === $parent_post->post_type && empty( $template->description ) && ( empty( $template->title ) || $template->title === $template->slug ) ) { $matches = array(); // Check for a block template for a single author, page, post, tag, category, custom post type, or custom taxonomy. diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 00d9fdae3e26e..3a2e943ad5cfc 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -779,7 +779,9 @@ function make_before_block_visitor( $hooked_blocks, $context ) { * @return string The serialized markup for the given block, with the markup for any hooked blocks prepended to it. */ return function ( &$block, $parent_block = null, $prev = null ) use ( $hooked_blocks, $context ) { - _inject_theme_attribute_in_template_part_block( $block ); + if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { + _inject_theme_attribute_in_template_part_block( $block ); + } $markup = ''; @@ -1946,3 +1948,85 @@ function get_comments_pagination_arrow( $block, $pagination_type = 'next' ) { } return null; } + +/** + * Strips all HTML from the content of footnotes, and sanitizes the ID. + * This function expects slashed data on the footnotes content. + * + * @access private + * @since 6.3.2 + * + * @param string $footnotes JSON encoded string of an array containing the content and ID of each footnote. + * @return string Filtered content without any HTML on the footnote content and with the sanitized id. + */ +function _wp_filter_post_meta_footnotes( $footnotes ) { + $footnotes_decoded = json_decode( $footnotes, true ); + if ( ! is_array( $footnotes_decoded ) ) { + return ''; + } + $footnotes_sanitized = array(); + foreach ( $footnotes_decoded as $footnote ) { + if ( ! empty( $footnote['content'] ) && ! empty( $footnote['id'] ) ) { + $footnotes_sanitized[] = array( + 'id' => sanitize_key( $footnote['id'] ), + 'content' => wp_unslash( wp_filter_post_kses( wp_slash( $footnote['content'] ) ) ), + ); + } + } + return wp_json_encode( $footnotes_sanitized ); +} + +/** + * Adds the filters to filter footnotes meta field. + * + * @access private + * @since 6.3.2 + */ +function _wp_footnotes_kses_init_filters() { + add_filter( 'sanitize_post_meta_footnotes', '_wp_filter_post_meta_footnotes' ); +} + +/** + * Removes the filters that filter footnotes meta field. + * + * @access private + * @since 6.3.2 + */ +function _wp_footnotes_remove_filters() { + remove_filter( 'sanitize_post_meta_footnotes', '_wp_filter_post_meta_footnotes' ); +} + +/** + * Registers the filter of footnotes meta field if the user does not have unfiltered_html capability. + * + * @access private + * @since 6.3.2 + */ +function _wp_footnotes_kses_init() { + _wp_footnotes_remove_filters(); + if ( ! current_user_can( 'unfiltered_html' ) ) { + _wp_footnotes_kses_init_filters(); + } +} + +/** + * Initializes footnotes meta field filters when imported data should be filtered. + * + * This filter is the last being executed on force_filtered_html_on_import. + * If the input of the filter is true it means we are in an import situation and should + * enable kses, independently of the user capabilities. + * So in that case we call _wp_footnotes_kses_init_filters; + * + * @access private + * @since 6.3.2 + * + * @param string $arg Input argument of the filter. + * @return string Input argument of the filter. + */ +function _wp_footnotes_force_filtered_html_on_import_filter( $arg ) { + // force_filtered_html_on_import is true we need to init the global styles kses filters. + if ( $arg ) { + _wp_footnotes_kses_init_filters(); + } + return $arg; +} diff --git a/src/wp-includes/blocks/image.php b/src/wp-includes/blocks/image.php index bfc3af8754bc1..87e17a4c136b4 100644 --- a/src/wp-includes/blocks/image.php +++ b/src/wp-includes/blocks/image.php @@ -16,11 +16,13 @@ * @return string The block content with the data-id attribute added. */ function render_block_core_image( $attributes, $content, $block ) { + if ( false === stripos( $content, 'next_tag( 'img' ); - if ( $processor->get_attribute( 'src' ) === null ) { + if ( ! $processor->next_tag( 'img' ) || null === $processor->get_attribute( 'src' ) ) { return ''; } @@ -32,45 +34,47 @@ function render_block_core_image( $attributes, $content, $block ) { $processor->set_attribute( 'data-id', $attributes['data-id'] ); } - $lightbox_enabled = false; $link_destination = isset( $attributes['linkDestination'] ) ? $attributes['linkDestination'] : 'none'; $lightbox_settings = block_core_image_get_lightbox_settings( $block->parsed_block ); - // If the lightbox is enabled and the image is not linked, flag the lightbox to be rendered. - if ( isset( $lightbox_settings ) && 'none' === $link_destination ) { - - if ( isset( $lightbox_settings['enabled'] ) && true === $lightbox_settings['enabled'] ) { - $lightbox_enabled = true; - } - } + $view_js_file_handle = 'wp-block-image-view'; + $script_handles = $block->block_type->view_script_handles; - // If at least one block in the page has the lightbox, mark the block type as interactive. - if ( $lightbox_enabled ) { + /* + * If the lightbox is enabled and the image is not linked, add the filter + * and the JavaScript view file. + */ + if ( + isset( $lightbox_settings ) && + 'none' === $link_destination && + isset( $lightbox_settings['enabled'] ) && + true === $lightbox_settings['enabled'] + ) { $block->block_type->supports['interactivity'] = true; - } - - // Determine whether the view script should be enqueued or not. - $view_js_file = 'wp-block-image-view'; - 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 ( ! $lightbox_enabled && 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 ( $lightbox_enabled && ! in_array( $view_js_file, $script_handles, true ) ) { - $block->block_type->view_script_handles = array_merge( $script_handles, array( $view_js_file ) ); + 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 ) ); } - } - if ( $lightbox_enabled ) { - // 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. 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. + */ 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_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(); @@ -123,11 +127,28 @@ function block_core_image_get_lightbox_settings( $block ) { * @return string Filtered block content. */ function block_core_image_render_lightbox( $block_content, $block ) { + /* + * If it's not possible that an IMG element exists then return the given + * block content as-is. It may be that there's no actual image in the block + * or it could be that another plugin already modified this HTML. + */ + if ( false === stripos( $block_content, 'next_tag( 'img' ); + /* + * If there's definitely no IMG element in the block then return the given + * block content as-is. There's nothing that this code can knowingly modify + * to add the lightbox behavior. + */ + if ( ! $processor->next_tag( 'img' ) ) { + return $block_content; + } + $alt_attribute = $processor->get_attribute( 'alt' ); // An empty alt attribute `alt=""` is valid for decorative images. @@ -200,6 +221,7 @@ function block_core_image_render_lightbox( $block_content, $block ) { $w->set_attribute( 'data-wp-init', 'effects.core.image.setCurrentSrc' ); $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-effect--setStylesOnResize', 'effects.core.image.setStylesOnResize' ); $body_content = $w->get_updated_html(); // Wrap the image in the body content with a button. @@ -309,8 +331,6 @@ function block_core_image_render_lightbox( $block_content, $block ) { * @since 6.4.0 * * @global WP_Scripts $wp_scripts - * - * @return void */ function block_core_image_ensure_interactivity_dependency() { global $wp_scripts; @@ -326,8 +346,6 @@ function block_core_image_ensure_interactivity_dependency() { /** * Registers the `core/image` block on server. - * - * @return void */ function register_block_core_image() { register_block_type_from_metadata( diff --git a/src/wp-includes/blocks/image/view.asset.php b/src/wp-includes/blocks/image/view.asset.php index 855bdaa8c40b1..39e7e80313e40 100644 --- a/src/wp-includes/blocks/image/view.asset.php +++ b/src/wp-includes/blocks/image/view.asset.php @@ -1 +1 @@ - array(), 'version' => '21b886a7aa24f5c7c9ef'); + array(), 'version' => 'aaa9542ea1e8b0279ca6'); diff --git a/src/wp-includes/blocks/image/view.min.asset.php b/src/wp-includes/blocks/image/view.min.asset.php index a43c120c86c7e..51c4afc42de17 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' => '6e38467974481d14d2da'); + array(), 'version' => '658cda6fbef6b9d36ffd'); diff --git a/src/wp-includes/blocks/latest-posts.php b/src/wp-includes/blocks/latest-posts.php index d5f759c0c0e25..adc51d0c4fecb 100644 --- a/src/wp-includes/blocks/latest-posts.php +++ b/src/wp-includes/blocks/latest-posts.php @@ -152,10 +152,9 @@ function render_block_core_latest_posts( $attributes ) { if ( $excerpt_length <= $block_core_latest_posts_excerpt_length ) { $trimmed_excerpt = substr( $trimmed_excerpt, 0, -11 ); $trimmed_excerpt .= sprintf( - /* translators: 1: A URL to a post, 2: The static string "Read more", 3: The post title only visible to screen readers. */ - __( '… %2$s: %3$s' ), + /* translators: 1: A URL to a post, 2: Hidden accessibility text: Post title */ + __( '… Read more: %2$s' ), esc_url( $post_link ), - __( 'Read more' ), esc_html( $title ) ); } diff --git a/src/wp-includes/blocks/navigation.php b/src/wp-includes/blocks/navigation.php index a07235b601abb..c4854fbc4b26d 100644 --- a/src/wp-includes/blocks/navigation.php +++ b/src/wp-includes/blocks/navigation.php @@ -696,9 +696,22 @@ function render_block_core_navigation( $attributes, $content, $block ) { $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=\'{ "core": { "navigation": { "overlayOpenedBy": {}, "type": "overlay", "roleAttribute": "" } } }\' + data-wp-context=\'' . $nav_element_context . '\' '; $open_button_directives = ' data-wp-on--click="actions.core.navigation.openMenuOnClick" @@ -714,6 +727,7 @@ function render_block_core_navigation( $attributes, $content, $block ) { '; $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" '; @@ -723,11 +737,11 @@ function render_block_core_navigation( $attributes, $content, $block ) { } $responsive_container_markup = sprintf( - ' -
+ ' +
-
- +
+
%2$s
@@ -741,7 +755,6 @@ function render_block_core_navigation( $attributes, $content, $block ) { esc_attr( implode( ' ', $responsive_container_classes ) ), esc_attr( implode( ' ', $open_button_classes ) ), esc_attr( safecss_filter_attr( $colors['overlay_inline_styles'] ) ), - __( 'Menu' ), $toggle_button_content, $toggle_close_button_content, $open_button_directives, diff --git a/src/wp-includes/blocks/navigation/view.asset.php b/src/wp-includes/blocks/navigation/view.asset.php index 90eb5e0656d69..61200d5ae9b5a 100644 --- a/src/wp-includes/blocks/navigation/view.asset.php +++ b/src/wp-includes/blocks/navigation/view.asset.php @@ -1 +1 @@ - array(), 'version' => 'fa68a54f17d2cf6a40e0'); + array(), 'version' => '825c00b0743ccffd2242'); diff --git a/src/wp-includes/blocks/navigation/view.min.asset.php b/src/wp-includes/blocks/navigation/view.min.asset.php index 2d205a51af65d..ea614a4225fc4 100644 --- a/src/wp-includes/blocks/navigation/view.min.asset.php +++ b/src/wp-includes/blocks/navigation/view.min.asset.php @@ -1 +1 @@ - array(), 'version' => 'dde7635cad8b0819b900'); + array(), 'version' => 'a5ffa1bdbe6aee7a5c54'); diff --git a/src/wp-includes/blocks/pattern.php b/src/wp-includes/blocks/pattern.php index fc4652a7c22e8..f05bb333bd186 100644 --- a/src/wp-includes/blocks/pattern.php +++ b/src/wp-includes/blocks/pattern.php @@ -7,8 +7,6 @@ /** * Registers the `core/pattern` block on the server. - * - * @return void */ function register_block_core_pattern() { register_block_type_from_metadata( @@ -46,7 +44,6 @@ function render_block_core_pattern( $attributes ) { // Backward compatibility for handling Block Hooks and injecting the theme attribute in the Gutenberg plugin. // This can be removed when the minimum supported WordPress is >= 6.4. if ( defined( 'IS_GUTENBERG_PLUGIN' ) && IS_GUTENBERG_PLUGIN && ! function_exists( 'traverse_and_serialize_blocks' ) ) { - $content = _inject_theme_attribute_in_block_template_content( $content ); $blocks = parse_blocks( $content ); $content = gutenberg_serialize_blocks( $blocks ); } diff --git a/src/wp-includes/blocks/query.php b/src/wp-includes/blocks/query.php index c35bf2ba00af2..1b05e9c92c95e 100644 --- a/src/wp-includes/blocks/query.php +++ b/src/wp-includes/blocks/query.php @@ -34,7 +34,8 @@ function render_block_core_query( $attributes, $content, $block ) { 'loadedText' => __( 'Page Loaded.' ), ), ), - ) + ), + JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP ) ); $content = $p->get_updated_html(); diff --git a/src/wp-includes/blocks/search.php b/src/wp-includes/blocks/search.php index ed3d1cf4b847a..f00ecfe6abe1c 100644 --- a/src/wp-includes/blocks/search.php +++ b/src/wp-includes/blocks/search.php @@ -281,8 +281,6 @@ function classnames_for_block_core_search( $attributes ) { * @param array $wrapper_styles Current collection of wrapper styles. * @param array $button_styles Current collection of button styles. * @param array $input_styles Current collection of input styles. - * - * @return void */ function apply_block_core_search_border_style( $attributes, $property, $side, &$wrapper_styles, &$button_styles, &$input_styles ) { $is_button_inside = isset( $attributes['buttonPosition'] ) && 'button-inside' === $attributes['buttonPosition']; @@ -327,8 +325,6 @@ function apply_block_core_search_border_style( $attributes, $property, $side, &$ * @param array $wrapper_styles Current collection of wrapper styles. * @param array $button_styles Current collection of button styles. * @param array $input_styles Current collection of input styles. - * - * @return void */ function apply_block_core_search_border_styles( $attributes, $property, &$wrapper_styles, &$button_styles, &$input_styles ) { apply_block_core_search_border_style( $attributes, $property, null, $wrapper_styles, $button_styles, $input_styles ); diff --git a/src/wp-includes/blocks/template-part.php b/src/wp-includes/blocks/template-part.php index a7bd4033affc3..3ad400906945b 100644 --- a/src/wp-includes/blocks/template-part.php +++ b/src/wp-includes/blocks/template-part.php @@ -18,13 +18,10 @@ function render_block_core_template_part( $attributes ) { $template_part_id = null; $content = null; $area = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; + $theme = isset( $attributes['theme'] ) ? $attributes['theme'] : get_stylesheet(); - if ( - isset( $attributes['slug'] ) && - isset( $attributes['theme'] ) && - get_stylesheet() === $attributes['theme'] - ) { - $template_part_id = $attributes['theme'] . '//' . $attributes['slug']; + if ( isset( $attributes['slug'] ) && get_stylesheet() === $theme ) { + $template_part_id = $theme . '//' . $attributes['slug']; $template_part_query = new WP_Query( array( 'post_type' => 'wp_template_part', @@ -34,7 +31,7 @@ function render_block_core_template_part( $attributes ) { array( 'taxonomy' => 'wp_theme', 'field' => 'name', - 'terms' => $attributes['theme'], + 'terms' => $theme, ), ), 'posts_per_page' => 1, diff --git a/src/wp-includes/class-wp-block-patterns-registry.php b/src/wp-includes/class-wp-block-patterns-registry.php index d1ef2ad422a59..1c528abb3f92e 100644 --- a/src/wp-includes/class-wp-block-patterns-registry.php +++ b/src/wp-includes/class-wp-block-patterns-registry.php @@ -164,11 +164,16 @@ public function unregister( $pattern_name ) { */ private function prepare_content( $pattern, $hooked_blocks ) { $content = $pattern['content']; + + $before_block_visitor = ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ? '_inject_theme_attribute_in_template_part_block' : null; + $after_block_visitor = null; if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) { - $blocks = parse_blocks( $content ); $before_block_visitor = make_before_block_visitor( $hooked_blocks, $pattern ); $after_block_visitor = make_after_block_visitor( $hooked_blocks, $pattern ); - $content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor ); + } + if ( null !== $before_block_visitor || null !== $after_block_visitor ) { + $blocks = parse_blocks( $content ); + $content = traverse_and_serialize_blocks( $blocks, $before_block_visitor, $after_block_visitor ); } return $content; @@ -227,6 +232,21 @@ public function is_registered( $pattern_name ) { return isset( $this->registered_patterns[ $pattern_name ] ); } + public function __wakeup() { + if ( ! $this->registered_patterns ) { + return; + } + if ( ! is_array( $this->registered_patterns ) ) { + throw new UnexpectedValueException(); + } + foreach ( $this->registered_patterns as $value ) { + if ( ! is_array( $value ) ) { + throw new UnexpectedValueException(); + } + } + $this->registered_patterns_outside_init = array(); + } + /** * Utility method to retrieve the main instance of the class. * diff --git a/src/wp-includes/class-wp-block-type-registry.php b/src/wp-includes/class-wp-block-type-registry.php index 84adecd5d0774..49e7bd60aee61 100644 --- a/src/wp-includes/class-wp-block-type-registry.php +++ b/src/wp-includes/class-wp-block-type-registry.php @@ -168,6 +168,20 @@ public function is_registered( $name ) { return isset( $this->registered_block_types[ $name ] ); } + public function __wakeup() { + if ( ! $this->registered_block_types ) { + return; + } + if ( ! is_array( $this->registered_block_types ) ) { + throw new UnexpectedValueException(); + } + foreach ( $this->registered_block_types as $value ) { + if ( ! $value instanceof WP_Block_Type ) { + throw new UnexpectedValueException(); + } + } + } + /** * Utility method to retrieve the main instance of the class. * diff --git a/src/wp-includes/class-wp-http-requests-response.php b/src/wp-includes/class-wp-http-requests-response.php index 821077656c84b..8032c54d875a7 100644 --- a/src/wp-includes/class-wp-http-requests-response.php +++ b/src/wp-includes/class-wp-http-requests-response.php @@ -8,7 +8,7 @@ */ /** - * Core wrapper object for a WpOrg\Requests\Response for standardisation. + * Core wrapper object for a WpOrg\Requests\Response for standardization. * * @since 4.6.0 * diff --git a/src/wp-includes/class-wp-post-type.php b/src/wp-includes/class-wp-post-type.php index ce6d9d348b480..7a2769ed88327 100644 --- a/src/wp-includes/class-wp-post-type.php +++ b/src/wp-includes/class-wp-post-type.php @@ -396,6 +396,54 @@ final class WP_Post_Type { */ public $rest_controller; + /** + * The controller for this post type's revisions REST API endpoints. + * + * Custom controllers must extend WP_REST_Controller. + * + * @since 6.4.0 + * @var string|bool $revisions_rest_controller_class + */ + public $revisions_rest_controller_class; + + /** + * The controller instance for this post type's revisions REST API endpoints. + * + * Lazily computed. Should be accessed using {@see WP_Post_Type::get_revisions_rest_controller()}. + * + * @since 6.4.0 + * @var WP_REST_Controller $revisions_rest_controller + */ + public $revisions_rest_controller; + + /** + * The controller for this post type's autosave REST API endpoints. + * + * Custom controllers must extend WP_REST_Controller. + * + * @since 6.4.0 + * @var string|bool $autosave_rest_controller_class + */ + public $autosave_rest_controller_class; + + /** + * The controller instance for this post type's autosave REST API endpoints. + * + * Lazily computed. Should be accessed using {@see WP_Post_Type::get_autosave_rest_controller()}. + * + * @since 6.4.0 + * @var WP_REST_Controller $autosave_rest_controller + */ + public $autosave_rest_controller; + + /** + * A flag to register the post type REST API controller after its associated autosave / revisions controllers, instead of before. Registration order affects route matching priority. + * + * @since 6.4.0 + * @var bool $late_route_registration + */ + public $late_route_registration; + /** * Constructor. * @@ -455,6 +503,7 @@ public function set_props( $args ) { * - `register_page_post_type_args` * * @since 6.0.0 + * @since 6.4.0 Added `late_route_registration`, `autosave_rest_controller_class` and `revisions_rest_controller_class` arguments. * * @param array $args Array of arguments for registering a post type. * See the register_post_type() function for accepted arguments. @@ -466,37 +515,40 @@ public function set_props( $args ) { // Args prefixed with an underscore are reserved for internal use. $defaults = array( - 'labels' => array(), - 'description' => '', - 'public' => false, - 'hierarchical' => false, - 'exclude_from_search' => null, - 'publicly_queryable' => null, - 'show_ui' => null, - 'show_in_menu' => null, - 'show_in_nav_menus' => null, - 'show_in_admin_bar' => null, - 'menu_position' => null, - 'menu_icon' => null, - 'capability_type' => 'post', - 'capabilities' => array(), - 'map_meta_cap' => null, - 'supports' => array(), - 'register_meta_box_cb' => null, - 'taxonomies' => array(), - 'has_archive' => false, - 'rewrite' => true, - 'query_var' => true, - 'can_export' => true, - 'delete_with_user' => null, - 'show_in_rest' => false, - 'rest_base' => false, - 'rest_namespace' => false, - 'rest_controller_class' => false, - 'template' => array(), - 'template_lock' => false, - '_builtin' => false, - '_edit_link' => 'post.php?post=%d', + 'labels' => array(), + 'description' => '', + 'public' => false, + 'hierarchical' => false, + 'exclude_from_search' => null, + 'publicly_queryable' => null, + 'show_ui' => null, + 'show_in_menu' => null, + 'show_in_nav_menus' => null, + 'show_in_admin_bar' => null, + 'menu_position' => null, + 'menu_icon' => null, + 'capability_type' => 'post', + 'capabilities' => array(), + 'map_meta_cap' => null, + 'supports' => array(), + 'register_meta_box_cb' => null, + 'taxonomies' => array(), + 'has_archive' => false, + 'rewrite' => true, + 'query_var' => true, + 'can_export' => true, + 'delete_with_user' => null, + 'show_in_rest' => false, + 'rest_base' => false, + 'rest_namespace' => false, + 'rest_controller_class' => false, + 'autosave_rest_controller_class' => false, + 'revisions_rest_controller_class' => false, + 'late_route_registration' => false, + 'template' => array(), + 'template_lock' => false, + '_builtin' => false, + '_edit_link' => 'post.php?post=%d', ); $args = array_merge( $defaults, $args ); @@ -816,6 +868,85 @@ public function get_rest_controller() { return $this->rest_controller; } + /** + * Gets the REST API revisions controller for this post type. + * + * Will only instantiate the controller class once per request. + * + * @since 6.4.0 + * + * @return WP_REST_Controller|null The controller instance, or null if the post type + * is set not to show in rest. + */ + public function get_revisions_rest_controller() { + if ( ! $this->show_in_rest ) { + return null; + } + + if ( ! post_type_supports( $this->name, 'revisions' ) ) { + return null; + } + + $class = $this->revisions_rest_controller_class ? $this->revisions_rest_controller_class : WP_REST_Revisions_Controller::class; + if ( ! class_exists( $class ) ) { + return null; + } + + if ( ! is_subclass_of( $class, WP_REST_Controller::class ) ) { + return null; + } + + if ( ! $this->revisions_rest_controller ) { + $this->revisions_rest_controller = new $class( $this->name ); + } + + if ( ! ( $this->revisions_rest_controller instanceof $class ) ) { + return null; + } + + return $this->revisions_rest_controller; + } + + /** + * Gets the REST API autosave controller for this post type. + * + * Will only instantiate the controller class once per request. + * + * @since 6.4.0 + * + * @return WP_REST_Controller|null The controller instance, or null if the post type + * is set not to show in rest. + */ + public function get_autosave_rest_controller() { + if ( ! $this->show_in_rest ) { + return null; + } + + if ( 'attachment' === $this->name ) { + return null; + } + + $class = $this->autosave_rest_controller_class ? $this->autosave_rest_controller_class : WP_REST_Autosaves_Controller::class; + + if ( ! class_exists( $class ) ) { + return null; + } + + if ( ! is_subclass_of( $class, WP_REST_Controller::class ) ) { + return null; + } + + if ( ! $this->autosave_rest_controller ) { + $this->autosave_rest_controller = new $class( $this->name ); + } + + if ( ! ( $this->autosave_rest_controller instanceof $class ) ) { + return null; + } + + return $this->autosave_rest_controller; + } + /** * Returns the default labels for post types. * diff --git a/src/wp-includes/class-wp-query.php b/src/wp-includes/class-wp-query.php index a52b5a484e841..a9ed269d72244 100644 --- a/src/wp-includes/class-wp-query.php +++ b/src/wp-includes/class-wp-query.php @@ -2020,8 +2020,7 @@ public function get_posts() { } if ( isset( $q['page'] ) ) { - $q['page'] = trim( $q['page'], '/' ); - $q['page'] = absint( $q['page'] ); + $q['page'] = is_scalar( $q['page'] ) ? absint( trim( $q['page'], '/' ) ) : 0; } // If true, forcibly turns off SQL_CALC_FOUND_ROWS even when limits are present. @@ -3191,14 +3190,19 @@ public function get_posts() { return $this->posts; } elseif ( 'id=>parent' === $q['fields'] ) { - _prime_post_parents_caches( $post_ids ); + _prime_post_parent_id_caches( $post_ids ); + + $post_parent_cache_keys = array(); + foreach ( $post_ids as $post_id ) { + $post_parent_cache_keys[] = 'post_parent:' . (string) $post_id; + } /** @var int[] */ - $post_parents = wp_cache_get_multiple( $post_ids, 'post_parent' ); + $post_parents = wp_cache_get_multiple( $post_parent_cache_keys, 'posts' ); - foreach ( $post_parents as $id => $post_parent ) { + foreach ( $post_parents as $cache_key => $post_parent ) { $obj = new stdClass(); - $obj->ID = (int) $id; + $obj->ID = (int) str_replace( 'post_parent:', '', $cache_key ); $obj->post_parent = (int) $post_parent; $this->posts[] = $obj; @@ -3246,8 +3250,9 @@ public function get_posts() { $this->set_found_posts( $q, $limits ); /** @var int[] */ - $post_parents = array(); - $post_ids = array(); + $post_parents = array(); + $post_ids = array(); + $post_parents_cache = array(); foreach ( $this->posts as $key => $post ) { $this->posts[ $key ]->ID = (int) $post->ID; @@ -3255,9 +3260,11 @@ public function get_posts() { $post_parents[ (int) $post->ID ] = (int) $post->post_parent; $post_ids[] = (int) $post->ID; + + $post_parents_cache[ 'post_parent:' . (string) $post->ID ] = (int) $post->post_parent; } // Prime post parent caches, so that on second run, there is not another database query. - wp_cache_add_multiple( $post_parents, 'post_parent' ); + wp_cache_add_multiple( $post_parents_cache, 'posts' ); if ( $q['cache_results'] && $id_query_is_cacheable ) { $cache_value = array( diff --git a/src/wp-includes/class-wp-scripts.php b/src/wp-includes/class-wp-scripts.php index a6a283f953cb9..116e98f673bca 100644 --- a/src/wp-includes/class-wp-scripts.php +++ b/src/wp-includes/class-wp-scripts.php @@ -231,6 +231,25 @@ public function print_extra_script( $handle, $display = true ) { return true; } + /** + * Checks whether all dependents of a given handle are in the footer. + * + * If there are no dependents, this is considered the same as if all dependents were in the footer. + * + * @since 6.4.0 + * + * @param string $handle Script handle. + * @return bool Whether all dependents are in the footer. + */ + private function are_all_dependents_in_footer( $handle ) { + foreach ( $this->get_dependents( $handle ) as $dep ) { + if ( isset( $this->groups[ $dep ] ) && 0 === $this->groups[ $dep ] ) { + return false; + } + } + return true; + } + /** * Processes a script dependency. * @@ -281,6 +300,25 @@ public function do_item( $handle, $group = false ) { $intended_strategy = ''; } + /* + * Move this script to the footer if: + * 1. The script is in the header group. + * 2. The current output is the header. + * 3. The intended strategy is delayed. + * 4. The actual strategy is not delayed. + * 5. All dependent scripts are in the footer. + */ + if ( + 0 === $group && + 0 === $this->groups[ $handle ] && + $intended_strategy && + ! $this->is_delayed_strategy( $strategy ) && + $this->are_all_dependents_in_footer( $handle ) + ) { + $this->in_footer[] = $handle; + return false; + } + if ( $conditional ) { $cond_before = "\n"; diff --git a/src/wp-includes/class-wp-theme-json.php b/src/wp-includes/class-wp-theme-json.php index 4955fcc264a89..e5f174138de35 100644 --- a/src/wp-includes/class-wp-theme-json.php +++ b/src/wp-includes/class-wp-theme-json.php @@ -1146,9 +1146,23 @@ protected function process_blocks_custom_css( $css, $selector ) { // Split CSS nested rules. $parts = explode( '&', $css ); foreach ( $parts as $part ) { - $processed_css .= ( ! str_contains( $part, '{' ) ) - ? trim( $selector ) . '{' . trim( $part ) . '}' // If the part doesn't contain braces, it applies to the root level. - : trim( $selector . $part ); // Prepend the selector, which effectively replaces the "&" character. + $is_root_css = ( ! str_contains( $part, '{' ) ); + if ( $is_root_css ) { + // If the part doesn't contain braces, it applies to the root level. + $processed_css .= trim( $selector ) . '{' . trim( $part ) . '}'; + } else { + // If the part contains braces, it's a nested CSS rule. + $part = explode( '{', str_replace( '}', '', $part ) ); + if ( count( $part ) !== 2 ) { + continue; + } + $nested_selector = $part[0]; + $css_value = $part[1]; + $part_selector = str_starts_with( $nested_selector, ' ' ) + ? static::scope_selector( $selector, $nested_selector ) + : static::append_to_selector( $selector, $nested_selector ); + $processed_css .= $part_selector . '{' . trim( $css_value ) . '}'; + } } return $processed_css; } diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php index 89c4cb976ae92..40812c72bcb03 100644 --- a/src/wp-includes/class-wp-theme.php +++ b/src/wp-includes/class-wp-theme.php @@ -772,6 +772,28 @@ public function parent() { return isset( $this->parent ) ? $this->parent : false; } + /** + * Perform reinitialization tasks. + * + * Prevents a callback from being injected during unserialization of an object. + * + * @return void + */ + public function __wakeup() { + if ( $this->parent && ! $this->parent instanceof self ) { + throw new UnexpectedValueException(); + } + if ( $this->headers && ! is_array( $this->headers ) ) { + throw new UnexpectedValueException(); + } + foreach ( $this->headers as $value ) { + if ( ! is_string( $value ) ) { + throw new UnexpectedValueException(); + } + } + $this->headers_sanitized = array(); + } + /** * Adds theme data to cache. * @@ -1918,4 +1940,16 @@ private static function _name_sort( $a, $b ) { private static function _name_sort_i18n( $a, $b ) { return strnatcasecmp( $a->name_translated, $b->name_translated ); } + + private static function _check_headers_property_has_correct_type( $headers ) { + if ( ! is_array( $headers ) ) { + return false; + } + foreach ( $headers as $key => $value ) { + if ( ! is_string( $key ) || ! is_string( $value ) ) { + return false; + } + } + return true; + } } diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 4a7787761b18b..fa756427d1552 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -612,6 +612,15 @@ add_action( 'wp_head', 'wp_maybe_inline_styles', 1 ); // Run for styles enqueued in . add_action( 'wp_footer', 'wp_maybe_inline_styles', 1 ); // Run for late-loaded styles in the footer. +/* + * Block specific actions and filters. + */ + +// Footnotes Block. +add_action( 'init', '_wp_footnotes_kses_init' ); +add_action( 'set_current_user', '_wp_footnotes_kses_init' ); +add_filter( 'force_filtered_html_on_import', '_wp_footnotes_force_filtered_html_on_import_filter', 999 ); + /* * Disable "Post Attributes" for wp_navigation post type. The attributes are * also conditionally enabled when a site has custom templates. Block Theme @@ -707,7 +716,8 @@ add_filter( 'render_block_context', '_block_template_render_without_post_block_context' ); add_filter( 'pre_wp_unique_post_slug', 'wp_filter_wp_template_unique_post_slug', 10, 5 ); add_action( 'save_post_wp_template_part', 'wp_set_unique_slug_on_create_template_part' ); -add_action( 'wp_footer', 'the_block_template_skip_link' ); +add_action( 'wp_enqueue_scripts', 'wp_enqueue_block_template_skip_link' ); +add_action( 'wp_footer', 'the_block_template_skip_link' ); // Retained for backwards-compatibility. Unhooked by wp_enqueue_block_template_skip_link(). add_action( 'setup_theme', 'wp_enable_block_templates' ); add_action( 'wp_loaded', '_add_template_loader_filters' ); diff --git a/src/wp-includes/deprecated.php b/src/wp-includes/deprecated.php index 51d7490c87c25..e98cad915fd11 100644 --- a/src/wp-includes/deprecated.php +++ b/src/wp-includes/deprecated.php @@ -6124,3 +6124,112 @@ function _remove_theme_attribute_in_block_template_content( $template_content ) return $new_content; } + +/** + * Prints the skip-link script & styles. + * + * @since 5.8.0 + * @access private + * @deprecated 6.4.0 Use wp_enqueue_block_template_skip_link() instead. + * + * @global string $_wp_current_template_content + */ +function the_block_template_skip_link() { + _deprecated_function( __FUNCTION__, '6.4.0', 'wp_enqueue_block_template_skip_link()' ); + + global $_wp_current_template_content; + + // Early exit if not a block theme. + if ( ! current_theme_supports( 'block-templates' ) ) { + return; + } + + // Early exit if not a block template. + if ( ! $_wp_current_template_content ) { + return; + } + ?> + + + + + + diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index c383a8c58673e..078e3a2daab20 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -2607,6 +2607,7 @@ function gallery_shortcode( $attr ) { $attachments[ $val->ID ] = $_attachments[ $key ]; } } elseif ( ! empty( $atts['exclude'] ) ) { + $post_parent_id = $id; $attachments = get_children( array( 'post_parent' => $id, @@ -2619,6 +2620,7 @@ function gallery_shortcode( $attr ) { ) ); } else { + $post_parent_id = $id; $attachments = get_children( array( 'post_parent' => $id, @@ -2631,6 +2633,17 @@ function gallery_shortcode( $attr ) { ); } + if ( ! empty( $post_parent_id ) ) { + $post_parent = get_post( $post_parent_id ); + + // terminate the shortcode execution if user cannot read the post or password-protected + if ( + ( ! is_post_publicly_viewable( $post_parent->ID ) && ! current_user_can( 'read_post', $post_parent->ID ) ) + || post_password_required( $post_parent ) ) { + return ''; + } + } + if ( empty( $attachments ) ) { return ''; } @@ -2963,6 +2976,15 @@ function wp_playlist_shortcode( $attr ) { $attachments = get_children( $args ); } + if ( ! empty( $args['post_parent'] ) ) { + $post_parent = get_post( $id ); + + // terminate the shortcode execution if user cannot read the post or password-protected + if ( ! current_user_can( 'read_post', $post_parent->ID ) || post_password_required( $post_parent ) ) { + return ''; + } + } + if ( empty( $attachments ) ) { return ''; } diff --git a/src/wp-includes/option.php b/src/wp-includes/option.php index d2ffa675b1854..4df0b81458b68 100644 --- a/src/wp-includes/option.php +++ b/src/wp-includes/option.php @@ -2125,7 +2125,7 @@ function update_network_option( $network_id, $option, $value ) { wp_protect_special_option( $option ); - $old_value = get_network_option( $network_id, $option, false ); + $old_value = get_network_option( $network_id, $option ); /** * Filters a specific network option before its value is updated. @@ -2144,20 +2144,80 @@ function update_network_option( $network_id, $option, $value ) { */ $value = apply_filters( "pre_update_site_option_{$option}", $value, $old_value, $option, $network_id ); + /* + * To get the actual raw old value from the database, any existing pre filters need to be temporarily disabled. + * Immediately after getting the raw value, they are reinstated. + * The raw value is only used to determine whether a value is present in the database. It is not used anywhere + * else, and is not passed to any of the hooks either. + */ + global $wp_filter; + + /** This filter is documented in wp-includes/option.php */ + $default_value = apply_filters( "default_site_option_{$option}", false, $option, $network_id ); + + $has_site_filter = has_filter( "pre_site_option_{$option}" ); + $has_option_filter = has_filter( "pre_option_{$option}" ); + if ( $has_site_filter || $has_option_filter ) { + if ( $has_site_filter ) { + $old_ms_filters = $wp_filter[ "pre_site_option_{$option}" ]; + unset( $wp_filter[ "pre_site_option_{$option}" ] ); + } + + if ( $has_option_filter ) { + $old_single_site_filters = $wp_filter[ "pre_option_{$option}" ]; + unset( $wp_filter[ "pre_option_{$option}" ] ); + } + + if ( is_multisite() ) { + $raw_old_value = get_network_option( $network_id, $option ); + } else { + $raw_old_value = get_option( $option, $default_value ); + } + + if ( $has_site_filter ) { + $wp_filter[ "pre_site_option_{$option}" ] = $old_ms_filters; + } + if ( $has_option_filter ) { + $wp_filter[ "pre_option_{$option}" ] = $old_single_site_filters; + } + } else { + $raw_old_value = $old_value; + } + + if ( ! is_multisite() ) { + /** This filter is documented in wp-includes/option.php */ + $default_value = apply_filters( "default_option_{$option}", $default_value, $option, true ); + } + /* * If the new and old values are the same, no need to update. * - * Unserialized values will be adequate in most cases. If the unserialized - * data differs, the (maybe) serialized data is checked to avoid - * unnecessary database calls for otherwise identical object instances. + * An exception applies when no value is set in the database, i.e. the old value is the default. + * In that case, the new value should always be added as it may be intentional to store it rather than relying on the default. * - * See https://core.trac.wordpress.org/ticket/44956 + * See https://core.trac.wordpress.org/ticket/44956 and https://core.trac.wordpress.org/ticket/22192 and https://core.trac.wordpress.org/ticket/59360 */ - if ( $value === $old_value || maybe_serialize( $value ) === maybe_serialize( $old_value ) ) { + if ( + $value === $raw_old_value || + ( + false !== $raw_old_value && + /* + * Single site stores values in the `option_value` field, which cannot be set to NULL. + * This means a PHP `null` value will be cast to an empty string, which can be considered + * equal to values such as an empty string, or false when cast to string. + * + * However, Multisite stores values in the `meta_value` field, which can be set to NULL. + * As NULL is unique in the database, skip checking an old or new value of NULL + * against any other value. + */ + ( ! is_multisite() || ! ( null === $raw_old_value || null === $value ) ) && + _is_equal_database_value( $raw_old_value, $value ) + ) + ) { return false; } - if ( false === $old_value ) { + if ( $default_value === $raw_old_value ) { return add_network_option( $network_id, $option, $value ); } @@ -2843,7 +2903,10 @@ function unregister_setting( $option_group, $option_name, $deprecated = '' ) { $option_group = 'reading'; } - $pos = array_search( $option_name, (array) $new_allowed_options[ $option_group ], true ); + $pos = false; + if ( isset( $new_allowed_options[ $option_group ] ) ) { + $pos = array_search( $option_name, (array) $new_allowed_options[ $option_group ], true ); + } if ( false !== $pos ) { unset( $new_allowed_options[ $option_group ][ $pos ] ); diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 1f2c65e1580e4..edad5218fa6f0 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -346,7 +346,7 @@ function create_initial_post_types() { register_post_type( 'wp_template', array( - 'labels' => array( + 'labels' => array( 'name' => _x( 'Templates', 'post type general name' ), 'singular_name' => _x( 'Template', 'post type singular name' ), 'add_new' => __( 'Add New Template' ), @@ -366,19 +366,22 @@ function create_initial_post_types() { 'items_list_navigation' => __( 'Templates list navigation' ), 'items_list' => __( 'Templates list' ), ), - 'description' => __( 'Templates to include in your theme.' ), - 'public' => false, - '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ - '_edit_link' => $template_edit_link, /* internal use only. don't use this when registering your own post type. */ - 'has_archive' => false, - 'show_ui' => false, - 'show_in_menu' => false, - 'show_in_rest' => true, - 'rewrite' => false, - 'rest_base' => 'templates', - 'rest_controller_class' => 'WP_REST_Templates_Controller', - 'capability_type' => array( 'template', 'templates' ), - 'capabilities' => array( + 'description' => __( 'Templates to include in your theme.' ), + 'public' => false, + '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ + '_edit_link' => $template_edit_link, /* internal use only. don't use this when registering your own post type. */ + 'has_archive' => false, + 'show_ui' => false, + 'show_in_menu' => false, + 'show_in_rest' => true, + 'rewrite' => false, + 'rest_base' => 'templates', + 'rest_controller_class' => 'WP_REST_Templates_Controller', + 'autosave_rest_controller_class' => 'WP_REST_Template_Autosaves_Controller', + 'revisions_rest_controller_class' => 'WP_REST_Template_Revisions_Controller', + 'late_route_registration' => true, + 'capability_type' => array( 'template', 'templates' ), + 'capabilities' => array( 'create_posts' => 'edit_theme_options', 'delete_posts' => 'edit_theme_options', 'delete_others_posts' => 'edit_theme_options', @@ -392,8 +395,8 @@ function create_initial_post_types() { 'read' => 'edit_theme_options', 'read_private_posts' => 'edit_theme_options', ), - 'map_meta_cap' => true, - 'supports' => array( + 'map_meta_cap' => true, + 'supports' => array( 'title', 'slug', 'excerpt', @@ -407,7 +410,7 @@ function create_initial_post_types() { register_post_type( 'wp_template_part', array( - 'labels' => array( + 'labels' => array( 'name' => _x( 'Template Parts', 'post type general name' ), 'singular_name' => _x( 'Template Part', 'post type singular name' ), 'add_new' => __( 'Add New Template Part' ), @@ -427,19 +430,22 @@ function create_initial_post_types() { 'items_list_navigation' => __( 'Template parts list navigation' ), 'items_list' => __( 'Template parts list' ), ), - 'description' => __( 'Template parts to include in your templates.' ), - 'public' => false, - '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ - '_edit_link' => $template_edit_link, /* internal use only. don't use this when registering your own post type. */ - 'has_archive' => false, - 'show_ui' => false, - 'show_in_menu' => false, - 'show_in_rest' => true, - 'rewrite' => false, - 'rest_base' => 'template-parts', - 'rest_controller_class' => 'WP_REST_Templates_Controller', - 'map_meta_cap' => true, - 'capabilities' => array( + 'description' => __( 'Template parts to include in your templates.' ), + 'public' => false, + '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ + '_edit_link' => $template_edit_link, /* internal use only. don't use this when registering your own post type. */ + 'has_archive' => false, + 'show_ui' => false, + 'show_in_menu' => false, + 'show_in_rest' => true, + 'rewrite' => false, + 'rest_base' => 'template-parts', + 'rest_controller_class' => 'WP_REST_Templates_Controller', + 'autosave_rest_controller_class' => 'WP_REST_Template_Autosaves_Controller', + 'revisions_rest_controller_class' => 'WP_REST_Template_Revisions_Controller', + 'late_route_registration' => true, + 'map_meta_cap' => true, + 'capabilities' => array( 'create_posts' => 'edit_theme_options', 'delete_posts' => 'edit_theme_options', 'delete_others_posts' => 'edit_theme_options', @@ -453,7 +459,7 @@ function create_initial_post_types() { 'read' => 'edit_theme_options', 'read_private_posts' => 'edit_theme_options', ), - 'supports' => array( + 'supports' => array( 'title', 'slug', 'excerpt', @@ -1575,85 +1581,88 @@ function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) * @param array|string $args { * Array or string of arguments for registering a post type. * - * @type string $label Name of the post type shown in the menu. Usually plural. - * Default is value of $labels['name']. - * @type string[] $labels An array of labels for this post type. If not set, post - * labels are inherited for non-hierarchical types and page - * labels for hierarchical ones. See get_post_type_labels() for a full - * list of supported labels. - * @type string $description A short descriptive summary of what the post type is. - * Default empty. - * @type bool $public Whether a post type is intended for use publicly either via - * the admin interface or by front-end users. While the default - * settings of $exclude_from_search, $publicly_queryable, $show_ui, - * and $show_in_nav_menus are inherited from $public, each does not - * rely on this relationship and controls a very specific intention. - * Default false. - * @type bool $hierarchical Whether the post type is hierarchical (e.g. page). Default false. - * @type bool $exclude_from_search Whether to exclude posts with this post type from front end search - * results. Default is the opposite value of $public. - * @type bool $publicly_queryable Whether queries can be performed on the front end for the post type - * as part of parse_request(). Endpoints would include: - * * ?post_type={post_type_key} - * * ?{post_type_key}={single_post_slug} - * * ?{post_type_query_var}={single_post_slug} - * If not set, the default is inherited from $public. - * @type bool $show_ui Whether to generate and allow a UI for managing this post type in the - * admin. Default is value of $public. - * @type bool|string $show_in_menu Where to show the post type in the admin menu. To work, $show_ui - * must be true. If true, the post type is shown in its own top level - * menu. If false, no menu is shown. If a string of an existing top - * level menu ('tools.php' or 'edit.php?post_type=page', for example), the - * post type will be placed as a sub-menu of that. - * Default is value of $show_ui. - * @type bool $show_in_nav_menus Makes this post type available for selection in navigation menus. - * Default is value of $public. - * @type bool $show_in_admin_bar Makes this post type available via the admin bar. Default is value - * of $show_in_menu. - * @type bool $show_in_rest Whether to include the post type in the REST API. Set this to true - * for the post type to be available in the block editor. - * @type string $rest_base To change the base URL of REST API route. Default is $post_type. - * @type string $rest_namespace To change the namespace URL of REST API route. Default is wp/v2. - * @type string $rest_controller_class REST API controller class name. Default is 'WP_REST_Posts_Controller'. - * @type int $menu_position The position in the menu order the post type should appear. To work, - * $show_in_menu must be true. Default null (at the bottom). - * @type string $menu_icon The URL to the icon to be used for this menu. Pass a base64-encoded - * SVG using a data URI, which will be colored to match the color scheme - * -- this should begin with 'data:image/svg+xml;base64,'. Pass the name - * of a Dashicons helper class to use a font icon, e.g. - * 'dashicons-chart-pie'. Pass 'none' to leave div.wp-menu-image empty - * so an icon can be added via CSS. Defaults to use the posts icon. - * @type string|array $capability_type The string to use to build the read, edit, and delete capabilities. - * May be passed as an array to allow for alternative plurals when using - * this argument as a base to construct the capabilities, e.g. - * array('story', 'stories'). Default 'post'. - * @type string[] $capabilities Array of capabilities for this post type. $capability_type is used - * as a base to construct capabilities by default. - * See get_post_type_capabilities(). - * @type bool $map_meta_cap Whether to use the internal default meta capability handling. - * Default false. - * @type array $supports Core feature(s) the post type supports. Serves as an alias for calling - * add_post_type_support() directly. Core features include 'title', - * 'editor', 'comments', 'revisions', 'trackbacks', 'author', 'excerpt', - * 'page-attributes', 'thumbnail', 'custom-fields', and 'post-formats'. - * Additionally, the 'revisions' feature dictates whether the post type - * will store revisions, and the 'comments' feature dictates whether the - * comments count will show on the edit screen. A feature can also be - * specified as an array of arguments to provide additional information - * about supporting that feature. - * Example: `array( 'my_feature', array( 'field' => 'value' ) )`. - * Default is an array containing 'title' and 'editor'. - * @type callable $register_meta_box_cb Provide a callback function that sets up the meta boxes for the - * edit form. Do remove_meta_box() and add_meta_box() calls in the - * callback. Default null. - * @type string[] $taxonomies An array of taxonomy identifiers that will be registered for the - * post type. Taxonomies can be registered later with register_taxonomy() - * or register_taxonomy_for_object_type(). - * Default empty array. - * @type bool|string $has_archive Whether there should be post type archives, or if a string, the - * archive slug to use. Will generate the proper rewrite rules if - * $rewrite is enabled. Default false. - * @type bool|array $rewrite { + * @type string $label Name of the post type shown in the menu. Usually plural. + * Default is value of $labels['name']. + * @type string[] $labels An array of labels for this post type. If not set, post + * labels are inherited for non-hierarchical types and page + * labels for hierarchical ones. See get_post_type_labels() for a full + * list of supported labels. + * @type string $description A short descriptive summary of what the post type is. + * Default empty. + * @type bool $public Whether a post type is intended for use publicly either via + * the admin interface or by front-end users. While the default + * settings of $exclude_from_search, $publicly_queryable, $show_ui, + * and $show_in_nav_menus are inherited from $public, each does not + * rely on this relationship and controls a very specific intention. + * Default false. + * @type bool $hierarchical Whether the post type is hierarchical (e.g. page). Default false. + * @type bool $exclude_from_search Whether to exclude posts with this post type from front end search + * results. Default is the opposite value of $public. + * @type bool $publicly_queryable Whether queries can be performed on the front end for the post type + * as part of parse_request(). Endpoints would include: + * * ?post_type={post_type_key} + * * ?{post_type_key}={single_post_slug} + * * ?{post_type_query_var}={single_post_slug} + * If not set, the default is inherited from $public. + * @type bool $show_ui Whether to generate and allow a UI for managing this post type in the + * admin. Default is value of $public. + * @type bool|string $show_in_menu Where to show the post type in the admin menu. To work, $show_ui + * must be true. If true, the post type is shown in its own top level + * menu. If false, no menu is shown. If a string of an existing top + * level menu ('tools.php' or 'edit.php?post_type=page', for example), the + * post type will be placed as a sub-menu of that. + * Default is value of $show_ui. + * @type bool $show_in_nav_menus Makes this post type available for selection in navigation menus. + * Default is value of $public. + * @type bool $show_in_admin_bar Makes this post type available via the admin bar. Default is value + * of $show_in_menu. + * @type bool $show_in_rest Whether to include the post type in the REST API. Set this to true + * for the post type to be available in the block editor. + * @type string $rest_base To change the base URL of REST API route. Default is $post_type. + * @type string $rest_namespace To change the namespace URL of REST API route. Default is wp/v2. + * @type string $rest_controller_class REST API controller class name. Default is 'WP_REST_Posts_Controller'. + * @type string|bool $autosave_rest_controller_class REST API controller class name. Default is 'WP_REST_Autosaves_Controller'. + * @type string|bool $revisions_rest_controller_class REST API controller class name. Default is 'WP_REST_Revisions_Controller'. + * @type bool $late_route_registration A flag to direct the REST API controllers for autosave / revisions should be registered before/after the post type controller. + * @type int $menu_position The position in the menu order the post type should appear. To work, + * $show_in_menu must be true. Default null (at the bottom). + * @type string $menu_icon The URL to the icon to be used for this menu. Pass a base64-encoded + * SVG using a data URI, which will be colored to match the color scheme + * -- this should begin with 'data:image/svg+xml;base64,'. Pass the name + * of a Dashicons helper class to use a font icon, e.g. + * 'dashicons-chart-pie'. Pass 'none' to leave div.wp-menu-image empty + * so an icon can be added via CSS. Defaults to use the posts icon. + * @type string|array $capability_type The string to use to build the read, edit, and delete capabilities. + * May be passed as an array to allow for alternative plurals when using + * this argument as a base to construct the capabilities, e.g. + * array('story', 'stories'). Default 'post'. + * @type string[] $capabilities Array of capabilities for this post type. $capability_type is used + * as a base to construct capabilities by default. + * See get_post_type_capabilities(). + * @type bool $map_meta_cap Whether to use the internal default meta capability handling. + * Default false. + * @type array $supports Core feature(s) the post type supports. Serves as an alias for calling + * add_post_type_support() directly. Core features include 'title', + * 'editor', 'comments', 'revisions', 'trackbacks', 'author', 'excerpt', + * 'page-attributes', 'thumbnail', 'custom-fields', and 'post-formats'. + * Additionally, the 'revisions' feature dictates whether the post type + * will store revisions, and the 'comments' feature dictates whether the + * comments count will show on the edit screen. A feature can also be + * specified as an array of arguments to provide additional information + * about supporting that feature. + * Example: `array( 'my_feature', array( 'field' => 'value' ) )`. + * Default is an array containing 'title' and 'editor'. + * @type callable $register_meta_box_cb Provide a callback function that sets up the meta boxes for the + * edit form. Do remove_meta_box() and add_meta_box() calls in the + * callback. Default null. + * @type string[] $taxonomies An array of taxonomy identifiers that will be registered for the + * post type. Taxonomies can be registered later with register_taxonomy() + * or register_taxonomy_for_object_type(). + * Default empty array. + * @type bool|string $has_archive Whether there should be post type archives, or if a string, the + * archive slug to use. Will generate the proper rewrite rules if + * $rewrite is enabled. Default false. + * @type bool|array $rewrite { * Triggers the handling of rewrites for this post type. To prevent rewrite, set to false. * Defaults to true, using $post_type as slug. To specify rewrite rules, an array can be * passed with any of these keys: @@ -1668,32 +1677,32 @@ function get_post_types( $args = array(), $output = 'names', $operator = 'and' ) * inherits from $permalink_epmask. If not specified and permalink_epmask * is not set, defaults to EP_PERMALINK. * } - * @type string|bool $query_var Sets the query_var key for this post type. Defaults to $post_type - * key. If false, a post type cannot be loaded at - * ?{query_var}={post_slug}. If specified as a string, the query - * ?{query_var_string}={post_slug} will be valid. - * @type bool $can_export Whether to allow this post type to be exported. Default true. - * @type bool $delete_with_user Whether to delete posts of this type when deleting a user. - * * If true, posts of this type belonging to the user will be moved - * to Trash when the user is deleted. - * * If false, posts of this type belonging to the user will *not* - * be trashed or deleted. - * * If not set (the default), posts are trashed if post type supports - * the 'author' feature. Otherwise posts are not trashed or deleted. - * Default null. - * @type array $template Array of blocks to use as the default initial state for an editor - * session. Each item should be an array containing block name and - * optional attributes. Default empty array. - * @type string|false $template_lock Whether the block template should be locked if $template is set. - * * If set to 'all', the user is unable to insert new blocks, - * move existing blocks and delete blocks. - * * If set to 'insert', the user is able to move existing blocks - * but is unable to insert new blocks and delete blocks. - * Default false. - * @type bool $_builtin FOR INTERNAL USE ONLY! True if this post type is a native or - * "built-in" post_type. Default false. - * @type string $_edit_link FOR INTERNAL USE ONLY! URL segment to use for edit link of - * this post type. Default 'post.php?post=%d'. + * @type string|bool $query_var Sets the query_var key for this post type. Defaults to $post_type + * key. If false, a post type cannot be loaded at + * ?{query_var}={post_slug}. If specified as a string, the query + * ?{query_var_string}={post_slug} will be valid. + * @type bool $can_export Whether to allow this post type to be exported. Default true. + * @type bool $delete_with_user Whether to delete posts of this type when deleting a user. + * * If true, posts of this type belonging to the user will be moved + * to Trash when the user is deleted. + * * If false, posts of this type belonging to the user will *not* + * be trashed or deleted. + * * If not set (the default), posts are trashed if post type supports + * the 'author' feature. Otherwise posts are not trashed or deleted. + * Default null. + * @type array $template Array of blocks to use as the default initial state for an editor + * session. Each item should be an array containing block name and + * optional attributes. Default empty array. + * @type string|false $template_lock Whether the block template should be locked if $template is set. + * * If set to 'all', the user is unable to insert new blocks, + * move existing blocks and delete blocks. + * * If set to 'insert', the user is able to move existing blocks + * but is unable to insert new blocks and delete blocks. + * Default false. + * @type bool $_builtin FOR INTERNAL USE ONLY! True if this post type is a native or + * "built-in" post_type. Default false. + * @type string $_edit_link FOR INTERNAL USE ONLY! URL segment to use for edit link of + * this post type. Default 'post.php?post=%d'. * } * @return WP_Post_Type|WP_Error The registered post type object on success, * WP_Error object on failure. @@ -7261,8 +7270,8 @@ function clean_post_cache( $post ) { } wp_cache_delete( $post->ID, 'posts' ); + wp_cache_delete( 'post_parent:' . (string) $post->ID, 'posts' ); wp_cache_delete( $post->ID, 'post_meta' ); - wp_cache_delete( $post->ID, 'post_parent' ); clean_object_term_cache( $post->ID, $post->post_type ); @@ -7797,7 +7806,7 @@ function _prime_post_caches( $ids, $update_term_cache = true, $update_meta_cache } /** - * Prime post parent caches. + * Prime the cache containing the parent ID of various post objects. * * @global wpdb $wpdb WordPress database abstraction object. * @@ -7805,20 +7814,40 @@ function _prime_post_caches( $ids, $update_term_cache = true, $update_meta_cache * * @param int[] $ids ID list. */ -function _prime_post_parents_caches( array $ids ) { +function _prime_post_parent_id_caches( array $ids ) { global $wpdb; - $non_cached_ids = _get_non_cached_ids( $ids, 'post_parent' ); + $ids = array_filter( $ids, '_validate_cache_id' ); + $ids = array_unique( array_map( 'intval', $ids ), SORT_NUMERIC ); + + if ( empty( $ids ) ) { + return; + } + + $cache_keys = array(); + foreach ( $ids as $id ) { + $cache_keys[ $id ] = 'post_parent:' . (string) $id; + } + + $cached_data = wp_cache_get_multiple( array_values( $cache_keys ), 'posts' ); + + $non_cached_ids = array(); + foreach ( $cache_keys as $id => $cache_key ) { + if ( false === $cached_data[ $cache_key ] ) { + $non_cached_ids[] = $id; + } + } + if ( ! empty( $non_cached_ids ) ) { $fresh_posts = $wpdb->get_results( sprintf( "SELECT $wpdb->posts.ID, $wpdb->posts.post_parent FROM $wpdb->posts WHERE ID IN (%s)", implode( ',', $non_cached_ids ) ) ); if ( $fresh_posts ) { $post_parent_data = array(); foreach ( $fresh_posts as $fresh_post ) { - $post_parent_data[ (int) $fresh_post->ID ] = (int) $fresh_post->post_parent; + $post_parent_data[ 'post_parent:' . (string) $fresh_post->ID ] = (int) $fresh_post->post_parent; } - wp_cache_add_multiple( $post_parent_data, 'post_parent' ); + wp_cache_add_multiple( $post_parent_data, 'posts' ); } } } diff --git a/src/wp-includes/rest-api.php b/src/wp-includes/rest-api.php index 71539b084c26d..61e324e801445 100644 --- a/src/wp-includes/rest-api.php +++ b/src/wp-includes/rest-api.php @@ -241,17 +241,23 @@ function create_initial_rest_routes() { continue; } - $controller->register_routes(); + if ( ! $post_type->late_route_registration ) { + $controller->register_routes(); + } - if ( post_type_supports( $post_type->name, 'revisions' ) ) { - $revisions_controller = new WP_REST_Revisions_Controller( $post_type->name ); + $revisions_controller = $post_type->get_revisions_rest_controller(); + if ( $revisions_controller ) { $revisions_controller->register_routes(); } - if ( 'attachment' !== $post_type->name ) { - $autosaves_controller = new WP_REST_Autosaves_Controller( $post_type->name ); + $autosaves_controller = $post_type->get_autosave_rest_controller(); + if ( $autosaves_controller ) { $autosaves_controller->register_routes(); } + + if ( $post_type->late_route_registration ) { + $controller->register_routes(); + } } // Post types. @@ -1084,6 +1090,7 @@ function rest_cookie_check_errors( $result ) { $result = wp_verify_nonce( $nonce, 'wp_rest' ); if ( ! $result ) { + add_filter( 'rest_send_nocache_headers', '__return_true', 20 ); return new WP_Error( 'rest_cookie_invalid_nonce', __( 'Cookie check failed' ), array( 'status' => 403 ) ); } 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 ae7f0ee67e0f2..fdc3034755981 100644 --- a/src/wp-includes/rest-api/class-wp-rest-server.php +++ b/src/wp-includes/rest-api/class-wp-rest-server.php @@ -322,24 +322,6 @@ public function serve_request( $path = null ) { */ $this->send_header( 'X-Content-Type-Options', 'nosniff' ); - /** - * Filters whether to send nocache headers on a REST API request. - * - * @since 4.4.0 - * - * @param bool $rest_send_nocache_headers Whether to send no-cache headers. - */ - $send_no_cache_headers = apply_filters( 'rest_send_nocache_headers', is_user_logged_in() ); - if ( $send_no_cache_headers ) { - foreach ( wp_get_nocache_headers() as $header => $header_value ) { - if ( empty( $header_value ) ) { - $this->remove_header( $header ); - } else { - $this->send_header( $header, $header_value ); - } - } - } - /** * Filters whether the REST API is enabled. * @@ -394,10 +376,12 @@ public function serve_request( $path = null ) { * $_GET['_method']. If that is not set, we check for the HTTP_X_HTTP_METHOD_OVERRIDE * header. */ + $method_overridden = false; if ( isset( $_GET['_method'] ) ) { $request->set_method( $_GET['_method'] ); } elseif ( isset( $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ) ) { $request->set_method( $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] ); + $method_overridden = true; } $expose_headers = array( 'X-WP-Total', 'X-WP-TotalPages', 'Link' ); @@ -498,6 +482,28 @@ public function serve_request( $path = null ) { */ $served = apply_filters( 'rest_pre_serve_request', false, $result, $request, $this ); + /** + * Filters whether to send nocache headers on a REST API request. + * + * @since 4.4.0 + * @since 6.3.2 Moved the block to catch the filter added on rest_cookie_check_errors() from rest-api.php + * + * @param bool $rest_send_nocache_headers Whether to send no-cache headers. + */ + $send_no_cache_headers = apply_filters( 'rest_send_nocache_headers', is_user_logged_in() ); + + // send no cache headers if the $send_no_cache_headers is true + // OR if the HTTP_X_HTTP_METHOD_OVERRIDE is used but resulted a 4x response code. + if ( $send_no_cache_headers || ( true === $method_overridden && strpos( $code, '4' ) === 0 ) ) { + foreach ( wp_get_nocache_headers() as $header => $header_value ) { + if ( empty( $header_value ) ) { + $this->remove_header( $header ); + } else { + $this->send_header( $header, $header_value ); + } + } + } + if ( ! $served ) { if ( 'HEAD' === $request->get_method() ) { return null; diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php index d14119133aff3..5545625df4609 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php @@ -65,8 +65,13 @@ public function __construct( $parent_post_type ) { $parent_controller = new WP_REST_Posts_Controller( $parent_post_type ); } - $this->parent_controller = $parent_controller; - $this->revisions_controller = new WP_REST_Revisions_Controller( $parent_post_type ); + $this->parent_controller = $parent_controller; + + $revisions_controller = $post_type_object->get_revisions_rest_controller(); + if ( ! $revisions_controller ) { + $revisions_controller = new WP_REST_Revisions_Controller( $parent_post_type ); + } + $this->revisions_controller = $revisions_controller; $this->rest_base = 'autosaves'; $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; @@ -205,11 +210,11 @@ public function create_item_permissions_check( $request ) { */ public function create_item( $request ) { - if ( ! defined( 'DOING_AUTOSAVE' ) ) { + if ( ! defined( 'WP_RUN_CORE_TESTS' ) && ! defined( 'DOING_AUTOSAVE' ) ) { define( 'DOING_AUTOSAVE', true ); } - $post = get_post( $request['id'] ); + $post = $this->get_parent( $request['id'] ); if ( is_wp_error( $post ) ) { return $post; diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php new file mode 100644 index 0000000000000..c996894a5933c --- /dev/null +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php @@ -0,0 +1,276 @@ +parent_post_type = $parent_post_type; + $post_type_object = get_post_type_object( $parent_post_type ); + $parent_controller = $post_type_object->get_rest_controller(); + + if ( ! $parent_controller ) { + $parent_controller = new WP_REST_Templates_Controller( $parent_post_type ); + } + + $this->parent_controller = $parent_controller; + + $revisions_controller = $post_type_object->get_revisions_rest_controller(); + if ( ! $revisions_controller ) { + $revisions_controller = new WP_REST_Revisions_Controller( $parent_post_type ); + } + $this->revisions_controller = $revisions_controller; + $this->rest_base = 'autosaves'; + $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; + $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; + } + + /** + * Registers the routes for autosaves. + * + * @since 6.4.0 + * + * @see register_rest_route() + */ + public function register_routes() { + register_rest_route( + $this->namespace, + sprintf( + '/%s/(?P%s%s)/%s', + $this->parent_base, + /* + * Matches theme's directory: `/themes///` or `/themes//`. + * Excludes invalid directory name characters: `/:<>*?"|`. + */ + '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', + // Matches the template name. + '[\/\w%-]+', + $this->rest_base + ), + array( + 'args' => array( + 'id' => array( + 'description' => __( 'The id of a template' ), + 'type' => 'string', + 'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ), + ), + ), + 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->parent_controller->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + + register_rest_route( + $this->namespace, + sprintf( + '/%s/(?P%s%s)/%s/%s', + $this->parent_base, + /* + * Matches theme's directory: `/themes///` or `/themes//`. + * Excludes invalid directory name characters: `/:<>*?"|`. + */ + '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', + // Matches the template name. + '[\/\w%-]+', + $this->rest_base, + '(?P[\d]+)' + ), + array( + 'args' => array( + 'parent' => array( + 'description' => __( 'The id of a template' ), + 'type' => 'string', + 'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ), + ), + 'id' => array( + 'description' => __( 'The ID for the autosave.' ), + 'type' => 'integer', + ), + ), + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this->revisions_controller, 'get_item_permissions_check' ), + 'args' => array( + 'context' => $this->get_context_param( array( 'default' => 'view' ) ), + ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + } + + /** + * Prepares the item for the REST response. + * + * @since 6.4.0 + * + * @param WP_Post $item Post revision object. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response Response object. + */ + public function prepare_item_for_response( $item, $request ) { + $template = _build_block_template_result_from_post( $item ); + $response = $this->parent_controller->prepare_item_for_response( $template, $request ); + + $fields = $this->get_fields_for_response( $request ); + $data = $response->get_data(); + + if ( in_array( 'parent', $fields, true ) ) { + $data['parent'] = (int) $item->post_parent; + } + + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + $data = $this->filter_response_by_context( $data, $context ); + + // Wrap the data in a response object. + $response = new WP_REST_Response( $data ); + + if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { + $links = $this->prepare_links( $template ); + $response->add_links( $links ); + } + + return $response; + } + + /** + * Gets the autosave, if the ID is valid. + * + * @since 6.4.0 + * + * @param WP_REST_Request $request Full details about the request. + * @return WP_Post|WP_Error Autosave post object if ID is valid, WP_Error otherwise. + */ + public function get_item( $request ) { + $parent = $this->get_parent( $request['parent'] ); + if ( is_wp_error( $parent ) ) { + return $parent; + } + + $autosave = wp_get_post_autosave( $parent->ID ); + + if ( ! $autosave ) { + return new WP_Error( + 'rest_post_no_autosave', + __( 'There is no autosave revision for this template.' ), + array( 'status' => 404 ) + ); + } + + $response = $this->prepare_item_for_response( $autosave, $request ); + return $response; + } + + /** + * Get the parent post. + * + * @since 6.4.0 + * + * @param int $parent_id Supplied ID. + * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. + */ + protected function get_parent( $parent_id ) { + return $this->revisions_controller->get_parent( $parent_id ); + } + + /** + * Prepares links for the request. + * + * @since 6.4.0 + * + * @param WP_Block_Template $template Template. + * @return array Links for the given post. + */ + protected function prepare_links( $template ) { + $links = array( + 'self' => array( + 'href' => rest_url( sprintf( '/%s/%s/%s/%s/%d', $this->namespace, $this->parent_base, $template->id, $this->rest_base, $template->wp_id ) ), + ), + 'parent' => array( + 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->parent_base, $template->id ) ), + ), + ); + + return $links; + } + + /** + * Retrieves the autosave's schema, conforming to JSON Schema. + * + * @since 6.4.0 + * + * @return array Item schema data. + */ + public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + + $this->schema = $this->revisions_controller->get_item_schema(); + + return $this->add_additional_fields_schema( $this->schema ); + } +} diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php new file mode 100644 index 0000000000000..8d32ecb7c0904 --- /dev/null +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php @@ -0,0 +1,297 @@ +parent_post_type = $parent_post_type; + $post_type_object = get_post_type_object( $parent_post_type ); + $parent_controller = $post_type_object->get_rest_controller(); + + if ( ! $parent_controller ) { + $parent_controller = new WP_REST_Templates_Controller( $parent_post_type ); + } + + $this->parent_controller = $parent_controller; + $this->rest_base = 'revisions'; + $this->parent_base = ! empty( $post_type_object->rest_base ) ? $post_type_object->rest_base : $post_type_object->name; + $this->namespace = ! empty( $post_type_object->rest_namespace ) ? $post_type_object->rest_namespace : 'wp/v2'; + } + + /** + * Registers the routes for revisions based on post types supporting revisions. + * + * @since 6.4.0 + * + * @see register_rest_route() + */ + public function register_routes() { + + register_rest_route( + $this->namespace, + sprintf( + '/%s/(?P%s%s)/%s', + $this->parent_base, + /* + * Matches theme's directory: `/themes///` or `/themes//`. + * Excludes invalid directory name characters: `/:<>*?"|`. + */ + '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', + // Matches the template name. + '[\/\w%-]+', + $this->rest_base + ), + array( + 'args' => array( + 'parent' => array( + 'description' => __( 'The id of a template' ), + 'type' => 'string', + 'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ), + ), + ), + 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, + sprintf( + '/%s/(?P%s%s)/%s/%s', + $this->parent_base, + /* + * Matches theme's directory: `/themes///` or `/themes//`. + * Excludes invalid directory name characters: `/:<>*?"|`. + */ + '([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', + // Matches the template name. + '[\/\w%-]+', + $this->rest_base, + '(?P[\d]+)' + ), + array( + 'args' => array( + 'parent' => array( + 'description' => __( 'The id of a template' ), + 'type' => 'string', + 'sanitize_callback' => array( $this->parent_controller, '_sanitize_template_id' ), + ), + 'id' => array( + 'description' => __( 'Unique identifier for the 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' ) ), + ), + ), + 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' => __( 'Required to be true, as revisions do not support trashing.' ), + ), + ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + } + + /** + * Gets the parent post, if the ID is valid. + * + * @since 6.4.0 + * + * @param int $parent_post_id Supplied ID. + * @return WP_Post|WP_Error Post object if ID is valid, WP_Error otherwise. + */ + protected function get_parent( $parent_post_id ) { + $template = get_block_template( $parent_post_id, $this->parent_post_type ); + + if ( ! $template ) { + return new WP_Error( + 'rest_post_invalid_parent', + __( 'Invalid template parent ID.' ), + array( 'status' => 404 ) + ); + } + + return get_post( $template->wp_id ); + } + + /** + * Prepares the item for the REST response. + * + * @since 6.4.0 + * + * @param WP_Post $item Post revision object. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response Response object. + */ + public function prepare_item_for_response( $item, $request ) { + $template = _build_block_template_result_from_post( $item ); + $response = $this->parent_controller->prepare_item_for_response( $template, $request ); + + $fields = $this->get_fields_for_response( $request ); + $data = $response->get_data(); + + if ( in_array( 'parent', $fields, true ) ) { + $data['parent'] = (int) $item->post_parent; + } + + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + $data = $this->filter_response_by_context( $data, $context ); + + // Wrap the data in a response object. + $response = new WP_REST_Response( $data ); + + if ( rest_is_field_included( '_links', $fields ) || rest_is_field_included( '_embedded', $fields ) ) { + $links = $this->prepare_links( $template ); + $response->add_links( $links ); + } + + return $response; + } + + /** + * Checks if a given request has access to delete a revision. + * + * @since 6.4.0 + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has access to delete the item, WP_Error object otherwise. + */ + public function delete_item_permissions_check( $request ) { + $parent = $this->get_parent( $request['parent'] ); + if ( is_wp_error( $parent ) ) { + return $parent; + } + + if ( ! current_user_can( 'delete_post', $parent->ID ) ) { + return new WP_Error( + 'rest_cannot_delete', + __( 'Sorry, you are not allowed to delete revisions of this post.' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + $revision = $this->get_revision( $request['id'] ); + if ( is_wp_error( $revision ) ) { + return $revision; + } + + if ( ! current_user_can( 'edit_theme_options' ) ) { + return new WP_Error( + 'rest_cannot_delete', + __( 'Sorry, you are not allowed to delete this revision.' ), + array( 'status' => rest_authorization_required_code() ) + ); + } + + return true; + } + + /** + * Prepares links for the request. + * + * @since 6.4.0 + * + * @param WP_Block_Template $template Template. + * @return array Links for the given post. + */ + protected function prepare_links( $template ) { + $links = array( + 'self' => array( + 'href' => rest_url( sprintf( '/%s/%s/%s/%s/%d', $this->namespace, $this->parent_base, $template->id, $this->rest_base, $template->wp_id ) ), + ), + 'parent' => array( + 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->parent_base, $template->id ) ), + ), + ); + + return $links; + } + + /** + * Retrieves the item's schema, conforming to JSON Schema. + * + * @since 6.4.0 + * + * @return array Item schema data. + */ + public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + + $schema = $this->parent_controller->get_item_schema(); + + $schema['properties']['parent'] = array( + 'description' => __( 'The ID for the parent of the revision.' ), + 'type' => 'integer', + 'context' => array( 'view', 'edit', 'embed' ), + ); + + $this->schema = $schema; + + return $this->add_additional_fields_schema( $this->schema ); + } +} 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 e9904ff234912..53f8faa75595b 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 @@ -760,7 +760,7 @@ public function prepare_item_for_response( $item, $request ) { protected function prepare_links( $id ) { $links = array( 'self' => array( - 'href' => rest_url( rest_get_route_for_post( $id ) ), + 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $id ) ), ), 'collection' => array( 'href' => rest_url( rest_get_route_for_post_type_items( $this->post_type ) ), @@ -770,6 +770,27 @@ protected function prepare_links( $id ) { ), ); + if ( post_type_supports( $this->post_type, 'revisions' ) ) { + $template = get_block_template( $id, $this->post_type ); + if ( $template instanceof WP_Block_Template && ! empty( $template->wp_id ) ) { + $revisions = wp_get_latest_revision_id_and_total_count( $template->wp_id ); + $revisions_count = ! is_wp_error( $revisions ) ? $revisions['count'] : 0; + $revisions_base = sprintf( '/%s/%s/%s/revisions', $this->namespace, $this->rest_base, $id ); + + $links['version-history'] = array( + 'href' => rest_url( $revisions_base ), + 'count' => $revisions_count, + ); + + if ( $revisions_count > 0 ) { + $links['predecessor-version'] = array( + 'href' => rest_url( $revisions_base . '/' . $revisions['latest_id'] ), + 'id' => $revisions['latest_id'], + ); + } + } + } + return $links; } diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php index ce358ffc6701d..9b3847063163e 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php @@ -318,6 +318,9 @@ public function get_items( $request ) { } if ( ! empty( $prepared_args['search'] ) ) { + if ( ! current_user_can( 'list_users' ) ) { + $prepared_args['search_columns'] = array( 'ID', 'user_login', 'user_nicename', 'display_name' ); + } $prepared_args['search'] = '*' . $prepared_args['search'] . '*'; } /** diff --git a/src/wp-includes/shortcodes.php b/src/wp-includes/shortcodes.php index 538b6e79daca0..24df21d4da11e 100644 --- a/src/wp-includes/shortcodes.php +++ b/src/wp-includes/shortcodes.php @@ -168,6 +168,44 @@ function has_shortcode( $content, $tag ) { return false; } +/** + * Returns a list of registered shortcode names found in the given content. + * + * Example usage: + * + * get_shortcode_tags_in_content( '[audio src="file.mp3"][/audio] [foo] [gallery ids="1,2,3"]' ); + * // array( 'audio', 'gallery' ) + * + * @since 6.3.2 + * + * @param string $content The content to check. + * @return string[] An array of registered shortcode names found in the content. + */ +function get_shortcode_tags_in_content( $content ) { + if ( false === strpos( $content, '[' ) ) { + return array(); + } + + preg_match_all( '/' . get_shortcode_regex() . '/', $content, $matches, PREG_SET_ORDER ); + if ( empty( $matches ) ) { + return array(); + } + + $tags = array(); + foreach ( $matches as $shortcode ) { + $tags[] = $shortcode[2]; + + if ( ! empty( $shortcode[5] ) ) { + $deep_tags = get_shortcode_tags_in_content( $shortcode[5] ); + if ( ! empty( $deep_tags ) ) { + $tags = array_merge( $tags, $deep_tags ); + } + } + } + + return $tags; +} + /** * Searches content for shortcodes and filter shortcodes through their hooks. * diff --git a/src/wp-includes/theme-templates.php b/src/wp-includes/theme-templates.php index cc4b19ecce5bc..c01a4ec6721e8 100644 --- a/src/wp-includes/theme-templates.php +++ b/src/wp-includes/theme-templates.php @@ -99,16 +99,22 @@ function wp_filter_wp_template_unique_post_slug( $override_slug, $slug, $post_id } /** - * Prints the skip-link script & styles. + * Enqueues the skip-link script & styles. * * @access private - * @since 5.8.0 + * @since 6.4.0 * * @global string $_wp_current_template_content */ -function the_block_template_skip_link() { +function wp_enqueue_block_template_skip_link() { global $_wp_current_template_content; + // Back-compat for plugins that disable functionality by unhooking this action. + if ( ! has_action( 'wp_footer', 'the_block_template_skip_link' ) ) { + return; + } + remove_action( 'wp_footer', 'the_block_template_skip_link' ); + // Early exit if not a block theme. if ( ! current_theme_supports( 'block-templates' ) ) { return; @@ -207,7 +213,7 @@ function the_block_template_skip_link() { true ) ); wp_add_inline_script( $script_handle, $skip_link_script ); wp_enqueue_script( $script_handle ); } diff --git a/src/wp-includes/version.php b/src/wp-includes/version.php index c55a294362b1a..ecbc04ea0e819 100644 --- a/src/wp-includes/version.php +++ b/src/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.4-beta2-56769-src'; +$wp_version = '6.4-beta4-56923-src'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. diff --git a/src/wp-settings.php b/src/wp-settings.php index 5b1e1205d2719..38b03ecf7268f 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -273,7 +273,9 @@ require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-types-controller.php'; require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-post-statuses-controller.php'; require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-revisions-controller.php'; +require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-template-revisions-controller.php'; require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-autosaves-controller.php'; +require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php'; require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-taxonomies-controller.php'; require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-terms-controller.php'; require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-menu-items-controller.php'; diff --git a/tests/e2e/README.md b/tests/e2e/README.md index fffb5e6fc4a82..23eb8016710af 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -1 +1 @@ -# E2E Tests End-To-End (E2E) tests for WordPress. ## Running the tests The e2e tests require a production-like environment to run. By default, they will assume an environment is available at `http://localhost:8889`, with username=admin and password=password. If you don't already have an environment ready, you can set one up by following [these instructions](https://github.com/WordPress/wordpress-develop/blob/master/README.md). Then you can launch the tests by running: ``` npm run test:e2e ``` which will run the test suite using a headless browser. If your environment has a different url, username or password to the default, you can provide the base URL, username and password like this: ``` npm run test:e2e -- --wordpress-base-url=http://mycustomurl --wordpress-username=username --wordpress-password=password ``` **DO NOT run these tests in an actual production environment, as they will delete all your content.** For debugging purposes, you might want to follow the test visually. You can do so by running the tests in an interactive mode. ``` npm run test:e2e -- --puppeteer-interactive ``` You can also run a single test file separately: ``` npm run test:e2e tests/e2e/specs/hello.test.js ``` ## Documentation * Block Editor Handbook end to end testing overview: https://developer.wordpress.org/block-editor/contributors/code/testing-overview/#end-to-end-testing * Gutenberg e2e-test-utils package API docs: https://github.com/WordPress/gutenberg/tree/trunk/packages/e2e-test-utils * Puppeteer API docs: https://github.com/puppeteer/puppeteer#readme (the version we are using is indicated in the @wordpress/scripts package: https://github.com/WordPress/gutenberg/blob/trunk/packages/scripts/package.json) \ No newline at end of file +# E2E Tests End-To-End (E2E) tests for WordPress. ## Running the tests The e2e tests require a production-like environment to run. By default, they will assume an environment is available at `http://localhost:8889`, with username `admin` and password `password`. If you don't already have an environment ready, you can set one up by following [these instructions](https://github.com/WordPress/wordpress-develop/blob/master/README.md). Then you can launch the tests by running: ``` npm run test:e2e ``` which will run the test suite using a headless browser. If your environment has a different url, username or password to the default, you can provide the base URL, username and password like this: ``` WP_BASE_URL=http://mycustomurl WP_USERNAME=username WP_PASSWORD=password npm run test:e2e ``` **DO NOT run these tests in an actual production environment, as they will delete all your content.** For debugging purposes, you might want to follow the test visually. You can do so by running the tests in an interactive mode: ``` npm run test:e2e -- --ui ``` [UI Mode](https://playwright.dev/docs/test-ui-mode) let's you explore, run and debug tests with a time travel experience complete with watch mode. All test files are loaded into the testing sidebar where you can expand each file and describe block to individually run, view, watch and debug each test. You can also run a single test file separately: ``` npm run test:e2e tests/e2e/specs/hello.test.js ``` ## Documentation * Block Editor Handbook end to end testing overview: https://developer.wordpress.org/block-editor/contributors/code/testing-overview/#end-to-end-testing * Gutenberg e2e-test-utils-playwright package API docs: https://github.com/WordPress/gutenberg/tree/trunk/packages/e2e-test-utils-playwright * Playwright API docs: https://playwright.dev/docs (the version we are using is indicated in the `@wordpress/scripts` package: https://github.com/WordPress/gutenberg/blob/trunk/packages/scripts/package.json) \ No newline at end of file diff --git a/tests/e2e/config/bootstrap.js b/tests/e2e/config/bootstrap.js deleted file mode 100644 index a9642034f5fad..0000000000000 --- a/tests/e2e/config/bootstrap.js +++ /dev/null @@ -1,145 +0,0 @@ -import { get } from 'lodash'; -import { - clearLocalStorage, - enablePageDialogAccept, - setBrowserViewport, -} from '@wordpress/e2e-test-utils'; - -/** - * Environment variables - */ -const { PUPPETEER_TIMEOUT } = process.env; - -/** - * Set of console logging types observed to protect against unexpected yet - * handled (i.e. not catastrophic) errors or warnings. Each key corresponds - * to the Puppeteer ConsoleMessage type, its value the corresponding function - * on the console global object. - * - * @type {Object} - */ -const OBSERVED_CONSOLE_MESSAGE_TYPES = { - warning: 'warn', - error: 'error', -}; - -/** - * Array of page event tuples of [ eventName, handler ]. - * - * @type {Array} - */ -const pageEvents = []; - -// The Jest timeout is increased because these tests are a bit slow -jest.setTimeout( PUPPETEER_TIMEOUT || 100000 ); - - -/** - * Adds an event listener to the page to handle additions of page event - * handlers, to assure that they are removed at test teardown. - */ -function capturePageEventsForTearDown() { - page.on( 'newListener', ( eventName, listener ) => { - pageEvents.push( [ eventName, listener ] ); - } ); -} - -/** - * Removes all bound page event handlers. - */ -function removePageEvents() { - pageEvents.forEach( ( [ eventName, handler ] ) => { - page.removeListener( eventName, handler ); - } ); -} - -/** - * Adds a page event handler to emit uncaught exception to process if one of - * the observed console logging types is encountered. - */ -function observeConsoleLogging() { - page.on( 'console', ( message ) => { - const type = message.type(); - if ( ! OBSERVED_CONSOLE_MESSAGE_TYPES.hasOwnProperty( type ) ) { - return; - } - - let text = message.text(); - - // An exception is made for _blanket_ deprecation warnings: Those - // which log regardless of whether a deprecated feature is in use. - if ( text.includes( 'This is a global warning' ) ) { - return; - } - - // An exception is made for jQuery migrate console warnings output by - // the unminified script loaded in development environments. - if ( text.includes( 'JQMIGRATE' ) ) { - return; - } - - // Viewing posts on the front end can result in this error, which - // has nothing to do with Gutenberg. - if ( text.includes( 'net::ERR_UNKNOWN_URL_SCHEME' ) ) { - return; - } - - // A bug present in WordPress 5.2 will produce console warnings when - // loading the Dashicons font. These can be safely ignored, as they do - // not otherwise regress on application behavior. This logic should be - // removed once the associated ticket has been closed. - // - // See: https://core.trac.wordpress.org/ticket/47183 - if ( - text.startsWith( 'Failed to decode downloaded font:' ) || - text.startsWith( 'OTS parsing error:' ) - ) { - return; - } - - const logFunction = OBSERVED_CONSOLE_MESSAGE_TYPES[ type ]; - - // As of Puppeteer 1.6.1, `message.text()` wrongly returns an object of - // type JSHandle for error logging, instead of the expected string. - // - // See: https://github.com/GoogleChrome/puppeteer/issues/3397 - // - // The recommendation there to asynchronously resolve the error value - // upon a console event may be prone to a race condition with the test - // completion, leaving a possibility of an error not being surfaced - // correctly. Instead, the logic here synchronously inspects the - // internal object shape of the JSHandle to find the error text. If it - // cannot be found, the default text value is used instead. - text = get( message.args(), [ 0, '_remoteObject', 'description' ], text ); - - // Disable reason: We intentionally bubble up the console message - // which, unless the test explicitly anticipates the logging via - // @wordpress/jest-console matchers, will cause the intended test - // failure. - - // eslint-disable-next-line no-console - console[ logFunction ]( text ); - } ); -} - -// Before every test suite run, delete all content created by the test. This ensures -// other posts/comments/etc. aren't dirtying tests and tests don't depend on -// each other's side-effects. -beforeAll( async () => { - capturePageEventsForTearDown(); - enablePageDialogAccept(); - observeConsoleLogging(); - await page.emulateMediaFeatures( [ - { name: 'prefers-reduced-motion', value: 'reduce' }, - ] ); - await setBrowserViewport( 'large' ); -} ); - -afterEach( async () => { - await clearLocalStorage(); - await setBrowserViewport( 'large' ); -} ); - -afterAll( () => { - removePageEvents(); -} ); diff --git a/tests/e2e/config/global-setup.js b/tests/e2e/config/global-setup.js new file mode 100644 index 0000000000000..0c8063cf1a5a5 --- /dev/null +++ b/tests/e2e/config/global-setup.js @@ -0,0 +1,43 @@ +/** + * External dependencies + */ +import { request } from '@playwright/test'; + +/** + * WordPress dependencies + */ +import { RequestUtils } from '@wordpress/e2e-test-utils-playwright'; + +/** + * + * @param {import('@playwright/test').FullConfig} config + * @returns {Promise} + */ +async function globalSetup( config ) { + const { storageState, baseURL } = config.projects[ 0 ].use; + const storageStatePath = + typeof storageState === 'string' ? storageState : undefined; + + const requestContext = await request.newContext( { + baseURL, + } ); + + const requestUtils = new RequestUtils( requestContext, { + storageStatePath, + } ); + + // Authenticate and save the storageState to disk. + await requestUtils.setupRest(); + + // Reset the test environment before running the tests. + await Promise.all( [ + requestUtils.activateTheme( 'twentytwentyone' ), + requestUtils.deleteAllPosts(), + requestUtils.deleteAllBlocks(), + requestUtils.resetPreferences(), + ] ); + + await requestContext.dispose(); +} + +export default globalSetup; diff --git a/tests/e2e/jest.config.js b/tests/e2e/jest.config.js deleted file mode 100644 index c0b5ca35e1945..0000000000000 --- a/tests/e2e/jest.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const config = require( '@wordpress/scripts/config/jest-e2e.config' ); - -const jestE2EConfig = { - ...config, - setupFilesAfterEnv: [ - '/config/bootstrap.js', - ], -}; - -module.exports = jestE2EConfig; diff --git a/tests/e2e/playwright.config.js b/tests/e2e/playwright.config.js new file mode 100644 index 0000000000000..0de694e324c24 --- /dev/null +++ b/tests/e2e/playwright.config.js @@ -0,0 +1,27 @@ +/** + * External dependencies + */ +import path from 'node:path'; +import { defineConfig } from '@playwright/test'; + +/** + * WordPress dependencies + */ +const baseConfig = require( '@wordpress/scripts/config/playwright.config' ); + +process.env.WP_ARTIFACTS_PATH ??= path.join( process.cwd(), 'artifacts' ); +process.env.STORAGE_STATE_PATH ??= path.join( + process.env.WP_ARTIFACTS_PATH, + 'storage-states/admin.json' +); + +const config = defineConfig( { + ...baseConfig, + globalSetup: require.resolve( './config/global-setup.js' ), + webServer: { + ...baseConfig.webServer, + command: 'npm run env:start', + }, +} ); + +export default config; diff --git a/tests/e2e/run-tests.js b/tests/e2e/run-tests.js deleted file mode 100644 index d52a56f221a56..0000000000000 --- a/tests/e2e/run-tests.js +++ /dev/null @@ -1,13 +0,0 @@ -const dotenv = require( 'dotenv' ); -const dotenv_expand = require( 'dotenv-expand' ); -const { execSync } = require( 'child_process' ); - -// WP_BASE_URL interpolates LOCAL_PORT, so needs to be parsed by dotenv_expand(). -dotenv_expand.expand( dotenv.config() ); - -// Run the tests, passing additional arguments through to the test script. -execSync( - 'wp-scripts test-e2e --config tests/e2e/jest.config.js ' + - process.argv.slice( 2 ).join( ' ' ), - { stdio: 'inherit' } -); diff --git a/tests/e2e/specs/cache-control-headers-directives.test.js b/tests/e2e/specs/cache-control-headers-directives.test.js index f451e251721a6..427188915098a 100644 --- a/tests/e2e/specs/cache-control-headers-directives.test.js +++ b/tests/e2e/specs/cache-control-headers-directives.test.js @@ -1,38 +1,46 @@ -import { - visitAdminPage, - createNewPost, - publishPost, - trashAllPosts, - createURL, - logout, -} from "@wordpress/e2e-test-utils"; - -describe( 'Cache Control header directives', () => { - - beforeEach( async () => { - await trashAllPosts(); - } ); - - it( 'No private directive present in cache control when user not logged in.', async () => { - await createNewPost( { title: 'Hello World' } ); - await publishPost(); - await logout(); - - const response = await page.goto( createURL( '/hello-world/' ) ); +/** + * WordPress dependencies + */ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; + +test.describe( 'Cache Control header directives', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.deleteAllPosts(); + }); + + test( + 'No private directive present in cache control when user not logged in.', + async ( { browser, admin, editor} + ) => { + await admin.createNewPost( { title: 'Hello World' } ); + await editor.publishPost(); + + await admin.visitAdminPage( '/' ); + + // Create a new incognito browser context to simulate logged-out state. + const context = await browser.newContext(); + const loggedOutPage = await context.newPage(); + + const response = await loggedOutPage.goto( '/hello-world/' ); const responseHeaders = response.headers(); + // Dispose context once it's no longer needed. + await context.close(); + expect( responseHeaders ).toEqual( expect.not.objectContaining( { "cache-control": "no-store" } ) ); expect( responseHeaders ).toEqual( expect.not.objectContaining( { "cache-control": "private" } ) ); } ); - it( 'Private directive header present in cache control when logged in.', async () => { - await visitAdminPage( '/' ); + test( + 'Private directive header present in cache control when logged in.', + async ( { page, admin } + ) => { + await admin.visitAdminPage( '/' ); - const response = await page.goto( createURL( '/wp-admin' ) ); + const response = await page.goto( '/wp-admin' ); const responseHeaders = response.headers(); expect( responseHeaders[ 'cache-control' ] ).toContain( 'no-store' ); expect( responseHeaders[ 'cache-control' ] ).toContain( 'private' ); } ); - } ); diff --git a/tests/e2e/specs/dashboard.test.js b/tests/e2e/specs/dashboard.test.js index 21da4dba0b97c..90459ac83ae6f 100644 --- a/tests/e2e/specs/dashboard.test.js +++ b/tests/e2e/specs/dashboard.test.js @@ -1,25 +1,28 @@ -import { - pressKeyTimes, - trashAllPosts, - visitAdminPage, -} from '@wordpress/e2e-test-utils'; - -describe( 'Quick Draft', () => { - beforeEach( async () => { - await trashAllPosts(); +/** + * WordPress dependencies + */ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; + +test.describe( 'Quick Draft', () => { + test.beforeEach( async ({ requestUtils }) => { + await requestUtils.deleteAllPosts(); } ); - it( 'Allows draft to be created with Title and Content', async () => { - await visitAdminPage( '/' ); + test( 'Allows draft to be created with Title and Content', async ( { + admin, + page + } ) => { + await admin.visitAdminPage( '/' ); - // Wait for Quick Draft title field to appear and focus it - const draftTitleField = await page.waitForSelector( - '#quick-press #title' - ); - await draftTitleField.focus(); + // Wait for Quick Draft title field to appear. + const draftTitleField = page.locator( + '#quick-press' + ).getByRole( 'textbox', { name: 'Title' } ); - // Type in a title. - await page.keyboard.type( 'Test Draft Title' ); + await expect( draftTitleField ).toBeVisible(); + + // Focus and fill in a title. + await draftTitleField.fill( 'Test Draft Title' ); // Navigate to content field and type in some content await page.keyboard.press( 'Tab' ); @@ -30,47 +33,42 @@ describe( 'Quick Draft', () => { await page.keyboard.press( 'Enter' ); // Check that new draft appears in Your Recent Drafts section - const newDraft = await page.waitForSelector( '.drafts .draft-title' ); - - expect( - await newDraft.evaluate( ( element ) => element.innerText ) - ).toContain( 'Test Draft Title' ); + await expect( + page.locator( '.drafts .draft-title' ).first().getByRole( 'link' ) + ).toHaveText( 'Test Draft Title' ); // Check that new draft appears in Posts page - await visitAdminPage( '/edit.php' ); - const postsListDraft = await page.waitForSelector( - '.type-post.status-draft .title' - ); - - expect( - await postsListDraft.evaluate( ( element ) => element.innerText ) - ).toContain( 'Test Draft Title' ); + await admin.visitAdminPage( '/edit.php' ); + + await expect( + page.locator( '.type-post.status-draft .title' ).first() + ).toContainText( 'Test Draft Title' ); } ); - it( 'Allows draft to be created without Title or Content', async () => { - await visitAdminPage( '/' ); + test( 'Allows draft to be created without Title or Content', async ( { + admin, + page + } ) => { + await admin.visitAdminPage( '/' ); // Wait for Save Draft button to appear and click it - const saveDraftButton = await page.waitForSelector( - '#quick-press #save-post' - ); + const saveDraftButton = page.locator( + '#quick-press' + ).getByRole( 'button', { name: 'Save Draft' } ); + + await expect( saveDraftButton ).toBeVisible(); await saveDraftButton.click(); // Check that new draft appears in Your Recent Drafts section - const newDraft = await page.waitForSelector( '.drafts .draft-title a' ); - - expect( - await newDraft.evaluate( ( element ) => element.innerText ) - ).toContain( '(no title)' ); + await expect( + page.locator( '.drafts .draft-title' ).first().getByRole( 'link' ) + ).toHaveText( 'Untitled' ); // Check that new draft appears in Posts page - await visitAdminPage( '/edit.php' ); - const postsListDraft = await page.waitForSelector( - '.type-post.status-draft .title a' - ); - - expect( - await postsListDraft.evaluate( ( element ) => element.innerText ) - ).toContain( '(no title)' ); + await admin.visitAdminPage( '/edit.php' ); + + await expect( + page.locator( '.type-post.status-draft .title' ).first() + ).toContainText( 'Untitled' ); } ); } ); diff --git a/tests/e2e/specs/edit-posts.test.js b/tests/e2e/specs/edit-posts.test.js index 5c07019f4d1e6..0e2eb3687f778 100644 --- a/tests/e2e/specs/edit-posts.test.js +++ b/tests/e2e/specs/edit-posts.test.js @@ -1,137 +1,135 @@ -import { - createNewPost, - pressKeyTimes, - publishPost, - trashAllPosts, - visitAdminPage, -} from '@wordpress/e2e-test-utils'; - -describe( 'Edit Posts', () => { - beforeEach( async () => { - await trashAllPosts(); +/** + * WordPress dependencies + */ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; + +test.describe( 'Edit Posts', () => { + test.beforeEach( async ( { requestUtils }) => { + await requestUtils.deleteAllPosts(); } ); - it( 'displays a message in the posts table when no posts are present', async () => { - await visitAdminPage( '/edit.php' ); - const noPostsMessage = await page.$x( - '//td[text()="No posts found."]' - ); - expect( noPostsMessage.length ).toBe( 1 ); + test( 'displays a message in the posts table when no posts are present',async ( { + admin, + page, + } ) => { + await admin.visitAdminPage( '/edit.php' ); + await expect( + page.getByRole( 'cell', { name: 'No posts found.' } ) + ).toBeVisible(); } ); - it( 'shows a single post after one is published with the correct title', async () => { + test( 'shows a single post after one is published with the correct title',async ( { + admin, + editor, + page, + } ) => { const title = 'Test Title'; - await createNewPost( { title } ); - await publishPost(); - await visitAdminPage( '/edit.php' ); + await admin.createNewPost( { title } ); + await editor.publishPost(); + await admin.visitAdminPage( '/edit.php' ); - await page.waitForSelector( '#the-list .type-post' ); + const listTable = page.getByRole( 'table', { name: 'Table ordered by' } ); + await expect( listTable ).toBeVisible(); // Expect there to be one row in the post list. - const posts = await page.$$( '#the-list .type-post' ); - expect( posts.length ).toBe( 1 ); - - const [ firstPost ] = posts; + const posts = listTable.locator( '.row-title' ); + await expect( posts ).toHaveCount( 1 ); // Expect the title of the post to be correct. - const postTitle = await firstPost.$x( - `//a[contains(@class, "row-title")][contains(text(), "${ title }")]` - ); - expect( postTitle.length ).toBe( 1 ); + expect( posts.first() ).toHaveText( title ); } ); - it( 'allows an existing post to be edited using the Edit button', async () => { + test( 'allows an existing post to be edited using the Edit button', async ( { + admin, + editor, + page, + } ) => { const title = 'Test Title'; - await createNewPost( { title } ); - await publishPost(); - await visitAdminPage( '/edit.php' ); + await admin.createNewPost( { title } ); + await editor.publishPost(); + await admin.visitAdminPage( '/edit.php' ); - await page.waitForSelector( '#the-list .type-post' ); + const listTable = page.getByRole( 'table', { name: 'Table ordered by' } ); + await expect( listTable ).toBeVisible(); // Click the post title (edit) link - const [ editLink ] = await page.$x( - `//a[contains(@class, "row-title")][contains(text(), "${ title }")]` - ); - await editLink.click(); + await listTable.getByRole( 'link', { name: `“${ title }” (Edit)` } ).click(); // Wait for the editor iframe to load, and switch to it as the active content frame. - const editorFrame = await page.waitForSelector( 'iframe[name="editor-canvas"]' ); - - const innerFrame = await editorFrame.contentFrame(); + await page + .frameLocator( '[name=editor-canvas]' ) + .locator( 'body > *' ) + .first() + .waitFor(); - // Wait for title field to render onscreen. - await innerFrame.waitForSelector( '.editor-post-title__input' ); + const editorPostTitle = editor.canvas.getByRole( 'textbox', { name: 'Add title' } ); - // Expect to now be in the editor with the correct post title shown. - const editorPostTitleInput = await innerFrame.$x( - `//h1[contains(@class, "editor-post-title__input")][contains(text(), "${ title }")]` - ); - expect( editorPostTitleInput.length ).toBe( 1 ); + // Expect title field to be in the editor with correct title shown. + await expect( editorPostTitle ).toBeVisible(); + await expect( editorPostTitle ).toHaveText( title ); } ); - it( 'allows an existing post to be quick edited using the Quick Edit button', async () => { + test( 'allows an existing post to be quick edited using the Quick Edit button', async ( { + admin, + editor, + page, + pageUtils + } ) => { const title = 'Test Title'; - await createNewPost( { title } ); - await publishPost(); - await visitAdminPage( '/edit.php' ); + await admin.createNewPost( { title } ); + await editor.publishPost(); + await admin.visitAdminPage( '/edit.php' ); - await page.waitForSelector( '#the-list .type-post' ); + const listTable = page.getByRole( 'table', { name: 'Table ordered by' } ); + await expect( listTable ).toBeVisible(); - // Focus on the post title link. - const [ editLink ] = await page.$x( - `//a[contains(@class, "row-title")][contains(text(), "${ title }")]` - ); - await editLink.focus(); + // // Focus on the post title link. + await listTable.getByRole( 'link', { name: `“${ title }” (Edit)` } ).focus(); // Tab to the Quick Edit button and press Enter to quick edit. - await pressKeyTimes( 'Tab', 2 ); + await pageUtils.pressKeys( 'Tab', { times: 2 } ) await page.keyboard.press( 'Enter' ); // Type in the currently focused (title) field to modify the title, testing that focus is moved to the input. await page.keyboard.type( ' Edited' ); // Update the post. - await page.click( '.button.save' ); + await page.getByRole( 'button', { name: 'Update' } ).click(); // Wait for the quick edit button to reappear. - await page.waitForSelector( 'button.editinline', { visible: true } ); + await expect( page.getByRole( 'button', { name: 'Quick Edit' } ) ).toBeVisible(); // Expect there to be one row in the post list. - const posts = await page.$$( '#the-list tr.type-post' ); - expect( posts.length ).toBe( 1 ); - - const [ firstPost ] = posts; + const posts = listTable.locator( '.row-title' ); + await expect( posts ).toHaveCount( 1 ); // Expect the title of the post to be correct. - const postTitle = await firstPost.$x( - `//a[contains(@class, "row-title")][contains(text(), "${ title } Edited")]` - ); - expect( postTitle.length ).toBe( 1 ); + expect( posts.first() ).toHaveText( `${ title } Edited` ); } ); - it( 'allows an existing post to be deleted using the Trash button', async () => { + + test( 'allows an existing post to be deleted using the Trash button', async ( { + admin, + editor, + page, + pageUtils + } ) => { const title = 'Test Title'; - await createNewPost( { title } ); - await publishPost(); - await visitAdminPage( '/edit.php' ); + await admin.createNewPost( { title } ); + await editor.publishPost(); + await admin.visitAdminPage( '/edit.php' ); - await page.waitForSelector( '#the-list .type-post' ); + const listTable = page.getByRole( 'table', { name: 'Table ordered by' } ); + await expect( listTable ).toBeVisible(); // Focus on the post title link. - const [ editLink ] = await page.$x( - `//a[contains(@class, "row-title")][contains(text(), "${ title }")]` - ); - await editLink.focus(); + await listTable.getByRole( 'link', { name: `“${ title }” (Edit)` } ).focus(); // Tab to the Trash button and press Enter to delete the post. - await pressKeyTimes( 'Tab', 3 ); + await pageUtils.pressKeys( 'Tab', { times: 3 } ) await page.keyboard.press( 'Enter' ); - const noPostsMessage = await page.waitForSelector( - '#the-list .no-items td' - ); - - expect( - await noPostsMessage.evaluate( ( element ) => element.innerText ) - ).toBe( 'No posts found.' ); + await expect( + page.getByRole( 'cell', { name: 'No posts found.' } ) + ).toBeVisible(); } ); } ); diff --git a/tests/e2e/specs/empty-trash-restore-trashed-posts.test.js b/tests/e2e/specs/empty-trash-restore-trashed-posts.test.js index e18df9f8fe7b1..d970ca09b1c90 100644 --- a/tests/e2e/specs/empty-trash-restore-trashed-posts.test.js +++ b/tests/e2e/specs/empty-trash-restore-trashed-posts.test.js @@ -1,72 +1,55 @@ -import { - visitAdminPage, - createNewPost, - trashAllPosts, - publishPost, -} from "@wordpress/e2e-test-utils"; +/** + * WordPress dependencies + */ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; -const POST_TITLE = "Test Title"; +const POST_TITLE = 'Test Title'; -describe("Empty Trash", () => { - async function createPost(title) { - // Create a Post - await createNewPost({ title }); - await publishPost(); - } +test.describe( 'Empty Trash', () => { + test.beforeEach( async ( { requestUtils } ) => { + await requestUtils.deleteAllPosts(); + }); - afterEach(async () => { - await trashAllPosts(); - }); + test('Empty Trash', async ({ admin, editor, page }) => { + await admin.createNewPost( { title: POST_TITLE } ); + await editor.publishPost(); - it("Empty Trash", async () => { - await createPost(POST_TITLE); + await admin.visitAdminPage( '/edit.php' ); - await visitAdminPage("/edit.php"); + const listTable = page.getByRole( 'table', { name: 'Table ordered by' } ); + await expect( listTable ).toBeVisible(); - // Move post to trash - await page.hover(`[aria-label^="“${POST_TITLE}”"]`); - await page.click(`[aria-label='Move “${POST_TITLE}” to the Trash']`); + // Move post to trash + await listTable.getByRole( 'link', { name: `“${ POST_TITLE }” (Edit)` } ).hover(); + await listTable.getByRole( 'link', { name: `Move “${POST_TITLE}” to the Trash` } ).click(); - // Empty trash - const trashTab = await page.waitForXPath('//h2[text()="Filter posts list"]/following-sibling::ul//a[contains(text(), "Trash")]'); - await Promise.all([ - trashTab.click(), - page.waitForNavigation(), - ]); - const deleteAllButton = await page.waitForSelector('input[value="Empty Trash"]'); - await Promise.all([ - deleteAllButton.click(), - page.waitForNavigation(), - ]); + // Empty trash + await page.getByRole( 'link', { name: 'Trash' } ).click(); + await page.getByRole( 'button', { name: 'Empty Trash' } ).first().click(); - const messageElement = await page.waitForSelector("#message"); - const message = await messageElement.evaluate((node) => node.innerText); - // Until we have `deleteAllPosts`, the number of posts being deleted could be dynamic. - expect(message).toMatch(/\d+ posts? permanently deleted\./); - }); + await expect( page.locator( '#message' ) ).toContainText( '1 post permanently deleted.' ); + } ); - it("Restore trash post", async () => { - await createPost(POST_TITLE); + test('Restore trash post', async ( { admin, editor, page }) => { + await admin.createNewPost( { title: POST_TITLE } ); + await editor.publishPost(); - await visitAdminPage("/edit.php"); + await admin.visitAdminPage( '/edit.php' ); - // Move one post to trash. - await page.hover(`[aria-label^="“${POST_TITLE}”"]`); - await page.click(`[aria-label='Move “${POST_TITLE}” to the Trash']`); + const listTable = page.getByRole( 'table', { name: 'Table ordered by' } ); + await expect( listTable ).toBeVisible(); - // Remove post from trash. - const trashTab = await page.waitForXPath('//h2[text()="Filter posts list"]/following-sibling::ul//a[contains(text(), "Trash")]'); - await Promise.all([ - trashTab.click(), - page.waitForNavigation(), - ]); - const [postTitle] = await page.$x(`//*[text()="${POST_TITLE}"]`); - await postTitle.hover(); - await page.click(`[aria-label="Restore “${POST_TITLE}” from the Trash"]`); + // Move post to trash + await listTable.getByRole( 'link', { name: `“${ POST_TITLE }” (Edit)` } ).hover(); + await listTable.getByRole( 'link', { name: `Move “${POST_TITLE}” to the Trash` } ).click(); - // Expect for success message for trashed post. - const messageElement = await page.waitForSelector("#message"); - const message = await messageElement.evaluate((element) => element.innerText); - expect(message).toContain("1 post restored from the Trash."); - }); -}); + await page.getByRole( 'link', { name: 'Trash' } ).click(); + + // Remove post from trash. + await listTable.getByRole( 'cell' ).filter( { hasText: POST_TITLE } ).hover(); + await listTable.getByRole( 'link', { name: `Restore “${POST_TITLE}” from the Trash` } ).click(); + + // Expect for success message for restored post. + await expect( page.locator( '#message' ) ).toContainText( '1 post restored from the Trash.' ); + } ); +} ); diff --git a/tests/e2e/specs/gutenberg-plugin.test.js b/tests/e2e/specs/gutenberg-plugin.test.js index 21b6e9737d0f1..8f3ff20acc1c1 100644 --- a/tests/e2e/specs/gutenberg-plugin.test.js +++ b/tests/e2e/specs/gutenberg-plugin.test.js @@ -1,26 +1,48 @@ -import { - activatePlugin, - deactivatePlugin, - installPlugin, - uninstallPlugin, -} from '@wordpress/e2e-test-utils'; - -describe( 'Gutenberg plugin', () => { - beforeAll( async () => { - await installPlugin( 'gutenberg' ); - } ); +/** + * WordPress dependencies + */ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; + +test.describe( 'Gutenberg plugin', () => { + // Increasing timeout to 5 minutes because potential plugin install could take longer. + test.setTimeout( 300_000 ); + + test.beforeAll( async ( { requestUtils } ) => { + // Install Gutenberg plugin if it's not yet installed. + const pluginsMap = await requestUtils.getPluginsMap(); + if ( ! pluginsMap.gutenberg ) { + await requestUtils.rest( { + method: 'POST', + path: 'wp/v2/plugins?slug=gutenberg', + } ); + } - afterAll( async () => { - await uninstallPlugin( 'gutenberg' ); + // Refetch installed plugin details. It avoids stale values when the test installs the plugin. + await requestUtils.getPluginsMap( /* forceRefetch */ true ); + await requestUtils.deactivatePlugin( 'gutenberg' ); } ); - it( 'should activate', async () => { - await activatePlugin( 'gutenberg' ); - /* - * If plugin activation fails, it will time out and throw an error, - * since the activatePlugin helper is looking for a `.deactivate` link - * which is only there if activation succeeds. - */ - await deactivatePlugin( 'gutenberg' ); + test( 'should activate', async ( { requestUtils }) => { + let plugin = await requestUtils.rest( { + path: 'wp/v2/plugins/gutenberg/gutenberg', + } ); + + expect( plugin.status ).toBe( 'inactive' ); + + await requestUtils.activatePlugin( 'gutenberg' ); + + plugin = await requestUtils.rest( { + path: 'wp/v2/plugins/gutenberg/gutenberg', + } ); + + expect( plugin.status ).toBe( 'active' ); + + await requestUtils.deactivatePlugin( 'gutenberg' ); + + plugin = await requestUtils.rest( { + path: 'wp/v2/plugins/gutenberg/gutenberg', + } ); + + expect( plugin.status ).toBe( 'inactive' ); } ); } ); diff --git a/tests/e2e/specs/hello.test.js b/tests/e2e/specs/hello.test.js index 038957883be09..cfe018bbd6260 100644 --- a/tests/e2e/specs/hello.test.js +++ b/tests/e2e/specs/hello.test.js @@ -1,11 +1,13 @@ -import { visitAdminPage } from '@wordpress/e2e-test-utils'; +/** + * WordPress dependencies + */ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; -describe( 'Hello World', () => { - it( 'Should load properly', async () => { - await visitAdminPage( '/' ); - const nodes = await page.$x( - '//h2[contains(text(), "Welcome to WordPress!")]' - ); - expect( nodes.length ).not.toEqual( 0 ); +test.describe( 'Hello World', () => { + test( 'Should load properly', async ( { admin, page }) => { + await admin.visitAdminPage( '/' ); + await expect( + page.getByRole('heading', { name: 'Welcome to WordPress', level: 2 }) + ).toBeVisible(); } ); } ); diff --git a/tests/e2e/specs/profile/applications-passwords.test.js b/tests/e2e/specs/profile/applications-passwords.test.js index 1b53a76811d10..38aed7372eace 100644 --- a/tests/e2e/specs/profile/applications-passwords.test.js +++ b/tests/e2e/specs/profile/applications-passwords.test.js @@ -1,138 +1,133 @@ -import { - visitAdminPage, - __experimentalRest as rest, -} from "@wordpress/e2e-test-utils"; - -async function getResponseForApplicationPassword() { - return await rest({ - method: "GET", - path: "/wp/v2/users/me/application-passwords", - }); -} - -async function createApplicationPassword(applicationName) { - await visitAdminPage("profile.php"); - await page.waitForSelector("#new_application_password_name"); - await page.type("#new_application_password_name", applicationName); - await page.click("#do_new_application_password"); +/** + * WordPress dependencies + */ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; - await page.waitForSelector("#application-passwords-section .notice"); -} +const TEST_APPLICATION_NAME = 'Test Application'; -async function createApplicationPasswordWithApi(applicationName) { - await rest({ - method: "POST", - path: "/wp/v2/users/me/application-passwords", - data: { - name: applicationName, +test.describe( 'Manage applications passwords', () => { + test.use( { + applicationPasswords: async ( { requestUtils, admin, page }, use ) => { + await use( new ApplicationPasswords( { requestUtils, admin, page } ) ); }, - }); -} + } ); -async function revokeAllApplicationPasswordsWithApi() { - await rest({ - method: "DELETE", - path: `/wp/v2/users/me/application-passwords`, - }); -} + test.beforeEach(async ( { applicationPasswords } ) => { + await applicationPasswords.delete(); + } ); -describe("Manage applications passwords", () => { - const TEST_APPLICATION_NAME = "Test Application"; + test('should correctly create a new application password', async ( { + page, + applicationPasswords + } ) => { + await applicationPasswords.create(); - beforeEach(async () => { - await revokeAllApplicationPasswordsWithApi(); - }); + const [ app ] = await applicationPasswords.get(); + expect( app['name']).toBe( TEST_APPLICATION_NAME ); - it("should correctly create a new application password", async () => { - await createApplicationPassword(TEST_APPLICATION_NAME); + const successMessage = page.getByRole( 'alert' ); - const response = await getResponseForApplicationPassword(); - expect(response[0]["name"]).toBe(TEST_APPLICATION_NAME); - - const successMessage = await page.waitForSelector( - "#application-passwords-section .notice-success" - ); - expect( - await successMessage.evaluate((element) => element.innerText) - ).toContain( + await expect( successMessage ).toHaveClass( /notice-success/ ); + await expect( + successMessage + ).toContainText( `Your new password for ${TEST_APPLICATION_NAME} is: \n\nBe sure to save this in a safe location. You will not be able to retrieve it.` ); - }); - - it("should not allow to create two applications passwords with the same name", async () => { - await createApplicationPassword(TEST_APPLICATION_NAME); - await createApplicationPassword(TEST_APPLICATION_NAME); - - const errorMessage = await page.waitForSelector( - "#application-passwords-section .notice-error" + } ); + + test('should not allow to create two applications passwords with the same name', async ( { + page, + applicationPasswords + } ) => { + await applicationPasswords.create(); + await applicationPasswords.create(); + + const errorMessage = page.getByRole( 'alert' ); + + await expect( errorMessage ).toHaveClass( /notice-error/ ); + await expect( + errorMessage + ).toContainText( + 'Each application name should be unique.' ); - - expect( - await errorMessage.evaluate((element) => element.textContent) - ).toContain("Each application name should be unique."); }); - it("should correctly revoke a single application password", async () => { - await createApplicationPassword(TEST_APPLICATION_NAME); + test( 'should correctly revoke a single application password', async ( { + page, + applicationPasswords + } ) => { + await applicationPasswords.create(); - const revokeApplicationButton = await page.waitForSelector( - ".application-passwords-user tr button.delete" - ); - - const revocationDialogPromise = new Promise((resolve) => { - page.once("dialog", resolve); - }); - - await Promise.all([ - revocationDialogPromise, - revokeApplicationButton.click(), - ]); - - const successMessage = await page.waitForSelector( - "#application-passwords-section .notice-success" - ); - expect( - await successMessage.evaluate((element) => element.textContent) - ).toContain("Application password revoked."); + const revokeButton = page.getByRole( 'button', { name: `Revoke "${ TEST_APPLICATION_NAME }"` } ); + await expect( revokeButton ).toBeVisible(); - const response = await getResponseForApplicationPassword(); - expect(response).toEqual([]); - }); - - it("should correctly revoke all the application passwords", async () => { - await createApplicationPassword(TEST_APPLICATION_NAME); + // Revoke password. + page.on( 'dialog', ( dialog ) => dialog.accept() ); + await revokeButton.click(); - const revokeAllApplicationPasswordsButton = await page.waitForSelector( - "#revoke-all-application-passwords" + await expect( + page.getByRole( 'alert' ) + ).toContainText( + 'Application password revoked.' ); - const revocationDialogPromise = new Promise((resolve) => { - page.once("dialog", resolve); - }); + const response = await applicationPasswords.get(); + expect( response ).toEqual([]); + } ); - await Promise.all([ - revocationDialogPromise, - revokeAllApplicationPasswordsButton.click(), - ]); + test( 'should correctly revoke all the application passwords', async ( { + page, + applicationPasswords + } ) => { + await applicationPasswords.create(); - /** - * This is commented out because we're using enablePageDialogAccept - * which is overly aggressive and no way to temporary disable it either. - */ - // await dialog.accept(); + const revokeAllButton = page.getByRole( 'button', { name: 'Revoke all application passwords' } ); + await expect( revokeAllButton ).toBeVisible(); - await page.waitForSelector( - "#application-passwords-section .notice-success" - ); + // Confirms revoking action. + page.on( 'dialog', ( dialog ) => dialog.accept() ); + await revokeAllButton.click(); - const successMessage = await page.waitForSelector( - "#application-passwords-section .notice-success" + await expect( + page.getByRole( 'alert' ) + ).toContainText( + 'All application passwords revoked.' ); - expect( - await successMessage.evaluate((element) => element.textContent) - ).toContain("All application passwords revoked."); - const response = await getResponseForApplicationPassword(); - expect(response).toEqual([]); - }); -}); + const response = await applicationPasswords.get(); + expect( response ).toEqual([]); + } ); +} ); + +class ApplicationPasswords { + constructor( { requestUtils, page, admin }) { + this.requestUtils = requestUtils; + this.page = page; + this.admin = admin; + } + + async create(applicationName = TEST_APPLICATION_NAME) { + await this.admin.visitAdminPage( '/profile.php' ); + + const newPasswordField = this.page.getByRole( 'textbox', { name: 'New Application Password Name' } ); + await expect( newPasswordField ).toBeVisible(); + await newPasswordField.fill( applicationName ); + + await this.page.getByRole( 'button', { name: 'Add New Application Password' } ).click(); + await expect( this.page.getByRole( 'alert' ) ).toBeVisible(); + } + + async get() { + return this.requestUtils.rest( { + method: 'GET', + path: '/wp/v2/users/me/application-passwords', + } ); + } + + async delete() { + await this.requestUtils.rest( { + method: 'DELETE', + path: '/wp/v2/users/me/application-passwords', + } ); + } +} diff --git a/tests/performance/compare-results.js b/tests/performance/compare-results.js index e722552aeda04..5682f08dc2245 100644 --- a/tests/performance/compare-results.js +++ b/tests/performance/compare-results.js @@ -3,8 +3,12 @@ /** * External dependencies. */ -const fs = require( 'fs' ); -const path = require( 'path' ); +const fs = require( 'node:fs' ); +const path = require( 'node:path' ); + +/** + * Internal dependencies + */ const { median } = require( './utils' ); /** @@ -23,18 +27,16 @@ const testSuites = [ 'home-block-theme', 'home-classic-theme' ]; // The current commit's results. const testResults = Object.fromEntries( - testSuites.map( ( key ) => [ - key, - parseFile( `${ key }.test.results.json` ), - ] ) + testSuites + .filter( ( key ) => fs.existsSync( path.join( __dirname, '/specs/', `${ key }.test.results.json` ) ) ) + .map( ( key ) => [ key, parseFile( `${ key }.test.results.json` ) ] ) ); // The previous commit's results. const prevResults = Object.fromEntries( - testSuites.map( ( key ) => [ - key, - parseFile( `before-${ key }.test.results.json` ), - ] ) + testSuites + .filter( ( key ) => fs.existsSync( path.join( __dirname, '/specs/', `before-${ key }.test.results.json` ) ) ) + .map( ( key ) => [ key, parseFile( `before-${ key }.test.results.json` ) ] ) ); const args = process.argv.slice( 2 ); @@ -127,8 +129,8 @@ console.log( 'Performance Test Results\n' ); console.log( 'Note: Due to the nature of how GitHub Actions work, some variance in the results is expected.\n' ); for ( const key of testSuites ) { - const current = testResults[ key ]; - const prev = prevResults[ key ]; + const current = testResults[ key ] || {}; + const prev = prevResults[ key ] || {}; const title = ( key.charAt( 0 ).toUpperCase() + key.slice( 1 ) ).replace( /-+/g, @@ -142,7 +144,7 @@ for ( const key of testSuites ) { const prevValue = median( prev[ metric ] ); const delta = value - prevValue; - const percentage = Math.round( ( delta / value ) * 100 ); + const percentage = ( delta / value ) * 100; rows.push( { Metric: metric, Before: `${ prevValue.toFixed( 2 ) } ms`, @@ -152,14 +154,18 @@ for ( const key of testSuites ) { } ); } - summaryMarkdown += `## ${ title }\n\n`; - summaryMarkdown += `${ formatAsMarkdownTable( rows ) }\n`; + if ( rows.length > 0 ) { + summaryMarkdown += `## ${ title }\n\n`; + summaryMarkdown += `${ formatAsMarkdownTable( rows ) }\n`; - console.log( title ); - console.table( rows ); + console.log( title ); + console.table( rows ); + } } -fs.writeFileSync( - summaryFile, - summaryMarkdown -); +if ( summaryFile ) { + fs.writeFileSync( + summaryFile, + summaryMarkdown + ); +} diff --git a/tests/performance/config/bootstrap.js b/tests/performance/config/bootstrap.js deleted file mode 100644 index 773d2c1d74f87..0000000000000 --- a/tests/performance/config/bootstrap.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * WordPress dependencies. - */ -import { - clearLocalStorage, - enablePageDialogAccept, - setBrowserViewport, -} from '@wordpress/e2e-test-utils'; - -/** - * Timeout, in seconds, that the test should be allowed to run. - * - * @type {string|undefined} - */ -const PUPPETEER_TIMEOUT = process.env.PUPPETEER_TIMEOUT; - -// The Jest timeout is increased because these tests are a bit slow. -jest.setTimeout( PUPPETEER_TIMEOUT || 100000 ); - -async function setupBrowser() { - await clearLocalStorage(); - await setBrowserViewport( 'large' ); -} - -/* - * Before every test suite run, delete all content created by the test. This ensures - * other posts/comments/etc. aren't dirtying tests and tests don't depend on - * each other's side-effects. - */ -beforeAll( async () => { - enablePageDialogAccept(); - - await setBrowserViewport( 'large' ); - await page.emulateMediaFeatures( [ - { name: 'prefers-reduced-motion', value: 'reduce' }, - ] ); -} ); - -afterEach( async () => { - await setupBrowser(); -} ); diff --git a/tests/performance/config/global-setup.js b/tests/performance/config/global-setup.js new file mode 100644 index 0000000000000..f3a0a4f26a691 --- /dev/null +++ b/tests/performance/config/global-setup.js @@ -0,0 +1,40 @@ +/** + * External dependencies + */ +import { request } from '@playwright/test'; + +/** + * WordPress dependencies + */ +import { RequestUtils } from '@wordpress/e2e-test-utils-playwright'; + +/** + * + * @param {import('@playwright/test').FullConfig} config + * @returns {Promise} + */ +async function globalSetup( config ) { + const { storageState, baseURL } = config.projects[ 0 ].use; + const storageStatePath = + typeof storageState === 'string' ? storageState : undefined; + + const requestContext = await request.newContext( { + baseURL, + } ); + + const requestUtils = new RequestUtils( requestContext, { + storageStatePath, + } ); + + // Authenticate and save the storageState to disk. + await requestUtils.setupRest(); + + // Reset the test environment before running the tests. + await Promise.all( [ + requestUtils.activateTheme( 'twentytwentyone' ), + ] ); + + await requestContext.dispose(); +} + +export default globalSetup; diff --git a/tests/performance/config/performance-reporter.js b/tests/performance/config/performance-reporter.js new file mode 100644 index 0000000000000..e557faa135cbd --- /dev/null +++ b/tests/performance/config/performance-reporter.js @@ -0,0 +1,38 @@ +/** + * External dependencies + */ +import { join, dirname, basename } from 'node:path'; +import { writeFileSync } from 'node:fs'; + +/** + * Internal dependencies + */ +import { getResultsFilename } from '../utils'; + +/** + * @implements {import('@playwright/test/reporter').Reporter} + */ +class PerformanceReporter { + /** + * + * @param {import('@playwright/test/reporter').TestCase} test + * @param {import('@playwright/test/reporter').TestResult} result + */ + onTestEnd( test, result ) { + const performanceResults = result.attachments.find( + ( attachment ) => attachment.name === 'results' + ); + + if ( performanceResults?.body ) { + writeFileSync( + join( + dirname( test.location.file ), + getResultsFilename( basename( test.location.file, '.js' ) ) + ), + performanceResults.body.toString( 'utf-8' ) + ); + } + } +} + +export default PerformanceReporter; diff --git a/tests/performance/jest.config.js b/tests/performance/jest.config.js deleted file mode 100644 index b62bb016c3b03..0000000000000 --- a/tests/performance/jest.config.js +++ /dev/null @@ -1,14 +0,0 @@ -const config = require( '@wordpress/scripts/config/jest-e2e.config' ); - -const jestE2EConfig = { - ...config, - setupFilesAfterEnv: [ - '/config/bootstrap.js', - ], - globals: { - // Number of requests to run per test. - TEST_RUNS: 20, - } -}; - -module.exports = jestE2EConfig; diff --git a/tests/performance/playwright.config.js b/tests/performance/playwright.config.js new file mode 100644 index 0000000000000..6c2ff454725ed --- /dev/null +++ b/tests/performance/playwright.config.js @@ -0,0 +1,42 @@ +/** + * External dependencies + */ +import path from 'node:path'; +import { defineConfig } from '@playwright/test'; + +/** + * WordPress dependencies + */ +import baseConfig from '@wordpress/scripts/config/playwright.config'; + +process.env.WP_ARTIFACTS_PATH ??= path.join( process.cwd(), 'artifacts' ); +process.env.STORAGE_STATE_PATH ??= path.join( + process.env.WP_ARTIFACTS_PATH, + 'storage-states/admin.json' +); +process.env.TEST_RUNS ??= '20'; + +const config = defineConfig( { + ...baseConfig, + globalSetup: require.resolve( './config/global-setup.js' ), + reporter: process.env.CI + ? './config/performance-reporter.js' + : [ [ 'list' ], [ './config/performance-reporter.js' ] ], + forbidOnly: !! process.env.CI, + workers: 1, + retries: 0, + timeout: parseInt( process.env.TIMEOUT || '', 10 ) || 600_000, // Defaults to 10 minutes. + // Don't report slow test "files", as we will be running our tests in serial. + reportSlowTests: null, + webServer: { + ...baseConfig.webServer, + command: 'npm run env:start', + }, + use: { + ...baseConfig.use, + video: 'off', + }, +} ); + +export default config; + diff --git a/tests/performance/results.js b/tests/performance/results.js index 3ebf47edaabd0..c7a977181da6a 100644 --- a/tests/performance/results.js +++ b/tests/performance/results.js @@ -3,8 +3,8 @@ /** * External dependencies. */ -const fs = require( 'fs' ); -const { join } = require( 'path' ); +const fs = require( 'node:fs' ); +const { join } = require( 'node:path' ); const { median, getResultsFilename } = require( './utils' ); const testSuites = [ diff --git a/tests/performance/run-tests.js b/tests/performance/run-tests.js deleted file mode 100644 index 84e3c847842c2..0000000000000 --- a/tests/performance/run-tests.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * External dependencies. - */ -const dotenv = require( 'dotenv' ); -const dotenv_expand = require( 'dotenv-expand' ); -const { execSync } = require( 'child_process' ); - -// WP_BASE_URL interpolates LOCAL_PORT, so needs to be parsed by dotenv_expand(). -dotenv_expand.expand( dotenv.config() ); - -// Run the tests, passing additional arguments through to the test script. -execSync( - 'wp-scripts test-e2e --config tests/performance/jest.config.js ' + - process.argv.slice( 2 ).join( ' ' ), - { stdio: 'inherit' } -); diff --git a/tests/performance/specs/home-block-theme.test.js b/tests/performance/specs/home-block-theme.test.js index f9a93824a6077..496445ad0d0c8 100644 --- a/tests/performance/specs/home-block-theme.test.js +++ b/tests/performance/specs/home-block-theme.test.js @@ -1,67 +1,57 @@ /** - * External dependencies. + * WordPress dependencies */ -const { basename, join } = require( 'path' ); -const { writeFileSync } = require( 'fs' ); -const { - getResultsFilename, - getTimeToFirstByte, - getLargestContentfulPaint, -} = require( './../utils' ); +import { test } from '@wordpress/e2e-test-utils-playwright'; /** - * WordPress dependencies. + * Internal dependencies */ -import { activateTheme, createURL } from '@wordpress/e2e-test-utils'; +import { camelCaseDashes } from '../utils'; -describe( 'Server Timing - Twenty Twenty Three', () => { - const results = { - wpBeforeTemplate: [], - wpTemplate: [], - wpTotal: [], - timeToFirstByte: [], - largestContentfulPaint: [], - lcpMinusTtfb: [], - }; +const results = { + timeToFirstByte: [], + largestContentfulPaint: [], + lcpMinusTtfb: [], +}; - beforeAll( async () => { - await activateTheme( 'twentytwentythree' ); +test.describe( 'Front End - Twenty Twenty Three', () => { + test.use( { + storageState: {}, // User will be logged out. } ); - afterAll( async () => { - const resultsFilename = getResultsFilename( - basename( __filename, '.js' ) - ); - writeFileSync( - join( __dirname, resultsFilename ), - JSON.stringify( results, null, 2 ) - ); + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activateTheme( 'twentytwentythree' ); } ); - it( 'Server Timing Metrics', async () => { - let i = TEST_RUNS; - while ( i-- ) { - await page.goto( createURL( '/' ) ); - const navigationTimingJson = await page.evaluate( () => - JSON.stringify( performance.getEntriesByType( 'navigation' ) ) - ); + test.afterAll( async ( { requestUtils }, testInfo ) => { + await testInfo.attach( 'results', { + body: JSON.stringify( results, null, 2 ), + contentType: 'application/json', + } ); + await requestUtils.activateTheme( 'twentytwentyone' ); + } ); - const [ navigationTiming ] = JSON.parse( navigationTimingJson ); + const iterations = Number( process.env.TEST_RUNS ); + for ( let i = 1; i <= iterations; i++ ) { + test( `Measure load time metrics (${ i } of ${ iterations })`, async ( { + page, + metrics, + } ) => { + await page.goto( '/' ); - results.wpBeforeTemplate.push( - navigationTiming.serverTiming[ 0 ].duration - ); - results.wpTemplate.push( - navigationTiming.serverTiming[ 1 ].duration - ); - results.wpTotal.push( navigationTiming.serverTiming[ 2 ].duration ); + const serverTiming = await metrics.getServerTiming(); - const ttfb = await getTimeToFirstByte(); - const lcp = await getLargestContentfulPaint(); + for ( const [key, value] of Object.entries( serverTiming ) ) { + results[ camelCaseDashes( key ) ] ??= []; + results[ camelCaseDashes( key ) ].push( value ); + } + + const ttfb = await metrics.getTimeToFirstByte(); + const lcp = await metrics.getLargestContentfulPaint(); - results.timeToFirstByte.push( ttfb ); results.largestContentfulPaint.push( lcp ); + results.timeToFirstByte.push( ttfb ); results.lcpMinusTtfb.push( lcp - ttfb ); - } - } ); + } ); + } } ); diff --git a/tests/performance/specs/home-classic-theme.test.js b/tests/performance/specs/home-classic-theme.test.js index 7ae9282ddc3cc..32125c37a42a1 100644 --- a/tests/performance/specs/home-classic-theme.test.js +++ b/tests/performance/specs/home-classic-theme.test.js @@ -1,71 +1,56 @@ /** - * External dependencies. + * WordPress dependencies */ -const { basename, join } = require( 'path' ); -const { writeFileSync } = require( 'fs' ); -const { exec } = require( 'child_process' ); -const { - getResultsFilename, - getTimeToFirstByte, - getLargestContentfulPaint, -} = require( './../utils' ); +import { test } from '@wordpress/e2e-test-utils-playwright'; /** - * WordPress dependencies. + * Internal dependencies */ -import { activateTheme, createURL } from '@wordpress/e2e-test-utils'; +import { camelCaseDashes } from '../utils'; -describe( 'Server Timing - Twenty Twenty One', () => { - const results = { - wpBeforeTemplate: [], - wpTemplate: [], - wpTotal: [], - timeToFirstByte: [], - largestContentfulPaint: [], - lcpMinusTtfb: [], - }; +const results = { + timeToFirstByte: [], + largestContentfulPaint: [], + lcpMinusTtfb: [], +}; - beforeAll( async () => { - await activateTheme( 'twentytwentyone' ); - await exec( - 'npm run env:cli -- menu location assign all-pages primary' - ); +test.describe( 'Front End - Twenty Twenty One', () => { + test.use( { + storageState: {}, // User will be logged out. } ); - afterAll( async () => { - const resultsFilename = getResultsFilename( - basename( __filename, '.js' ) - ); - writeFileSync( - join( __dirname, resultsFilename ), - JSON.stringify( results, null, 2 ) - ); + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activateTheme( 'twentytwentyone' ); } ); - it( 'Server Timing Metrics', async () => { - let i = TEST_RUNS; - while ( i-- ) { - await page.goto( createURL( '/' ) ); - const navigationTimingJson = await page.evaluate( () => - JSON.stringify( performance.getEntriesByType( 'navigation' ) ) - ); + test.afterAll( async ( {}, testInfo ) => { + await testInfo.attach( 'results', { + body: JSON.stringify( results, null, 2 ), + contentType: 'application/json', + } ); + } ); - const [ navigationTiming ] = JSON.parse( navigationTimingJson ); + const iterations = Number( process.env.TEST_RUNS ); + for ( let i = 1; i <= iterations; i++ ) { + test( `Measure load time metrics (${ i } of ${ iterations })`, async ( { + page, + metrics, + } ) => { + await page.goto( '/' ); - results.wpBeforeTemplate.push( - navigationTiming.serverTiming[ 0 ].duration - ); - results.wpTemplate.push( - navigationTiming.serverTiming[ 1 ].duration - ); - results.wpTotal.push( navigationTiming.serverTiming[ 2 ].duration ); + const serverTiming = await metrics.getServerTiming(); - const ttfb = await getTimeToFirstByte(); - const lcp = await getLargestContentfulPaint(); + for (const [key, value] of Object.entries( serverTiming ) ) { + results[ camelCaseDashes( key ) ] ??= []; + results[ camelCaseDashes( key ) ].push( value ); + } + + const ttfb = await metrics.getTimeToFirstByte(); + const lcp = await metrics.getLargestContentfulPaint(); - results.timeToFirstByte.push( ttfb ); results.largestContentfulPaint.push( lcp ); + results.timeToFirstByte.push( ttfb ); results.lcpMinusTtfb.push( lcp - ttfb ); - } - } ); + } ); + } } ); diff --git a/tests/performance/utils.js b/tests/performance/utils.js index 732ab66d447fa..f56380e9c241a 100644 --- a/tests/performance/utils.js +++ b/tests/performance/utils.js @@ -16,63 +16,24 @@ function median( array ) { /** * Gets the result file name. * - * @param {string} File name. + * @param {string} fileName File name. * * @return {string} Result file name. */ function getResultsFilename( fileName ) { - const prefixArg = process.argv.find( ( arg ) => - arg.startsWith( '--prefix' ) - ); - const fileNamePrefix = prefixArg ? `${ prefixArg.split( '=' )[ 1 ] }-` : ''; - const resultsFilename = fileNamePrefix + fileName + '.results.json'; - return resultsFilename; + const prefix = process.env.TEST_RESULTS_PREFIX; + const fileNamePrefix = prefix ? `${ prefix }-` : ''; + return `${fileNamePrefix + fileName}.results.json`; } -/** - * Returns time to first byte (TTFB) using the Navigation Timing API. - * - * @see https://web.dev/ttfb/#measure-ttfb-in-javascript - * - * @return {Promise} - */ -async function getTimeToFirstByte() { - return page.evaluate( () => { - const { responseStart, startTime } = - performance.getEntriesByType( 'navigation' )[ 0 ]; - return responseStart - startTime; +function camelCaseDashes( str ) { + return str.replace( /-([a-z])/g, function( g ) { + return g[ 1 ].toUpperCase(); } ); } -/** - * Returns the Largest Contentful Paint (LCP) value using the dedicated API. - * - * @see https://w3c.github.io/largest-contentful-paint/ - * @see https://web.dev/lcp/#measure-lcp-in-javascript - * - * @return {Promise} - */ -async function getLargestContentfulPaint() { - return page.evaluate( - () => - new Promise( ( resolve ) => { - new PerformanceObserver( ( entryList ) => { - const entries = entryList.getEntries(); - // The last entry is the largest contentful paint. - const largestPaintEntry = entries.at( -1 ); - - resolve( largestPaintEntry?.startTime || 0 ); - } ).observe( { - type: 'largest-contentful-paint', - buffered: true, - } ); - } ) - ); -} - module.exports = { median, getResultsFilename, - getTimeToFirstByte, - getLargestContentfulPaint, + camelCaseDashes, }; diff --git a/tests/phpunit/tests/ajax/wpAjaxParseMediaShortcode.php b/tests/phpunit/tests/ajax/wpAjaxParseMediaShortcode.php new file mode 100755 index 0000000000000..19c7f20449dfb --- /dev/null +++ b/tests/phpunit/tests/ajax/wpAjaxParseMediaShortcode.php @@ -0,0 +1,85 @@ +attachment->create_object( + get_temp_dir() . 'canola.jpg', + 0, + array( + 'post_mime_type' => 'image/jpeg', + 'post_excerpt' => 'A sample caption', + 'post_name' => 'restapi-client-fixture-attachment', + 'post_title' => 'REST API Client Fixture: Attachment', + 'post_date' => '2017-02-14 00:00:00', + 'post_date_gmt' => '2017-02-14 00:00:00', + 'post_author' => 0, + ) + ); + } + /** + * @dataProvider shortcode_provider + */ + public function test_parse_shortcode( array $payload, $expected ) { + add_shortcode( 'test', array( $this, 'shortcode_test' ) ); + + $_POST = array_merge( + array( + 'action' => 'paser-media-shortcode', + 'type' => '', + ), + $payload + ); + // Make the request. + try { + $this->_handleAjax( 'parse-media-shortcode' ); + } catch ( WPAjaxDieContinueException $e ) { + unset( $e ); + } + // Get the response, it is in heartbeat's response. + $response = json_decode( $this->_last_response, true ); + $body = $response['data']['body'] ?? ''; + if ( $body ) { + $this->assertStringNotContainsString( self::SHORTCODE_RETURN_VALUE, $body ); + } + $this->assertSame( $expected['success'], $response['success'] ); + } + + public function shortcode_test() { + return self::SHORTCODE_RETURN_VALUE; + } + + public function shortcode_provider() { + return array( + 'gallery_shortcode_is_allowed' => array( + 'payload' => array( 'shortcode' => '[gallery ids=" ' . self::$media_id . '"]' ), + 'expected' => array( 'success' => true ), + ), + 'gallery_and_custom_test_shortcode_is_not_allowed' => array( + 'payload' => array( 'shortcode' => '[gallery ids=" ' . self::$media_id . '"] [test]' ), + 'expected' => array( 'success' => false ), + ), + 'custom_test_shortcode_is_not_allowed' => array( + 'payload' => array( 'shortcode' => '[test]' ), + 'expected' => array( 'success' => false ), + ), + ); + } +} diff --git a/tests/phpunit/tests/block-supports/wpRenderElementsSupport.php b/tests/phpunit/tests/block-supports/wpRenderElementsSupport.php index a65f53b471b35..db5307d20743f 100644 --- a/tests/phpunit/tests/block-supports/wpRenderElementsSupport.php +++ b/tests/phpunit/tests/block-supports/wpRenderElementsSupport.php @@ -18,6 +18,39 @@ public function tear_down() { parent::tear_down(); } + /** + * Tests that block supports leaves block content alone if the block type + * isn't registered. + * + * @ticket 59578 + * + * @covers ::wp_render_elements_support + * + * @return void + */ + public function test_leaves_block_content_alone_when_block_type_not_registered() { + $block = array( + 'blockName' => 'test/element-block-supports', + 'attrs' => array( + 'style' => array( + 'elements' => array( + 'button' => array( + 'color' => array( + 'text' => 'var:preset|color|vivid-red', + 'background' => '#fff', + ), + ), + ), + ), + ), + ); + + $block_markup = '

Hello WordPress!

'; + $actual = wp_render_elements_support( $block_markup, $block ); + + $this->assertSame( $block_markup, $actual, 'Expected to leave block content unmodified, but found changes.' ); + } + /** * Tests that elements block support applies the correct classname. * @@ -64,7 +97,7 @@ public function test_elements_block_support_class( $color_settings, $elements_st $this->assertMatchesRegularExpression( $expected_markup, $actual, - 'Position block wrapper markup should be correct' + 'Block wrapper markup should be correct' ); } @@ -80,6 +113,34 @@ public function data_elements_block_support_class() { ); return array( + // @ticket 59578 + 'empty block markup remains untouched' => array( + 'color_settings' => array( + 'button' => true, + ), + 'elements_styles' => array( + 'button' => array( 'color' => $color_styles ), + ), + 'block_markup' => '', + 'expected_markup' => '/^$/', + ), + 'empty block markup remains untouched when no block attributes' => array( + 'color_settings' => array( + 'button' => true, + ), + 'elements_styles' => null, + 'block_markup' => '', + 'expected_markup' => '/^$/', + ), + 'block markup remains untouched when block has no attributes' => array( + 'color_settings' => array( + 'button' => true, + ), + 'elements_styles' => null, + 'block_markup' => '

Hello WordPress!

', + 'expected_markup' => '/^

Hello WordPress<\/a>!<\/p>$/', + ), + // @ticket 5418 'button element styles with serialization skipped' => array( 'color_settings' => array( 'button' => true, diff --git a/tests/phpunit/tests/block-template-utils.php b/tests/phpunit/tests/block-template-utils.php index b06e931529f1e..814e1ee8511ed 100644 --- a/tests/phpunit/tests/block-template-utils.php +++ b/tests/phpunit/tests/block-template-utils.php @@ -161,64 +161,6 @@ public function test_build_block_template_result_from_file() { $this->assertEmpty( $template_part->modified ); } - /** - * @ticket 59325 - * - * @covers ::_build_block_template_result_from_file - * - * @dataProvider data_build_block_template_result_from_file_injects_theme_attribute - * - * @param string $filename The template's filename. - * @param string $expected The expected block markup. - */ - public function test_build_block_template_result_from_file_injects_theme_attribute( $filename, $expected ) { - $template = _build_block_template_result_from_file( - array( - 'slug' => 'single', - 'path' => DIR_TESTDATA . "/templates/$filename", - ), - 'wp_template' - ); - $this->assertSame( $expected, $template->content ); - } - - /** - * Data provider. - * - * @return array[] - */ - public function data_build_block_template_result_from_file_injects_theme_attribute() { - $theme = 'block-theme'; - return array( - 'a template with a template part block' => array( - 'filename' => 'template-with-template-part.html', - 'expected' => sprintf( - '', - $theme - ), - ), - 'a template with a template part block nested inside another block' => array( - 'filename' => 'template-with-nested-template-part.html', - 'expected' => sprintf( - ' - -', - $theme - ), - ), - 'a template with a template part block with an existing theme attribute' => array( - 'filename' => 'template-with-template-part-with-existing-theme-attribute.html', - 'expected' => '', - ), - 'a template with no template part block' => array( - 'filename' => 'template.html', - 'expected' => ' -

Just a paragraph

-', - ), - ); - } - /** * @ticket 59338 * diff --git a/tests/phpunit/tests/blocks/renderBlockCoreTemplatePart.php b/tests/phpunit/tests/blocks/renderBlockCoreTemplatePart.php new file mode 100644 index 0000000000000..b85c4c821d6f6 --- /dev/null +++ b/tests/phpunit/tests/blocks/renderBlockCoreTemplatePart.php @@ -0,0 +1,121 @@ +original_block_to_render = WP_Block_Supports::$block_to_render; + } + + public function tear_down() { + WP_Block_Supports::$block_to_render = $this->original_block_to_render; + $this->original_block_to_render = null; + + if ( $this->switch_to_default_theme_at_teardown ) { + $this->switch_to_default_theme_at_teardown = false; + switch_theme( WP_DEFAULT_THEME ); + } + + parent::tear_down(); + } + + /** + * Tests that the core template part block assumes the current theme if no theme attribute provided. + * + * @ticket 59583 + */ + public function test_render_block_core_template_part_without_theme_attribute() { + $this->maybe_switch_theme( 'block-theme' ); + + WP_Block_Supports::$block_to_render = array( 'blockName' => 'core/template-part' ); + + $content = render_block_core_template_part( array( 'slug' => 'small-header' ) ); + + $expected = '
' . "\n"; + $expected .= '

Small Header Template Part

' . "\n"; + $expected .= '
'; + + $this->assertSame( $expected, $content ); + } + + /** + * Tests that the core template part block returns the relevant part if current theme attribute provided. + * + * @ticket 59583 + */ + public function test_render_block_core_template_part_with_current_theme_attribute() { + $this->maybe_switch_theme( 'block-theme' ); + + WP_Block_Supports::$block_to_render = array( 'blockName' => 'core/template-part' ); + + $content = render_block_core_template_part( + array( + 'slug' => 'small-header', + 'theme' => 'block-theme', + ) + ); + + $expected = '
' . "\n"; + $expected .= '

Small Header Template Part

' . "\n"; + $expected .= '
'; + + $this->assertSame( $expected, $content ); + } + + /** + * Tests that the core template part block returns nothing if theme attribute for a different theme provided. + * + * @ticket 59583 + */ + public function test_render_block_core_template_part_with_another_theme_attribute() { + $this->maybe_switch_theme( 'block-theme' ); + + WP_Block_Supports::$block_to_render = array( 'blockName' => 'core/template-part' ); + + $content = render_block_core_template_part( + array( + 'slug' => 'small-header', + 'theme' => WP_DEFAULT_THEME, + ) + ); + + $expected = 'Template part has been deleted or is unavailable: small-header'; + $this->assertSame( $expected, $content ); + } + + /** + * Switches the theme when not the default theme. + * + * @param string $theme Theme name to switch to. + */ + private function maybe_switch_theme( $theme ) { + if ( WP_DEFAULT_THEME === $theme ) { + return; + } + + switch_theme( $theme ); + $this->switch_to_default_theme_at_teardown = true; + } +} diff --git a/tests/phpunit/tests/blocks/wpGetBlockPatterns.php b/tests/phpunit/tests/blocks/wpGetBlockPatterns.php index aea0fbc6f16af..4e7f67612bb92 100644 --- a/tests/phpunit/tests/blocks/wpGetBlockPatterns.php +++ b/tests/phpunit/tests/blocks/wpGetBlockPatterns.php @@ -18,7 +18,6 @@ class Tests_Blocks_WpGetBlockPatterns extends WP_UnitTestCase { * * @param string $theme The theme's slug. * @param array $expected The expected pattern data. - */ public function test_should_return_block_patterns( $theme, $expected ) { $patterns = _wp_get_block_patterns( wp_get_theme( $theme ) ); @@ -118,4 +117,37 @@ public function data_wp_get_block_patterns() { ), ); } + + /** + * Tests that _wp_get_block_patterns() clears existing transient when in theme development mode. + * + * @ticket 59591 + */ + public function test_should_clear_existing_transient_when_in_development_mode() { + $theme = wp_get_theme( 'block-theme-patterns' ); + + // Calling the function should set the cache. + _wp_get_block_patterns( $theme ); + $this->assertSameSets( + array( + 'cta.php' => array( + 'title' => 'Centered Call To Action', + 'slug' => 'block-theme-patterns/cta', + 'description' => '', + 'categories' => array( 'call-to-action' ), + ), + ), + $theme->get_pattern_cache(), + 'The transient for block theme patterns should be set' + ); + + // Calling the function while in theme development mode should clear the cache. + $GLOBALS['_wp_tests_development_mode'] = 'theme'; + _wp_get_block_patterns( $theme ); + unset( $GLOBALS['_wp_tests_development_mode'] ); // Reset to not pollute other tests. + $this->assertFalse( + $theme->get_pattern_cache(), + 'The transient for block theme patterns should have been cleared due to theme development mode' + ); + } } diff --git a/tests/phpunit/tests/dependencies/scripts.php b/tests/phpunit/tests/dependencies/scripts.php index 1b1d63b86deb7..a49c8f783c6da 100644 --- a/tests/phpunit/tests/dependencies/scripts.php +++ b/tests/phpunit/tests/dependencies/scripts.php @@ -3146,4 +3146,291 @@ protected function assertEqualMarkup( $expected, $actual, $message = '' ) { protected function add_html5_script_theme_support() { add_theme_support( 'html5', array( 'script' ) ); } + + /** + * Test that a script is moved to the footer if it is made non-deferrable, was in the header and + * all scripts that depend on it are in the footer. + * + * @ticket 58599 + * + * @dataProvider data_provider_script_move_to_footer + * + * @param callable $set_up Test setup. + * @param string $expected_header Expected output for header. + * @param string $expected_footer Expected output for footer. + * @param string[] $expected_in_footer Handles expected to be in the footer. + * @param array $expected_groups Expected groups. + */ + public function test_wp_scripts_move_to_footer( $set_up, $expected_header, $expected_footer, $expected_in_footer, $expected_groups ) { + $set_up(); + + // Get the header output. + ob_start(); + wp_scripts()->do_head_items(); + $header = ob_get_clean(); + + // Print a script in the body just to make sure it doesn't cause problems. + ob_start(); + wp_print_scripts( array( 'jquery' ) ); + ob_end_clean(); + + // Get the footer output. + ob_start(); + wp_scripts()->do_footer_items(); + $footer = ob_get_clean(); + + $this->assertEqualMarkup( $expected_header, $header, 'Expected header script markup to match.' ); + $this->assertEqualMarkup( $expected_footer, $footer, 'Expected footer script markup to match.' ); + $this->assertEqualSets( $expected_in_footer, wp_scripts()->in_footer, 'Expected to have the same handles for in_footer.' ); + $this->assertEquals( $expected_groups, wp_scripts()->groups, 'Expected groups to match.' ); + } + + /** + * Data provider for test_wp_scripts_move_to_footer. + * + * @return array[] + */ + public function data_provider_script_move_to_footer() { + return array( + 'footer-blocking-dependent-of-defer-head-script' => array( + 'set_up' => static function () { + wp_enqueue_script( 'script-a', 'https://example.com/script-a.js', array(), null, array( 'strategy' => 'defer' ) ); + wp_enqueue_script( 'script-b', 'https://example.com/script-b.js', array( 'script-a' ), null, array( 'in_footer' => true ) ); + }, + 'expected_header' => '', + 'expected_footer' => ' + + + ', + 'expected_in_footer' => array( + 'script-a', + 'script-b', + ), + 'expected_groups' => array( + 'script-a' => 0, + 'script-b' => 1, + 'jquery' => 0, + ), + ), + + 'footer-blocking-dependent-of-async-head-script' => array( + 'set_up' => static function () { + wp_enqueue_script( 'script-a', 'https://example.com/script-a.js', array(), null, array( 'strategy' => 'async' ) ); + wp_enqueue_script( 'script-b', 'https://example.com/script-b.js', array( 'script-a' ), null, array( 'in_footer' => true ) ); + }, + 'expected_header' => '', + 'expected_footer' => ' + + + ', + 'expected_in_footer' => array( + 'script-a', + 'script-b', + ), + 'expected_groups' => array( + 'script-a' => 0, + 'script-b' => 1, + 'jquery' => 0, + ), + ), + + 'head-blocking-dependent-of-delayed-head-script' => array( + 'set_up' => static function () { + wp_enqueue_script( 'script-a', 'https://example.com/script-a.js', array(), null, array( 'strategy' => 'defer' ) ); + wp_enqueue_script( 'script-b', 'https://example.com/script-b.js', array( 'script-a' ), null, array( 'in_footer' => false ) ); + }, + 'expected_header' => ' + + + ', + 'expected_footer' => '', + 'expected_in_footer' => array(), + 'expected_groups' => array( + 'script-a' => 0, + 'script-b' => 0, + 'jquery' => 0, + ), + ), + + 'delayed-footer-dependent-of-delayed-head-script' => array( + 'set_up' => static function () { + wp_enqueue_script( 'script-a', 'https://example.com/script-a.js', array(), null, array( 'strategy' => 'defer' ) ); + wp_enqueue_script( + 'script-b', + 'https://example.com/script-b.js', + array( 'script-a' ), + null, + array( + 'strategy' => 'defer', + 'in_footer' => true, + ) + ); + }, + 'expected_header' => ' + + ', + 'expected_footer' => ' + + ', + 'expected_in_footer' => array( + 'script-b', + ), + 'expected_groups' => array( + 'script-a' => 0, + 'script-b' => 1, + 'jquery' => 0, + ), + ), + + 'delayed-dependent-in-header-and-delayed-dependents-in-footer' => array( + 'set_up' => static function () { + wp_enqueue_script( 'script-a', 'https://example.com/script-a.js', array(), null, array( 'strategy' => 'defer' ) ); + wp_enqueue_script( + 'script-b', + 'https://example.com/script-b.js', + array( 'script-a' ), + null, + array( + 'strategy' => 'defer', + 'in_footer' => false, + ) + ); + wp_enqueue_script( + 'script-c', + 'https://example.com/script-c.js', + array( 'script-a' ), + null, + array( + 'strategy' => 'defer', + 'in_footer' => true, + ) + ); + wp_enqueue_script( + 'script-d', + 'https://example.com/script-d.js', + array( 'script-a' ), + null, + array( + 'strategy' => 'defer', + 'in_footer' => true, + ) + ); + }, + 'expected_header' => ' + + + ', + 'expected_footer' => ' + + + ', + 'expected_in_footer' => array( + 'script-c', + 'script-d', + ), + 'expected_groups' => array( + 'script-a' => 0, + 'script-b' => 0, + 'script-c' => 1, + 'script-d' => 1, + 'jquery' => 0, + ), + ), + + 'all-dependents-in-footer-with-one-blocking' => array( + 'set_up' => static function () { + wp_enqueue_script( 'script-a', 'https://example.com/script-a.js', array(), null, array( 'strategy' => 'defer' ) ); + wp_enqueue_script( + 'script-b', + 'https://example.com/script-b.js', + array( 'script-a' ), + null, + array( + 'strategy' => 'defer', + 'in_footer' => true, + ) + ); + wp_enqueue_script( 'script-c', 'https://example.com/script-c.js', array( 'script-a' ), null, true ); + wp_enqueue_script( + 'script-d', + 'https://example.com/script-d.js', + array( 'script-a' ), + null, + array( + 'strategy' => 'defer', + 'in_footer' => true, + ) + ); + }, + 'expected_header' => '', + 'expected_footer' => ' + + + + + ', + 'expected_in_footer' => array( + 'script-a', + 'script-b', + 'script-c', + 'script-d', + ), + 'expected_groups' => array( + 'script-a' => 0, + 'script-b' => 1, + 'script-c' => 1, + 'script-d' => 1, + 'jquery' => 0, + + ), + ), + + 'blocking-dependents-in-head-and-footer' => array( + 'set_up' => static function () { + wp_enqueue_script( 'script-a', 'https://example.com/script-a.js', array(), null, array( 'strategy' => 'defer' ) ); + wp_enqueue_script( + 'script-b', + 'https://example.com/script-b.js', + array( 'script-a' ), + null, + array( + 'strategy' => 'defer', + 'in_footer' => false, + ) + ); + wp_enqueue_script( 'script-c', 'https://example.com/script-c.js', array( 'script-a' ), null, true ); + wp_enqueue_script( + 'script-d', + 'https://example.com/script-d.js', + array( 'script-a' ), + null, + array( + 'strategy' => 'defer', + 'in_footer' => true, + ) + ); + }, + 'expected_header' => ' + + + ', + 'expected_footer' => ' + + + ', + 'expected_in_footer' => array( + 'script-c', + 'script-d', + ), + 'expected_groups' => array( + 'script-a' => 0, + 'script-b' => 0, + 'script-c' => 1, + 'script-d' => 1, + 'jquery' => 0, + ), + ), + + ); + } } diff --git a/tests/phpunit/tests/option/networkOption.php b/tests/phpunit/tests/option/networkOption.php index 7ae19abbeeaee..2b0bed6504b5b 100644 --- a/tests/phpunit/tests/option/networkOption.php +++ b/tests/phpunit/tests/option/networkOption.php @@ -399,7 +399,7 @@ public function data_loosely_equal_values_that_should_update() { * @param mixed $old_value The old value. * @param mixed $new_value The new value to try to set. */ - public function test_update_option_should_not_update_some_values_from_cache( $old_value, $new_value ) { + public function test_update_network_option_should_not_update_some_values_from_cache( $old_value, $new_value ) { add_network_option( null, 'foo', $old_value ); $num_queries = get_num_queries(); @@ -407,9 +407,7 @@ public function test_update_option_should_not_update_some_values_from_cache( $ol // Comparison will happen against value cached during add_option() above. $updated = update_network_option( null, 'foo', $new_value ); - $expected_queries = $old_value === $new_value || ! is_multisite() ? 0 : 1; - $this->assertSame( $expected_queries, get_num_queries() - $num_queries, "The number of queries should have increased by $expected_queries." ); - + $this->assertSame( $num_queries, get_num_queries(), 'No additional queries should have run.' ); $this->assertFalse( $updated, 'update_network_option() should have returned false.' ); } @@ -441,14 +439,7 @@ public function test_update_network_option_should_not_update_some_values_from_db $updated = update_network_option( null, 'foo', $new_value ); - // Mimic the behavior of the database by casting the old value to string. - if ( is_scalar( $old_value ) ) { - $old_value = (string) $old_value; - } - - $expected_queries = $old_value === $new_value || ! is_multisite() ? 1 : 2; - $this->assertSame( $expected_queries, get_num_queries() - $num_queries, "The number of queries should have increased by $expected_queries." ); - + $this->assertSame( 1, get_num_queries() - $num_queries, 'One additional query should have run to update the value.' ); $this->assertFalse( $updated, 'update_network_option() should have returned false.' ); } @@ -480,9 +471,7 @@ public function test_update_network_option_should_not_update_some_values_from_re * Strictly equal old and new values will cause an early return * with no additional queries. */ - $expected_queries = $old_value === $new_value || ! is_multisite() ? 0 : 1; - $this->assertSame( $expected_queries, get_num_queries() - $num_queries, "The number of queries should have increased by $expected_queries." ); - + $this->assertSame( $num_queries, get_num_queries(), 'No additional queries should have run.' ); $this->assertFalse( $updated, 'update_network_option() should have returned false.' ); } @@ -574,7 +563,7 @@ public function data_strictly_equal_values() { * * @covers ::update_network_option */ - public function test_update_option_should_handle_a_null_new_value_from_cache() { + public function test_update_network_option_should_handle_a_null_new_value_from_cache() { add_network_option( null, 'foo', '' ); $num_queries = get_num_queries(); @@ -606,7 +595,7 @@ public function test_update_option_should_handle_a_null_new_value_from_cache() { * * @covers ::update_network_option */ - public function test_update_option_should_handle_a_null_new_value_from_db() { + public function test_update_network_option_should_handle_a_null_new_value_from_db() { add_network_option( null, 'foo', '' ); $num_queries = get_num_queries(); @@ -642,7 +631,7 @@ public function test_update_option_should_handle_a_null_new_value_from_db() { * * @covers ::update_network_option */ - public function test_update_option_should_handle_a_null_new_value_from_refreshed_cache() { + public function test_update_network_option_should_handle_a_null_new_value_from_refreshed_cache() { add_network_option( null, 'foo', '' ); // Delete and refresh cache from DB. @@ -699,4 +688,166 @@ public function data_stored_as_empty_string() { 'null' => array( null ), ); } + + /** + * Tests that a non-existent option is added even when its pre filter returns a value. + * + * @ticket 59360 + * + * @covers ::update_network_option + */ + public function test_update_network_option_with_pre_filter_adds_missing_option() { + $hook_name = is_multisite() ? 'pre_site_option_foo' : 'pre_option_foo'; + + // Force a return value of integer 0. + add_filter( $hook_name, '__return_zero' ); + + /* + * This should succeed, since the 'foo' option does not exist in the database. + * The default value is false, so it differs from 0. + */ + $this->assertTrue( update_network_option( null, 'foo', 0 ) ); + } + + /** + * Tests that an existing option is updated even when its pre filter returns the same value. + * + * @ticket 59360 + * + * @covers ::update_network_option + */ + public function test_update_network_option_with_pre_filter_updates_option_with_different_value() { + $hook_name = is_multisite() ? 'pre_site_option_foo' : 'pre_option_foo'; + + // Add the option with a value of 1 to the database. + update_network_option( null, 'foo', 1 ); + + // Force a return value of integer 0. + add_filter( $hook_name, '__return_zero' ); + + /* + * This should succeed, since the 'foo' option has a value of 1 in the database. + * Therefore it differs from 0 and should be updated. + */ + $this->assertTrue( update_network_option( null, 'foo', 0 ) ); + } + + /** + * Tests that calling update_network_option() does not permanently remove pre filters. + * + * @ticket 59360 + * + * @covers ::update_network_option + */ + public function test_update_network_option_maintains_pre_filters() { + $hook_name = is_multisite() ? 'pre_site_option_foo' : 'pre_option_foo'; + + add_filter( $hook_name, '__return_zero' ); + update_network_option( null, 'foo', 0 ); + + // Assert that the filter is still present. + $this->assertSame( 10, has_filter( $hook_name, '__return_zero' ) ); + } + + /** + * Tests that update_network_option() conditionally applies + * 'pre_site_option_{$option}' and 'pre_option_{$option}' filters. + * + * @ticket 59360 + * + * @covers ::update_network_option + */ + public function test_update_network_option_should_conditionally_apply_pre_site_option_and_pre_option_filters() { + $option = 'foo'; + $site_hook = new MockAction(); + $option_hook = new MockAction(); + + add_filter( "pre_site_option_{$option}", array( $site_hook, 'filter' ) ); + add_filter( "pre_option_{$option}", array( $option_hook, 'filter' ) ); + + update_network_option( null, $option, 'false' ); + + $this->assertSame( 1, $site_hook->get_call_count(), "'pre_site_option_{$option}' filters occurred an unexpected number of times." ); + $this->assertSame( is_multisite() ? 0 : 1, $option_hook->get_call_count(), "'pre_option_{$option}' filters occurred an unexpected number of times." ); + } + + /** + * Tests that update_network_option() conditionally applies + * 'default_site_{$option}' and 'default_option_{$option}' filters. + * + * @ticket 59360 + * + * @covers ::update_network_option + */ + public function test_update_network_option_should_conditionally_apply_site_and_option_default_value_filters() { + $option = 'foo'; + $site_hook = new MockAction(); + $option_hook = new MockAction(); + + add_filter( "default_site_option_{$option}", array( $site_hook, 'filter' ) ); + add_filter( "default_option_{$option}", array( $option_hook, 'filter' ) ); + + update_network_option( null, $option, 'false' ); + + $this->assertSame( 2, $site_hook->get_call_count(), "'default_site_option_{$option}' filters occurred an unexpected number of times." ); + $this->assertSame( is_multisite() ? 0 : 2, $option_hook->get_call_count(), "'default_option_{$option}' filters occurred an unexpected number of times." ); + } + + /** + * Tests that update_network_option() adds a non-existent option that uses a filtered default value. + * + * @ticket 59360 + * + * @covers ::update_network_option + */ + public function test_update_network_option_should_add_option_with_filtered_default_value() { + global $wpdb; + + $option = 'foo'; + $default_site_value = 'default-site-value'; + $default_option_value = 'default-option-value'; + + add_filter( + "default_site_option_{$option}", + static function () use ( $default_site_value ) { + return $default_site_value; + } + ); + + add_filter( + "default_option_{$option}", + static function () use ( $default_option_value ) { + return $default_option_value; + } + ); + + /* + * For a non existing option with the unfiltered default of false, passing false here wouldn't work. + * Because the default is different than false here though, passing false is expected to result in + * a database update. + */ + $this->assertTrue( update_network_option( null, $option, false ), 'update_network_option() should have returned true.' ); + + if ( is_multisite() ) { + $actual = $wpdb->get_row( + $wpdb->prepare( + "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = %s LIMIT 1", + $option + ) + ); + } else { + $actual = $wpdb->get_row( + $wpdb->prepare( + "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", + $option + ) + ); + } + + $value_field = is_multisite() ? 'meta_value' : 'option_value'; + + $this->assertIsObject( $actual, 'The option was not added to the database.' ); + $this->assertObjectHasProperty( $value_field, $actual, "The '$value_field' property was not included." ); + $this->assertSame( '', $actual->$value_field, 'The new value was not stored in the database.' ); + } } diff --git a/tests/phpunit/tests/option/registration.php b/tests/phpunit/tests/option/registration.php index 04991e4a33832..9b0e418c91c57 100644 --- a/tests/phpunit/tests/option/registration.php +++ b/tests/phpunit/tests/option/registration.php @@ -149,4 +149,18 @@ public function test_unregister_setting_removes_default() { $this->assertFalse( has_filter( 'default_option_test_default', 'filter_default_option' ) ); } + + /** + * The test passes if a Notice | Warning | Error is not raised. Thus. the absence of a Notice | Warning | Error + * is an indicator the fix in the ticket resolves the issue. + * + * @ticket 57674 + * + * @covers ::unregister_setting + */ + public function test_unregister_invalid_setting_does_not_raise_php_notice_warning_or_error() { + $setting = uniqid(); + unregister_setting( $setting, $setting ); + $this->assertFalse( has_filter( 'default_option_' . $setting, 'filter_default_option' ) ); + } } diff --git a/tests/phpunit/tests/post/primePostParentsCaches.php b/tests/phpunit/tests/post/primePostParentsCaches.php index a430450aabcf7..1379aa4afbe94 100644 --- a/tests/phpunit/tests/post/primePostParentsCaches.php +++ b/tests/phpunit/tests/post/primePostParentsCaches.php @@ -1,19 +1,19 @@ assertSame( 1, $num_queries, 'Unexpected number of queries.' ); - $this->assertSameSets( array( 0 ), wp_cache_get_multiple( array( $post_id ), 'post_parent' ), 'Array of parent ids' ); + $this->assertSameSets( array( 0 ), wp_cache_get_multiple( array( "post_parent:{$post_id}" ), 'posts' ), 'Array of parent ids' ); } /** * @ticket 59188 */ - public function test_prime_post_parents_caches_multiple() { + public function test_prime_post_parent_id_caches_multiple() { $before_num_queries = get_num_queries(); - _prime_post_parents_caches( self::$posts ); + _prime_post_parent_id_caches( self::$posts ); $num_queries = get_num_queries() - $before_num_queries; + $cache_keys = array_map( + function ( $post_id ) { + return "post_parent:{$post_id}"; + }, + self::$posts + ); + $this->assertSame( 1, $num_queries, 'Unexpected number of queries.' ); - $this->assertSameSets( array( 0, 0, 0 ), wp_cache_get_multiple( self::$posts, 'post_parent' ), 'Array of parent ids' ); + $this->assertSameSets( array( 0, 0, 0 ), wp_cache_get_multiple( $cache_keys, 'posts' ), 'Array of parent ids' ); } /** * @ticket 59188 */ - public function test_prime_post_parents_caches_multiple_runs() { - _prime_post_parents_caches( self::$posts ); + public function test_prime_post_parent_id_caches_multiple_runs() { + _prime_post_parent_id_caches( self::$posts ); $before_num_queries = get_num_queries(); - _prime_post_parents_caches( self::$posts ); + _prime_post_parent_id_caches( self::$posts ); $num_queries = get_num_queries() - $before_num_queries; $this->assertSame( 0, $num_queries, 'Unexpected number of queries.' ); @@ -72,7 +79,7 @@ public function test_prime_post_parents_caches_multiple_runs() { /** * @ticket 59188 */ - public function test_prime_post_parents_caches_update() { + public function test_prime_post_parent_id_caches_update() { $page_id = self::factory()->post->create( array( 'post_type' => 'page', @@ -80,11 +87,11 @@ public function test_prime_post_parents_caches_update() { ) ); $before_num_queries = get_num_queries(); - _prime_post_parents_caches( array( $page_id ) ); + _prime_post_parent_id_caches( array( $page_id ) ); $num_queries = get_num_queries() - $before_num_queries; $this->assertSame( 1, $num_queries, 'Unexpected number of queries on first run' ); - $this->assertSameSets( array( self::$posts[0] ), wp_cache_get_multiple( array( $page_id ), 'post_parent' ), 'Array of parent ids with post 0 as parent' ); + $this->assertSameSets( array( self::$posts[0] ), wp_cache_get_multiple( array( "post_parent:{$page_id}" ), 'posts' ), 'Array of parent ids with post 0 as parent' ); wp_update_post( array( @@ -94,17 +101,17 @@ public function test_prime_post_parents_caches_update() { ); $before_num_queries = get_num_queries(); - _prime_post_parents_caches( array( $page_id ) ); + _prime_post_parent_id_caches( array( $page_id ) ); $num_queries = get_num_queries() - $before_num_queries; $this->assertSame( 1, $num_queries, 'Unexpected number of queries on second run' ); - $this->assertSameSets( array( self::$posts[1] ), wp_cache_get_multiple( array( $page_id ), 'post_parent' ), 'Array of parent ids with post 1 as parent' ); + $this->assertSameSets( array( self::$posts[1] ), wp_cache_get_multiple( array( "post_parent:{$page_id}" ), 'posts' ), 'Array of parent ids with post 1 as parent' ); } /** * @ticket 59188 */ - public function test_prime_post_parents_caches_delete() { + public function test_prime_post_parent_id_caches_delete() { $parent_page_id = self::factory()->post->create( array( 'post_type' => 'page', @@ -117,15 +124,15 @@ public function test_prime_post_parents_caches_delete() { ) ); $before_num_queries = get_num_queries(); - _prime_post_parents_caches( array( $page_id ) ); + _prime_post_parent_id_caches( array( $page_id ) ); $num_queries = get_num_queries() - $before_num_queries; $this->assertSame( 1, $num_queries, 'Unexpected number of queries on first run' ); - $this->assertSameSets( array( $parent_page_id ), wp_cache_get_multiple( array( $page_id ), 'post_parent' ), 'Array of parent ids with post 0 as parent' ); + $this->assertSameSets( array( $parent_page_id ), wp_cache_get_multiple( array( "post_parent:{$page_id}" ), 'posts' ), 'Array of parent ids with post 0 as parent' ); wp_delete_post( $parent_page_id, true ); $this->assertSame( 1, $num_queries, 'Unexpected number of queries on second run' ); - $this->assertSameSets( array( false ), wp_cache_get_multiple( array( $page_id ), 'post_parent' ), 'Array of parent ids with false values' ); + $this->assertSameSets( array( false ), wp_cache_get_multiple( array( "post_parent:{$page_id}" ), 'posts' ), 'Array of parent ids with false values' ); } } diff --git a/tests/phpunit/tests/post/wpPostType.php b/tests/phpunit/tests/post/wpPostType.php index 8443c804ad868..2a8ad42f0a2ca 100644 --- a/tests/phpunit/tests/post/wpPostType.php +++ b/tests/phpunit/tests/post/wpPostType.php @@ -229,4 +229,214 @@ public function test_applies_registration_args_filters() { $this->assertSame( 3, $action->get_call_count() ); } + + /** + * @ticket 56922 + * + * @dataProvider data_should_have_correct_custom_revisions_and_autosaves_controllers_properties + * + * @covers WP_Post_Type::set_props + * + * @param string $property_name Property name. + * @param string $property_value Property value. + * @param string|bool $expected_property_value Expected property value. + */ + public function test_should_have_correct_custom_revisions_and_autosaves_controllers_properties( $property_name, $property_value, $expected_property_value ) { + $properties = null === $property_value ? array() : array( $property_name => $property_value ); + + $post_type = new WP_Post_Type( 'test_post_type', $properties ); + + $this->assertObjectHasProperty( $property_name, $post_type, "The WP_Post_Type object does not have the expected {$property_name} property." ); + $this->assertSame( + $expected_property_value, + $post_type->$property_name, + sprintf( 'Expected the property "%s" to have the %s value.', $property_name, var_export( $expected_property_value, true ) ) + ); + } + + /** + * Data provider for test_should_allow_to_set_custom_revisions_and_autosaves_controllers_properties. + * + * @return array[] Arguments { + * @type string $property_name Property name. + * @type string $property_value Property value. + * @type string|bool $expected_property_value Expected property value. + * } + */ + public function data_should_have_correct_custom_revisions_and_autosaves_controllers_properties() { + return array( + 'autosave_rest_controller_class property' => array( + 'autosave_rest_controller_class', + 'My_Custom_Template_Autosaves_Controller', + 'My_Custom_Template_Autosaves_Controller', + ), + 'autosave_rest_controller_class property (null value)' => array( + 'autosave_rest_controller_class', + null, + false, + ), + 'revisions_rest_controller_class property' => array( + 'revisions_rest_controller_class', + 'My_Custom_Template_Revisions_Controller', + 'My_Custom_Template_Revisions_Controller', + ), + 'revisions_rest_controller_class property (null value)' => array( + 'revisions_rest_controller_class', + null, + false, + ), + ); + } + + /** + * @ticket 56922 + * + * @covers WP_Post_Type::get_revisions_rest_controller + * + * @dataProvider data_get_revisions_rest_controller_should_return_correct_values + * + * @param bool $show_in_rest Enables "show_in_rest" support. + * @param bool $supports_revisions Enables revisions support. + * @param string|bool $revisions_rest_controller_class Custom revisions REST controller class. + * @param string|null $expected_value Expected value. + */ + public function test_get_revisions_rest_controller_should_return_correct_values( $show_in_rest, $supports_revisions, $revisions_rest_controller_class, $expected_value ) { + $post_type = 'test_post_type'; + $properties = array( + 'show_in_rest' => $show_in_rest, + 'supports' => $supports_revisions ? array( 'revisions' ) : array(), + 'revisions_rest_controller_class' => $revisions_rest_controller_class, + ); + register_post_type( $post_type, $properties ); + $post_type = get_post_type_object( $post_type ); + + $controller = $post_type->get_revisions_rest_controller(); + if ( $expected_value ) { + $this->assertInstanceOf( $expected_value, $controller ); + + return; + } + + $this->assertSame( $expected_value, $controller ); + } + + /** + * Data provider for test_get_revisions_rest_controller_should_return_correct_values. + * + * @return array[] Arguments { + * @type bool $show_in_rest Enables "show_in_rest" support. + * @type bool $supports_revisions Enables revisions support. + * @type string|bool $revisions_rest_controller_class Custom revisions REST controller class. + * @type string|null $expected_value Expected value. + * } + */ + public function data_get_revisions_rest_controller_should_return_correct_values() { + return array( + 'disable show_in_rest' => array( + false, + false, + false, + null, + ), + 'disable revisions support' => array( + true, + false, + false, + null, + ), + 'default rest revisions controller' => array( + true, + true, + false, + WP_REST_Revisions_Controller::class, + ), + 'incorrect rest revisions controller' => array( + true, + true, + stdClass::class, + null, + ), + 'correct rest revisions controller' => array( + true, + true, + WP_REST_Template_Revisions_Controller::class, + WP_REST_Template_Revisions_Controller::class, + ), + ); + } + + /** + * @ticket 56922 + * + * @covers WP_Post_Type::get_autosave_rest_controller + * + * @dataProvider data_get_autosave_rest_controller_should_return_correct_values + * + * @param bool $show_in_rest Enables "show_in_rest" support. + * @param string $post_type Post type. + * @param string|bool $autosave_rest_controller_class Custom autosave REST controller class. + * @param string|null $expected_value Expected value. + */ + public function test_get_autosave_rest_controller_should_return_correct_values( $show_in_rest, $post_type, $autosave_rest_controller_class, $expected_value ) { + $properties = array( + 'show_in_rest' => $show_in_rest, + 'autosave_rest_controller_class' => $autosave_rest_controller_class, + ); + register_post_type( $post_type, $properties ); + $post_type = get_post_type_object( $post_type ); + + $controller = $post_type->get_autosave_rest_controller(); + if ( $expected_value ) { + $this->assertInstanceOf( $expected_value, $controller ); + + return; + } + + $this->assertSame( $expected_value, $controller ); + } + + /** + * Data provider for test_get_autosave_rest_controller_should_return_correct_values. + * + * @return array[] Arguments { + * @type bool $show_in_rest Enables "show_in_rest" support. + * @type string $post_type Post type. + * @type string|bool $autosave_rest_controller_class Custom autosave REST controller class. + * @type string|null $expected_value Expected value. + * } + */ + public function data_get_autosave_rest_controller_should_return_correct_values() { + return array( + 'disable show_in_rest' => array( + false, + 'attachment', + false, + null, + ), + 'invalid post type' => array( + true, + 'attachment', + false, + null, + ), + 'default rest autosave controller' => array( + true, + 'test_post_type', + false, + WP_REST_Autosaves_Controller::class, + ), + 'incorrect rest autosave controller' => array( + true, + 'test_post_type', + stdClass::class, + null, + ), + 'correct rest autosave controller' => array( + true, + 'test_post_type', + WP_REST_Template_Autosaves_Controller::class, + WP_REST_Template_Autosaves_Controller::class, + ), + ); + } } diff --git a/tests/phpunit/tests/query/cacheResults.php b/tests/phpunit/tests/query/cacheResults.php index 3e2d405850ff4..dace2e313b33e 100644 --- a/tests/phpunit/tests/query/cacheResults.php +++ b/tests/phpunit/tests/query/cacheResults.php @@ -738,8 +738,15 @@ public function test_query_cache_unprimed_parents() { $query1 = new WP_Query(); $query1->query( $args ); - $post_ids = wp_list_pluck( $query1->posts, 'ID' ); - wp_cache_delete_multiple( $post_ids, 'post_parent' ); + $post_ids = wp_list_pluck( $query1->posts, 'ID' ); + $cache_keys = array_map( + function ( $post_id ) { + return "post_parent:{$post_id}"; + }, + $post_ids + ); + + wp_cache_delete_multiple( $cache_keys, 'posts' ); $queries_before = get_num_queries(); $query2 = new WP_Query(); diff --git a/tests/phpunit/tests/query/invalidQueries.php b/tests/phpunit/tests/query/invalidQueries.php index 4c0b631f8057b..0cec94224567d 100644 --- a/tests/phpunit/tests/query/invalidQueries.php +++ b/tests/phpunit/tests/query/invalidQueries.php @@ -159,4 +159,20 @@ public function test_deprecated_parameters_have_no_effect_on_post() { // Only the published post should be returned. $this->assertCount( 1, $query->posts ); } + + /** + * Ensure a non-scalar page parameter does not throw a fatal error for trim(). + * + * @ticket 56558 + * @covers WP_Query::get_posts + */ + public function test_non_scalar_page_value() { + $query = new WP_Query( + array( + 'page' => array( 1, 2, 3 ), + ) + ); + + $this->assertSame( 0, $query->query_vars['page'] ); + } } diff --git a/tests/phpunit/tests/rest-api/rest-schema-setup.php b/tests/phpunit/tests/rest-api/rest-schema-setup.php index dfd98877d8ed3..c53f887bc822c 100644 --- a/tests/phpunit/tests/rest-api/rest-schema-setup.php +++ b/tests/phpunit/tests/rest-api/rest-schema-setup.php @@ -144,18 +144,18 @@ public function test_expected_routes_in_schema() { '/wp/v2/block-types/(?P[a-zA-Z0-9_-]+)/(?P[a-zA-Z0-9_-]+)', '/wp/v2/settings', '/wp/v2/template-parts', - '/wp/v2/template-parts/(?P[\d]+)/autosaves', '/wp/v2/template-parts/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)', - '/wp/v2/template-parts/(?P[\d]+)/autosaves/(?P[\d]+)', - '/wp/v2/template-parts/(?P[\d]+)/revisions', - '/wp/v2/template-parts/(?P[\d]+)/revisions/(?P[\d]+)', + '/wp/v2/template-parts/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/autosaves', + '/wp/v2/template-parts/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/autosaves/(?P[\d]+)', + '/wp/v2/template-parts/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/revisions', + '/wp/v2/template-parts/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/revisions/(?P[\d]+)', '/wp/v2/template-parts/lookup', '/wp/v2/templates', - '/wp/v2/templates/(?P[\d]+)/autosaves', '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)', - '/wp/v2/templates/(?P[\d]+)/autosaves/(?P[\d]+)', - '/wp/v2/templates/(?P[\d]+)/revisions', - '/wp/v2/templates/(?P[\d]+)/revisions/(?P[\d]+)', + '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/autosaves', + '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/autosaves/(?P[\d]+)', + '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/revisions', + '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/revisions/(?P[\d]+)', '/wp/v2/templates/lookup', '/wp/v2/themes', '/wp/v2/themes/(?P[^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)', diff --git a/tests/phpunit/tests/rest-api/rest-users-controller.php b/tests/phpunit/tests/rest-api/rest-users-controller.php index f4dbc2d57f379..ac5b0741e90a0 100644 --- a/tests/phpunit/tests/rest-api/rest-users-controller.php +++ b/tests/phpunit/tests/rest-api/rest-users-controller.php @@ -691,6 +691,25 @@ public function test_get_items_search() { $this->assertSame( $adam_id, $data[0]['id'] ); } + public function test_get_items_search_fields() { + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'search', 'yololololo' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertCount( 0, $response->get_data() ); + + $yolo_id = self::factory()->user->create( array( 'user_email' => 'yololololo@example.localhost' ) ); + + wp_set_current_user( self::$user ); + $request = new WP_REST_Request( 'GET', '/wp/v2/users' ); + $request->set_param( 'search', 'yololololo' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertCount( 1, $response->get_data() ); + + wp_set_current_user( self::$editor ); + $response = rest_get_server()->dispatch( $request ); + $this->assertCount( 0, $response->get_data() ); + } + public function test_get_items_slug_query() { wp_set_current_user( self::$user ); diff --git a/tests/phpunit/tests/rest-api/wpRestTemplateAutosavesController.php b/tests/phpunit/tests/rest-api/wpRestTemplateAutosavesController.php new file mode 100644 index 0000000000000..9452a188433be --- /dev/null +++ b/tests/phpunit/tests/rest-api/wpRestTemplateAutosavesController.php @@ -0,0 +1,413 @@ +user->create( + array( + 'role' => 'contributor', + ) + ); + + self::$admin_id = $factory->user->create( + array( + 'role' => 'administrator', + ) + ); + wp_set_current_user( self::$admin_id ); + + // Set up template post. + self::$template_post = $factory->post->create_and_get( + array( + 'post_type' => self::PARENT_POST_TYPE, + 'post_name' => self::TEMPLATE_NAME, + 'post_title' => 'My Template', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my template', + 'tax_input' => array( + 'wp_theme' => array( + self::TEST_THEME, + ), + ), + ) + ); + wp_set_post_terms( self::$template_post->ID, self::TEST_THEME, 'wp_theme' ); + } + + /** + * @covers WP_REST_Template_Autosaves_Controller::register_routes + * @ticket 56922 + */ + public function test_register_routes() { + $routes = rest_get_server()->get_routes(); + $this->assertArrayHasKey( + '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/autosaves', + $routes, + 'Template autosaves route does not exist.' + ); + $this->assertArrayHasKey( + '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/autosaves/(?P[\d]+)', + $routes, + 'Single template autosave based on the given ID route does not exist.' + ); + $this->assertArrayHasKey( + '/wp/v2/template-parts/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/autosaves', + $routes, + 'Template part autosaves route does not exist.' + ); + $this->assertArrayHasKey( + '/wp/v2/template-parts/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/autosaves/(?P[\d]+)', + $routes, + 'Single template part autosave based on the given ID route does not exist.' + ); + } + + /** + * @covers WP_REST_Template_Autosaves_Controller::get_context_param + * @ticket 56922 + */ + public function test_context_param() { + // Collection. + $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/autosaves' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + // Collection. + $this->assertCount( + 2, + $data['endpoints'], + 'Failed to assert that the collection autosave endpoints count is 2.' + ); + $this->assertSame( + 'view', + $data['endpoints'][0]['args']['context']['default'], + 'Failed to assert that the default context for the GET collection endpoint is "view".' + ); + $this->assertSame( + array( 'view', 'embed', 'edit' ), + $data['endpoints'][0]['args']['context']['enum'], + "Failed to assert that the enum values for the GET collection endpoint are 'view', 'embed', and 'edit'." + ); + + // Single. + $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/autosaves/1' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $this->assertCount( + 1, + $data['endpoints'], + 'Failed to assert that the single autosave endpoints count is 1.' + ); + $this->assertSame( + 'view', + $data['endpoints'][0]['args']['context']['default'], + 'Failed to assert that the default context for the single autosave endpoint is "view".' + ); + $this->assertSame( + array( 'view', 'embed', 'edit' ), + $data['endpoints'][0]['args']['context']['enum'], + "Failed to assert that the enum values for the single autosave endpoint are 'view', 'embed', and 'edit'." + ); + } + + /** + * @covers WP_REST_Template_Autosaves_Controller::get_items + * @ticket 56922 + */ + public function test_get_items() { + wp_set_current_user( self::$admin_id ); + $autosave_post_id = wp_create_post_autosave( + array( + 'post_content' => 'Autosave content.', + 'post_ID' => self::$template_post->ID, + 'post_type' => self::PARENT_POST_TYPE, + ) + ); + + $request = new WP_REST_Request( + 'GET', + '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/autosaves' + ); + $response = rest_get_server()->dispatch( $request ); + $autosaves = $response->get_data(); + + $this->assertCount( + 1, + $autosaves, + 'Failed asserting that the response data contains exactly 1 item.' + ); + + $this->assertSame( + $autosave_post_id, + $autosaves[0]['wp_id'], + 'Failed asserting that the ID of the autosave matches the expected autosave post ID.' + ); + $this->assertSame( + self::$template_post->ID, + $autosaves[0]['parent'], + 'Failed asserting that the parent ID of the autosave matches the template post ID.' + ); + $this->assertSame( + 'Autosave content.', + $autosaves[0]['content']['raw'], + 'Failed asserting that the content of the autosave is "Autosave content.".' + ); + } + + /** + * @covers WP_REST_Template_Autosaves_Controller::get_item + * @ticket 56922 + */ + public function test_get_item() { + wp_set_current_user( self::$admin_id ); + + $autosave_post_id = wp_create_post_autosave( + array( + 'post_content' => 'Autosave content.', + 'post_ID' => self::$template_post->ID, + 'post_type' => self::PARENT_POST_TYPE, + ) + ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/autosaves/' . $autosave_post_id ); + $response = rest_get_server()->dispatch( $request ); + $autosave = $response->get_data(); + + $this->assertIsArray( $autosave, 'Failed asserting that the autosave is an array.' ); + $this->assertSame( + $autosave_post_id, + $autosave['wp_id'], + "Failed asserting that the autosave id is the same as $autosave_post_id." + ); + $this->assertSame( + self::$template_post->ID, + $autosave['parent'], + sprintf( + 'Failed asserting that the parent id of the autosave is the same as %s.', + self::$template_post->ID + ) + ); + } + + /** + * @covers WP_REST_Template_Autosaves_Controller::prepare_item_for_response + * @ticket 56922 + */ + public function test_prepare_item() { + wp_set_current_user( self::$admin_id ); + $autosave_post_id = wp_create_post_autosave( + array( + 'post_content' => 'Autosave content.', + 'post_ID' => self::$template_post->ID, + 'post_type' => self::PARENT_POST_TYPE, + ) + ); + $autosave_db_post = get_post( $autosave_post_id ); + $template_id = self::TEST_THEME . '//' . self::TEMPLATE_NAME; + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/' . $template_id . '/autosaves/' . $autosave_db_post->ID ); + $controller = new WP_REST_Template_Autosaves_Controller( self::PARENT_POST_TYPE ); + $response = $controller->prepare_item_for_response( $autosave_db_post, $request ); + $this->assertInstanceOf( + WP_REST_Response::class, + $response, + 'Failed asserting that the response object is an instance of WP_REST_Response.' + ); + + $autosave = $response->get_data(); + $this->assertIsArray( $autosave, 'Failed asserting that the autosave is an array.' ); + $this->assertSame( + $autosave_db_post->ID, + $autosave['wp_id'], + "Failed asserting that the autosave id is the same as $autosave_db_post->ID." + ); + $this->assertSame( + self::$template_post->ID, + $autosave['parent'], + sprintf( + 'Failed asserting that the parent id of the autosave is the same as %s.', + self::$template_post->ID + ) + ); + + $links = $response->get_links(); + $this->assertIsArray( $links, 'Failed asserting that the links are an array.' ); + + $this->assertStringEndsWith( + $template_id . '/autosaves/' . $autosave_db_post->ID, + $links['self'][0]['href'], + "Failed asserting that the self link ends with $template_id . '/autosaves/' . $autosave_db_post->ID." + ); + + $this->assertStringEndsWith( + $template_id, + $links['parent'][0]['href'], + "Failed asserting that the parent link ends with %$template_id." + ); + } + + /** + * @covers WP_REST_Template_Autosaves_Controller::get_item_schema + * @ticket 56922 + */ + public function test_get_item_schema() { + $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/autosaves' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $properties = $data['schema']['properties']; + + $this->assertCount( 16, $properties ); + $this->assertArrayHasKey( 'id', $properties, 'ID key should exist in properties.' ); + $this->assertArrayHasKey( 'slug', $properties, 'Slug key should exist in properties.' ); + $this->assertArrayHasKey( 'theme', $properties, 'Theme key should exist in properties.' ); + $this->assertArrayHasKey( 'source', $properties, 'Source key should exist in properties.' ); + $this->assertArrayHasKey( 'origin', $properties, 'Origin key should exist in properties.' ); + $this->assertArrayHasKey( 'content', $properties, 'Content key should exist in properties.' ); + $this->assertArrayHasKey( 'title', $properties, 'Title key should exist in properties.' ); + $this->assertArrayHasKey( 'description', $properties, 'description key should exist in properties.' ); + $this->assertArrayHasKey( 'status', $properties, 'status key should exist in properties.' ); + $this->assertArrayHasKey( 'wp_id', $properties, 'wp_id key should exist in properties.' ); + $this->assertArrayHasKey( 'has_theme_file', $properties, 'has_theme_file key should exist in properties.' ); + $this->assertArrayHasKey( 'author', $properties, 'author key should exist in properties.' ); + $this->assertArrayHasKey( 'modified', $properties, 'modified key should exist in properties.' ); + $this->assertArrayHasKey( 'is_custom', $properties, 'is_custom key should exist in properties.' ); + $this->assertArrayHasKey( 'parent', $properties, 'Parent key should exist in properties.' ); + } + + /** + * @covers WP_REST_Template_Autosaves_Controller::create_item + * @ticket 56922 + */ + public function test_create_item() { + wp_set_current_user( self::$admin_id ); + + $template_id = self::TEST_THEME . '/' . self::TEMPLATE_NAME; + $request = new WP_REST_Request( 'POST', '/wp/v2/templates/' . $template_id . '/autosaves' ); + $request->add_header( 'Content-Type', 'application/x-www-form-urlencoded' ); + + $request_parameters = array( + 'title' => 'Post Title', + 'content' => 'Post content', + 'excerpt' => 'Post excerpt', + 'name' => 'test', + 'id' => $template_id, + ); + + $request->set_body_params( $request_parameters ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertNotWPError( $response, 'The response from this request should not return a WP_Error object' ); + $response = rest_ensure_response( $response ); + $data = $response->get_data(); + + $this->assertArrayHasKey( 'content', $data, 'Response should contain a key called content' ); + $this->assertSame( $request_parameters['content'], $data['content']['raw'], 'Response data should match for field content' ); + + $this->assertArrayHasKey( 'title', $data, 'Response should contain a key called title' ); + $this->assertSame( $request_parameters['title'], $data['title']['raw'], 'Response data should match for field title' ); + } + + /** + * @covers WP_REST_Template_Autosaves_Controller::delete_item + * @ticket 56922 + */ + public function test_create_item_incorrect_permission() { + wp_set_current_user( self::$contributor_id ); + $template_id = self::TEST_THEME . '/' . self::TEMPLATE_NAME; + $request = new WP_REST_Request( 'POST', '/wp/v2/templates/' . $template_id . '/autosaves' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_manage_templates', $response, WP_Http::FORBIDDEN ); + } + + /** + * @covers WP_REST_Template_Autosaves_Controller::delete_item + * @ticket 56922 + */ + public function test_create_item_no_permission() { + wp_set_current_user( 0 ); + $template_id = self::TEST_THEME . '/' . self::TEMPLATE_NAME; + $request = new WP_REST_Request( 'POST', '/wp/v2/templates/' . $template_id . '/autosaves' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_manage_templates', $response, WP_Http::UNAUTHORIZED ); + } + + /** + * @coversNothing + * @ticket 56922 + */ + public function test_update_item() { + $this->markTestSkipped( + sprintf( + "The '%s' controller doesn't currently support the ability to update template autosaves.", + WP_REST_Template_Autosaves_Controller::class + ) + ); + } + + /** + * @coversNothing + * @ticket 56922 + */ + public function test_delete_item() { + $this->markTestSkipped( + sprintf( + "The '%s' controller doesn't currently support the ability to delete template autosaves.", + WP_REST_Template_Autosaves_Controller::class + ) + ); + } +} diff --git a/tests/phpunit/tests/rest-api/wpRestTemplateRevisionsController.php b/tests/phpunit/tests/rest-api/wpRestTemplateRevisionsController.php new file mode 100644 index 0000000000000..91370b21c726b --- /dev/null +++ b/tests/phpunit/tests/rest-api/wpRestTemplateRevisionsController.php @@ -0,0 +1,511 @@ +user->create( + array( + 'role' => 'administrator', + ) + ); + wp_set_current_user( self::$admin_id ); + + self::$contributor_id = $factory->user->create( + array( + 'role' => 'contributor', + ) + ); + + // Set up template post. + self::$template_post = $factory->post->create_and_get( + array( + 'post_type' => self::PARENT_POST_TYPE, + 'post_name' => self::TEMPLATE_NAME, + 'post_title' => 'My Template', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my template', + 'tax_input' => array( + 'wp_theme' => array( + self::TEST_THEME, + ), + ), + ) + ); + wp_set_post_terms( self::$template_post->ID, self::TEST_THEME, 'wp_theme' ); + + // Update post to create a new revisions. + self::$revisions[] = _wp_put_post_revision( + array( + 'ID' => self::$template_post->ID, + 'post_content' => 'Content revision #2', + ) + ); + + // Update post to create a new revisions. + self::$revisions[] = _wp_put_post_revision( + array( + 'ID' => self::$template_post->ID, + 'post_content' => 'Content revision #3', + ) + ); + + // Update post to create a new revisions. + self::$revisions[] = _wp_put_post_revision( + array( + 'ID' => self::$template_post->ID, + 'post_content' => 'Content revision #4', + ) + ); + + // Update post to create a new revisions. + self::$revisions[] = _wp_put_post_revision( + array( + 'ID' => self::$template_post->ID, + 'post_content' => 'Content revision #5', + ) + ); + } + + /** + * Remove revisions when tests are complete. + */ + public static function wpTearDownAfterClass() { + // Also deletes revisions. + foreach ( self::$revisions as $revision ) { + wp_delete_post( $revision, true ); + } + } + + /** + * @covers WP_REST_Template_Revisions_Controller::register_routes + * @ticket 56922 + */ + public function test_register_routes() { + $routes = rest_get_server()->get_routes(); + $this->assertArrayHasKey( + '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/revisions', + $routes, + 'Template revisions route does not exist.' + ); + $this->assertArrayHasKey( + '/wp/v2/templates/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/revisions/(?P[\d]+)', + $routes, + 'Single template revision based on the given ID route does not exist.' + ); + $this->assertArrayHasKey( + '/wp/v2/template-parts/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/revisions', + $routes, + 'Template part revisions route does not exist.' + ); + $this->assertArrayHasKey( + '/wp/v2/template-parts/(?P([^\/:<>\*\?"\|]+(?:\/[^\/:<>\*\?"\|]+)?)[\/\w%-]+)/revisions/(?P[\d]+)', + $routes, + 'Single template part revision based on the given ID route does not exist.' + ); + } + + /** + * @covers WP_REST_Template_Revisions_Controller::get_context_param + * @ticket 56922 + */ + public function test_context_param() { + // Collection. + $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $this->assertSame( + 'view', + $data['endpoints'][0]['args']['context']['default'], + 'Failed to assert that the default context for the collection endpoint is "view".' + ); + $this->assertSame( + array( 'view', 'embed', 'edit' ), + $data['endpoints'][0]['args']['context']['enum'], + 'Failed to assert correct enum values for the collection endpoint.' + ); + + // Single. + $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions/1' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $this->assertCount( + 2, + $data['endpoints'], + 'Failed to assert that the single revision endpoint count is 2.' + ); + $this->assertSame( + 'view', + $data['endpoints'][0]['args']['context']['default'], + 'Failed to assert that the default context for the single revision endpoint is "view".' + ); + $this->assertSame( + array( 'view', 'embed', 'edit' ), + $data['endpoints'][0]['args']['context']['enum'], + 'Failed to assert correct enum values for the single revision endpoint.' + ); + } + + /** + * @covers WP_REST_Template_Revisions_Controller::get_items + * @ticket 56922 + */ + public function test_get_items() { + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( + 'GET', + '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions' + ); + $response = rest_get_server()->dispatch( $request ); + $revisions = $response->get_data(); + + $this->assertCount( + 4, + $revisions, + 'Failed asserting that the response data contains exactly 4 items.' + ); + + $this->assertSame( + self::$template_post->ID, + $revisions[0]['parent'], + 'Failed asserting that the parent ID of the revision matches the template post ID.' + ); + $this->assertSame( + 'Content revision #5', + $revisions[0]['content']['raw'], + 'Failed asserting that the content of the revision is "Content revision #5".' + ); + + $this->assertSame( + self::$template_post->ID, + $revisions[1]['parent'], + 'Failed asserting that the parent ID of the revision matches the template post ID.' + ); + $this->assertSame( + 'Content revision #4', + $revisions[1]['content']['raw'], + 'Failed asserting that the content of the revision is "Content revision #4".' + ); + + $this->assertSame( + self::$template_post->ID, + $revisions[2]['parent'], + 'Failed asserting that the parent ID of the revision matches the template post ID.' + ); + $this->assertSame( + 'Content revision #3', + $revisions[2]['content']['raw'], + 'Failed asserting that the content of the revision is "Content revision #3".' + ); + + $this->assertSame( + self::$template_post->ID, + $revisions[3]['parent'], + 'Failed asserting that the parent ID of the revision matches the template post ID.' + ); + $this->assertSame( + 'Content revision #2', + $revisions[3]['content']['raw'], + 'Failed asserting that the content of the revision is "Content revision #2".' + ); + } + + + /** + * @covers WP_REST_Template_Revisions_Controller::get_items_permissions_check + * @ticket 56922 + */ + public function test_get_items_endpoint_should_return_unauthorized_https_status_code_for_unauthorized_request() { + wp_set_current_user( 0 ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_read', $response, WP_Http::UNAUTHORIZED ); + } + + /** + * @covers WP_REST_Template_Revisions_Controller::get_items_permissions_check + * @ticket 56922 + */ + public function test_get_items_endpoint_should_return_forbidden_https_status_code_for_users_with_insufficient_permissions() { + wp_set_current_user( self::$contributor_id ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_read', $response, WP_Http::FORBIDDEN ); + } + + /** + * @covers WP_REST_Template_Revisions_Controller::get_item + * @ticket 56922 + */ + public function test_get_item() { + wp_set_current_user( self::$admin_id ); + + $revisions = wp_get_post_revisions( self::$template_post, array( 'fields' => 'ids' ) ); + $revision_id = array_shift( $revisions ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions/' . $revision_id ); + $response = rest_get_server()->dispatch( $request ); + $revision = $response->get_data(); + + $this->assertIsArray( $revision, 'Failed asserting that the revision is an array.' ); + $this->assertSame( + $revision_id, + $revision['wp_id'], + "Failed asserting that the revision id is the same as $revision_id" + ); + $this->assertSame( + self::$template_post->ID, + $revision['parent'], + sprintf( + 'Failed asserting that the parent id of the revision is the same as %s.', + self::$template_post->ID + ) + ); + } + + /** + * @covers WP_REST_Template_Revisions_Controller::get_item + * @ticket 56922 + */ + public function test_get_item_not_found() { + wp_set_current_user( self::$admin_id ); + + $revisions = wp_get_post_revisions( self::$template_post, array( 'fields' => 'ids' ) ); + $revision_id = array_shift( $revisions ); + + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/invalid//parent/revisions/' . $revision_id ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_post_invalid_parent', $response, WP_Http::NOT_FOUND ); + } + + /** + * @covers WP_REST_Template_Revisions_Controller::prepare_item_for_response + * @ticket 56922 + */ + public function test_prepare_item() { + $revisions = wp_get_post_revisions( self::$template_post, array( 'fields' => 'ids' ) ); + $revision_id = array_shift( $revisions ); + $post = get_post( $revision_id ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions/' . $revision_id ); + $controller = new WP_REST_Template_Revisions_Controller( self::PARENT_POST_TYPE ); + $response = $controller->prepare_item_for_response( $post, $request ); + $this->assertInstanceOf( + WP_REST_Response::class, + $response, + 'Failed asserting that the response object is an instance of WP_REST_Response.' + ); + + $revision = $response->get_data(); + $this->assertIsArray( $revision, 'Failed asserting that the revision is an array.' ); + $this->assertSame( + $revision_id, + $revision['wp_id'], + "Failed asserting that the revision id is the same as $revision_id." + ); + $this->assertSame( + self::$template_post->ID, + $revision['parent'], + sprintf( + 'Failed asserting that the parent id of the revision is the same as %s.', + self::$template_post->ID + ) + ); + + $links = $response->get_links(); + $this->assertIsArray( $links, 'Failed asserting that the links are an array.' ); + + $this->assertStringEndsWith( + self::TEST_THEME . '//' . self::TEMPLATE_NAME . '/revisions/' . $revision_id, + $links['self'][0]['href'], + sprintf( + 'Failed asserting that the self link ends with %s.', + self::TEST_THEME . '//' . self::TEMPLATE_NAME . '/revisions/' . $revision_id + ) + ); + + $this->assertStringEndsWith( + self::TEST_THEME . '//' . self::TEMPLATE_NAME, + $links['parent'][0]['href'], + sprintf( + 'Failed asserting that the parent link ends with %s.', + self::TEST_THEME . '//' . self::TEMPLATE_NAME + ) + ); + } + + /** + * @covers WP_REST_Template_Revisions_Controller::get_item_schema + * @ticket 56922 + */ + public function test_get_item_schema() { + $request = new WP_REST_Request( 'OPTIONS', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $properties = $data['schema']['properties']; + + $this->assertCount( 16, $properties ); + $this->assertArrayHasKey( 'id', $properties, 'ID key should exist in properties.' ); + $this->assertArrayHasKey( 'slug', $properties, 'Slug key should exist in properties.' ); + $this->assertArrayHasKey( 'theme', $properties, 'Theme key should exist in properties.' ); + $this->assertArrayHasKey( 'source', $properties, 'Source key should exist in properties.' ); + $this->assertArrayHasKey( 'origin', $properties, 'Origin key should exist in properties.' ); + $this->assertArrayHasKey( 'content', $properties, 'Content key should exist in properties.' ); + $this->assertArrayHasKey( 'title', $properties, 'Title key should exist in properties.' ); + $this->assertArrayHasKey( 'description', $properties, 'description key should exist in properties.' ); + $this->assertArrayHasKey( 'status', $properties, 'status key should exist in properties.' ); + $this->assertArrayHasKey( 'wp_id', $properties, 'wp_id key should exist in properties.' ); + $this->assertArrayHasKey( 'has_theme_file', $properties, 'has_theme_file key should exist in properties.' ); + $this->assertArrayHasKey( 'author', $properties, 'author key should exist in properties.' ); + $this->assertArrayHasKey( 'modified', $properties, 'modified key should exist in properties.' ); + $this->assertArrayHasKey( 'is_custom', $properties, 'is_custom key should exist in properties.' ); + $this->assertArrayHasKey( 'parent', $properties, 'Parent key should exist in properties.' ); + } + + /** + * @coversNothing + * @ticket 56922 + */ + public function test_create_item() { + $this->markTestSkipped( + sprintf( + "The '%s' controller doesn't currently support the ability to create template revisions.", + WP_REST_Template_Revisions_Controller::class + ) + ); + } + + /** + * @coversNothing + * @ticket 56922 + */ + public function test_update_item() { + $this->markTestSkipped( + sprintf( + "The '%s' controller doesn't currently support the ability to update template revisions.", + WP_REST_Template_Revisions_Controller::class + ) + ); + } + + /** + * @covers WP_REST_Templates_Controller::delete_item + * @ticket 56922 + */ + public function test_delete_item() { + wp_set_current_user( self::$admin_id ); + + $revision_id = _wp_put_post_revision( self::$template_post ); + self::$revisions[] = $revision_id; + + $request = new WP_REST_Request( 'DELETE', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions/' . $revision_id ); + $request->set_param( 'force', true ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertSame( 200, $response->get_status(), 'Failed asserting that the response status is 200.' ); + $this->assertNull( get_post( $revision_id ), 'Failed asserting that the post with the given revision ID is deleted.' ); + } + + /** + * @covers WP_REST_Templates_Controller::delete_item + * @ticket 56922 + */ + public function test_delete_item_incorrect_permission() { + wp_set_current_user( self::$contributor_id ); + $revision_id = _wp_put_post_revision( self::$template_post ); + self::$revisions[] = $revision_id; + + $request = new WP_REST_Request( 'DELETE', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions/' . $revision_id ); + $request->set_param( 'force', true ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_delete', $response, WP_Http::FORBIDDEN ); + } + + /** + * @covers WP_REST_Templates_Controller::delete_item + * @ticket 56922 + */ + public function test_delete_item_no_permission() { + wp_set_current_user( 0 ); + $revision_id = _wp_put_post_revision( self::$template_post ); + self::$revisions[] = $revision_id; + + $request = new WP_REST_Request( 'DELETE', '/wp/v2/templates/' . self::TEST_THEME . '/' . self::TEMPLATE_NAME . '/revisions/' . $revision_id ); + $request->set_param( 'force', true ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_delete', $response, WP_Http::UNAUTHORIZED ); + } + + /** + * @covers WP_REST_Template_Revisions_Controller::get_item + * @ticket 56922 + */ + public function test_delete_item_not_found() { + wp_set_current_user( self::$admin_id ); + + $revision_id = _wp_put_post_revision( self::$template_post ); + self::$revisions[] = $revision_id; + + $request = new WP_REST_Request( 'DELETE', '/wp/v2/templates/invalid//parent/revisions/' . $revision_id ); + $request->set_param( 'force', true ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_post_invalid_parent', $response, WP_Http::NOT_FOUND ); + } +} diff --git a/tests/qunit/fixtures/wp-api-generated.js b/tests/qunit/fixtures/wp-api-generated.js index 8341830452a1f..d212facf26006 100644 --- a/tests/qunit/fixtures/wp-api-generated.js +++ b/tests/qunit/fixtures/wp-api-generated.js @@ -2707,7 +2707,7 @@ mockedApiResponse.Schema = { } ] }, - "/wp/v2/media": { + "/wp/v2/menu-items": { "namespace": "wp/v2", "methods": [ "GET", @@ -2718,6 +2718,9 @@ mockedApiResponse.Schema = { "methods": [ "GET" ], + "allow_batch": { + "v1": true + }, "args": { "context": { "description": "Scope under which the request is made; determines fields present in response.", @@ -2740,7 +2743,7 @@ mockedApiResponse.Schema = { "per_page": { "description": "Maximum number of items to be returned in result set.", "type": "integer", - "default": 10, + "default": 100, "minimum": 1, "maximum": 100, "required": false @@ -2762,24 +2765,6 @@ mockedApiResponse.Schema = { "format": "date-time", "required": false }, - "author": { - "description": "Limit result set to posts assigned to specific authors.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [], - "required": false - }, - "author_exclude": { - "description": "Ensure result set excludes posts assigned to specific authors.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [], - "required": false - }, "before": { "description": "Limit response to posts published before a given ISO8601 compliant date.", "type": "string", @@ -2818,7 +2803,7 @@ mockedApiResponse.Schema = { "order": { "description": "Order sort attribute ascending or descending.", "type": "string", - "default": "desc", + "default": "asc", "enum": [ "asc", "desc" @@ -2826,9 +2811,9 @@ mockedApiResponse.Schema = { "required": false }, "orderby": { - "description": "Sort collection by post attribute.", + "description": "Sort collection by object attribute.", "type": "string", - "default": "date", + "default": "menu_order", "enum": [ "author", "date", @@ -2839,28 +2824,11 @@ mockedApiResponse.Schema = { "relevance", "slug", "include_slugs", - "title" + "title", + "menu_order" ], "required": false }, - "parent": { - "description": "Limit result set to items with particular parent IDs.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [], - "required": false - }, - "parent_exclude": { - "description": "Limit result set to all items except those of a particular parent ID.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [], - "required": false - }, "search_columns": { "default": [], "description": "Array of column names to be searched.", @@ -2884,36 +2852,118 @@ mockedApiResponse.Schema = { "required": false }, "status": { - "default": "inherit", + "default": "publish", "description": "Limit result set to posts assigned one or more statuses.", "type": "array", "items": { "enum": [ - "inherit", + "publish", + "future", + "draft", + "pending", "private", - "trash" + "trash", + "auto-draft", + "inherit", + "request-pending", + "request-confirmed", + "request-failed", + "request-completed", + "any" ], "type": "string" }, "required": false }, - "media_type": { - "default": null, - "description": "Limit result set to attachments of a particular media type.", + "tax_relation": { + "description": "Limit result set based on relationship between multiple taxonomies.", "type": "string", "enum": [ - "image", - "video", - "text", - "application", - "audio" + "AND", + "OR" ], "required": false }, - "mime_type": { - "default": null, - "description": "Limit result set to attachments of a particular MIME type.", - "type": "string", + "menus": { + "description": "Limit result set to items with specific terms assigned in the menus taxonomy.", + "type": [ + "object", + "array" + ], + "oneOf": [ + { + "title": "Term ID List", + "description": "Match terms with the listed IDs.", + "type": "array", + "items": { + "type": "integer" + } + }, + { + "title": "Term ID Taxonomy Query", + "description": "Perform an advanced term query.", + "type": "object", + "properties": { + "terms": { + "description": "Term IDs.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [] + }, + "operator": { + "description": "Whether items must be assigned all or any of the specified terms.", + "type": "string", + "enum": [ + "AND", + "OR" + ], + "default": "OR" + } + }, + "additionalProperties": false + } + ], + "required": false + }, + "menus_exclude": { + "description": "Limit result set to items except those with specific terms assigned in the menus taxonomy.", + "type": [ + "object", + "array" + ], + "oneOf": [ + { + "title": "Term ID List", + "description": "Match terms with the listed IDs.", + "type": "array", + "items": { + "type": "integer" + } + }, + { + "title": "Term ID Taxonomy Query", + "description": "Perform an advanced term query.", + "type": "object", + "properties": { + "terms": { + "description": "Term IDs.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [] + } + }, + "additionalProperties": false + } + ], + "required": false + }, + "menu_order": { + "description": "Limit result set to posts with a specific menu_order value.", + "type": "integer", "required": false } } @@ -2922,55 +2972,26 @@ mockedApiResponse.Schema = { "methods": [ "POST" ], + "allow_batch": { + "v1": true + }, "args": { - "date": { - "description": "The date the post was published, in the site's timezone.", - "type": [ - "string", - "null" - ], - "format": "date-time", - "required": false - }, - "date_gmt": { - "description": "The date the post was published, as GMT.", + "title": { + "description": "The title for the object.", "type": [ "string", - "null" - ], - "format": "date-time", - "required": false - }, - "slug": { - "description": "An alphanumeric identifier for the post unique to its type.", - "type": "string", - "required": false - }, - "status": { - "description": "A named status for the post.", - "type": "string", - "enum": [ - "publish", - "future", - "draft", - "pending", - "private" + "object" ], - "required": false - }, - "title": { - "description": "The title for the post.", - "type": "object", "properties": { "raw": { - "description": "Title for the post, as it exists in the database.", + "description": "Title for the object, as it exists in the database.", "type": "string", "context": [ "edit" ] }, "rendered": { - "description": "HTML title for the post, transformed for display.", + "description": "HTML title for the object, transformed for display.", "type": "string", "context": [ "view", @@ -2982,817 +3003,40 @@ mockedApiResponse.Schema = { }, "required": false }, - "author": { - "description": "The ID for the author of the post.", - "type": "integer", - "required": false - }, - "comment_status": { - "description": "Whether or not comments are open on the post.", + "type": { + "default": "custom", + "description": "The family of objects originally represented, such as \"post_type\" or \"taxonomy\".", "type": "string", "enum": [ - "open", - "closed" + "taxonomy", + "post_type", + "post_type_archive", + "custom" ], "required": false }, - "ping_status": { - "description": "Whether or not the post can be pinged.", + "status": { + "default": "publish", + "description": "A named status for the object.", "type": "string", "enum": [ - "open", - "closed" + "publish", + "future", + "draft", + "pending", + "private" ], "required": false }, - "meta": { - "description": "Meta fields.", - "type": "object", - "properties": [], - "required": false - }, - "template": { - "description": "The theme file to use to display the post.", - "type": "string", + "parent": { + "default": 0, + "description": "The ID for the parent of the object.", + "type": "integer", + "minimum": 0, "required": false }, - "alt_text": { - "description": "Alternative text to display when attachment is not displayed.", - "type": "string", - "required": false - }, - "caption": { - "description": "The attachment caption.", - "type": "object", - "properties": { - "raw": { - "description": "Caption for the attachment, as it exists in the database.", - "type": "string", - "context": [ - "edit" - ] - }, - "rendered": { - "description": "HTML caption for the attachment, transformed for display.", - "type": "string", - "context": [ - "view", - "edit", - "embed" - ], - "readonly": true - } - }, - "required": false - }, - "description": { - "description": "The attachment description.", - "type": "object", - "properties": { - "raw": { - "description": "Description for the attachment, as it exists in the database.", - "type": "string", - "context": [ - "edit" - ] - }, - "rendered": { - "description": "HTML description for the attachment, transformed for display.", - "type": "string", - "context": [ - "view", - "edit" - ], - "readonly": true - } - }, - "required": false - }, - "post": { - "description": "The ID for the associated post of the attachment.", - "type": "integer", - "required": false - } - } - } - ], - "_links": { - "self": "http://example.org/index.php?rest_route=/wp/v2/media" - } - }, - "/wp/v2/media/(?P[\\d]+)": { - "namespace": "wp/v2", - "methods": [ - "GET", - "POST", - "PUT", - "PATCH", - "DELETE" - ], - "endpoints": [ - { - "methods": [ - "GET" - ], - "args": { - "id": { - "description": "Unique identifier for the post.", - "type": "integer", - "required": false - }, - "context": { - "description": "Scope under which the request is made; determines fields present in response.", - "type": "string", - "enum": [ - "view", - "embed", - "edit" - ], - "default": "view", - "required": false - } - } - }, - { - "methods": [ - "POST", - "PUT", - "PATCH" - ], - "args": { - "id": { - "description": "Unique identifier for the post.", - "type": "integer", - "required": false - }, - "date": { - "description": "The date the post was published, in the site's timezone.", - "type": [ - "string", - "null" - ], - "format": "date-time", - "required": false - }, - "date_gmt": { - "description": "The date the post was published, as GMT.", - "type": [ - "string", - "null" - ], - "format": "date-time", - "required": false - }, - "slug": { - "description": "An alphanumeric identifier for the post unique to its type.", - "type": "string", - "required": false - }, - "status": { - "description": "A named status for the post.", - "type": "string", - "enum": [ - "publish", - "future", - "draft", - "pending", - "private" - ], - "required": false - }, - "title": { - "description": "The title for the post.", - "type": "object", - "properties": { - "raw": { - "description": "Title for the post, as it exists in the database.", - "type": "string", - "context": [ - "edit" - ] - }, - "rendered": { - "description": "HTML title for the post, transformed for display.", - "type": "string", - "context": [ - "view", - "edit", - "embed" - ], - "readonly": true - } - }, - "required": false - }, - "author": { - "description": "The ID for the author of the post.", - "type": "integer", - "required": false - }, - "comment_status": { - "description": "Whether or not comments are open on the post.", - "type": "string", - "enum": [ - "open", - "closed" - ], - "required": false - }, - "ping_status": { - "description": "Whether or not the post can be pinged.", - "type": "string", - "enum": [ - "open", - "closed" - ], - "required": false - }, - "meta": { - "description": "Meta fields.", - "type": "object", - "properties": [], - "required": false - }, - "template": { - "description": "The theme file to use to display the post.", - "type": "string", - "required": false - }, - "alt_text": { - "description": "Alternative text to display when attachment is not displayed.", - "type": "string", - "required": false - }, - "caption": { - "description": "The attachment caption.", - "type": "object", - "properties": { - "raw": { - "description": "Caption for the attachment, as it exists in the database.", - "type": "string", - "context": [ - "edit" - ] - }, - "rendered": { - "description": "HTML caption for the attachment, transformed for display.", - "type": "string", - "context": [ - "view", - "edit", - "embed" - ], - "readonly": true - } - }, - "required": false - }, - "description": { - "description": "The attachment description.", - "type": "object", - "properties": { - "raw": { - "description": "Description for the attachment, as it exists in the database.", - "type": "string", - "context": [ - "edit" - ] - }, - "rendered": { - "description": "HTML description for the attachment, transformed for display.", - "type": "string", - "context": [ - "view", - "edit" - ], - "readonly": true - } - }, - "required": false - }, - "post": { - "description": "The ID for the associated post of the attachment.", - "type": "integer", - "required": false - } - } - }, - { - "methods": [ - "DELETE" - ], - "args": { - "id": { - "description": "Unique identifier for the post.", - "type": "integer", - "required": false - }, - "force": { - "type": "boolean", - "default": false, - "description": "Whether to bypass Trash and force deletion.", - "required": false - } - } - } - ] - }, - "/wp/v2/media/(?P[\\d]+)/post-process": { - "namespace": "wp/v2", - "methods": [ - "POST" - ], - "endpoints": [ - { - "methods": [ - "POST" - ], - "args": { - "id": { - "description": "Unique identifier for the attachment.", - "type": "integer", - "required": false - }, - "action": { - "type": "string", - "enum": [ - "create-image-subsizes" - ], - "required": true - } - } - } - ] - }, - "/wp/v2/media/(?P[\\d]+)/edit": { - "namespace": "wp/v2", - "methods": [ - "POST" - ], - "endpoints": [ - { - "methods": [ - "POST" - ], - "args": { - "src": { - "description": "URL to the edited image file.", - "type": "string", - "format": "uri", - "required": true - }, - "modifiers": { - "description": "Array of image edits.", - "type": "array", - "minItems": 1, - "items": { - "description": "Image edit.", - "type": "object", - "required": [ - "type", - "args" - ], - "oneOf": [ - { - "title": "Rotation", - "properties": { - "type": { - "description": "Rotation type.", - "type": "string", - "enum": [ - "rotate" - ] - }, - "args": { - "description": "Rotation arguments.", - "type": "object", - "required": [ - "angle" - ], - "properties": { - "angle": { - "description": "Angle to rotate clockwise in degrees.", - "type": "number" - } - } - } - } - }, - { - "title": "Crop", - "properties": { - "type": { - "description": "Crop type.", - "type": "string", - "enum": [ - "crop" - ] - }, - "args": { - "description": "Crop arguments.", - "type": "object", - "required": [ - "left", - "top", - "width", - "height" - ], - "properties": { - "left": { - "description": "Horizontal position from the left to begin the crop as a percentage of the image width.", - "type": "number" - }, - "top": { - "description": "Vertical position from the top to begin the crop as a percentage of the image height.", - "type": "number" - }, - "width": { - "description": "Width of the crop as a percentage of the image width.", - "type": "number" - }, - "height": { - "description": "Height of the crop as a percentage of the image height.", - "type": "number" - } - } - } - } - } - ] - }, - "required": false - }, - "rotation": { - "description": "The amount to rotate the image clockwise in degrees. DEPRECATED: Use `modifiers` instead.", - "type": "integer", - "minimum": 0, - "exclusiveMinimum": true, - "maximum": 360, - "exclusiveMaximum": true, - "required": false - }, - "x": { - "description": "As a percentage of the image, the x position to start the crop from. DEPRECATED: Use `modifiers` instead.", - "type": "number", - "minimum": 0, - "maximum": 100, - "required": false - }, - "y": { - "description": "As a percentage of the image, the y position to start the crop from. DEPRECATED: Use `modifiers` instead.", - "type": "number", - "minimum": 0, - "maximum": 100, - "required": false - }, - "width": { - "description": "As a percentage of the image, the width to crop the image to. DEPRECATED: Use `modifiers` instead.", - "type": "number", - "minimum": 0, - "maximum": 100, - "required": false - }, - "height": { - "description": "As a percentage of the image, the height to crop the image to. DEPRECATED: Use `modifiers` instead.", - "type": "number", - "minimum": 0, - "maximum": 100, - "required": false - } - } - } - ] - }, - "/wp/v2/menu-items": { - "namespace": "wp/v2", - "methods": [ - "GET", - "POST" - ], - "endpoints": [ - { - "methods": [ - "GET" - ], - "allow_batch": { - "v1": true - }, - "args": { - "context": { - "description": "Scope under which the request is made; determines fields present in response.", - "type": "string", - "enum": [ - "view", - "embed", - "edit" - ], - "default": "view", - "required": false - }, - "page": { - "description": "Current page of the collection.", - "type": "integer", - "default": 1, - "minimum": 1, - "required": false - }, - "per_page": { - "description": "Maximum number of items to be returned in result set.", - "type": "integer", - "default": 100, - "minimum": 1, - "maximum": 100, - "required": false - }, - "search": { - "description": "Limit results to those matching a string.", - "type": "string", - "required": false - }, - "after": { - "description": "Limit response to posts published after a given ISO8601 compliant date.", - "type": "string", - "format": "date-time", - "required": false - }, - "modified_after": { - "description": "Limit response to posts modified after a given ISO8601 compliant date.", - "type": "string", - "format": "date-time", - "required": false - }, - "before": { - "description": "Limit response to posts published before a given ISO8601 compliant date.", - "type": "string", - "format": "date-time", - "required": false - }, - "modified_before": { - "description": "Limit response to posts modified before a given ISO8601 compliant date.", - "type": "string", - "format": "date-time", - "required": false - }, - "exclude": { - "description": "Ensure result set excludes specific IDs.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [], - "required": false - }, - "include": { - "description": "Limit result set to specific IDs.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [], - "required": false - }, - "offset": { - "description": "Offset the result set by a specific number of items.", - "type": "integer", - "required": false - }, - "order": { - "description": "Order sort attribute ascending or descending.", - "type": "string", - "default": "asc", - "enum": [ - "asc", - "desc" - ], - "required": false - }, - "orderby": { - "description": "Sort collection by object attribute.", - "type": "string", - "default": "menu_order", - "enum": [ - "author", - "date", - "id", - "include", - "modified", - "parent", - "relevance", - "slug", - "include_slugs", - "title", - "menu_order" - ], - "required": false - }, - "search_columns": { - "default": [], - "description": "Array of column names to be searched.", - "type": "array", - "items": { - "enum": [ - "post_title", - "post_content", - "post_excerpt" - ], - "type": "string" - }, - "required": false - }, - "slug": { - "description": "Limit result set to posts with one or more specific slugs.", - "type": "array", - "items": { - "type": "string" - }, - "required": false - }, - "status": { - "default": "publish", - "description": "Limit result set to posts assigned one or more statuses.", - "type": "array", - "items": { - "enum": [ - "publish", - "future", - "draft", - "pending", - "private", - "trash", - "auto-draft", - "inherit", - "request-pending", - "request-confirmed", - "request-failed", - "request-completed", - "any" - ], - "type": "string" - }, - "required": false - }, - "tax_relation": { - "description": "Limit result set based on relationship between multiple taxonomies.", - "type": "string", - "enum": [ - "AND", - "OR" - ], - "required": false - }, - "menus": { - "description": "Limit result set to items with specific terms assigned in the menus taxonomy.", - "type": [ - "object", - "array" - ], - "oneOf": [ - { - "title": "Term ID List", - "description": "Match terms with the listed IDs.", - "type": "array", - "items": { - "type": "integer" - } - }, - { - "title": "Term ID Taxonomy Query", - "description": "Perform an advanced term query.", - "type": "object", - "properties": { - "terms": { - "description": "Term IDs.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [] - }, - "operator": { - "description": "Whether items must be assigned all or any of the specified terms.", - "type": "string", - "enum": [ - "AND", - "OR" - ], - "default": "OR" - } - }, - "additionalProperties": false - } - ], - "required": false - }, - "menus_exclude": { - "description": "Limit result set to items except those with specific terms assigned in the menus taxonomy.", - "type": [ - "object", - "array" - ], - "oneOf": [ - { - "title": "Term ID List", - "description": "Match terms with the listed IDs.", - "type": "array", - "items": { - "type": "integer" - } - }, - { - "title": "Term ID Taxonomy Query", - "description": "Perform an advanced term query.", - "type": "object", - "properties": { - "terms": { - "description": "Term IDs.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [] - } - }, - "additionalProperties": false - } - ], - "required": false - }, - "menu_order": { - "description": "Limit result set to posts with a specific menu_order value.", - "type": "integer", - "required": false - } - } - }, - { - "methods": [ - "POST" - ], - "allow_batch": { - "v1": true - }, - "args": { - "title": { - "description": "The title for the object.", - "type": [ - "string", - "object" - ], - "properties": { - "raw": { - "description": "Title for the object, as it exists in the database.", - "type": "string", - "context": [ - "edit" - ] - }, - "rendered": { - "description": "HTML title for the object, transformed for display.", - "type": "string", - "context": [ - "view", - "edit", - "embed" - ], - "readonly": true - } - }, - "required": false - }, - "type": { - "default": "custom", - "description": "The family of objects originally represented, such as \"post_type\" or \"taxonomy\".", - "type": "string", - "enum": [ - "taxonomy", - "post_type", - "post_type_archive", - "custom" - ], - "required": false - }, - "status": { - "default": "publish", - "description": "A named status for the object.", - "type": "string", - "enum": [ - "publish", - "future", - "draft", - "pending", - "private" - ], - "required": false - }, - "parent": { - "default": 0, - "description": "The ID for the parent of the object.", - "type": "integer", - "minimum": 0, - "required": false - }, - "attr_title": { - "description": "Text for the title attribute of the link element for this menu item.", + "attr_title": { + "description": "Text for the title attribute of the link element for this menu item.", "type": "string", "required": false }, @@ -4631,33 +3875,316 @@ mockedApiResponse.Schema = { "properties": [], "required": false }, - "template": { - "description": "The theme file to use to display the post.", - "type": "string", + "template": { + "description": "The theme file to use to display the post.", + "type": "string", + "required": false + }, + "wp_pattern_category": { + "description": "The terms assigned to the post in the wp_pattern_category taxonomy.", + "type": "array", + "items": { + "type": "integer" + }, + "required": false + } + } + } + ], + "_links": { + "self": "http://example.org/index.php?rest_route=/wp/v2/blocks" + } + }, + "/wp/v2/blocks/(?P[\\d]+)": { + "namespace": "wp/v2", + "methods": [ + "GET", + "POST", + "PUT", + "PATCH", + "DELETE" + ], + "endpoints": [ + { + "methods": [ + "GET" + ], + "allow_batch": { + "v1": true + }, + "args": { + "id": { + "description": "Unique identifier for the post.", + "type": "integer", + "required": false + }, + "context": { + "description": "Scope under which the request is made; determines fields present in response.", + "type": "string", + "enum": [ + "view", + "embed", + "edit" + ], + "default": "view", + "required": false + }, + "password": { + "description": "The password for the post if it is password protected.", + "type": "string", + "required": false + } + } + }, + { + "methods": [ + "POST", + "PUT", + "PATCH" + ], + "allow_batch": { + "v1": true + }, + "args": { + "id": { + "description": "Unique identifier for the post.", + "type": "integer", + "required": false + }, + "date": { + "description": "The date the post was published, in the site's timezone.", + "type": [ + "string", + "null" + ], + "format": "date-time", + "required": false + }, + "date_gmt": { + "description": "The date the post was published, as GMT.", + "type": [ + "string", + "null" + ], + "format": "date-time", + "required": false + }, + "slug": { + "description": "An alphanumeric identifier for the post unique to its type.", + "type": "string", + "required": false + }, + "status": { + "description": "A named status for the post.", + "type": "string", + "enum": [ + "publish", + "future", + "draft", + "pending", + "private" + ], + "required": false + }, + "password": { + "description": "A password to protect access to the content and excerpt.", + "type": "string", + "required": false + }, + "title": { + "description": "The title for the post.", + "type": "object", + "properties": { + "raw": { + "description": "Title for the post, as it exists in the database.", + "type": "string", + "context": [ + "view", + "edit" + ] + } + }, + "required": false + }, + "content": { + "description": "The content for the post.", + "type": "object", + "properties": { + "raw": { + "description": "Content for the post, as it exists in the database.", + "type": "string", + "context": [ + "view", + "edit" + ] + }, + "block_version": { + "description": "Version of the content block format used by the post.", + "type": "integer", + "context": [ + "edit" + ], + "readonly": true + }, + "protected": { + "description": "Whether the content is protected with a password.", + "type": "boolean", + "context": [ + "view", + "edit", + "embed" + ], + "readonly": true + } + }, + "required": false + }, + "meta": { + "description": "Meta fields.", + "type": "object", + "properties": [], + "required": false + }, + "template": { + "description": "The theme file to use to display the post.", + "type": "string", + "required": false + }, + "wp_pattern_category": { + "description": "The terms assigned to the post in the wp_pattern_category taxonomy.", + "type": "array", + "items": { + "type": "integer" + }, + "required": false + } + } + }, + { + "methods": [ + "DELETE" + ], + "allow_batch": { + "v1": true + }, + "args": { + "id": { + "description": "Unique identifier for the post.", + "type": "integer", + "required": false + }, + "force": { + "type": "boolean", + "default": false, + "description": "Whether to bypass Trash and force deletion.", + "required": false + } + } + } + ] + }, + "/wp/v2/blocks/(?P[\\d]+)/revisions": { + "namespace": "wp/v2", + "methods": [ + "GET" + ], + "endpoints": [ + { + "methods": [ + "GET" + ], + "args": { + "parent": { + "description": "The ID for the parent of the revision.", + "type": "integer", + "required": false + }, + "context": { + "description": "Scope under which the request is made; determines fields present in response.", + "type": "string", + "enum": [ + "view", + "embed", + "edit" + ], + "default": "view", + "required": false + }, + "page": { + "description": "Current page of the collection.", + "type": "integer", + "default": 1, + "minimum": 1, + "required": false + }, + "per_page": { + "description": "Maximum number of items to be returned in result set.", + "type": "integer", + "minimum": 1, + "maximum": 100, + "required": false + }, + "search": { + "description": "Limit results to those matching a string.", + "type": "string", + "required": false + }, + "exclude": { + "description": "Ensure result set excludes specific IDs.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [], "required": false }, - "wp_pattern_category": { - "description": "The terms assigned to the post in the wp_pattern_category taxonomy.", + "include": { + "description": "Limit result set to specific IDs.", "type": "array", "items": { "type": "integer" }, + "default": [], + "required": false + }, + "offset": { + "description": "Offset the result set by a specific number of items.", + "type": "integer", + "required": false + }, + "order": { + "description": "Order sort attribute ascending or descending.", + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ], + "required": false + }, + "orderby": { + "description": "Sort collection by object attribute.", + "type": "string", + "default": "date", + "enum": [ + "date", + "id", + "include", + "relevance", + "slug", + "include_slugs", + "title" + ], "required": false } } } - ], - "_links": { - "self": "http://example.org/index.php?rest_route=/wp/v2/blocks" - } + ] }, - "/wp/v2/blocks/(?P[\\d]+)": { + "/wp/v2/blocks/(?P[\\d]+)/revisions/(?P[\\d]+)": { "namespace": "wp/v2", "methods": [ "GET", - "POST", - "PUT", - "PATCH", "DELETE" ], "endpoints": [ @@ -4665,12 +4192,14 @@ mockedApiResponse.Schema = { "methods": [ "GET" ], - "allow_batch": { - "v1": true - }, "args": { + "parent": { + "description": "The ID for the parent of the revision.", + "type": "integer", + "required": false + }, "id": { - "description": "Unique identifier for the post.", + "description": "Unique identifier for the revision.", "type": "integer", "required": false }, @@ -4684,26 +4213,71 @@ mockedApiResponse.Schema = { ], "default": "view", "required": false + } + } + }, + { + "methods": [ + "DELETE" + ], + "args": { + "parent": { + "description": "The ID for the parent of the revision.", + "type": "integer", + "required": false }, - "password": { - "description": "The password for the post if it is password protected.", + "id": { + "description": "Unique identifier for the revision.", + "type": "integer", + "required": false + }, + "force": { + "type": "boolean", + "default": false, + "description": "Required to be true, as revisions do not support trashing.", + "required": false + } + } + } + ] + }, + "/wp/v2/blocks/(?P[\\d]+)/autosaves": { + "namespace": "wp/v2", + "methods": [ + "GET", + "POST" + ], + "endpoints": [ + { + "methods": [ + "GET" + ], + "args": { + "parent": { + "description": "The ID for the parent of the autosave.", + "type": "integer", + "required": false + }, + "context": { + "description": "Scope under which the request is made; determines fields present in response.", "type": "string", + "enum": [ + "view", + "embed", + "edit" + ], + "default": "view", "required": false } } }, { "methods": [ - "POST", - "PUT", - "PATCH" + "POST" ], - "allow_batch": { - "v1": true - }, "args": { - "id": { - "description": "Unique identifier for the post.", + "parent": { + "description": "The ID for the parent of the autosave.", "type": "integer", "required": false }, @@ -4815,31 +4389,46 @@ mockedApiResponse.Schema = { "required": false } } - }, + } + ] + }, + "/wp/v2/blocks/(?P[\\d]+)/autosaves/(?P[\\d]+)": { + "namespace": "wp/v2", + "methods": [ + "GET" + ], + "endpoints": [ { "methods": [ - "DELETE" + "GET" ], - "allow_batch": { - "v1": true - }, "args": { + "parent": { + "description": "The ID for the parent of the autosave.", + "type": "integer", + "required": false + }, "id": { - "description": "Unique identifier for the post.", + "description": "The ID for the autosave.", "type": "integer", "required": false }, - "force": { - "type": "boolean", - "default": false, - "description": "Whether to bypass Trash and force deletion.", + "context": { + "description": "Scope under which the request is made; determines fields present in response.", + "type": "string", + "enum": [ + "view", + "embed", + "edit" + ], + "default": "view", "required": false } } } ] }, - "/wp/v2/blocks/(?P[\\d]+)/revisions": { + "/wp/v2/templates/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)/revisions": { "namespace": "wp/v2", "methods": [ "GET" @@ -4851,8 +4440,8 @@ mockedApiResponse.Schema = { ], "args": { "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", + "description": "The id of a template", + "type": "string", "required": false }, "context": { @@ -4937,7 +4526,7 @@ mockedApiResponse.Schema = { } ] }, - "/wp/v2/blocks/(?P[\\d]+)/revisions/(?P[\\d]+)": { + "/wp/v2/templates/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)/revisions/(?P[\\d]+)": { "namespace": "wp/v2", "methods": [ "GET", @@ -4950,8 +4539,8 @@ mockedApiResponse.Schema = { ], "args": { "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", + "description": "The id of a template", + "type": "string", "required": false }, "id": { @@ -4978,8 +4567,8 @@ mockedApiResponse.Schema = { ], "args": { "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", + "description": "The id of a template", + "type": "string", "required": false }, "id": { @@ -4997,7 +4586,7 @@ mockedApiResponse.Schema = { } ] }, - "/wp/v2/blocks/(?P[\\d]+)/autosaves": { + "/wp/v2/templates/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)/autosaves": { "namespace": "wp/v2", "methods": [ "GET", @@ -5009,9 +4598,9 @@ mockedApiResponse.Schema = { "GET" ], "args": { - "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", + "id": { + "description": "The id of a template", + "type": "string", "required": false }, "context": { @@ -5032,89 +4621,73 @@ mockedApiResponse.Schema = { "POST" ], "args": { - "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", - "required": false - }, - "date": { - "description": "The date the post was published, in the site's timezone.", - "type": [ - "string", - "null" - ], - "format": "date-time", - "required": false - }, - "date_gmt": { - "description": "The date the post was published, as GMT.", - "type": [ - "string", - "null" - ], - "format": "date-time", + "id": { + "description": "The id of a template", + "type": "string", "required": false }, "slug": { - "description": "An alphanumeric identifier for the post unique to its type.", + "description": "Unique slug identifying the template.", "type": "string", + "minLength": 1, + "pattern": "[a-zA-Z0-9_\\%-]+", "required": false }, - "status": { - "description": "A named status for the post.", + "theme": { + "description": "Theme identifier for the template.", "type": "string", - "enum": [ - "publish", - "future", - "draft", - "pending", - "private" - ], "required": false }, - "password": { - "description": "A password to protect access to the content and excerpt.", + "type": { + "description": "Type of template.", "type": "string", "required": false }, - "title": { - "description": "The title for the post.", - "type": "object", + "content": { + "description": "Content of template.", + "type": [ + "object", + "string" + ], "properties": { "raw": { - "description": "Title for the post, as it exists in the database.", + "description": "Content for the template, as it exists in the database.", "type": "string", "context": [ "view", "edit" ] + }, + "block_version": { + "description": "Version of the content block format used by the template.", + "type": "integer", + "context": [ + "edit" + ], + "readonly": true } }, "required": false }, - "content": { - "description": "The content for the post.", - "type": "object", + "title": { + "description": "Title of template.", + "type": [ + "object", + "string" + ], "properties": { "raw": { - "description": "Content for the post, as it exists in the database.", + "description": "Title for the template, as it exists in the database.", "type": "string", "context": [ "view", - "edit" + "edit", + "embed" ] }, - "block_version": { - "description": "Version of the content block format used by the post.", - "type": "integer", - "context": [ - "edit" - ], - "readonly": true - }, - "protected": { - "description": "Whether the content is protected with a password.", - "type": "boolean", + "rendered": { + "description": "HTML title for the template, transformed for display.", + "type": "string", "context": [ "view", "edit", @@ -5125,30 +4698,33 @@ mockedApiResponse.Schema = { }, "required": false }, - "meta": { - "description": "Meta fields.", - "type": "object", - "properties": [], + "description": { + "description": "Description of template.", + "type": "string", "required": false }, - "template": { - "description": "The theme file to use to display the post.", + "status": { + "description": "Status of template.", "type": "string", + "enum": [ + "publish", + "future", + "draft", + "pending", + "private" + ], "required": false }, - "wp_pattern_category": { - "description": "The terms assigned to the post in the wp_pattern_category taxonomy.", - "type": "array", - "items": { - "type": "integer" - }, + "author": { + "description": "The ID for the author of the template.", + "type": "integer", "required": false } } } ] }, - "/wp/v2/blocks/(?P[\\d]+)/autosaves/(?P[\\d]+)": { + "/wp/v2/templates/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)/autosaves/(?P[\\d]+)": { "namespace": "wp/v2", "methods": [ "GET" @@ -5160,8 +4736,8 @@ mockedApiResponse.Schema = { ], "args": { "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", + "description": "The id of a template", + "type": "string", "required": false }, "id": { @@ -5536,7 +5112,7 @@ mockedApiResponse.Schema = { } ] }, - "/wp/v2/templates/(?P[\\d]+)/revisions": { + "/wp/v2/template-parts/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)/revisions": { "namespace": "wp/v2", "methods": [ "GET" @@ -5548,8 +5124,8 @@ mockedApiResponse.Schema = { ], "args": { "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", + "description": "The id of a template", + "type": "string", "required": false }, "context": { @@ -5634,7 +5210,7 @@ mockedApiResponse.Schema = { } ] }, - "/wp/v2/templates/(?P[\\d]+)/revisions/(?P[\\d]+)": { + "/wp/v2/template-parts/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)/revisions/(?P[\\d]+)": { "namespace": "wp/v2", "methods": [ "GET", @@ -5647,8 +5223,8 @@ mockedApiResponse.Schema = { ], "args": { "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", + "description": "The id of a template", + "type": "string", "required": false }, "id": { @@ -5675,8 +5251,8 @@ mockedApiResponse.Schema = { ], "args": { "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", + "description": "The id of a template", + "type": "string", "required": false }, "id": { @@ -5694,7 +5270,7 @@ mockedApiResponse.Schema = { } ] }, - "/wp/v2/templates/(?P[\\d]+)/autosaves": { + "/wp/v2/template-parts/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)/autosaves": { "namespace": "wp/v2", "methods": [ "GET", @@ -5706,204 +5282,20 @@ mockedApiResponse.Schema = { "GET" ], "args": { - "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", - "required": false - }, - "context": { - "description": "Scope under which the request is made; determines fields present in response.", - "type": "string", - "enum": [ - "view", - "embed", - "edit" - ], - "default": "view", - "required": false - } - } - }, - { - "methods": [ - "POST" - ], - "args": { - "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", - "required": false - }, - "slug": { - "description": "Unique slug identifying the template.", - "type": "string", - "minLength": 1, - "pattern": "[a-zA-Z0-9_\\%-]+", - "required": false - }, - "theme": { - "description": "Theme identifier for the template.", - "type": "string", - "required": false - }, - "type": { - "description": "Type of template.", - "type": "string", - "required": false - }, - "content": { - "description": "Content of template.", - "type": [ - "object", - "string" - ], - "properties": { - "raw": { - "description": "Content for the template, as it exists in the database.", - "type": "string", - "context": [ - "view", - "edit" - ] - }, - "block_version": { - "description": "Version of the content block format used by the template.", - "type": "integer", - "context": [ - "edit" - ], - "readonly": true - } - }, - "required": false - }, - "title": { - "description": "Title of template.", - "type": [ - "object", - "string" - ], - "properties": { - "raw": { - "description": "Title for the template, as it exists in the database.", - "type": "string", - "context": [ - "view", - "edit", - "embed" - ] - }, - "rendered": { - "description": "HTML title for the template, transformed for display.", - "type": "string", - "context": [ - "view", - "edit", - "embed" - ], - "readonly": true - } - }, - "required": false - }, - "description": { - "description": "Description of template.", - "type": "string", - "required": false - }, - "status": { - "description": "Status of template.", - "type": "string", - "enum": [ - "publish", - "future", - "draft", - "pending", - "private" - ], - "required": false - }, - "author": { - "description": "The ID for the author of the template.", - "type": "integer", - "required": false - } - } - } - ] - }, - "/wp/v2/templates/(?P[\\d]+)/autosaves/(?P[\\d]+)": { - "namespace": "wp/v2", - "methods": [ - "GET" - ], - "endpoints": [ - { - "methods": [ - "GET" - ], - "args": { - "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", - "required": false - }, "id": { - "description": "The ID for the autosave.", - "type": "integer", - "required": false - }, - "context": { - "description": "Scope under which the request is made; determines fields present in response.", + "description": "The id of a template", "type": "string", - "enum": [ - "view", - "embed", - "edit" - ], - "default": "view", "required": false - } - } - } - ] - }, - "/wp/v2/template-parts": { - "namespace": "wp/v2", - "methods": [ - "GET", - "POST" - ], - "endpoints": [ - { - "methods": [ - "GET" - ], - "args": { + }, "context": { "description": "Scope under which the request is made; determines fields present in response.", "type": "string", "enum": [ "view", "embed", - "edit" - ], - "default": "view", - "required": false - }, - "wp_id": { - "description": "Limit to the specified post id.", - "type": "integer", - "required": false - }, - "area": { - "description": "Limit to the specified template part area.", - "type": "string", - "required": false - }, - "post_type": { - "description": "Post type to get the templates for.", - "type": "string", + "edit" + ], + "default": "view", "required": false } } @@ -5913,12 +5305,17 @@ mockedApiResponse.Schema = { "POST" ], "args": { + "id": { + "description": "The id of a template", + "type": "string", + "required": false + }, "slug": { "description": "Unique slug identifying the template.", "type": "string", "minLength": 1, "pattern": "[a-zA-Z0-9_\\%-]+", - "required": true + "required": false }, "theme": { "description": "Theme identifier for the template.", @@ -5931,7 +5328,6 @@ mockedApiResponse.Schema = { "required": false }, "content": { - "default": "", "description": "Content of template.", "type": [ "object", @@ -5958,7 +5354,6 @@ mockedApiResponse.Schema = { "required": false }, "title": { - "default": "", "description": "Title of template.", "type": [ "object", @@ -5988,13 +5383,11 @@ mockedApiResponse.Schema = { "required": false }, "description": { - "default": "", "description": "Description of template.", "type": "string", "required": false }, "status": { - "default": "publish", "description": "Status of template.", "type": "string", "enum": [ @@ -6018,16 +5411,9 @@ mockedApiResponse.Schema = { } } } - ], - "_links": { - "self": [ - { - "href": "http://example.org/index.php?rest_route=/wp/v2/template-parts" - } - ] - } + ] }, - "/wp/v2/template-parts/lookup": { + "/wp/v2/template-parts/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)/autosaves/(?P[\\d]+)": { "namespace": "wp/v2", "methods": [ "GET" @@ -6038,40 +5424,36 @@ mockedApiResponse.Schema = { "GET" ], "args": { - "slug": { - "description": "The slug of the template to get the fallback for", + "parent": { + "description": "The id of a template", "type": "string", - "required": true + "required": false }, - "is_custom": { - "description": "Indicates if a template is custom or part of the template hierarchy", - "type": "boolean", + "id": { + "description": "The ID for the autosave.", + "type": "integer", "required": false }, - "template_prefix": { - "description": "The template prefix for the created template. This is used to extract the main template type, e.g. in `taxonomy-books` extracts the `taxonomy`", + "context": { + "description": "Scope under which the request is made; determines fields present in response.", "type": "string", + "enum": [ + "view", + "embed", + "edit" + ], + "default": "view", "required": false } } } - ], - "_links": { - "self": [ - { - "href": "http://example.org/index.php?rest_route=/wp/v2/template-parts/lookup" - } - ] - } + ] }, - "/wp/v2/template-parts/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)": { + "/wp/v2/template-parts": { "namespace": "wp/v2", "methods": [ "GET", - "POST", - "PUT", - "PATCH", - "DELETE" + "POST" ], "endpoints": [ { @@ -6079,11 +5461,6 @@ mockedApiResponse.Schema = { "GET" ], "args": { - "id": { - "description": "The id of a template", - "type": "string", - "required": false - }, "context": { "description": "Scope under which the request is made; determines fields present in response.", "type": "string", @@ -6094,27 +5471,35 @@ mockedApiResponse.Schema = { ], "default": "view", "required": false + }, + "wp_id": { + "description": "Limit to the specified post id.", + "type": "integer", + "required": false + }, + "area": { + "description": "Limit to the specified template part area.", + "type": "string", + "required": false + }, + "post_type": { + "description": "Post type to get the templates for.", + "type": "string", + "required": false } } }, { "methods": [ - "POST", - "PUT", - "PATCH" + "POST" ], "args": { - "id": { - "description": "The id of a template", - "type": "string", - "required": false - }, "slug": { "description": "Unique slug identifying the template.", "type": "string", "minLength": 1, "pattern": "[a-zA-Z0-9_\\%-]+", - "required": false + "required": true }, "theme": { "description": "Theme identifier for the template.", @@ -6127,6 +5512,7 @@ mockedApiResponse.Schema = { "required": false }, "content": { + "default": "", "description": "Content of template.", "type": [ "object", @@ -6153,6 +5539,7 @@ mockedApiResponse.Schema = { "required": false }, "title": { + "default": "", "description": "Title of template.", "type": [ "object", @@ -6182,11 +5569,13 @@ mockedApiResponse.Schema = { "required": false }, "description": { + "default": "", "description": "Description of template.", "type": "string", "required": false }, "status": { + "default": "publish", "description": "Status of template.", "type": "string", "enum": [ @@ -6209,190 +5598,61 @@ mockedApiResponse.Schema = { "required": false } } - }, - { - "methods": [ - "DELETE" - ], - "args": { - "id": { - "description": "The id of a template", - "type": "string", - "required": false - }, - "force": { - "type": "boolean", - "default": false, - "description": "Whether to bypass Trash and force deletion.", - "required": false - } - } } - ] - }, - "/wp/v2/template-parts/(?P[\\d]+)/revisions": { - "namespace": "wp/v2", - "methods": [ - "GET" ], - "endpoints": [ - { - "methods": [ - "GET" - ], - "args": { - "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", - "required": false - }, - "context": { - "description": "Scope under which the request is made; determines fields present in response.", - "type": "string", - "enum": [ - "view", - "embed", - "edit" - ], - "default": "view", - "required": false - }, - "page": { - "description": "Current page of the collection.", - "type": "integer", - "default": 1, - "minimum": 1, - "required": false - }, - "per_page": { - "description": "Maximum number of items to be returned in result set.", - "type": "integer", - "minimum": 1, - "maximum": 100, - "required": false - }, - "search": { - "description": "Limit results to those matching a string.", - "type": "string", - "required": false - }, - "exclude": { - "description": "Ensure result set excludes specific IDs.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [], - "required": false - }, - "include": { - "description": "Limit result set to specific IDs.", - "type": "array", - "items": { - "type": "integer" - }, - "default": [], - "required": false - }, - "offset": { - "description": "Offset the result set by a specific number of items.", - "type": "integer", - "required": false - }, - "order": { - "description": "Order sort attribute ascending or descending.", - "type": "string", - "default": "desc", - "enum": [ - "asc", - "desc" - ], - "required": false - }, - "orderby": { - "description": "Sort collection by object attribute.", - "type": "string", - "default": "date", - "enum": [ - "date", - "id", - "include", - "relevance", - "slug", - "include_slugs", - "title" - ], - "required": false - } + "_links": { + "self": [ + { + "href": "http://example.org/index.php?rest_route=/wp/v2/template-parts" } - } - ] + ] + } }, - "/wp/v2/template-parts/(?P[\\d]+)/revisions/(?P[\\d]+)": { + "/wp/v2/template-parts/lookup": { "namespace": "wp/v2", "methods": [ - "GET", - "DELETE" + "GET" ], "endpoints": [ { "methods": [ - "GET" - ], - "args": { - "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", - "required": false - }, - "id": { - "description": "Unique identifier for the revision.", - "type": "integer", - "required": false - }, - "context": { - "description": "Scope under which the request is made; determines fields present in response.", - "type": "string", - "enum": [ - "view", - "embed", - "edit" - ], - "default": "view", - "required": false - } - } - }, - { - "methods": [ - "DELETE" - ], - "args": { - "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", - "required": false + "GET" + ], + "args": { + "slug": { + "description": "The slug of the template to get the fallback for", + "type": "string", + "required": true }, - "id": { - "description": "Unique identifier for the revision.", - "type": "integer", + "is_custom": { + "description": "Indicates if a template is custom or part of the template hierarchy", + "type": "boolean", "required": false }, - "force": { - "type": "boolean", - "default": false, - "description": "Required to be true, as revisions do not support trashing.", + "template_prefix": { + "description": "The template prefix for the created template. This is used to extract the main template type, e.g. in `taxonomy-books` extracts the `taxonomy`", + "type": "string", "required": false } } } - ] + ], + "_links": { + "self": [ + { + "href": "http://example.org/index.php?rest_route=/wp/v2/template-parts/lookup" + } + ] + } }, - "/wp/v2/template-parts/(?P[\\d]+)/autosaves": { + "/wp/v2/template-parts/(?P([^\\/:<>\\*\\?\"\\|]+(?:\\/[^\\/:<>\\*\\?\"\\|]+)?)[\\/\\w%-]+)": { "namespace": "wp/v2", "methods": [ "GET", - "POST" + "POST", + "PUT", + "PATCH", + "DELETE" ], "endpoints": [ { @@ -6400,9 +5660,9 @@ mockedApiResponse.Schema = { "GET" ], "args": { - "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", + "id": { + "description": "The id of a template", + "type": "string", "required": false }, "context": { @@ -6420,12 +5680,14 @@ mockedApiResponse.Schema = { }, { "methods": [ - "POST" + "POST", + "PUT", + "PATCH" ], "args": { - "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", + "id": { + "description": "The id of a template", + "type": "string", "required": false }, "slug": { @@ -6528,39 +5790,21 @@ mockedApiResponse.Schema = { "required": false } } - } - ] - }, - "/wp/v2/template-parts/(?P[\\d]+)/autosaves/(?P[\\d]+)": { - "namespace": "wp/v2", - "methods": [ - "GET" - ], - "endpoints": [ + }, { "methods": [ - "GET" + "DELETE" ], "args": { - "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", - "required": false - }, "id": { - "description": "The ID for the autosave.", - "type": "integer", + "description": "The id of a template", + "type": "string", "required": false }, - "context": { - "description": "Scope under which the request is made; determines fields present in response.", - "type": "string", - "enum": [ - "view", - "embed", - "edit" - ], - "default": "view", + "force": { + "type": "boolean", + "default": false, + "description": "Whether to bypass Trash and force deletion.", "required": false } } @@ -6702,48 +5946,229 @@ mockedApiResponse.Schema = { }, "required": false }, - "slug": { - "description": "Limit result set to posts with one or more specific slugs.", - "type": "array", - "items": { - "type": "string" - }, + "slug": { + "description": "Limit result set to posts with one or more specific slugs.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "status": { + "default": "publish", + "description": "Limit result set to posts assigned one or more statuses.", + "type": "array", + "items": { + "enum": [ + "publish", + "future", + "draft", + "pending", + "private", + "trash", + "auto-draft", + "inherit", + "request-pending", + "request-confirmed", + "request-failed", + "request-completed", + "any" + ], + "type": "string" + }, + "required": false + } + } + }, + { + "methods": [ + "POST" + ], + "allow_batch": { + "v1": true + }, + "args": { + "date": { + "description": "The date the post was published, in the site's timezone.", + "type": [ + "string", + "null" + ], + "format": "date-time", + "required": false + }, + "date_gmt": { + "description": "The date the post was published, as GMT.", + "type": [ + "string", + "null" + ], + "format": "date-time", + "required": false + }, + "slug": { + "description": "An alphanumeric identifier for the post unique to its type.", + "type": "string", + "required": false + }, + "status": { + "description": "A named status for the post.", + "type": "string", + "enum": [ + "publish", + "future", + "draft", + "pending", + "private" + ], + "required": false + }, + "password": { + "description": "A password to protect access to the content and excerpt.", + "type": "string", + "required": false + }, + "title": { + "description": "The title for the post.", + "type": "object", + "properties": { + "raw": { + "description": "Title for the post, as it exists in the database.", + "type": "string", + "context": [ + "edit", + "embed" + ] + }, + "rendered": { + "description": "HTML title for the post, transformed for display.", + "type": "string", + "context": [ + "view", + "edit", + "embed" + ], + "readonly": true + } + }, + "required": false + }, + "content": { + "description": "The content for the post.", + "type": "object", + "properties": { + "raw": { + "description": "Content for the post, as it exists in the database.", + "type": "string", + "context": [ + "edit", + "embed" + ] + }, + "rendered": { + "description": "HTML content for the post, transformed for display.", + "type": "string", + "context": [ + "view", + "edit", + "embed" + ], + "readonly": true + }, + "block_version": { + "description": "Version of the content block format used by the post.", + "type": "integer", + "context": [ + "edit", + "embed" + ], + "readonly": true + }, + "protected": { + "description": "Whether the content is protected with a password.", + "type": "boolean", + "context": [ + "view", + "edit", + "embed" + ], + "readonly": true + } + }, + "required": false + }, + "template": { + "description": "The theme file to use to display the post.", + "type": "string", + "required": false + } + } + } + ], + "_links": { + "self": [ + { + "href": "http://example.org/index.php?rest_route=/wp/v2/navigation" + } + ] + } + }, + "/wp/v2/navigation/(?P[\\d]+)": { + "namespace": "wp/v2", + "methods": [ + "GET", + "POST", + "PUT", + "PATCH", + "DELETE" + ], + "endpoints": [ + { + "methods": [ + "GET" + ], + "allow_batch": { + "v1": true + }, + "args": { + "id": { + "description": "Unique identifier for the post.", + "type": "integer", + "required": false + }, + "context": { + "description": "Scope under which the request is made; determines fields present in response.", + "type": "string", + "enum": [ + "view", + "embed", + "edit" + ], + "default": "view", "required": false }, - "status": { - "default": "publish", - "description": "Limit result set to posts assigned one or more statuses.", - "type": "array", - "items": { - "enum": [ - "publish", - "future", - "draft", - "pending", - "private", - "trash", - "auto-draft", - "inherit", - "request-pending", - "request-confirmed", - "request-failed", - "request-completed", - "any" - ], - "type": "string" - }, + "password": { + "description": "The password for the post if it is password protected.", + "type": "string", "required": false } } }, { "methods": [ - "POST" + "POST", + "PUT", + "PATCH" ], "allow_batch": { "v1": true }, "args": { + "id": { + "description": "Unique identifier for the post.", + "type": "integer", + "required": false + }, "date": { "description": "The date the post was published, in the site's timezone.", "type": [ @@ -6859,23 +6284,132 @@ mockedApiResponse.Schema = { "required": false } } + }, + { + "methods": [ + "DELETE" + ], + "allow_batch": { + "v1": true + }, + "args": { + "id": { + "description": "Unique identifier for the post.", + "type": "integer", + "required": false + }, + "force": { + "type": "boolean", + "default": false, + "description": "Whether to bypass Trash and force deletion.", + "required": false + } + } } + ] + }, + "/wp/v2/navigation/(?P[\\d]+)/revisions": { + "namespace": "wp/v2", + "methods": [ + "GET" ], - "_links": { - "self": [ - { - "href": "http://example.org/index.php?rest_route=/wp/v2/navigation" + "endpoints": [ + { + "methods": [ + "GET" + ], + "args": { + "parent": { + "description": "The ID for the parent of the revision.", + "type": "integer", + "required": false + }, + "context": { + "description": "Scope under which the request is made; determines fields present in response.", + "type": "string", + "enum": [ + "view", + "embed", + "edit" + ], + "default": "view", + "required": false + }, + "page": { + "description": "Current page of the collection.", + "type": "integer", + "default": 1, + "minimum": 1, + "required": false + }, + "per_page": { + "description": "Maximum number of items to be returned in result set.", + "type": "integer", + "minimum": 1, + "maximum": 100, + "required": false + }, + "search": { + "description": "Limit results to those matching a string.", + "type": "string", + "required": false + }, + "exclude": { + "description": "Ensure result set excludes specific IDs.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [], + "required": false + }, + "include": { + "description": "Limit result set to specific IDs.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [], + "required": false + }, + "offset": { + "description": "Offset the result set by a specific number of items.", + "type": "integer", + "required": false + }, + "order": { + "description": "Order sort attribute ascending or descending.", + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ], + "required": false + }, + "orderby": { + "description": "Sort collection by object attribute.", + "type": "string", + "default": "date", + "enum": [ + "date", + "id", + "include", + "relevance", + "slug", + "include_slugs", + "title" + ], + "required": false + } } - ] - } + } + ] }, - "/wp/v2/navigation/(?P[\\d]+)": { + "/wp/v2/navigation/(?P[\\d]+)/revisions/(?P[\\d]+)": { "namespace": "wp/v2", "methods": [ "GET", - "POST", - "PUT", - "PATCH", "DELETE" ], "endpoints": [ @@ -6883,12 +6417,14 @@ mockedApiResponse.Schema = { "methods": [ "GET" ], - "allow_batch": { - "v1": true - }, "args": { + "parent": { + "description": "The ID for the parent of the revision.", + "type": "integer", + "required": false + }, "id": { - "description": "Unique identifier for the post.", + "description": "Unique identifier for the revision.", "type": "integer", "required": false }, @@ -6902,26 +6438,71 @@ mockedApiResponse.Schema = { ], "default": "view", "required": false + } + } + }, + { + "methods": [ + "DELETE" + ], + "args": { + "parent": { + "description": "The ID for the parent of the revision.", + "type": "integer", + "required": false }, - "password": { - "description": "The password for the post if it is password protected.", + "id": { + "description": "Unique identifier for the revision.", + "type": "integer", + "required": false + }, + "force": { + "type": "boolean", + "default": false, + "description": "Required to be true, as revisions do not support trashing.", + "required": false + } + } + } + ] + }, + "/wp/v2/navigation/(?P[\\d]+)/autosaves": { + "namespace": "wp/v2", + "methods": [ + "GET", + "POST" + ], + "endpoints": [ + { + "methods": [ + "GET" + ], + "args": { + "parent": { + "description": "The ID for the parent of the autosave.", + "type": "integer", + "required": false + }, + "context": { + "description": "Scope under which the request is made; determines fields present in response.", "type": "string", + "enum": [ + "view", + "embed", + "edit" + ], + "default": "view", "required": false } } }, { "methods": [ - "POST", - "PUT", - "PATCH" + "POST" ], - "allow_batch": { - "v1": true - }, "args": { - "id": { - "description": "Unique identifier for the post.", + "parent": { + "description": "The ID for the parent of the autosave.", "type": "integer", "required": false }, @@ -7040,34 +6621,50 @@ mockedApiResponse.Schema = { "required": false } } - }, + } + ] + }, + "/wp/v2/navigation/(?P[\\d]+)/autosaves/(?P[\\d]+)": { + "namespace": "wp/v2", + "methods": [ + "GET" + ], + "endpoints": [ { "methods": [ - "DELETE" + "GET" ], - "allow_batch": { - "v1": true - }, "args": { + "parent": { + "description": "The ID for the parent of the autosave.", + "type": "integer", + "required": false + }, "id": { - "description": "Unique identifier for the post.", + "description": "The ID for the autosave.", "type": "integer", "required": false }, - "force": { - "type": "boolean", - "default": false, - "description": "Whether to bypass Trash and force deletion.", + "context": { + "description": "Scope under which the request is made; determines fields present in response.", + "type": "string", + "enum": [ + "view", + "embed", + "edit" + ], + "default": "view", "required": false } } } ] }, - "/wp/v2/navigation/(?P[\\d]+)/revisions": { + "/wp/v2/media": { "namespace": "wp/v2", "methods": [ - "GET" + "GET", + "POST" ], "endpoints": [ { @@ -7075,11 +6672,6 @@ mockedApiResponse.Schema = { "GET" ], "args": { - "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", - "required": false - }, "context": { "description": "Scope under which the request is made; determines fields present in response.", "type": "string", @@ -7101,6 +6693,7 @@ mockedApiResponse.Schema = { "per_page": { "description": "Maximum number of items to be returned in result set.", "type": "integer", + "default": 10, "minimum": 1, "maximum": 100, "required": false @@ -7110,6 +6703,48 @@ mockedApiResponse.Schema = { "type": "string", "required": false }, + "after": { + "description": "Limit response to posts published after a given ISO8601 compliant date.", + "type": "string", + "format": "date-time", + "required": false + }, + "modified_after": { + "description": "Limit response to posts modified after a given ISO8601 compliant date.", + "type": "string", + "format": "date-time", + "required": false + }, + "author": { + "description": "Limit result set to posts assigned to specific authors.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [], + "required": false + }, + "author_exclude": { + "description": "Ensure result set excludes posts assigned to specific authors.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [], + "required": false + }, + "before": { + "description": "Limit response to posts published before a given ISO8601 compliant date.", + "type": "string", + "format": "date-time", + "required": false + }, + "modified_before": { + "description": "Limit response to posts modified before a given ISO8601 compliant date.", + "type": "string", + "format": "date-time", + "required": false + }, "exclude": { "description": "Ensure result set excludes specific IDs.", "type": "array", @@ -7125,108 +6760,287 @@ mockedApiResponse.Schema = { "items": { "type": "integer" }, - "default": [], + "default": [], + "required": false + }, + "offset": { + "description": "Offset the result set by a specific number of items.", + "type": "integer", + "required": false + }, + "order": { + "description": "Order sort attribute ascending or descending.", + "type": "string", + "default": "desc", + "enum": [ + "asc", + "desc" + ], + "required": false + }, + "orderby": { + "description": "Sort collection by post attribute.", + "type": "string", + "default": "date", + "enum": [ + "author", + "date", + "id", + "include", + "modified", + "parent", + "relevance", + "slug", + "include_slugs", + "title" + ], + "required": false + }, + "parent": { + "description": "Limit result set to items with particular parent IDs.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [], + "required": false + }, + "parent_exclude": { + "description": "Limit result set to all items except those of a particular parent ID.", + "type": "array", + "items": { + "type": "integer" + }, + "default": [], + "required": false + }, + "search_columns": { + "default": [], + "description": "Array of column names to be searched.", + "type": "array", + "items": { + "enum": [ + "post_title", + "post_content", + "post_excerpt" + ], + "type": "string" + }, + "required": false + }, + "slug": { + "description": "Limit result set to posts with one or more specific slugs.", + "type": "array", + "items": { + "type": "string" + }, + "required": false + }, + "status": { + "default": "inherit", + "description": "Limit result set to posts assigned one or more statuses.", + "type": "array", + "items": { + "enum": [ + "inherit", + "private", + "trash" + ], + "type": "string" + }, + "required": false + }, + "media_type": { + "default": null, + "description": "Limit result set to attachments of a particular media type.", + "type": "string", + "enum": [ + "image", + "video", + "text", + "application", + "audio" + ], + "required": false + }, + "mime_type": { + "default": null, + "description": "Limit result set to attachments of a particular MIME type.", + "type": "string", + "required": false + } + } + }, + { + "methods": [ + "POST" + ], + "args": { + "date": { + "description": "The date the post was published, in the site's timezone.", + "type": [ + "string", + "null" + ], + "format": "date-time", + "required": false + }, + "date_gmt": { + "description": "The date the post was published, as GMT.", + "type": [ + "string", + "null" + ], + "format": "date-time", + "required": false + }, + "slug": { + "description": "An alphanumeric identifier for the post unique to its type.", + "type": "string", + "required": false + }, + "status": { + "description": "A named status for the post.", + "type": "string", + "enum": [ + "publish", + "future", + "draft", + "pending", + "private" + ], + "required": false + }, + "title": { + "description": "The title for the post.", + "type": "object", + "properties": { + "raw": { + "description": "Title for the post, as it exists in the database.", + "type": "string", + "context": [ + "edit" + ] + }, + "rendered": { + "description": "HTML title for the post, transformed for display.", + "type": "string", + "context": [ + "view", + "edit", + "embed" + ], + "readonly": true + } + }, "required": false }, - "offset": { - "description": "Offset the result set by a specific number of items.", + "author": { + "description": "The ID for the author of the post.", "type": "integer", "required": false }, - "order": { - "description": "Order sort attribute ascending or descending.", + "comment_status": { + "description": "Whether or not comments are open on the post.", "type": "string", - "default": "desc", "enum": [ - "asc", - "desc" + "open", + "closed" ], "required": false }, - "orderby": { - "description": "Sort collection by object attribute.", + "ping_status": { + "description": "Whether or not the post can be pinged.", "type": "string", - "default": "date", "enum": [ - "date", - "id", - "include", - "relevance", - "slug", - "include_slugs", - "title" + "open", + "closed" ], "required": false - } - } - } - ] - }, - "/wp/v2/navigation/(?P[\\d]+)/revisions/(?P[\\d]+)": { - "namespace": "wp/v2", - "methods": [ - "GET", - "DELETE" - ], - "endpoints": [ - { - "methods": [ - "GET" - ], - "args": { - "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", + }, + "meta": { + "description": "Meta fields.", + "type": "object", + "properties": [], "required": false }, - "id": { - "description": "Unique identifier for the revision.", - "type": "integer", + "template": { + "description": "The theme file to use to display the post.", + "type": "string", "required": false }, - "context": { - "description": "Scope under which the request is made; determines fields present in response.", + "alt_text": { + "description": "Alternative text to display when attachment is not displayed.", "type": "string", - "enum": [ - "view", - "embed", - "edit" - ], - "default": "view", "required": false - } - } - }, - { - "methods": [ - "DELETE" - ], - "args": { - "parent": { - "description": "The ID for the parent of the revision.", - "type": "integer", + }, + "caption": { + "description": "The attachment caption.", + "type": "object", + "properties": { + "raw": { + "description": "Caption for the attachment, as it exists in the database.", + "type": "string", + "context": [ + "edit" + ] + }, + "rendered": { + "description": "HTML caption for the attachment, transformed for display.", + "type": "string", + "context": [ + "view", + "edit", + "embed" + ], + "readonly": true + } + }, "required": false }, - "id": { - "description": "Unique identifier for the revision.", - "type": "integer", + "description": { + "description": "The attachment description.", + "type": "object", + "properties": { + "raw": { + "description": "Description for the attachment, as it exists in the database.", + "type": "string", + "context": [ + "edit" + ] + }, + "rendered": { + "description": "HTML description for the attachment, transformed for display.", + "type": "string", + "context": [ + "view", + "edit" + ], + "readonly": true + } + }, "required": false }, - "force": { - "type": "boolean", - "default": false, - "description": "Required to be true, as revisions do not support trashing.", + "post": { + "description": "The ID for the associated post of the attachment.", + "type": "integer", "required": false } } } - ] + ], + "_links": { + "self": "http://example.org/index.php?rest_route=/wp/v2/media" + } }, - "/wp/v2/navigation/(?P[\\d]+)/autosaves": { + "/wp/v2/media/(?P[\\d]+)": { "namespace": "wp/v2", "methods": [ "GET", - "POST" + "POST", + "PUT", + "PATCH", + "DELETE" ], "endpoints": [ { @@ -7234,8 +7048,8 @@ mockedApiResponse.Schema = { "GET" ], "args": { - "parent": { - "description": "The ID for the parent of the autosave.", + "id": { + "description": "Unique identifier for the post.", "type": "integer", "required": false }, @@ -7254,11 +7068,13 @@ mockedApiResponse.Schema = { }, { "methods": [ - "POST" + "POST", + "PUT", + "PATCH" ], "args": { - "parent": { - "description": "The ID for the parent of the autosave.", + "id": { + "description": "Unique identifier for the post.", "type": "integer", "required": false }, @@ -7297,11 +7113,6 @@ mockedApiResponse.Schema = { ], "required": false }, - "password": { - "description": "A password to protect access to the content and excerpt.", - "type": "string", - "required": false - }, "title": { "description": "The title for the post.", "type": "object", @@ -7310,8 +7121,7 @@ mockedApiResponse.Schema = { "description": "Title for the post, as it exists in the database.", "type": "string", "context": [ - "edit", - "embed" + "edit" ] }, "rendered": { @@ -7327,20 +7137,58 @@ mockedApiResponse.Schema = { }, "required": false }, - "content": { - "description": "The content for the post.", + "author": { + "description": "The ID for the author of the post.", + "type": "integer", + "required": false + }, + "comment_status": { + "description": "Whether or not comments are open on the post.", + "type": "string", + "enum": [ + "open", + "closed" + ], + "required": false + }, + "ping_status": { + "description": "Whether or not the post can be pinged.", + "type": "string", + "enum": [ + "open", + "closed" + ], + "required": false + }, + "meta": { + "description": "Meta fields.", + "type": "object", + "properties": [], + "required": false + }, + "template": { + "description": "The theme file to use to display the post.", + "type": "string", + "required": false + }, + "alt_text": { + "description": "Alternative text to display when attachment is not displayed.", + "type": "string", + "required": false + }, + "caption": { + "description": "The attachment caption.", "type": "object", "properties": { "raw": { - "description": "Content for the post, as it exists in the database.", + "description": "Caption for the attachment, as it exists in the database.", "type": "string", "context": [ - "edit", - "embed" + "edit" ] }, "rendered": { - "description": "HTML content for the post, transformed for display.", + "description": "HTML caption for the attachment, transformed for display.", "type": "string", "context": [ "view", @@ -7348,68 +7196,220 @@ mockedApiResponse.Schema = { "embed" ], "readonly": true + } + }, + "required": false + }, + "description": { + "description": "The attachment description.", + "type": "object", + "properties": { + "raw": { + "description": "Description for the attachment, as it exists in the database.", + "type": "string", + "context": [ + "edit" + ] }, - "block_version": { - "description": "Version of the content block format used by the post.", - "type": "integer", - "context": [ - "edit", - "embed" - ], - "readonly": true - }, - "protected": { - "description": "Whether the content is protected with a password.", - "type": "boolean", + "rendered": { + "description": "HTML description for the attachment, transformed for display.", + "type": "string", "context": [ "view", - "edit", - "embed" + "edit" ], "readonly": true } }, "required": false }, - "template": { - "description": "The theme file to use to display the post.", - "type": "string", + "post": { + "description": "The ID for the associated post of the attachment.", + "type": "integer", + "required": false + } + } + }, + { + "methods": [ + "DELETE" + ], + "args": { + "id": { + "description": "Unique identifier for the post.", + "type": "integer", + "required": false + }, + "force": { + "type": "boolean", + "default": false, + "description": "Whether to bypass Trash and force deletion.", "required": false } } } ] }, - "/wp/v2/navigation/(?P[\\d]+)/autosaves/(?P[\\d]+)": { + "/wp/v2/media/(?P[\\d]+)/post-process": { "namespace": "wp/v2", "methods": [ - "GET" + "POST" ], "endpoints": [ { "methods": [ - "GET" + "POST" ], "args": { - "parent": { - "description": "The ID for the parent of the autosave.", - "type": "integer", - "required": false - }, "id": { - "description": "The ID for the autosave.", + "description": "Unique identifier for the attachment.", "type": "integer", "required": false }, - "context": { - "description": "Scope under which the request is made; determines fields present in response.", + "action": { "type": "string", "enum": [ - "view", - "embed", - "edit" + "create-image-subsizes" ], - "default": "view", + "required": true + } + } + } + ] + }, + "/wp/v2/media/(?P[\\d]+)/edit": { + "namespace": "wp/v2", + "methods": [ + "POST" + ], + "endpoints": [ + { + "methods": [ + "POST" + ], + "args": { + "src": { + "description": "URL to the edited image file.", + "type": "string", + "format": "uri", + "required": true + }, + "modifiers": { + "description": "Array of image edits.", + "type": "array", + "minItems": 1, + "items": { + "description": "Image edit.", + "type": "object", + "required": [ + "type", + "args" + ], + "oneOf": [ + { + "title": "Rotation", + "properties": { + "type": { + "description": "Rotation type.", + "type": "string", + "enum": [ + "rotate" + ] + }, + "args": { + "description": "Rotation arguments.", + "type": "object", + "required": [ + "angle" + ], + "properties": { + "angle": { + "description": "Angle to rotate clockwise in degrees.", + "type": "number" + } + } + } + } + }, + { + "title": "Crop", + "properties": { + "type": { + "description": "Crop type.", + "type": "string", + "enum": [ + "crop" + ] + }, + "args": { + "description": "Crop arguments.", + "type": "object", + "required": [ + "left", + "top", + "width", + "height" + ], + "properties": { + "left": { + "description": "Horizontal position from the left to begin the crop as a percentage of the image width.", + "type": "number" + }, + "top": { + "description": "Vertical position from the top to begin the crop as a percentage of the image height.", + "type": "number" + }, + "width": { + "description": "Width of the crop as a percentage of the image width.", + "type": "number" + }, + "height": { + "description": "Height of the crop as a percentage of the image height.", + "type": "number" + } + } + } + } + } + ] + }, + "required": false + }, + "rotation": { + "description": "The amount to rotate the image clockwise in degrees. DEPRECATED: Use `modifiers` instead.", + "type": "integer", + "minimum": 0, + "exclusiveMinimum": true, + "maximum": 360, + "exclusiveMaximum": true, + "required": false + }, + "x": { + "description": "As a percentage of the image, the x position to start the crop from. DEPRECATED: Use `modifiers` instead.", + "type": "number", + "minimum": 0, + "maximum": 100, + "required": false + }, + "y": { + "description": "As a percentage of the image, the y position to start the crop from. DEPRECATED: Use `modifiers` instead.", + "type": "number", + "minimum": 0, + "maximum": 100, + "required": false + }, + "width": { + "description": "As a percentage of the image, the width to crop the image to. DEPRECATED: Use `modifiers` instead.", + "type": "number", + "minimum": 0, + "maximum": 100, + "required": false + }, + "height": { + "description": "As a percentage of the image, the height to crop the image to. DEPRECATED: Use `modifiers` instead.", + "type": "number", + "minimum": 0, + "maximum": 100, "required": false } } @@ -8780,12 +8780,12 @@ mockedApiResponse.Schema = { "enum": { "post": "post", "page": "page", - "attachment": "attachment", "nav_menu_item": "nav_menu_item", "wp_block": "wp_block", "wp_template": "wp_template", "wp_template_part": "wp_template_part", - "wp_navigation": "wp_navigation" + "wp_navigation": "wp_navigation", + "attachment": "attachment" } }, "required": false @@ -12352,36 +12352,6 @@ mockedApiResponse.TypesCollection = { ] } }, - "attachment": { - "description": "", - "hierarchical": false, - "has_archive": false, - "name": "Media", - "slug": "attachment", - "icon": "dashicons-admin-media", - "taxonomies": [], - "rest_base": "media", - "rest_namespace": "wp/v2", - "_links": { - "collection": [ - { - "href": "http://example.org/index.php?rest_route=/wp/v2/types" - } - ], - "wp:items": [ - { - "href": "http://example.org/index.php?rest_route=/wp/v2/media" - } - ], - "curies": [ - { - "name": "wp", - "href": "https://api.w.org/{rel}", - "templated": true - } - ] - } - }, "nav_menu_item": { "description": "", "hierarchical": false, @@ -12535,6 +12505,36 @@ mockedApiResponse.TypesCollection = { } ] } + }, + "attachment": { + "description": "", + "hierarchical": false, + "has_archive": false, + "name": "Media", + "slug": "attachment", + "icon": "dashicons-admin-media", + "taxonomies": [], + "rest_base": "media", + "rest_namespace": "wp/v2", + "_links": { + "collection": [ + { + "href": "http://example.org/index.php?rest_route=/wp/v2/types" + } + ], + "wp:items": [ + { + "href": "http://example.org/index.php?rest_route=/wp/v2/media" + } + ], + "curies": [ + { + "name": "wp", + "href": "https://api.w.org/{rel}", + "templated": true + } + ] + } } }; diff --git a/tests/visual-regression/README.md b/tests/visual-regression/README.md index fe32fc0688b13..d7ef71e64324b 100644 --- a/tests/visual-regression/README.md +++ b/tests/visual-regression/README.md @@ -1,11 +1,11 @@ # Visual Regression Tests in WordPress Core -These tests make use of Jest and Puppeteer, with a setup very similar to that of the e2e tests, together with [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot) for generating the visual diffs. +These tests make use of Playwright, with a setup very similar to that of the e2e tests. ## How to Run the Tests Locally 1. Check out trunk. 2. Run `npm run test:visual` to generate some base snapshots. 3. Check out the feature branch to be tested. -4. Run `npm run test:visual` again. If any tests fail, the diff images can be found in `tests/visual-regression/specs/__image_snapshots__/__diff_output__`. +4. Run `npm run test:visual` again. If any tests fail, the diff images can be found in `artifacts/` diff --git a/tests/visual-regression/config/bootstrap.js b/tests/visual-regression/config/bootstrap.js deleted file mode 100644 index 6130909e0c6fe..0000000000000 --- a/tests/visual-regression/config/bootstrap.js +++ /dev/null @@ -1,10 +0,0 @@ -import { configureToMatchImageSnapshot } from 'jest-image-snapshot'; - -// All available options: https://github.com/americanexpress/jest-image-snapshot#%EF%B8%8F-api -const toMatchImageSnapshot = configureToMatchImageSnapshot( { - // Maximum diff to allow in px. - failureThreshold: 1, -} ); - -// Extend Jest's "expect" with image snapshot functionality. -expect.extend( { toMatchImageSnapshot } ); diff --git a/tests/visual-regression/jest.config.js b/tests/visual-regression/jest.config.js deleted file mode 100644 index aa5d3d1fbd0fb..0000000000000 --- a/tests/visual-regression/jest.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const config = require( '@wordpress/scripts/config/jest-e2e.config' ); - -const jestVisualRegressionConfig = { - ...config, - setupFilesAfterEnv: [ '/config/bootstrap.js' ], -}; - -module.exports = jestVisualRegressionConfig; diff --git a/tests/visual-regression/playwright.config.js b/tests/visual-regression/playwright.config.js new file mode 100644 index 0000000000000..759d887bf71c2 --- /dev/null +++ b/tests/visual-regression/playwright.config.js @@ -0,0 +1,27 @@ +/** + * External dependencies + */ +import path from 'node:path'; +import { defineConfig } from '@playwright/test'; + +/** + * WordPress dependencies + */ +const baseConfig = require( '@wordpress/scripts/config/playwright.config' ); + +process.env.WP_ARTIFACTS_PATH ??= path.join( process.cwd(), 'artifacts' ); +process.env.STORAGE_STATE_PATH ??= path.join( + process.env.WP_ARTIFACTS_PATH, + 'storage-states/admin.json' +); + +const config = defineConfig( { + ...baseConfig, + globalSetup: undefined, + webServer: { + ...baseConfig.webServer, + command: 'npm run env:start', + }, +} ); + +export default config; diff --git a/tests/visual-regression/run-tests.js b/tests/visual-regression/run-tests.js deleted file mode 100644 index a94c914d72d22..0000000000000 --- a/tests/visual-regression/run-tests.js +++ /dev/null @@ -1,13 +0,0 @@ -const dotenv = require( 'dotenv' ); -const dotenv_expand = require( 'dotenv-expand' ); -const { execSync } = require( 'child_process' ); - -// WP_BASE_URL interpolates LOCAL_PORT, so needs to be parsed by dotenv_expand(). -dotenv_expand.expand( dotenv.config() ); - -// Run the tests, passing additional arguments through to the test script. -execSync( - 'wp-scripts test-e2e --config tests/visual-regression/jest.config.js ' + - process.argv.slice( 2 ).join( ' ' ), - { stdio: 'inherit' } -); diff --git a/tests/visual-regression/specs/visual-snapshots.test.js b/tests/visual-regression/specs/visual-snapshots.test.js index 458c40f86e0b7..d2f1eb9e7ebe0 100644 --- a/tests/visual-regression/specs/visual-snapshots.test.js +++ b/tests/visual-regression/specs/visual-snapshots.test.js @@ -1,222 +1,166 @@ -import { visitAdminPage } from '@wordpress/e2e-test-utils'; - -// See https://github.com/puppeteer/puppeteer/blob/main/docs/api.md#pagescreenshotoptions for more available options. -const screenshotOptions = { - fullPage: true, -}; - -async function hideElementVisibility( elements ) { - for ( let i = 0; i < elements.length; i++ ) { - const elementOnPage = await page.$( elements[ i ] ); - if ( elementOnPage ) { - await elementOnPage.evaluate( ( el ) => { - el.style.visibility = 'hidden'; - } ); - } - } - await page.waitFor( 1000 ); -} - -async function removeElementFromLayout( elements ) { - for ( let i = 0; i < elements.length; i++ ) { - const elementOnPage = await page.$( elements[ i ] ); - if ( elementOnPage ) { - await elementOnPage.evaluate( ( el ) => { - el.style.visibility = 'hidden'; - } ); - } - } - await page.waitFor( 1000 ); -} - -const elementsToHide = [ '#footer-upgrade', '#wp-admin-bar-root-default' ]; - -const elementsToRemove = [ '#toplevel_page_gutenberg' ]; - -describe( 'Admin Visual Snapshots', () => { - beforeAll( async () => { - await page.setViewport( { - width: 1000, - height: 750, - } ); - } ); - - it( 'All Posts', async () => { - await visitAdminPage( '/edit.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'Categories', async () => { - await visitAdminPage( '/edit-tags.php', 'taxonomy=category' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'Tags', async () => { - await visitAdminPage( '/edit-tags.php', 'taxonomy=post_tag' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'Media Library', async () => { - await visitAdminPage( '/upload.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'Add New Media', async () => { - await visitAdminPage( '/media-new.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'All Pages', async () => { - await visitAdminPage( '/edit.php', 'post_type=page' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'Comments', async () => { - await visitAdminPage( '/edit-comments.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'Widgets', async () => { - await visitAdminPage( '/widgets.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'Menus', async () => { - await visitAdminPage( '/nav-menus.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'Plugins', async () => { - await visitAdminPage( '/plugins.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); - - it( 'All Users', async () => { - await visitAdminPage( '/users.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; + +const elementsToHide = [ + '#footer-upgrade', + '#wp-admin-bar-root-default', + '#toplevel_page_gutenberg' +]; + +test.describe( 'Admin Visual Snapshots', () => { + test( 'All Posts', async ({ admin, page }) => { + await admin.visitAdminPage( '/edit.php' ); + await expect( page ).toHaveScreenshot( 'All Posts.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'Categories', async ({ admin, page }) => { + await admin.visitAdminPage( '/edit-tags.php', 'taxonomy=category' ); + await expect( page ).toHaveScreenshot( 'Categories.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'Tags', async ({ admin, page }) => { + await admin.visitAdminPage( '/edit-tags.php', 'taxonomy=post_tag' ); + await expect( page ).toHaveScreenshot( 'Tags.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'Media Library', async ({ admin, page }) => { + await admin.visitAdminPage( '/upload.php' ); + await expect( page ).toHaveScreenshot( 'Media Library.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'Add New Media', async ({ admin, page }) => { + await admin.visitAdminPage( '/media-new.php' ); + await expect( page ).toHaveScreenshot( 'Add New Media.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'All Pages', async ({ admin, page }) => { + await admin.visitAdminPage( '/edit.php', 'post_type=page' ); + await expect( page ).toHaveScreenshot( 'All Pages.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'Comments', async ({ admin, page }) => { + await admin.visitAdminPage( '/edit-comments.php' ); + await expect( page ).toHaveScreenshot( 'Comments.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'Widgets', async ({ admin, page }) => { + await admin.visitAdminPage( '/widgets.php' ); + await expect( page ).toHaveScreenshot( 'Widgets.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); } ); - it( 'Add New User', async () => { - await visitAdminPage( '/user-new.php' ); - await hideElementVisibility( [ - ...elementsToHide, - '.password-input-wrapper', - ] ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Menus', async ({ admin, page }) => { + await admin.visitAdminPage( '/nav-menus.php' ); + await expect( page ).toHaveScreenshot( 'Menus.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'Plugins', async ({ admin, page }) => { + await admin.visitAdminPage( '/plugins.php' ); + await expect( page ).toHaveScreenshot( 'Plugins.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'All Users', async ({ admin, page }) => { + await admin.visitAdminPage( '/users.php' ); + await expect( page ).toHaveScreenshot( 'All Users.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); + + test( 'Add New User', async ({ admin, page }) => { + await admin.visitAdminPage( '/user-new.php' ); + await expect( page ).toHaveScreenshot( 'Add New User.png', { + mask: [ + ...elementsToHide, + '.password-input-wrapper' + ].map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Your Profile', async () => { - await visitAdminPage( '/profile.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Your Profile', async ({ admin, page }) => { + await admin.visitAdminPage( '/profile.php' ); + await expect( page ).toHaveScreenshot( 'Your Profile.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Available Tools', async () => { - await visitAdminPage( '/tools.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Available Tools', async ({ admin, page }) => { + await admin.visitAdminPage( '/tools.php' ); + await expect( page ).toHaveScreenshot( 'Available Tools.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Import', async () => { - await visitAdminPage( '/import.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Import', async ({ admin, page }) => { + await admin.visitAdminPage( '/import.php' ); + await expect( page ).toHaveScreenshot( 'Import.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Export', async () => { - await visitAdminPage( '/export.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Export', async ({ admin, page }) => { + await admin.visitAdminPage( '/export.php' ); + await expect( page ).toHaveScreenshot( 'Export.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Export Personal Data', async () => { - await visitAdminPage( '/export-personal-data.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Export Personal Data', async ({ admin, page }) => { + await admin.visitAdminPage( '/export-personal-data.php' ); + await expect( page ).toHaveScreenshot( 'Export Personal Data.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Erase Personal Data', async () => { - await visitAdminPage( '/erase-personal-data.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Erase Personal Data', async ({ admin, page }) => { + await admin.visitAdminPage( '/erase-personal-data.php' ); + await expect( page ).toHaveScreenshot( 'Erase Personal Data.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Reading Settings', async () => { - await visitAdminPage( '/options-reading.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Reading Settings', async ({ admin, page }) => { + await admin.visitAdminPage( '/options-reading.php' ); + await expect( page ).toHaveScreenshot( 'Reading Settings.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Discussion Settings', async () => { - await visitAdminPage( '/options-discussion.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Discussion Settings', async ({ admin, page }) => { + await admin.visitAdminPage( '/options-discussion.php' ); + await expect( page ).toHaveScreenshot( 'Discussion Settings.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Media Settings', async () => { - await visitAdminPage( '/options-media.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); - } ); + test( 'Media Settings', async ({ admin, page }) => { + await admin.visitAdminPage( '/options-media.php' ); + await expect( page ).toHaveScreenshot( 'Media Settings.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); + } ); - it( 'Privacy Settings', async () => { - await visitAdminPage( '/options-privacy.php' ); - await hideElementVisibility( elementsToHide ); - await removeElementFromLayout( elementsToRemove ); - const image = await page.screenshot( screenshotOptions ); - expect( image ).toMatchImageSnapshot(); + test( 'Privacy Settings', async ({ admin, page }) => { + await admin.visitAdminPage( '/options-privacy.php' ); + await expect( page ).toHaveScreenshot( 'Privacy Settings.png', { + mask: elementsToHide.map( ( selector ) => page.locator( selector ) ), + }); } ); } );