While re-checking the WordPress homepage recently, I noticed a familiar issue reappearing in the category dropdown list.
After selecting PHP Simple HTML DOM Parser from the category dropdown list on the right side of the homepage, the browser accessed:
https://www.shuijingwanwq.com/?category_name=php-simple-html-dom-parser
However, the page did not proceed to the actual category archive; instead, it still displayed the homepage content.

category_name query parameter, and the current page does not enter the corresponding category archive.This phenomenon quickly reminded me of two previous adjustments: one was a multilingual domain fix for the category dropdown list, and the other was a cache optimization for CDN Query Strings.
These two features, originally functioning normally on their own, created a new conflict when combined later.
1. This category dropdown list was actually fixed once before
On July 13, 2026, after migrating the WordPress English site to an independent subdomain, I dealt with a category dropdown list redirect error.
The complete troubleshooting process at that time is documented in WordPress Polylang Links Still Point to Chinese Site After English Subdomain Migration: A Complete Fix for Category Dropdowns, Breadcrumbs, and Block Templates.
When publishing to WordPress, these body links are all set to “open in new tab”.
The most obvious issue back then was that after selecting the Browser category on the English homepage, even though the category slug belonged to the English category, the redirect URL still used the Chinese main domain. The article ultimately confirmed that there was no issue with the English category data or the official category permalink itself; the error mainly occurred in the redirect address generated by the category dropdown list.
The workflow after that fix remained:
Select category
↓
Generate /?category_name=category-slug
↓
WordPress parses category_name
↓
Redirect to final category permalink
For example:
https://en.shuijingwanwq.com/?category_name=browser-en
Then it would proceed to:
https://en.shuijingwanwq.com/category/application-tool-en/browser-en/
This approach worked fine at the time.
2. The subsequent Query String optimization exposed this problem again
On August 3, 2026, I performed a Query String normalization optimization for WordPress page caching and CDN Cache Keys.
The relevant process is documented in From EdgeOne 524 to Query String Normalization: WordPress Posts and Public List Pages CDN Cache Optimization in Practice.
The core goal of this optimization was to prevent query parameters that do not change page content from continuously generating new cache versions.
For example, for standard public pages:
/
And:
/?random=123
If the final page content is exactly the same, there is no need to maintain separate page caches.
There was nothing wrong with this optimization direction itself.
But after re-testing the category dropdown list, I realized:
category_name
is not just a meaningless query string.
It serves the actual redirect function for the WordPress category dropdown list.
This led to the following conflict chain:
Category dropdown list
↓
Generates ?category_name=slug
↓
CDN Query String normalization
↓
category_name no longer affects the request as it originally did
↓
WordPress receives an effect similar to a standard homepage
The initially obvious fix was to continue modifying EdgeOne or Cloudflare rules to include:
category_name
among the functional query strings that need to be protected.
But thinking one step further, I realized there was a simpler question:
Why must the category dropdown list go through ?category_name= first?
3. Since we already know the final address, why not redirect directly?
What WordPress categories actually need to access is the standard category permalink.
For example, the final address for PHP Simple HTML DOM Parser looks like:
/category/web-devel/html-parser/php-simple-html-dom-parser/
So the current chain:
Select category
↓
/?category_name=slug
↓
WordPress parses again
↓
Final category address
can be completely simplified to:
Select category
↓
Final category address
The benefits of this are straightforward.
First, it eliminates an intermediate request.
Second, the category dropdown list no longer relies on Query Strings.
Third, it is completely decoupled from the CDN’s Query String caching rules.
Fourth, category archives are inherently standard permalink formats, making subsequent caching strategies much more intuitive.
However, we cannot simply construct the URL ourselves based on the slug:
/category/php-simple-html-dom-parser/
Because my WordPress categories have a parent-child hierarchy.
The actual address might be:
/category/web-devel/html-parser/php-simple-html-dom-parser/
Therefore, the final URL should still be generated by WordPress itself, rather than guessing the path in JavaScript.
4. Continue using WPCode without modifying Twenty Twenty-Five
This time, I chose to use WPCode to complete the adjustment, rather than directly modifying the Twenty Twenty-Five theme files.
The original code snippet name was:
Fix category dropdown list redirect domain for non-default language sites
Its primary responsibility was to fix the issue found on July 13, where the English site redirected back to the Chinese main domain.
Now that the functionality has changed, I renamed it to:
Category dropdown list direct redirect to final category link
I did not create a second code snippet, but directly modified the original code.
This avoids having two JavaScript snippets listening to the same category dropdown list simultaneously.

5. Leave page scope to WPCode as much as possible, instead of piling up PHP conditionals
During this adjustment, I also continued using a WPCode workflow that I have preferred lately:
If page checks can be handled via Location and Smart Conditional Logic, do not duplicate them in PHP.
The code snippet uses:
Code Type:
PHP Snippet
Insert Method:
Auto Insert
Location:
Frontend Conditional Logic
Initially, I considered restricting it to the Homepage only.
But upon inspection, I found that the category dropdown list exists not only on the homepage but also on archive pages like category pages.
Therefore, the final configuration is:
Type of Page → Is → Homepage
OR
Type of Page → Is → Archive

