Skip to content

Taxonomy: Prevent overlong term slugs in wp_unique_term_slug() - #13155

Open
itzmekhokan wants to merge 2 commits into
WordPress:trunkfrom
itzmekhokan:fix/46010-term-slug-length
Open

Taxonomy: Prevent overlong term slugs in wp_unique_term_slug()#13155
itzmekhokan wants to merge 2 commits into
WordPress:trunkfrom
itzmekhokan:fix/46010-term-slug-length

Conversation

@itzmekhokan

Copy link
Copy Markdown

wp_unique_term_slug() appends a parent slug or numeric suffix without
reserving room in the 200 character slug column. wp_insert_term() then
fails with a generic "Could not insert term into the database.";
wp_update_term() discards the write without reporting an error.

Non-ASCII slugs are stored percent-encoded, so this is reachable from the
Categories screen with short names in any non-Latin script — the ticket uses a
21 character Cyrillic name.

The slug is now truncated before appending, reserving room for the suffix, as
wp_unique_post_slug() already does. The helper is renamed _truncate_slug()
and moved to formatting.php since it is not post specific, with
_truncate_post_slug() kept as a silent alias. Fixing this inside
wp_unique_term_slug() covers wp_update_term() too, as suggested on the
ticket.

Trac ticket: https://core.trac.wordpress.org/ticket/46010

Use of AI Tools

AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: Root-cause investigation against trunk, the patch, the unit tests, and running the PHPUnit/PHPCS/PHPStan validation. All changes were reviewed and validated by me.
and final review are mine.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

The helper is not post specific: it truncates any slug on a character boundary so
that a percent-encoded sequence is never cut in half. Move it to
wp-includes/formatting.php under a generic name and update core's call sites in
post.php and theme-templates.php.

`_truncate_post_slug()` is retained as an alias. It is marked `@access private` so
it carries no backward compatibility guarantee, but it has existed since 3.6.0 and
is called by plugins in the wild, so removing it outright would fatal them. It does
not emit a deprecation notice, for the same reason it was never public API.

The existing data provider moves to the new function's test file; the old file now
covers the alias.

See #46010.
Appending a parent slug or a numeric suffix could push a term slug past the 200
character limit of the `slug` column in the terms table. When that happened
`wp_insert_term()` failed with a generic "Could not insert term into the
database." error, and `wp_update_term()` discarded the write without reporting an
error at all.

Non-ASCII slugs are stored percent-encoded, so this is reachable from the
Categories screen with short term names in any non-Latin script: the ticket's
original report used a 21 character Cyrillic name.

Truncate the slug before appending, reserving room for the suffix, the same way
`wp_unique_post_slug()` already does. `_truncate_slug()` truncates on a character
boundary, so a percent-encoded sequence is never cut in half. Doing this inside
`wp_unique_term_slug()` covers `wp_update_term()` as well as `wp_insert_term()`.

Fixes #46010.
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props khokansardar.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant