Recently, I received a content rectification notice requiring me to handle 8 Chinese articles on my website related to self-hosted VPNs, network proxies, and associated configurations.
These articles all belong to my “Self-hosted VPN” series, and several had accumulated significant traffic. Deleting the articles directly from the WordPress admin would be easy, but I did not want to take that approach.
If I deleted the articles, moved them to the trash, or changed them to drafts, their titles would disappear from the series directory. This would create an obvious gap in the continuous content record, and readers would struggle to understand why parts of the series suddenly vanished.
Therefore, I wanted to find a compromise:
- Strictly take offline the 8 Chinese articles listed in the rectification list;
- No longer publicly provide the Chinese text of these articles;
- Have the original Chinese URLs return a genuine HTTP 404;
- Display a clear notice on the page stating that the content is no longer available;
- Retain the article titles within the “Self-hosted VPN” series;
- Keep the complete original text intact in the WordPress admin;
- Avoid continuing to provide the original content via PDFs, attachments, redirects, or other Chinese pages;
- Keep the English translations, which were not included in the rectification list, normally accessible;
- Publish a public explanatory article detailing why some titles in the series remain visible but return a 404 when clicked.
Ultimately, I achieved this using a standalone WordPress MU Plugin.
1. Receiving the notice to process 8 Chinese articles
The content to be processed this time came from a specific Excel list containing 8 Chinese article URLs.
These URLs all belong to the Chinese main site:
www.shuijingwanwq.com
The list did not include the English site:
en.shuijingwanwq.com


