Make WordPress Core

Opened 6 days ago

Last modified 6 days ago

#66496 new enhancement

Tests: Add unit coverage for the permalink methods of WP_Rewrite

Reported by: hmbashar Owned by:
Priority: normal Milestone: Awaiting Review
Component: Rewrite Rules Version:
Severity: normal Keywords: has-patch has-unit-tests
Cc: Focuses: tests

Description

WP_Rewrite in src/wp-includes/class-wp-rewrite.php builds the permalink structures of the site, but several of its methods have no direct PHPUnit coverage. A search of tests/phpunit/tests finds no references to:

  • using_permalinks(), using_mod_rewrite_permalinks(), preg_index(), set_category_base() and set_tag_base().
  • get_date_permastruct(), get_year_permastruct(), get_month_permastruct(), get_day_permastruct(), get_extra_permastruct(), get_category_permastruct() and get_tag_permastruct().
  • get_author_permastruct(), get_search_permastruct(), get_page_permastruct(), get_feed_permastruct() and get_comment_feed_permastruct().
  • add_external_rule() and add_endpoint().

They are exercised indirectly through the rewrite and query tests, so a change in the structure of a permalink is hard to spot and to attribute. Direct tests describe the current behavior of each method.

Proposed scope

This ticket is meant to be handled with several small patches, one for each group of related methods, so each one is easy to review. The tests go in tests/phpunit/tests/rewrite/, one class per method or per small group of methods.

  1. Permalink checks and bases. using_permalinks() and using_mod_rewrite_permalinks() with plain, pretty and index.php structures. preg_index() with and without a prefix for the matches. set_category_base() and set_tag_base(): the option is updated and the rules are initialized again only when the base changes.
  2. Date and taxonomy structures. get_date_permastruct() for each order of the year, month and day, and with %post_id% near the start. get_year_permastruct(), get_month_permastruct() and get_day_permastruct() derived from it, and false without permalinks. get_extra_permastruct(), get_category_permastruct() and get_tag_permastruct().
  3. Other structures, external rules and endpoints. get_author_permastruct(), get_search_permastruct(), get_page_permastruct(), get_feed_permastruct() and get_comment_feed_permastruct() with the front and the root, and the custom bases. add_external_rule() and add_endpoint(), including the query variable.

Out of scope

This ticket only adds tests and does not change behavior. The following are left out on purpose because other tickets are working on them:

  • using_index_permalinks(), see #58764.
  • generate_rewrite_rules(), generate_rewrite_rule() and page_rewrite_rules(), see #35916 and #36812.
  • mod_rewrite_rules() and iis7_url_rewrite_rules(), which build server configuration, see #34776 and #40719.

Related: #65819.

Change History (4)

This ticket was mentioned in ​PR #15535 on ​WordPress/wordpress-develop by ​@hmbashar.


6 days ago
#1

  • Keywords has-patch has-unit-tests added; needs-patch removed

Adds unit tests for the permalink checks and the category and tag bases of WP_Rewrite in src/wp-includes/class-wp-rewrite.php, which had no direct test coverage. This is the first group of the work described in the ticket, and each of the groups is a separate PR. No behavior is changed.

Methods covered, each in its own test class in tests/phpunit/tests/rewrite/:

  • using_permalinks() and using_mod_rewrite_permalinks()
    • Plain permalinks, pretty permalinks, and structures that start with index.php (with and without leading slashes), or have it later in the structure or in a longer name.
    • Both return booleans, the name of the index file of the object is used, and the global object follows the permalink structure of the site.
  • preg_index()
    • A reference to a match such as $3 without a prefix, and $matches[3] with one.
  • set_category_base() and set_tag_base()
    • The option is updated and the object is initialized again only when the base changes, the other base is not changed, and the base is used in the permalinks of categories and tags.

using_index_permalinks() is not tested here, because #58764 is about its return type.

Testing:

  • vendor/bin/phpunit --filter 'Tests_Rewrite_(UsingPermalinks|PregIndex|SetCategoryBase|SetTagBase)'
  • vendor/bin/phpunit -c tests/phpunit/multisite.xml --filter 'Tests_Rewrite_(UsingPermalinks|PregIndex|SetCategoryBase|SetTagBase)'
  • vendor/bin/phpunit --group rewrite
  • vendor/bin/phpcs tests/phpunit/tests/rewrite/

I also temporarily broke the related lines in src/wp-includes/class-wp-rewrite.php (the checks of the permalinks and of the index, the prefix and the suffix of the reference, and for each base the update, the initialization, the check for a change, and the option that is written) and confirmed that a new test fails for each one.

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Sonnet 5.5
Used for: Written with AI and manually reviewed by me.

This ticket was mentioned in ​PR #15536 on ​WordPress/wordpress-develop by ​@hmbashar.


6 days ago
#2

Adds unit tests for the date and the taxonomy structures of WP_Rewrite in src/wp-includes/class-wp-rewrite.php, which had no direct test coverage. This is the second group of the work described in the ticket, and is independent from the other groups. No behavior is changed.

Methods covered, in tests/phpunit/tests/rewrite/:

  • get_date_permastruct()
    • The structure of the date for each order of the year, month and day, and the default order when the permalinks have no date.
    • A front or index.php before the date is kept, and a date/ part is added when %post_id% is one of the first three tags (and not when it is later).
    • false is returned without permalinks, the structure is kept after it was built, and it is built again after the object is initialized again.
  • get_year_permastruct(), get_month_permastruct() and get_day_permastruct()
    • The structures derived from the date, for each order and with a front or a date/ part, without repeated slashes.
    • false is returned without permalinks, and the structure of the days is the structure of the dates.
  • get_extra_permastruct(), get_category_permastruct() and get_tag_permastruct()
    • The structure of a name is returned, false for a name that does not exist or without permalinks, and the categories and the tags use the structures named category and post_tag.

