WordPress builds every post URL from two parts: the permalink structure you pick once under Settings → Permalinks, and the slug it creates for each post. This guide explains the six permalink settings and which one to choose, shows exactly how WordPress turns a title into a slug (including what happens to Chinese titles), and covers the safe way to change slugs or the whole structure later. The WordPress behavior described here comes from the official WordPress documentation and code reference, linked in the sources. The WordPress slugs in the tables were produced by a line-by-line port of WordPress's own sanitize_title_with_dashes() function, and the comparison slugs are real output from our URL slug generator.
Tip
The short answer
- Pick "Post name" for most sites. It gives short, readable URLs such as
/sample-post/that do not age. - Decide before you publish. WordPress's documentation says permanent URLs should never be changed. Changing the structure later changes every post URL at once.
- Write the slug yourself for important posts. WordPress drops
&and%and keeps every small word. For a Chinese title it stores a long percent-encoded slug. - Post slugs redirect automatically, pages do not. When you edit a published post's slug, WordPress remembers the old slug and sends a 301 redirect. Pages and other hierarchical post types need a redirect you add yourself.
The six permalink settings
WordPress supports three kinds of permalinks: plain, pretty and "almost pretty". Plain permalinks look like ?p=123, work on every server and are the default on a new install, but WordPress itself calls them not user-friendly. Pretty permalinks contain words such as the post name; "almost pretty" permalinks are the same with /index.php/ in front. Both need a web server configured for them, which your host normally does. Under Settings → Permalinks you choose one of six common settings:
| Setting | Example URL for post 123, "Sample Post" | Good for |
|---|---|---|
| Plain | https://example.com/?p=123 | Nothing public: the URL says nothing about the page |
| Day and name | https://example.com/2026/10/27/sample-post/ | News sites where the date matters |
| Month and name | https://example.com/2026/10/sample-post/ | Frequent, time-bound posts |
| Numeric | https://example.com/archives/123 | Rarely a good choice: an ID instead of words |
| Post name | https://example.com/sample-post/ | Most blogs, shops and business sites |
| Custom Structure | https://example.com/%category%/%postname%/ | Sites with a stable category tree |
A custom structure is built from structure tags: %year%, %monthnum%, %day%, %hour%, %minute%, %second%, %post_id%, %postname%, %category% and %author%. The documentation recommends ending the structure with %post_id% or %postname%, so that each URL points to exactly one post.
Which structure should you choose?
Use Post name unless you have a reason not to. It matches Google's advice to use simple, descriptive words rather than long ID numbers, and it keeps URLs short. Our URL slug length guide explains why short slugs are easier to read, share and maintain.
Use dates only when the date is part of the content. A date in the URL makes an evergreen tutorial look old the day the year changes, and you cannot remove the date later without changing every URL.
Be careful with %category%. It adds context, but a post in several categories gets the category that comes first alphabetically, and moving a post to another category changes its URL. The category and tag bases (category and tag by default) can be renamed in the optional settings, but not removed.
Avoid Plain and Numeric for public sites. Neither tells a reader or a search engine what the page is about.
How WordPress turns a title into a slug
When you save a post without typing a slug, WordPress runs the title through sanitize_title(). In the save context that function first calls remove_accents() and then the sanitize_title filter, whose default handler is sanitize_title_with_dashes(). That function:
- removes HTML tags and stray
%signs that are not part of an encoded byte; - lowercases the text and percent-encodes every non-ASCII character in lowercase hex, keeping at most 200 encoded characters;
- turns non-breaking spaces, en and em dashes and
/into hyphens, and strips curly quotes, the copyright sign, the ellipsis and similar symbols; - turns periods into hyphens and deletes everything except
a–z,0–9, spaces,_,-and the%of encoded bytes; - turns whitespace into hyphens, collapses repeated hyphens and trims hyphens from both ends.
Here is what that means for real titles, next to the default output of our generator:
| Title | WordPress slug | Our generator |
|---|---|---|
| This Is A Great Post! | this-is-a-great-post | this-is-a-great-post |
| I'm in LOVE with WordPress!!!1 | im-in-love-with-wordpress1 | im-in-love-with-wordpress-1 |
| 10 Tips & Tricks for Faster Pages | 10-tips-tricks-for-faster-pages | 10-tips-and-tricks-for-faster-pages |
| Price: 50% Off Today | price-50-off-today | price-50-percent-off-today |
| Node.js vs. Deno | node-js-vs-deno | node-js-vs-deno |
The first two rows are the examples from the WordPress documentation. The differences are small but visible: WordPress deletes & and % instead of spelling them out, and it glues digits to the preceding word when only punctuation separated them. Neither is wrong, but if you care about the exact wording, type the slug yourself.
WordPress also keeps every small word. If you prefer 10-tips-tricks-faster-pages, remove the stop words in the slug field, or let our generator do it with the Remove stop words option.
Chinese and other non-Latin titles
sanitize_title_with_dashes() does not transliterate. Chinese, Japanese, Cyrillic and other non-Latin characters are kept and stored percent-encoded:
| Title | WordPress slug |
|---|---|
| 重庆火锅攻略 | %e9%87%8d%e5%ba%86%e7%81%ab%e9%94%85%e6%94%bb%e7%95%a5 |
| 北京 Travel Guide 2026 | %e5%8c%97%e4%ba%ac-travel-guide-2026 |
Browsers decode these bytes and show 重庆火锅攻略 in the address bar, so the URL looks fine to you. But when the link is copied into an email, a chat app or a spreadsheet, it often appears in its encoded form, 54 characters long for six Chinese characters. Each Chinese character takes 3 bytes in UTF-8, and each byte becomes three characters such as %e9.
The 200-character limit matters too. Because each Chinese character costs 9 encoded characters, a title made only of Chinese characters keeps at most 22 of them; the rest of the title is silently cut off.
You have three choices for a Chinese-language WordPress site:
- Keep the Chinese slug. It is valid, Google supports it, and it reads well in the address bar. Keep titles short so the 22-character cap does not cut them.
- Use pinyin. Our URL slug generator converts Chinese to toneless pinyin:
重庆火锅攻略becomeschong-qing-huo-guo-gong-lve. Copy it into the slug field. - Use an English slug, such as
chongqing-hot-pot-guide, if your audience also searches in English.
Our Chinese URL slug guide compares the three options in depth, including the polyphone problems of automatic pinyin. For accented Latin titles, WordPress's remove_accents() step already removes most accents; see how to transliterate slugs for the details of each language.
Duplicate and numeric slugs
WordPress keeps post slugs unique. If sample-post already exists for the same post type, wp_unique_post_slug() appends a number and tries sample-post-2, then sample-post-3, and so on. Drafts and pending posts are not checked until they are published, so a duplicate can appear at the moment you click Publish.
Purely numeric slugs get special treatment, because they could clash with date archives. With the structure /%year%/%postname%/, a slug of 5 would look like the archive for May, so WordPress adds a suffix. Words make better slugs anyway.
When you see -2 at the end of a new URL, check for an old draft, a trashed post or an attachment with the same name, and fix the slug before you share the link.
Changing a slug after publishing
Posts: when you change the slug of a published post, WordPress stores the old slug in the post's _wp_old_slug meta field. If someone later requests the old URL and it returns a 404, wp_old_slug_redirect() looks up the old slug and redirects with a 301 to the current permalink. If no old slug matches, it also tries the post's old publication date, so date-based URLs survive a date change.
Pages: wp_old_slug_redirect() does not redirect hierarchical post types, so pages are not covered. If you rename a page, add a 301 redirect yourself, in your server configuration or with a redirect plugin.
Changing the whole permalink structure changes every URL on the site at once. Do not rely on WordPress to catch all of them. Treat it as a migration: export the old URLs, map each one to its new URL, and generate the rules with our 301 redirect generator. Our bulk URL change guide walks through the whole process, including testing. In .htaccess, place your rules above the # BEGIN WordPress block so WordPress does not answer first.
Warning
Common mistakes
- Leaving Plain permalinks on a public site. Choose a pretty structure before the first post goes live.
- Switching from dates to Post name without redirects. Every old link and bookmark breaks.
- Renaming pages and expecting an automatic redirect. Only posts get old-slug redirects.
- Trusting the automatic slug for important posts. Check for dropped
&or%, digits glued to words and long percent-encoded Chinese slugs. - Ignoring the
-2suffix. It usually means a forgotten draft or attachment already uses the slug. - Using numbers alone as slugs. They can clash with date archives and tell readers nothing.
Copyable WordPress permalink checklist
[ ] Permalink structure chosen before launch (Post name for most sites)
[ ] Custom structures end with %postname% or %post_id%
[ ] No dates in URLs of evergreen content
[ ] Slug typed or checked by hand for important posts
[ ] Chinese titles: Chinese slug kept short, or pinyin/English slug entered
[ ] No unexpected -2 suffix; no purely numeric slugs
[ ] Renamed pages have a manual 301 redirect
[ ] Structure change treated as a migration: map, rules, tests
[ ] Redirect rules placed above # BEGIN WordPress in .htaccessCreate WordPress slugs with the tools
Paste a title into the URL slug generator to get a clean slug with & spelled out, optional stop-word removal and pinyin for Chinese, then copy it into the slug field in WordPress. For a whole export of post titles, the bulk CSV slug generator creates every slug in one pass and can make duplicates unique. Before you publish, the slug checker flags uppercase letters, underscores and other problems.
Sources
- WordPress Documentation: Customize permalinks
- WordPress Code Reference: sanitize_title()
- WordPress Code Reference: sanitize_title_with_dashes()
- WordPress Code Reference: utf8_uri_encode()
- WordPress Code Reference: wp_unique_post_slug()
- WordPress Code Reference: wp_old_slug_redirect()
- Google Search Central: URL structure best practices for Google Search
FAQ
Frequently asked questions
Which WordPress permalink structure is best for SEO?
For most sites, Post name. It produces short, descriptive URLs, which is what Google's URL guidelines recommend. Use dates only when the publication date is part of the content, such as news.
Does WordPress redirect the old URL when I change a slug?
For published posts, yes: WordPress saves the old slug and answers requests for it with a 301 redirect to the new URL. Pages and other hierarchical post types are not covered, so add those redirects yourself.
Why does my WordPress URL end with -2?
Another item of the same post type already uses that slug, often a draft, a trashed post or an attachment. WordPress adds -2, -3 and so on to keep slugs unique. Rename or delete the other item, then edit the slug.
Should Chinese WordPress posts use Chinese or pinyin slugs?
Both work. Chinese slugs read well in the browser but are stored percent-encoded, look long when shared and are capped at 22 characters. Pinyin or English slugs stay short and portable. Pick one style and use it consistently.