Initially, I considered simply deleting these 8 articles from the WordPress admin.
However, they are not 8 isolated pieces of content; they are part of the “Self-hosted VPN” series. Deleting them directly would alter the article titles and the original sequence in the series page.
For a long-maintained blog, article titles, publication dates, and series sequences are themselves part of the site’s history.
Therefore, I wanted to preserve the record that these articles once existed, without continuing to publicly offer the Chinese text.
2. Why I didn’t convert the original text into a PDF download
I considered another approach:
- Clear the original article text;
- Display a notice on the page explaining that the content is no longer available;
- Create a new summary article;
- Export the 8 original articles as PDFs;
- Provide downloads in the summary article.
But after careful consideration, I abandoned this plan.
If the rectification requirement is to take the relevant Chinese content offline, converting the web content into a PDF download essentially just changes the method of public distribution.
Even if the original URL returns a 404, as long as users can still download the same content through other entry points on the site, it is hard to argue that the relevant Chinese content has truly ceased to be available.
Therefore, the final solution does not include:
- PDF downloads;
- Public attachments;
- A summary page for the original Chinese text;
- 301 or 302 redirects;
- Entry points pointing to other Chinese mirrors.
The complete original Chinese text is kept only in the WordPress admin and is no longer provided through public pages.
3. The intended final outcome
These 8 Chinese articles will maintain their “Published” status in WordPress.
This way, the existing series article list can still retrieve these articles, and their titles, publication dates, and original links can be retained.
However, when users click the title to enter the article page, the server will no longer return the original text. Instead, it will return:
HTTP 404
While displaying:
This page is no longer available
In accordance with relevant requirements from the Cyberspace Administration, this page has been made unavailable.
There is an important distinction here.
If I merely replaced the text with a notice but the page still returned:
HTTP 200
Then, from the perspective of browsers, search engines, and servers, this is still a normally existing web page; only its text content has changed.
And I wanted to explicitly convey:
These 8 Chinese URLs listed in the notice no longer provide their original content.
Therefore, the page must return a genuine HTTP 404, not just display “content deleted” on an HTTP 200 page.
4. Why I didn’t use HTTP 401
Initially, I also considered having these articles return an HTTP 401.
But the standard meaning of 401 is typically:
The current resource requires authentication.
This implies that the user might still have a chance to access the resource after logging in or providing credentials.
This is not suitable for expressing that “this public content is no longer available.”
In contrast, the semantics of 404 are more direct:
The current URL no longer provides the corresponding resource.
Therefore, I ultimately chose HTTP 404 over HTTP 401.
5. Why the articles couldn’t be changed to drafts
If the articles were changed to drafts, regular visitors would indeed be unable to access the text.
However, WordPress public queries by default only return published articles.
Once an article is changed to a draft:
- The series article list will no longer display the title;
- Category and tag archives will no longer display the article;
- Related article queries in the theme might ignore the article;
- The original series structure will have a gap.
So, the key to fulfilling this requirement is:
The articles remain in the
publishstatus in the database, but requests for individual Chinese articles are intercepted at the request stage.
In other words, this cannot be solved by modifying the article status; custom logic must be added during the WordPress page loading process.
6. Intercepting specific Chinese articles via an MU Plugin
To avoid directly modifying theme files and to prevent regular plugins from being accidentally disabled, I ultimately chose to use an MU Plugin.
MU Plugins are located in:
wp-content/mu-plugins/
As long as a PHP file exists in this directory, WordPress will automatically load it without needing manual activation in the admin.
The plugin maintains the 8 Chinese article IDs explicitly listed in the rectification notice:
function swq_blocked_posts_404_ids() {
return array(
19005,
17374,
18815,
9675,
9665,
9651,
9647,
9601,
);
}
It then checks whether the current article is in the list:
function swq_blocked_posts_404_is_blocked( $post_id ) {
return in_array(
(int) $post_id,
swq_blocked_posts_404_ids(),
true
);
}
The final version uses only these 8 specific Chinese article IDs.
The plugin will no longer automatically add the corresponding English translations to the takedown list via Polylang.
7. Returning a genuine 404 at the template_redirect stage
The actual page interception occurs during the WordPress template_redirect stage.
The core logic is as follows:
function swq_blocked_posts_404_render_notice() {
if ( ! is_singular( 'post' ) ) {
return;
}
$post_id = get_queried_object_id();
if ( ! swq_blocked_posts_404_is_blocked( $post_id ) ) {
return;
}
global $wp_query;
if ( $wp_query instanceof WP_Query ) {
$wp_query->set_404();
}
status_header( 404 );
nocache_headers();
header(
'Cache-Control: no-store, no-cache, must-revalidate, max-age=0, private',
true
);
header(
'X-Robots-Tag: noindex, nofollow, noarchive, nosnippet',
true
);
header(
'Content-Type: text/html; charset=' . get_option( 'blog_charset' ),
true
);
echo '<!doctype html>';
echo '<html lang="zh-CN">';
echo '<head>';
echo '<meta charset="' . esc_attr( get_option( 'blog_charset' ) ) . '">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1">';
echo '<meta name="robots" content="noindex,nofollow,noarchive,nosnippet">';
echo '<title>页面已停止提供</title>';
echo '</head>';
echo '<body>';
echo '<main>';
echo '<h1>该页面已停止提供</h1>';
echo '<p>根据网信部门相关要求,该页面已停止提供。</p>';
echo '<p>HTTP 状态码:404</p>';
echo '<a href="' . esc_url( home_url( '/' ) ) . '">返回网站首页</a>';
echo '</main>';
echo '</body>';
echo '</html>';
exit;
}
add_action(
'template_redirect',
'swq_blocked_posts_404_render_notice',
-1000
);
When a regular user visits one of these 8 Chinese articles, WordPress will halt further processing before loading the theme’s text template and return a custom 404 page.
The articles themselves still exist, and their publication status remains unchanged, so the “Self-hosted VPN” series can still display their titles.