This way, there is no need to maintain page conditionals like:
is_front_page()
is_home()
is_archive()
is_admin()
in the PHP code.
WPCode is responsible for answering:
Which pages need to execute this?
The PHP code is only responsible for answering:
How should the category dropdown list redirect directly to the final URL?
This makes the responsibilities much clearer.
6. Final code
The final WPCode used is as follows:
/**
* SWQ:分类下拉列表直接跳转最终分类链接。
*/
add_filter(
'render_block_core/categories',
function ( $block_content, $block ) {
if ( empty( $block['attrs']['displayAsDropdown'] ) ) {
return $block_content;
}
$processor = new WP_HTML_Tag_Processor( $block_content );
while ( $processor->next_tag( 'option' ) ) {
$slug = $processor->get_attribute( 'value' );
if ( empty( $slug ) || '-1' === $slug ) {
continue;
}
$term = get_term_by( 'slug', $slug, 'category' );
if ( ! $term || is_wp_error( $term ) ) {
continue;
}
$url = get_term_link( $term );
if ( is_wp_error( $url ) ) {
continue;
}
$processor->set_attribute(
'data-swq-term-url',
$url
);
}
$block_content = $processor->get_updated_html();
static $script_added = false;
if ( ! $script_added ) {
$script_added = true;
$block_content .= <<<'HTML'
<script>
document.addEventListener('change', function (event) {
const dropdown = event.target;
if (!(dropdown instanceof HTMLSelectElement)) {
return;
}
const option = dropdown.options[dropdown.selectedIndex];
const url = option?.dataset.swqTermUrl;
if (!url) {
return;
}
event.stopPropagation();
window.location.assign(url);
}, true);
</script>
HTML;
}
return $block_content;
},
20,
2
);
Here, I did not crudely change the original value of <option> from a slug to a URL.
The original structure is preserved, for example:
<option value="php-simple-html-dom-parser">
During rendering, the final category URL is simply added, roughly like:
<option
value="php-simple-html-dom-parser"
data-swq-term-url="https://www.shuijingwanwq.com/category/web-devel/html-parser/php-simple-html-dom-parser/"
>
When the user re-selects a category, JavaScript reads:
data-swq-term-url
Then:
window.location.assign(url);
It goes directly to the final address.
Most importantly, the final URL comes from:
get_term_link()
rather than being constructed manually.
This way, the parent-child category structure, category slugs, and the respective domains of the Chinese and English sites continue to be handled by WordPress and the existing multilingual system.
7. This time, I did not rush to clear the cache
After modifying WPCode, I did not immediately clear all page caches and CDN caches.
Because the old pages were already cached, manually clearing all caches immediately would make it difficult to observe the actual results received by visitors after a natural cache lifecycle.
Therefore, this time I simply waited for the cache to expire naturally.
From completing the modifications on August 8 to re-checking on August 14, I did not continue modifying the code out of anxiety over test results.
Testing again a few days later, I saw the naturally updated pages.
8. Conducting four sets of practical validation on August 14
After the cache expired naturally, I re-tested four scenarios:
- Chinese homepage → select a category
- Chinese archive page → select a category
- English homepage → select a category
- English archive page → select a category
All four passed.
Now, when interacting with the category dropdown list normally, the browser no longer needs to go through:
/?category_name=xxx
but goes directly to the final category permalink.
For example, after selecting Bootstrap 5 on the Chinese archive page, the browser goes directly to:
https://www.shuijingwanwq.com/category/web/html-css/css-framework/bootstrap/bootstrap-5/

category_name intermediate address appearing.This is the core validation result of this modification.
9. Ultimately, EdgeOne and Cloudflare were not modified for this
When the problem was first discovered, there was another entirely feasible approach:
Keep ?category_name=
+
Add category_name to the functional Query String exceptions in the CDN
But ultimately, I did not do this.
The reason is simple.
After the new category dropdown logic took effect, normal users no longer access categories via:
/?category_name=xxx
Since the business flow no longer needs this intermediate query parameter, there is naturally no need to have EdgeOne and Cloudflare specifically add an exception for it.
The responsibilities of the two layers ultimately became:
The two are no longer dependent on each other.
CDN
↓
Continues to handle existing Query String normalization and page caching
WordPress category dropdown list
↓
Directly accesses standard category permalinks
This is much simpler than continually expanding the Query String whitelist.
This is much simpler than continually expanding the Query String whitelist.
10. What was truly solved this time is more than just a redirect error
When I first saw:
/?category_name=php-simple-html-dom-parser
fail, my first thought was still:
Add another exception to the CDN.
This is a very natural line of thought when facing compatibility issues.
But the final solution this time felt more worth recording:
Rather than constantly patching exceptions for newly added rules, it is better to first check if there are intermediate layers in the old business flow that can simply be removed.
The original structure:
Category dropdown list
↓
category_name
↓
WordPress query parameter parsing
↓
Final category permalink
now becomes:
Category dropdown list
↓
Final category permalink
Less Query Strings, one less intermediate step, and one less layer of coupling with the CDN.
At the same time, this also further established a WPCode usage pattern I currently prefer:
Location / Enable Logic
↓
Responsible for "where to run"
PHP / JavaScript
↓
Only responsible for "what to run"
If page checks can be handled by the configuration interface, they should not be stuffed into the code.
This not only makes the code more concise, but also makes it easier to quickly understand its responsibilities when revisiting this code snippet months or even years later.
Summary
This WordPress category dropdown list issue initially appeared to be just a compatibility regression caused by Query String caching strategies.
But ultimately, it was not fixed by adding:
category_name
as a cache exception.
Instead, the entire category redirect flow was further simplified to:
WPCode
+
render_block_core/categories
+
WP_HTML_Tag_Processor
+
get_term_link()
+
JavaScript direct redirect to final URL
The code snippet is restricted by WPCode to:
Homepage OR Archive
After waiting for the cache to expire naturally, all four scenarios—Chinese homepage, Chinese archive page, English homepage, and English archive page—passed validation.
At this point, normal category dropdown list access no longer uses the following Query String:
?category_name=
Now, the category dropdown list can directly enter the final /category/…/ permalink.
This optimization appears to just remove a Query String, but what it actually reduces is the unnecessary coupling between business redirect logic and CDN caching rules.

