A Link Led to a 404 Because the Title Changed; 613 Posts Fixed

A Link Led to a 404 Because the Title Changed; 613 Posts Fixed

Written by Nguyễn Nhật Ánh Dương, reviewed under the Content Policy of Marketing365. Last updated .

Contents
  1. A link in the middle of the post, clicked into a non-existent page
  2. The post address was calculated twice, at two different times
  3. Patch the writing machine first, then clean up the old posts
  4. The first matching pattern almost removed a real link
  5. The numbers after cleanup, and the numbers I rechecked today
  6. Three things I still have not closed

On 08/08/2026, I clicked a link buried in the body of a post on marketing365.vn. That link pointed to another post on the same site. The result: a page that does not exist.

There was no warning beforehand. The post published normally, the writing machine said it had finished, and the logs showed no error lines. Only readers who clicked would see it. Below is the full path from that link to the number 613 posts that needed fixing, along with the numbers I rechecked today, 14/08/2026, to see what is settled and what is not.

A link in the middle of the post, clicked into a non-existent page

The first broken post I found was post number 12754. In the body, there was a link pointing to this address:

https://marketing365.vn/ai-siet-an-toan-nhung-phai-huu-ich-hon/   → 404
https://marketing365.vn/chuan-an-toan-ai-chi-co-y-nghia-khi-giam-sai-sot-ma-van-giu/   → 200

These two addresses belong to the same post. The second one is the real, live address. The first one is the address that post almost had — and it sits inside that very post as a self-referencing link.

I opened that old address again today, six days after the cleanup. It still returns 404. The trace is still there, so this is not something I am recounting from memory.

The post address was calculated twice, at two different times

My writing machine has a duplicate-title gate: if a new title is cast in the same form as an existing title, that gate rewrites the title. I built this gate on purpose, and it does exactly what it is supposed to do.

The problem was the order. The actual sequence was:

  1. The machine calculated the permalink from the draft title, then prebuilt a self-link in the body.
  2. The duplicate-title gate changed the title.
  3. WordPress received the new title and recalculated the permalink from that new title.
  4. The link assembled in step 1 remained in the body, pointing to a permalink that never existed.

No single step was wrong on its own. Step 1 was correct if the title did not change, step 2 was correct because duplicate titles must be changed, and step 3 was WordPress behaving properly. The mistake was letting a value calculated in step 1 survive step 3 without recalculating it.

There was another layer: the English version was translated from the Vietnamese version and copied over with the full body intact. That included the broken link. One mistake in the drafting stage became two dead-link posts.

Patch the writing machine first, then clean up the old posts

All three writing machines had the same self-link assembly block. I removed that block from all three. I did not change it so it would recalculate the permalink after the title changed; I removed it entirely — because if a post links to itself, a reader clicking it just lands back where they already are, which serves no purpose.

But I kept the variable that holds the permalink. Another part of the same writing machine uses it to avoid self-links when attaching topic links: if the current post’s address matches one in the list, skip it. Deleting that variable would break that other part. This is the kind of failure that often happens during cleanup: removing something that looks redundant without checking who else still uses it.

At the same time, I also removed a stock sentence the machine appends to the end of every post — the kind that says, “This article focuses on… with an angle for the Vietnamese market.” That sentence repeats across hundreds of posts and adds no information.

To clean up the old posts, I needed a matching pattern that could find self-links in each post. My first idea was to take the permalink stored in the database, build a pattern from it, and allow an extra two-letter prefix at the front so the English version would be caught too.

# method 1 — build the pattern from the permalink stored in the database
'#https://marketing365.vn/(?:[a-z]{2}/)?' . preg_quote($post->post_name) . '/#'

# method 2 — take the exact real permalink of each post
$path = parse_url(get_permalink($id), PHP_URL_PATH);
'#https://marketing365.vn' . preg_quote($path, '#') . '#'

Method 1 had a flaw. The English version of a post can share the same permalink slug as the Vietnamese version, differing only by the language prefix. That means /en/<same-slug>/ is not the post being examined — it is a different post. A link pointing there is a real link and must be kept. The two-letter prefix I added for “safety” was exactly the place where I almost removed the wrong link.

I ran both methods and compared the lists. Both returned 613 posts, so nothing was harmed this time. But that was only known after the comparison, not before. If I had run method 1 and overwritten the results, I would never have known where I had just been.

Before writing anything back, I dumped the full old body of those 613 posts into a backup file. Any bulk edit that touches post bodies without a copy of the original has no way back.

The numbers after cleanup, and the numbers I rechecked today

The 08/08 cleanup touched 613 posts: 310 stock paragraphs and 310 self-links were removed. A scan immediately afterward found none left.

Today I measured again from scratch, not trusting the old record. I scanned all 1,634 published posts, extracted every internal link in the body, and matched each URL against the real post:

  • 4,428 internal links in post bodies, spread across 787 different URLs.
  • 0 URLs that failed to match any post.

The number 0 is not trustworthy by itself — a broken checker can also produce 0. So I tested the reverse: I fed the exact dead URL from the start of the article into the checker. It reported no matching post, exactly as it should. Then I fed the real URL of that same post, and it returned post number 12754. The checker can distinguish the two, so the 0 now means something.

Summary table of the four steps leading to the dead link and the numbers rechecked on 14/08/2026 on marketing365.vn
The top section is taken from the operation log of 08/08/2026. The bottom section was remeasured across all published posts on marketing365.vn on 14/08/2026.

Three things I still have not closed

First, 14 posts still link to themselves. This is different from the type at the start of the article: it points to the current address, the correct address, not 404 — just useless. Notably, 5 of those 14 posts were published after the cleanup date: 09, 10, 11, 12 and 13/08. That means there is still a second publishing flow inserting self-links, and I have not patched that one yet. Fixing three writing machines does not mean everything is fixed.

Second, 3 posts still contain the stock sentence “…with an angle for the Vietnamese market.” It is a small number, but it shows that my matching pattern on 08/08 did not catch every variation of that sentence.

Third, one place where I once undercounted. The post page for 12754 currently contains its own address 15 times: the canonical tag, two language canonical tags, social sharing tags, two embedded-post entry points, the share button, the comment-reply cancel link… All of these belong to the interface and are correct — removing them would break the page. Last time I recorded a smaller number because I counted more narrowly. This time I counted every occurrence and wrote down the method so it can be compared next time. This is also the trap I fell into when measuring the post that ballooned 9x at display time: counting the interface elements the system adds and mistaking them for part of the post.

The lesson I drew is not “never generate links automatically.” It is: if a value is built from something that can change in a later step, recalculate it in that later step, or do not prebuild it at all. In the case of 412 posts with off-topic links, that same automatic link-adding block caused trouble too — just a different kind of failure.

And for the 14 remaining posts, I am leaving them in place while I check the second publishing flow. If I remove the symptom before finding the root cause, next week there will be another post with the same problem.

You may also like

Leave a Comment