diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..d877bfc --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,35 @@ + + +### πŸ”— Linked issue + + + +### ❓ Type of change + + + +- [ ] πŸ“– Documentation (updates to the documentation, readme or JSdoc annotations) +- [ ] 🐞 Bug fix (a non-breaking change that fixes an issue) +- [ ] πŸ‘Œ Enhancement (improving an existing functionality like performance) +- [ ] ✨ New feature (a non-breaking change that adds functionality) +- [ ] 🧹 Chore (updates to the build process or auxiliary tools and libraries) +- [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to change) + +### πŸ“š Description + + + + + +### πŸ“ Checklist + + + + + +- [ ] I have linked an issue or discussion. +- [ ] I have added tests (if possible). +- [ ] I have updated the documentation accordingly. +- [ ] I have updated the changelog. diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 0000000..8b3088d --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "github>studiometa/renovate" + ] +} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0d4e296..be13f7e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,28 +13,21 @@ jobs: with: fetch-depth: '0' - # @see https://github.com/actions/create-release/issues/38#issuecomment-715327220 - # @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#environment-files - - name: Prepare the changelog from the tag message - id: prepare_changelog - run: | - PRERELEASE=false - # Check release type + - run: | + NPM_TAG='latest' + IS_PRERELEASE=false + if [[ $GITHUB_REF_NAME =~ 'alpha' || $GITHUB_REF_NAME =~ 'beta' || $GITHUB_REF_NAME =~ 'rc' ]]; then - echo "This is a prerelease." - PRERELEASE=true + NPM_TAG='next' + IS_PRERELEASE=true fi - echo "is_prerelease=$PRERELEASE" >> $GITHUB_ENV - # @see https://github.com/actions/create-release - - name: Create Release - id: create_release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + echo "IS_PRERELEASE=$IS_PRERELEASE" >> $GITHUB_ENV + + - uses: ncipollo/release-action@v1 with: - tag_name: ${{ github.ref }} - release_name: v${{ github.ref_name }} + tag: ${{ github.ref }} + name: v${{ github.ref_name }} body: Please refer to [CHANGELOG.md](https://github.com/studiometa/wp-toolkit/blob/${{ github.ref_name }}/CHANGELOG.md) for details. draft: false - prerelease: ${{ env.is_prerelease }} + prerelease: ${{ env.IS_PRERELEASE }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3dd9f52..c942463 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,7 +19,7 @@ jobs: - '8.2' - '8.3' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup PHP, with composer and xdebug uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php @@ -32,7 +32,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -55,7 +55,7 @@ jobs: - '8.2' - '8.3' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup PHP, with composer and xdebug uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php @@ -68,7 +68,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -103,7 +103,7 @@ jobs: options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Setup PHP, with composer and xdebug uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php @@ -116,7 +116,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v4 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} @@ -125,6 +125,9 @@ jobs: - name: Install Composer dependencies run: composer install --no-progress --prefer-dist --optimize-autoloader + - name: Install WP Tests dependencies + run: sudo apt update && sudo apt install -y subversion + - name: Clean old WP Tests run: mysql --host 127.0.0.1 --port 3306 -uroot -proot -e "DROP DATABASE IF EXISTS wordpress_test;" && rm -fr /tmp/wordpress* @@ -135,11 +138,10 @@ jobs: run: XDEBUG_MODE=coverage ./vendor/bin/phpunit --coverage-clover='coverage.xml' - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v4 with: token: ${{ secrets.CODECOV_TOKEN }} file: ./coverage.xml flags: unittests fail_ci_if_error: true - path_to_write_report: ./codecov_report.txt verbose: true diff --git a/CHANGELOG.md b/CHANGELOG.md index 898f544..cf731b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +### Added + +- Add support for custom taxonomies filtering ([#42](https://github.com/studiometa/wp-toolkit/issues/42), [#43](https://github.com/studiometa/wp-toolkit/pull/43), [ae541b5](https://github.com/studiometa/wp-toolkit/commit/ae541b5)) + ## v2.2.2 - 2024.04.19 ### Fixed @@ -49,9 +53,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - Add an `EmailManager` to configure `PHPMailer` via environment variables ([#22](https://github.com/studiometa/wp-toolkit/pull/22)) - Add `enqueue_script($handle, $path)` and `enqueue_style($handle, $path)` method to the `AssetsManager` class ([#23](https://github.com/studiometa/wp-toolkit/pull/23)) - Add a `Plugin::disable` method to the `Plugin` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) -- Add a `request` helper function ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) +- Add a `request` helper function ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) - Add a `Request` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) -- Add a `env` helper function ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) +- Add a `env` helper function ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) - Add a `Env` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) ### Changed diff --git a/composer.lock b/composer.lock index fa33d45..6e23f71 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "dbac66e2af21cca739607377fdf3b4a3", + "content-hash": "6633aa682e8c566335320d476c4cbef3", "packages": [ { "name": "anahkiasen/html-object", @@ -54,16 +54,16 @@ }, { "name": "composer/installers", - "version": "v2.2.0", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/composer/installers.git", - "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35" + "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/c29dc4b93137acb82734f672c37e029dfbd95b35", - "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35", + "url": "https://api.github.com/repos/composer/installers/zipball/12fb2dfe5e16183de69e784a7b84046c43d97e8e", + "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e", "shasum": "" }, "require": { @@ -71,12 +71,12 @@ "php": "^7.2 || ^8.0" }, "require-dev": { - "composer/composer": "1.6.* || ^2.0", - "composer/semver": "^1 || ^3", - "phpstan/phpstan": "^0.12.55", - "phpstan/phpstan-phpunit": "^0.12.16", - "symfony/phpunit-bridge": "^5.3", - "symfony/process": "^5" + "composer/composer": "^1.10.27 || ^2.7", + "composer/semver": "^1.7.2 || ^3.4.0", + "phpstan/phpstan": "^1.11", + "phpstan/phpstan-phpunit": "^1", + "symfony/phpunit-bridge": "^7.1.1", + "symfony/process": "^5 || ^6 || ^7" }, "type": "composer-plugin", "extra": { @@ -133,6 +133,7 @@ "cockpit", "codeigniter", "concrete5", + "concreteCMS", "croogo", "dokuwiki", "drupal", @@ -179,7 +180,7 @@ ], "support": { "issues": "https://github.com/composer/installers/issues", - "source": "https://github.com/composer/installers/tree/v2.2.0" + "source": "https://github.com/composer/installers/tree/v2.3.0" }, "funding": [ { @@ -195,7 +196,7 @@ "type": "tidelift" } ], - "time": "2022-08-20T06:45:11+00:00" + "time": "2024-06-24T20:46:46+00:00" }, { "name": "guzzlehttp/psr7", @@ -813,16 +814,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.4.0", + "version": "v3.5.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/7c3aff79d10325257a001fcf92d991f24fc967cf", - "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", + "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1", "shasum": "" }, "require": { @@ -831,7 +832,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.4-dev" + "dev-main": "3.5-dev" }, "thanks": { "name": "symfony/contracts", @@ -860,7 +861,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.4.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0" }, "funding": [ { @@ -876,20 +877,20 @@ "type": "tidelift" } ], - "time": "2023-05-23T14:45:45+00:00" + "time": "2024-04-18T09:32:20+00:00" }, { "name": "symfony/http-foundation", - "version": "v6.4.4", + "version": "v6.4.14", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304" + "reference": "ba020a321a95519303a3f09ec2824d34d601c388" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ebc713bc6e6f4b53f46539fc158be85dfcd77304", - "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ba020a321a95519303a3f09ec2824d34d601c388", + "reference": "ba020a321a95519303a3f09ec2824d34d601c388", "shasum": "" }, "require": { @@ -937,7 +938,7 @@ "description": "Defines an object-oriented layer for the HTTP specification", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/http-foundation/tree/v6.4.4" + "source": "https://github.com/symfony/http-foundation/tree/v6.4.14" }, "funding": [ { @@ -953,7 +954,7 @@ "type": "tidelift" } ], - "time": "2024-02-08T15:01:18+00:00" + "time": "2024-11-05T16:39:55+00:00" }, { "name": "symfony/options-resolver", @@ -1024,16 +1025,16 @@ }, { "name": "symfony/polyfill-ctype", - "version": "v1.29.0", + "version": "v1.30.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" + "reference": "0424dff1c58f028c451efff2045f5d92410bd540" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", - "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/0424dff1c58f028c451efff2045f5d92410bd540", + "reference": "0424dff1c58f028c451efff2045f5d92410bd540", "shasum": "" }, "require": { @@ -1083,7 +1084,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.30.0" }, "funding": [ { @@ -1099,24 +1100,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-05-31T15:07:36+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", - "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/85181ba99b2345b0ef10ce42ecac37612d9fd341", + "reference": "85181ba99b2345b0ef10ce42ecac37612d9fd341", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "provide": { "ext-mbstring": "*" @@ -1163,7 +1164,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.31.0" }, "funding": [ { @@ -1179,24 +1180,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", - "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=7.2" }, "type": "library", "extra": { @@ -1243,7 +1244,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.31.0" }, "funding": [ { @@ -1259,25 +1260,24 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/polyfill-php83", - "version": "v1.29.0", + "version": "v1.31.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "86fcae159633351e5fd145d1c47de6c528f8caff" + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff", - "reference": "86fcae159633351e5fd145d1c47de6c528f8caff", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", "shasum": "" }, "require": { - "php": ">=7.1", - "symfony/polyfill-php80": "^1.14" + "php": ">=7.2" }, "type": "library", "extra": { @@ -1320,7 +1320,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.31.0" }, "funding": [ { @@ -1336,7 +1336,7 @@ "type": "tidelift" } ], - "time": "2024-01-29T20:11:03+00:00" + "time": "2024-09-09T11:45:10+00:00" }, { "name": "symfony/var-dumper", @@ -1552,16 +1552,16 @@ }, { "name": "timber/timber", - "version": "2.0.0", + "version": "v2.1.0", "source": { "type": "git", "url": "https://github.com/timber/timber.git", - "reference": "ee467c650e51d042a04d9107f35239cbc566d4d7" + "reference": "d353d1912a1a051f47ba2d3f2e3ae1af1e5bed53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/timber/timber/zipball/ee467c650e51d042a04d9107f35239cbc566d4d7", - "reference": "ee467c650e51d042a04d9107f35239cbc566d4d7", + "url": "https://api.github.com/repos/timber/timber/zipball/d353d1912a1a051f47ba2d3f2e3ae1af1e5bed53", + "reference": "d353d1912a1a051f47ba2d3f2e3ae1af1e5bed53", "shasum": "" }, "require": { @@ -1573,7 +1573,7 @@ "require-dev": { "ergebnis/composer-normalize": "^2.28", "php-parallel-lint/php-parallel-lint": "^1.3", - "php-stubs/acf-pro-stubs": "^5.12", + "php-stubs/acf-pro-stubs": "^6.0", "php-stubs/wp-cli-stubs": "^2.0", "phpro/grumphp": "^1.12", "phpstan/extension-installer": "^1.1", @@ -1601,24 +1601,39 @@ "MIT" ], "authors": [ + { + "name": "Erik van der Bas", + "email": "erik@basedonline.nl", + "homepage": "https://basedonline.nl" + }, + { + "name": "Lukas GΓ€chter", + "email": "lukas.gaechter@mind.ch", + "homepage": "https://www.mind.ch" + }, + { + "name": "Nicolas Lemoine", + "email": "nico@n5s.dev", + "homepage": "https://n5s.dev" + }, { "name": "Jared Novack", "email": "jared@upstatement.com", - "homepage": "http://upstatement.com" + "homepage": "https://upstatement.com" }, { - "name": "Connor J. Burton", - "email": "connorjburton@gmail.com", - "homepage": "http://connorburton.com" + "name": "Timber Community", + "homepage": "https://github.com/timber/timber" } ], - "description": "Plugin to write WordPress themes w Object-Oriented Code and the Twig Template Engine", + "description": "Create WordPress themes with beautiful OOP code and the Twig Template Engine", "homepage": "http://timber.upstatement.com", "keywords": [ "templating", "themes", "timber", - "twig" + "twig", + "wordpress" ], "support": { "docs": "https://timber.github.io/docs/", @@ -1631,34 +1646,41 @@ "type": "open_collective" } ], - "time": "2023-11-09T08:30:32+00:00" + "time": "2024-04-10T15:02:17+00:00" }, { "name": "twig/twig", - "version": "v3.8.0", + "version": "v3.10.3", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d" + "reference": "67f29781ffafa520b0bbfbd8384674b42db04572" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", - "reference": "9d15f0ac07f44dc4217883ec6ae02fd555c6f71d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/67f29781ffafa520b0bbfbd8384674b42db04572", + "reference": "67f29781ffafa520b0bbfbd8384674b42db04572", "shasum": "" }, "require": { "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "^1.3", "symfony/polyfill-php80": "^1.22" }, "require-dev": { "psr/container": "^1.0|^2.0", - "symfony/phpunit-bridge": "^5.4.9|^6.3|^7.0" + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" }, "type": "library", "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], "psr-4": { "Twig\\": "src/" } @@ -1691,7 +1713,7 @@ ], "support": { "issues": "https://github.com/twigphp/Twig/issues", - "source": "https://github.com/twigphp/Twig/tree/v3.8.0" + "source": "https://github.com/twigphp/Twig/tree/v3.10.3" }, "funding": [ { @@ -1703,7 +1725,7 @@ "type": "tidelift" } ], - "time": "2023-11-21T18:54:41+00:00" + "time": "2024-05-16T10:04:27+00:00" }, { "name": "wecodemore/wordpress-early-hook", @@ -4020,12 +4042,12 @@ ], "aliases": [], "minimum-stability": "dev", - "stability-flags": [], + "stability-flags": {}, "prefer-stable": true, "prefer-lowest": false, "platform": { "php": "^8.1" }, - "platform-dev": [], + "platform-dev": {}, "plugin-api-version": "2.6.0" } diff --git a/src/Managers/FacetsManager.php b/src/Managers/FacetsManager.php index db4e90c..5dc74d7 100644 --- a/src/Managers/FacetsManager.php +++ b/src/Managers/FacetsManager.php @@ -8,7 +8,6 @@ namespace Studiometa\WPToolkit\Managers; use WP_Query; -use Timber\Timber; use Twig\Environment; use Twig\TwigFunction; use Studiometa\WPToolkit\Managers\ManagerInterface; @@ -63,9 +62,106 @@ public function add_facets_to_query(WP_Query &$query): void return; } + $tax_queries = []; + $regular_vars = []; + foreach ($this->facets as $query_var => $value) { - $query->query_vars[ $query_var ] = $value; + $taxonomy_data = $this->parse_taxonomy_query_var($query_var); + + if ($taxonomy_data) { + $tax_queries[] = $this->build_tax_query($taxonomy_data, $value); + } else { + $regular_vars[$query_var] = $value; + } + } + + // Apply regular query vars + foreach ($regular_vars as $query_var => $value) { + $query->query_vars[$query_var] = $value; + } + + // Apply taxonomy queries + if (!empty($tax_queries)) { + $existing_tax_query = $query->get('tax_query', []); + if (!empty($existing_tax_query)) { + $tax_queries[] = $existing_tax_query; + } + $query->set('tax_query', $tax_queries); + } + } + + /** + * Parse a query variable to determine if it's a taxonomy query. + * + * @param string $query_var The query variable name. + * @return array|null Array with taxonomy and operator data, or null if not a taxonomy query. + */ + private function parse_taxonomy_query_var(string $query_var): ?array + { + $taxonomies = get_taxonomies(['public' => true]); + + // Direct taxonomy match + if (array_key_exists($query_var, $taxonomies)) { + return ['taxonomy' => $query_var, 'operator' => 'IN']; + } + + // Check for suffixed taxonomy queries + $suffixes = ['__in', '__not_in', '__and', '__exists']; + foreach ($suffixes as $suffix) { + if (str_ends_with($query_var, $suffix)) { + $taxonomy = substr($query_var, 0, -strlen($suffix)); + if (array_key_exists($taxonomy, $taxonomies)) { + $operator = match ($suffix) { + '__in' => 'IN', + '__not_in' => 'NOT IN', + '__and' => 'AND', + '__exists' => 'EXISTS', + }; + return ['taxonomy' => $taxonomy, 'operator' => $operator]; + } + } } + + return null; + } + + /** + * Build a tax_query array for a given taxonomy and value. + * + * @param array $taxonomy_data Array with taxonomy and operator info. + * @param string|array $value The query value. + * @return array The tax_query array. + */ + private function build_tax_query(array $taxonomy_data, string|array $value): array + { + $tax_query = [ + 'taxonomy' => $taxonomy_data['taxonomy'], + 'operator' => $taxonomy_data['operator'], + ]; + + if ($taxonomy_data['operator'] === 'EXISTS') { + // EXISTS queries don't need terms/field + return $tax_query; + } + + // Handle different value types + if (is_array($value)) { + $terms = $value; + } else { + $terms = array_map('trim', explode(',', $value)); + } + + // Determine if we're dealing with term IDs or slugs + $first_term = reset($terms); + if (is_numeric($first_term)) { + $tax_query['field'] = 'term_id'; + $tax_query['terms'] = array_map('intval', $terms); + } else { + $tax_query['field'] = 'slug'; + $tax_query['terms'] = $terms; + } + + return $tax_query; } /** diff --git a/src/TransientCleaner.php b/src/TransientCleaner.php index 1019c86..601b398 100644 --- a/src/TransientCleaner.php +++ b/src/TransientCleaner.php @@ -107,7 +107,7 @@ public function define_public_hooks() add_action('save_post', array( $this, 'post_transient_cleaner' ), 10, 2); add_action('edit_term', array( $this, 'term_transient_cleaner' ), 10, 3); add_action('updated_option', array( $this, 'option_transient_cleaner' ), 10, 2); - add_action('setted_transient', array( $this, 'store_transient_key' )); + add_action('set_transient', array( $this, 'store_transient_key' )); add_filter( 'pre_update_option_' . self::OPTION_STORED_TRANSIENTS, array( $this, 'merge_stored_transients_option_values' ), diff --git a/tests/Managers/FacetsManagerTest.php b/tests/Managers/FacetsManagerTest.php index 195811b..25e6236 100644 --- a/tests/Managers/FacetsManagerTest.php +++ b/tests/Managers/FacetsManagerTest.php @@ -51,4 +51,163 @@ public function test_it_should_add_a_twig_helper_function() $this->assertTrue($function instanceof TwigFunction); $this->assertTrue($function->getCallable()('cat') === 2); } + + public function test_it_should_handle_taxonomy_queries_with_slugs() + { + // Register a test taxonomy + register_taxonomy('test_taxonomy', 'post', ['public' => true]); + + request()->query->set('facets', ['test_taxonomy' => 'slug1,slug2']); + $manager = new FacetsManager(); + $manager->run(); + + $this->go_to('/?facets[test_taxonomy]=slug1,slug2'); + global $wp_query; + + $tax_query = $wp_query->get('tax_query'); + $this->assertIsArray($tax_query); + $this->assertCount(1, $tax_query); + $this->assertEquals('test_taxonomy', $tax_query[0]['taxonomy']); + $this->assertEquals('IN', $tax_query[0]['operator']); + $this->assertEquals('slug', $tax_query[0]['field']); + $this->assertEquals(['slug1', 'slug2'], $tax_query[0]['terms']); + } + + public function test_it_should_handle_taxonomy_queries_with_ids() + { + register_taxonomy('test_taxonomy', 'post', ['public' => true]); + + request()->query->set('facets', ['test_taxonomy' => '1,2,3']); + $manager = new FacetsManager(); + $manager->run(); + + $this->go_to('/?facets[test_taxonomy]=1,2,3'); + global $wp_query; + + $tax_query = $wp_query->get('tax_query'); + $this->assertEquals('term_id', $tax_query[0]['field']); + $this->assertEquals([1, 2, 3], $tax_query[0]['terms']); + } + + public function test_it_should_handle_taxonomy_not_in_queries() + { + register_taxonomy('test_taxonomy', 'post', ['public' => true]); + + request()->query->set('facets', ['test_taxonomy__not_in' => 'excluded-slug']); + $manager = new FacetsManager(); + $manager->run(); + + $this->go_to('/?facets[test_taxonomy__not_in]=excluded-slug'); + global $wp_query; + + $tax_query = $wp_query->get('tax_query'); + $this->assertEquals('test_taxonomy', $tax_query[0]['taxonomy']); + $this->assertEquals('NOT IN', $tax_query[0]['operator']); + $this->assertEquals(['excluded-slug'], $tax_query[0]['terms']); + } + + public function test_it_should_handle_taxonomy_and_queries() + { + register_taxonomy('test_taxonomy', 'post', ['public' => true]); + + request()->query->set('facets', ['test_taxonomy__and' => 'slug1,slug2']); + $manager = new FacetsManager(); + $manager->run(); + + $this->go_to('/?facets[test_taxonomy__and]=slug1,slug2'); + global $wp_query; + + $tax_query = $wp_query->get('tax_query'); + $this->assertEquals('AND', $tax_query[0]['operator']); + } + + public function test_it_should_handle_taxonomy_exists_queries() + { + register_taxonomy('test_taxonomy', 'post', ['public' => true]); + + request()->query->set('facets', ['test_taxonomy__exists' => '1']); + $manager = new FacetsManager(); + $manager->run(); + + $this->go_to('/?facets[test_taxonomy__exists]=1'); + global $wp_query; + + $tax_query = $wp_query->get('tax_query'); + $this->assertEquals('test_taxonomy', $tax_query[0]['taxonomy']); + $this->assertEquals('EXISTS', $tax_query[0]['operator']); + $this->assertArrayNotHasKey('terms', $tax_query[0]); + $this->assertArrayNotHasKey('field', $tax_query[0]); + } + + public function test_it_should_combine_taxonomy_and_regular_queries() + { + register_taxonomy('test_taxonomy', 'post', ['public' => true]); + + request()->query->set('facets', [ + 'test_taxonomy' => 'test-slug', + 'meta_key' => 'custom_field', + 'posts_per_page' => 5 + ]); + $manager = new FacetsManager(); + $manager->run(); + + $this->go_to('/?facets[test_taxonomy]=test-slug&facets[meta_key]=custom_field&facets[posts_per_page]=5'); + global $wp_query; + + // Check taxonomy query + $tax_query = $wp_query->get('tax_query'); + $this->assertIsArray($tax_query); + $this->assertEquals('test_taxonomy', $tax_query[0]['taxonomy']); + + // Check regular query vars + $this->assertEquals('custom_field', $wp_query->query_vars['meta_key']); + $this->assertEquals(5, $wp_query->query_vars['posts_per_page']); + } + + public function test_it_should_handle_existing_tax_query() + { + register_taxonomy('test_taxonomy', 'post', ['public' => true]); + + request()->query->set('facets', ['test_taxonomy' => 'new-slug']); + $manager = new FacetsManager(); + $manager->run(); + + // Set up existing tax_query + $existing_tax_query = [ + [ + 'taxonomy' => 'category', + 'field' => 'slug', + 'terms' => ['existing-category'], + 'operator' => 'IN' + ] + ]; + + $this->go_to('/?facets[test_taxonomy]=new-slug'); + global $wp_query; + $wp_query->set('tax_query', $existing_tax_query); + + // Trigger the facets query modification + $manager->add_facets_to_query($wp_query); + + $tax_query = $wp_query->get('tax_query'); + $this->assertCount(2, $tax_query); + $this->assertEquals('test_taxonomy', $tax_query[0]['taxonomy']); + $this->assertEquals('category', $tax_query[1][0]['taxonomy']); + } + + public function test_it_should_handle_array_values_in_facets() + { + register_taxonomy('test_taxonomy', 'post', ['public' => true]); + + request()->query->set('facets', ['test_taxonomy' => ['slug1', 'slug2']]); + $manager = new FacetsManager(); + $manager->run(); + + $this->go_to('/?facets[test_taxonomy][]=slug1&facets[test_taxonomy][]=slug2'); + global $wp_query; + + $tax_query = $wp_query->get('tax_query'); + $this->assertEquals(['slug1', 'slug2'], $tax_query[0]['terms']); + $this->assertEquals('slug', $tax_query[0]['field']); + } }