8. Why I ultimately didn’t force the original article layout
When I first saw the custom 404 page, I felt it looked quite different from the site’s original article pages.
I originally wanted the notice to appear directly in the main text area of the original article while preserving:
- The site header;
- The navigation menu;
- The article title;
- Series information;
- The language switcher;
- The footer;
- The original article page layout.
This is technically achievable.
For example, I could continue loading the theme template and then use the the_content filter to replace the text with the unavailability notice.
But this would introduce more components that need handling:
- The WordPress query object;
- The theme’s 404 status logic;
- The page title;
- Canonical tags;
- SEO plugin output;
- Related articles;
- Excerpts;
- The language switcher component;
- Page caching;
- CDN caching.
The more page components there are, the easier it becomes to inadvertently expose the original text, excerpts, or related entry points in other areas.
Considering that the primary goal of this process was to reliably take the listed Chinese content offline, I ultimately accepted a standalone, concise 404 notice page.
Although it does not fully apply the original article layout, the outcome is much clearer:
- It does not load the Chinese article text;
- It does not output the Chinese article excerpt;
- It provides no PDFs or attachments;
- It does not redirect to other Chinese pages;
- It explicitly returns an HTTP 404;
- Users can still return to the site homepage.
9. Explaining the 404 through a series notice article
Merely retaining the series titles presents a user experience issue.
When readers see the article titles in the “Self-hosted VPN” series, click through, and receive only a 404 page, they are likely to wonder:
- Is the website malfunctioning?
- Is the link address wrong?
- Why is the title still there, but the text won’t open?
- Were these articles accidentally deleted?
Therefore, I decided to add this article to the “Self-hosted VPN” series and place it in a relatively prominent position.
It is not a new VPN tutorial, but a series notice article meant to explain:
- Why 8 Chinese articles are no longer available;
- Why the articles were not directly deleted;
- Why the titles are still retained in the series;
- Why clicking them returns an HTTP 404;
- Why the English translations remain accessible;
- How the entire WordPress and caching process was handled.
The ideal sequence for the series titles would look like:
Series Notice: Taking offline 8 self-hosted VPN Chinese articles according to relevant CAC requirements
Original article title 1
Original article title 2
Original article title 3
......
This way, when readers browse the series list, they can see the notice first and then decide whether to continue viewing the subsequent titles.
After this article is published, I can further tweak the custom 404 page to add a notice entry point alongside the “Return to Homepage” link:
View the full explanation of this content adjustment
This link will only explain the reasons for the content adjustment; it will not provide the original Chinese text, nor will it point to any PDFs, attachments, or Chinese mirrors.
Because the explanatory article must be published and assigned a formal URL first, this entry point will need to be added to the MU Plugin after this article goes live.
10. Public REST API, RSS, and Sitemap also need handling
Intercepting only the Chinese article pages in the browser is not enough.
WordPress has several public entry points that might return article content, such as:
/wp-json/wp/v2/posts/19005
As well as:
- REST API article lists;
- RSS and Atom feeds;
- WordPress core Sitemap;
- Yoast SEO XML Sitemap;
- Excerpt lists generated by the theme;
- Third-party client APIs.
Therefore, corresponding restrictions were added to the MU Plugin.
These restrictions also apply solely to the 8 Chinese articles in the list.
1. Public REST API returns 404
When unauthenticated users access the REST API for the corresponding Chinese articles, it returns:
return new WP_Error(
'swq_content_unavailable',
'该内容已停止提供。',
array(
'status' => 404,
)
);
Administrators who are logged in and have editing permissions can still read and edit the articles normally via the Gutenberg editor.
2. Excluded from the public REST API article list
For public article collection queries, these 8 Chinese article IDs are added to:
post__not_in
This prevents users from retrieving the text via bulk REST API requests.
3. Excluded from RSS
The plugin excludes these 8 Chinese articles from the main RSS query, preventing the old text from continuing to be served via feeds.
4. Excluded from Sitemaps
The plugin simultaneously handles:
- WordPress core XML Sitemap;
- Yoast SEO XML Sitemap.
The article titles can still be displayed in the “Self-hosted VPN” series directory, but these 8 Chinese URLs will no longer be submitted to search engines as normal articles.
11. Should the English translations be taken offline simultaneously?
This was the one point I deliberated over repeatedly throughout the entire process.
The initial plugin version called Polylang:
pll_get_post_translations()
Based on the 8 Chinese article IDs, it would automatically find the corresponding English translations and add all language versions to the takedown list together.
This approach was more thorough and less likely to miss the corresponding English articles.
But later, I re-examined the rectification Excel file.
The file explicitly listed only 8 Chinese URLs:
https://www.shuijingwanwq.com/...
It did not list the corresponding English URLs:
https://en.shuijingwanwq.com/...
Therefore, the strategy I ultimately adopted is:
Only take offline the 8 Chinese URLs explicitly listed in the Excel file, without proactively expanding to the unlisted English articles.
The final version removed the logic for automatically expanding to Polylang translation IDs.
This means:
- The Chinese articles return an HTTP 404;
- The English articles continue to return an HTTP 200;
- The English text remains accessible via search engines;
- The English articles remain in the English Sitemap;
- The English REST API and RSS are unaffected by this Chinese list.
It should be specifically noted that this article will not list the full URLs of the corresponding English articles, nor will it serve as a navigation page to those English versions.
The corresponding English translations continue to exist normally because they were not included in the rectification list currently received, not because they are intended to replace the unavailable Chinese text via the English pages.
If a new explicit notice is received later requiring the handling of the same content, associated pages, or multilingual versions, I will expand the takedown list separately at that time.
12. Deploying the first MU Plugin version
I first uploaded the plugin archive to the server:
scp -O \
~/下载/swq-blocked-posts-404.zip \
aliyun:/root/swq-blocked-posts-404.zip
Then I extracted and deployed it on the server:
cd /root
rm -rf /root/swq-blocked-posts-404
mkdir -p /root/swq-blocked-posts-404
unzip -o \
/root/swq-blocked-posts-404.zip \
-d /root/swq-blocked-posts-404
php -l \
/root/swq-blocked-posts-404/swq-blocked-posts-404.php
install -m 0644 \
/root/swq-blocked-posts-404/swq-blocked-posts-404.php \
/data/wwwroot/www.shuijingwanwq.com/wp-content/mu-plugins/swq-blocked-posts-404.php
php -l \
/data/wwwroot/www.shuijingwanwq.com/wp-content/mu-plugins/swq-blocked-posts-404.php
The syntax check result was:
No syntax errors detected
There was a minor incident here.
I initially pasted the server commands into my local computer terminal by mistake, resulting in:
bash: cd: /root: Permission denied
And:
No such file or directory
These errors did not indicate a problem with the plugin or the server directories; rather, the command execution environment was incorrect.
After switching to the root terminal on the Alibaba Cloud server, the deployment completed successfully.
13. During the first verification, some Chinese articles still returned 200
After deploying the plugin, I used curl to bypass EdgeOne and directly request the origin server:
curl \
--resolve www.shuijingwanwq.com:443:127.0.0.1 \
https://www.shuijingwanwq.com/文章路径/
During the first verification, not all 8 Chinese articles returned a 404.
Some pages still showed:
200 | Notice not found
Only a few pages returned:
404 | Notice normal
At this point, it was easy to suspect:
- Whether the article IDs were written incorrectly;
- Whether the MU Plugin only handled some pages;
- Whether
template_redirectfailed to execute; - Whether there was an issue with the WordPress query logic.
But after adding a random query parameter and testing again:
test_url="${url}?swq_block_test=$(date +%s%N)"
All 8 pages returned:
404 | Notice normal
This proved that the plugin logic itself was fine.
The real issue was that W3 Total Cache still held the static HTML pages generated before the plugin was deployed.
When a regular URL request hit the old cache, Nginx and W3TC would directly return the old text, and the WordPress PHP code never had a chance to execute.
14. Clearing W3TC cache only for the specified Chinese articles
To avoid purging the page cache for the entire website, I only deleted the W3TC cache directories corresponding to these 8 Chinese articles:
cache_root="wp-content/cache/page_enhanced/www.shuijingwanwq.com"
paths=(
"2026/07/06/19005"
"2026/06/19/17374"
"2026/07/04/18815"
"2026/05/03/9675"
"2026/05/02/9665"
"2026/05/01/9651"
"2026/05/01/9647"
"2026/04/28/9601"
)
for path in "${paths[@]}"
do
rm -rf "$cache_root/$path"
echo "已清理:$path"
done
After clearing, I requested the origin server again using regular URLs without random parameters, and the results all changed to:
404 | Notice normal
This step confirmed that the previous HTTP 200 responses came entirely from the old page cache, not from a failure in the plugin’s interception.
15. Purging EdgeOne cache and verifying Chinese public network results
The Chinese main site uses EdgeOne.
After successfully verifying the origin server, I also purged the cache for the corresponding 8 Chinese URLs in EdgeOne.
I then verified via regular public network requests, no longer using:
--resolve
Ultimately, all 8 Chinese articles returned:
404 | Notice normal | eo-cache-status: MISS
This indicates:
- The old text cache in the EdgeOne nodes has been cleared;
- Requests are going back to the origin server;
- The origin server returns the custom 404 page;
- The CDN is no longer serving the old Chinese article text to users.
16. Adjusting the explanatory text on the page
The initial notice text was:
Due to content adjustments, this page is currently inaccessible.
Later, I wanted the page to reflect that this adjustment was related to cyberspace administration requirements.
If I directly wrote:
The CAC required me to delete this article.
It might seem too absolute, and could easily lead people to think that I had directly received a formal administrative document targeting a single article.
The final page adopted a more restrained wording:
In accordance with relevant requirements from the Cyberspace Administration, this page has been made unavailable.
In the article title, however, I used “relevant CAC requirements,” which is easier for readers to understand, to explain the background of the entire event.
I modified the plugin via sed:
plugin="wp-content/mu-plugins/swq-blocked-posts-404.php"
backup="${plugin}.bak-$(date +%Y%m%d-%H%M%S)"
cp -a "$plugin" "$backup"
sed -i \
's/因内容调整,此页面当前无法访问。/根据网信部门相关要求,该页面已停止提供。/' \
"$plugin"
php -l "$plugin"
After the modification, regular public network requests temporarily still showed the old notice.
But after adding a random parameter and bypassing the CDN, the origin server already displayed the new text:
Origin server new notice: Verification successful
This indicated that the PHP file modification had taken effect.
Because the page genuinely returned a 404 regardless of whether the old or new notice was shown, and the original Chinese text was inaccessible anyway, I did not repeatedly purge the cache just to update the text immediately. Instead, I allowed the old notice to expire naturally with the cache.
17. Encountering old 404 cache when restoring English articles
The initial version automatically intercepted the Polylang English translations, so the corresponding English articles had also returned a 404.
After removing the logic to automatically expand to English translations, the first time I conducted an English public network verification, the relevant English URLs still all returned:
404
But after adding a random parameter and bypassing Cloudflare and W3TC, the English origin server all returned:
200 | English text restored
This showed that the new plugin version was working correctly, and the 404 seen on the public network was just leftover cache.
18. Clearing the English site’s W3TC cache
The W3TC page cache directory for the English site is:
wp-content/cache/page_enhanced/en.shuijingwanwq.com
I only deleted the old 404 cache directories for the relevant English articles, without clearing the entire English site cache.
After clearing, I directly requested the English origin server without random parameters, and all relevant English articles returned:
200 | English text normal
19. Clearing the English 404 cache in Cloudflare
The English site uses Cloudflare.
After handling the W3TC origin cache, I also purged the old 404 cache for the relevant English articles by URL in Cloudflare.
Finally, I verified via public network requests:
200 | English text normal | cf-cache-status: MISS
All relevant English pages returned to normal.
This indicates:
- The previous 404 cache in Cloudflare has been deleted;
- Requests are going back to the origin;
- The origin server returns the normal English articles;
- The English text is restored to public access;
- Search engines can continue to access the English versions.
Subsequently, the Cloudflare cache status changing from MISS to HIT is also a normal phenomenon, because at this point it is caching the restored HTTP 200 page.
20. Final outcome
After two rounds of plugin adjustments and cache handling, the final state is as follows.
The 8 Chinese articles in the list
- The complete original text is retained in the WordPress admin;
- The article status remains “Published”;
- The article titles continue to display in the “Self-hosted VPN” series;
- The titles still link to the original Chinese URLs;
- Clicking through returns a genuine HTTP 404;
- The page displays “This page is no longer available”;
- The Chinese text is no longer publicly output;
- The public REST API cannot retrieve the text;
- RSS no longer includes these articles;
- The Sitemap no longer submits these Chinese URLs;
- EdgeOne no longer serves the old Chinese text cache;
- The original Chinese text is not continued to be provided via redirects, PDFs, or attachments.
Corresponding English articles
- Not included in the current Excel rectification list;
- No longer automatically added to the takedown list by the MU Plugin;
- The English pages normally return HTTP 200;
- The English text is accessible;
- The English articles remain accessible to search engines;
- The English Sitemap, REST API, and RSS remain normal;
- The old 404 caches in W3TC and Cloudflare have been cleared.
“Self-hosted VPN” series notice
- This article is added to the “Self-hosted VPN” series;
- It is placed in a relatively prominent position in the series title list;
- It explains to readers why some titles still exist but return a 404 when clicked;
- This article only provides a processing explanation; it does not re-provide the taken-down Chinese text;
- This article does not list the corresponding English article addresses, nor does it serve as a navigation page for the English versions;
- After this article is published, a “View full explanation” link can be considered for addition to the custom 404 page.
The final strategy can be summarized as:
Strictly execute the takedown of the 8 Chinese URLs explicitly listed in the rectification Excel, while preserving the series structure and historical records; the English translations not present in the list remain normally accessible.
21. Reflections on this process
For a typical blog, “deleting an article” is usually considered just a single click of “Move to Trash.”
But when a website has been running for years, and articles are interconnected through series, categories, multilingual mappings, CDN caches, search engine indexing, and historical access data, taking an article offline is not just deleting a database record.
A seemingly simple content processing request actually involves:
- WordPress article status;
- Series title lists;
- HTTP status codes;
- Custom notice pages;
- W3 Total Cache;
- EdgeOne;
- Cloudflare;
- REST API;
- RSS;
- Sitemap;
- Polylang multilingual mappings;
- Retaining the original text in the admin;
- The scope of takedown for Chinese versus English URLs;
- How to explain to series readers that the titles remain while the text is no longer available.
This time, I ultimately chose not to delete the articles directly, nor did I continue to publicly provide the Chinese text in other forms. Instead, I used an MU Plugin to handle “admin retention” and “Chinese frontend takedown” separately.
At the same time, I did not indefinitely expand the scope of the takedown.
After re-verifying the Excel file, I ultimately processed only the 8 Chinese URLs explicitly listed, leaving the corresponding English translations normally accessible.
To prevent readers from thinking the series page was malfunctioning, I also added this article as a notice piece within the “Self-hosted VPN” series, serving as a public record of this content adjustment and technical process.
Technically, this solution is much more complex than simply deleting the articles.
But it ultimately preserves:
- The blog series structure;
- The historical record of the Chinese articles;
- The original text in the WordPress admin;
- Search traffic for the English articles;
- The explicit takedown status for the listed Chinese URLs;
- A public explanation entry point for readers.
For WordPress sites that need to strike a balance between content compliance, historical records, multilingual site structure, search traffic, and reader experience, this is a workflow worth documenting.
需要长期技术维护或远程问题排查?
我是拥有 15+ 年经验的 PHP / Go 后端工程师,长期关注已有系统维护、Bug 修复、性能优化、服务器排查、WordPress 网站维护和小功能迭代。
如果你的项目遇到以下情况,可以先从一次小问题排查开始合作:
- ✅ PHP / Laravel / Yii2 老项目无人维护
- ✅ Go / Gin 后端接口需要排查或优化
- ✅ WordPress 网站访问慢、报错或插件冲突
- ✅ Nginx / MySQL / Redis / Linux 服务器异常
- ✅ CDN / Cloudflare / DNS / HTTPS 配置问题
- ✅ 需要长期远程技术支持或兼职维护
更多介绍请查看:关于我 & 合作
微信:13980074657
邮箱:shuijingwanwq@gmail.com
Telegram:@shuijingwan
GitHub:https://github.com/shuijingwan

发表回复