The tests of the three structures of the date call each method on a new object. After the first call, the structure of an object without permalinks is cached as an empty string, so the following calls do not return false, and the tests do not depend on that.

Testing:

  • vendor/bin/phpunit --filter 'Tests_Rewrite_(GetDatePermastruct|GetYearMonthDayPermastruct|GetExtraPermastruct)'
  • vendor/bin/phpunit -c tests/phpunit/multisite.xml --filter 'Tests_Rewrite_(GetDatePermastruct|GetYearMonthDayPermastruct|GetExtraPermastruct)'
  • vendor/bin/phpunit --group rewrite
  • vendor/bin/phpcs tests/phpunit/tests/rewrite/

I also temporarily broke the related lines in src/wp-includes/class-wp-rewrite.php (the cache and the check for permalinks of the date, each order of the date, the limit of the post ID, the front, each replacement of the year and the month, the slashes, the false results, and the names of the categories and tags) and confirmed that a new test fails for each one.

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Sonnet 5.5
Used for: Written with AI and manually reviewed by me.

This ticket was mentioned in ​PR #15537 on ​WordPress/wordpress-develop by ​@hmbashar.


6 days ago
#3

Adds unit tests for the other permalink structures, the external rules and the endpoints of WP_Rewrite in src/wp-includes/class-wp-rewrite.php, which had no direct test coverage. This is the third and last group of the work described in the ticket, and is independent from the other groups. No behavior is changed.

Methods covered, in tests/phpunit/tests/rewrite/:

  • get_author_permastruct(), get_search_permastruct(), get_page_permastruct(), get_feed_permastruct() and get_comment_feed_permastruct()
    • The structure for pretty permalinks, with a front and with index.php. The author structure uses the front, and the others use the root of the object.
    • The author_base, search_base, feed_base and comments_base of the object are used.
    • false is returned without permalinks (and the structure is empty), the structure is kept after it was built, and it is built again when the object is initialized again.
  • add_external_rule()
    • The rule is stored with its query, rules are kept in order and the same expression is replaced, the rules are removed when the object is initialized again, and the rule is not one of the rules of WordPress.
  • add_endpoint()
    • The endpoint is stored with the places and the query variable, and the name is the query variable when it is true or null.
    • Another name can be used, no query variable is added when it is false, and the endpoints are removed when the object is initialized again.
    • add_rewrite_endpoint() uses it.

Testing:

  • vendor/bin/phpunit --filter 'Tests_Rewrite_(GetPermastructs|AddExternalRule|AddEndpoint)'
  • vendor/bin/phpunit -c tests/phpunit/multisite.xml --filter 'Tests_Rewrite_(GetPermastructs|AddExternalRule|AddEndpoint)'
  • vendor/bin/phpunit --group rewrite
  • vendor/bin/phpcs tests/phpunit/tests/rewrite/

I also temporarily broke the related lines in src/wp-includes/class-wp-rewrite.php (the front, the root and each base of the structures, the caches, the checks for permalinks, where the external rules and the endpoints are stored, and each branch of the query variable) and confirmed that a new test fails for each one.

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Sonnet 5.5
Used for: Written with AI and manually reviewed by me.

This ticket was mentioned in ​PR #15537 on ​WordPress/wordpress-develop by ​@hmbashar.


6 days ago
#4

Adds unit tests for the other permalink structures, the external rules and the endpoints of WP_Rewrite in src/wp-includes/class-wp-rewrite.php, which had no direct test coverage. This is the third and last group of the work described in the ticket, and is independent from the other groups. No behavior is changed.

Methods covered, in tests/phpunit/tests/rewrite/:

  • get_author_permastruct(), get_search_permastruct(), get_page_permastruct(), get_feed_permastruct() and get_comment_feed_permastruct()
    • The structure for pretty permalinks, with a front and with index.php. The author structure uses the front, and the others use the root of the object.
    • The author_base, search_base, feed_base and comments_base of the object are used.
    • false is returned without permalinks (and the structure is empty), the structure is kept after it was built, and it is built again when the object is initialized again.
  • add_external_rule()
    • The rule is stored with its query, rules are kept in order and the same expression is replaced, the rules are removed when the object is initialized again, and the rule is not one of the rules of WordPress.
  • add_endpoint()
    • The endpoint is stored with the places and the query variable, and the name is the query variable when it is true or null.
    • Another name can be used, no query variable is added when it is false, and the endpoints are removed when the object is initialized again.
    • add_rewrite_endpoint() uses it.

Testing:

  • vendor/bin/phpunit --filter 'Tests_Rewrite_(GetPermastructs|AddExternalRule|AddEndpoint)'
  • vendor/bin/phpunit -c tests/phpunit/multisite.xml --filter 'Tests_Rewrite_(GetPermastructs|AddExternalRule|AddEndpoint)'
  • vendor/bin/phpunit --group rewrite
  • vendor/bin/phpcs tests/phpunit/tests/rewrite/

I also temporarily broke the related lines in src/wp-includes/class-wp-rewrite.php (the front, the root and each base of the structures, the caches, the checks for permalinks, where the external rules and the endpoints are stored, and each branch of the query variable) and confirmed that a new test fails for each one.

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Sonnet 5.5
Used for: Written with AI and manually reviewed by me.

Note: See TracTickets for help on using tickets.