Fix: Payload CMS Non-English Slug Link Bug

by Dimemap Team 43 views

Hey guys! Having trouble with Payload CMS and non-English slugs? You're not alone! This article dives into a bug in Payload CMS version 3.59.1 that affects linking to pages and posts when using non-English slugs. We'll walk through the problem, the solution, and how to implement it. So, let's get started and make your Payload CMS work smoothly with all languages!

The Issue: Non-English Slugs Not Linking Correctly

In Payload CMS version 3.59.1, a tricky bug surfaces when dealing with non-English slugs. If you're working with languages like Thai, you might notice that generating links to your pages or posts doesn't quite work as expected. This is because the system sometimes struggles to correctly process non-English characters in the URL.

When you create content with slugs containing characters outside the standard English alphabet, the links generated might lead to blank pages or 404 errors. This can be a major headache, especially for multilingual sites. The root cause lies in how the system encodes and decodes these slugs when generating URLs and querying content. Without proper encoding, the server can't correctly interpret the slug, leading to broken links.

Why This Happens

The issue stems from the way URLs handle special characters. URLs are designed to work with a limited set of characters, and anything outside this set needs to be properly encoded. When non-English characters are used in a slug, they need to be encoded so the URL remains valid. However, there can be inconsistencies in how these slugs are encoded and decoded throughout the application, leading to mismatches when trying to fetch the content.

For instance, the slug might be encoded in one part of the application but not properly decoded when querying the database, or vice versa. This discrepancy results in the system being unable to find the correct page or post, causing the link to fail. Understanding this encoding/decoding process is crucial to fixing the bug and ensuring your links work correctly across all languages.

Real-World Impact

Imagine you're building a website for a Thai restaurant, and you've meticulously created pages with Thai slugs. When users click on these links, instead of seeing the delicious menu or the restaurant's story, they're greeted with a blank page. This not only frustrates your users but also hurts your site's SEO and overall user experience. It’s a critical issue that needs addressing ASAP!

The impact extends beyond just user experience. Content creators and editors might find it challenging to preview their work or share links with colleagues, leading to workflow bottlenecks. Ensuring your links work correctly is about more than just aesthetics; it's about making your website functional and user-friendly for everyone.

The Solution: Encoding and Decoding Slugs

The good news is there’s a straightforward fix for this! The key is to ensure that slugs are properly encoded when generating links and decoded when querying content. By using the encodeURI() and decodeURI() functions, we can make sure the slugs are handled correctly throughout the application. Let's break down the fix step by step.

Step 1: Decoding Slugs in page.tsx

First up, we need to modify the page.tsx file (both /src/app/(frontend)/[slug]/page.tsx and /src/app/(frontend)/posts/index[slug]/page.tsx). This is where we fetch the content based on the slug, so we need to make sure the slug is correctly decoded before querying the database.

  const queryPageBySlug = cache(async ({ slug }: { slug: string }) => {
    const { isEnabled: draft } = await draftMode()
    const decodeSlug = decodeURI(slug) // Add this line
  
    const payload = await getPayload({ config: configPromise })
  
    const result = await payload.find({
      collection: 'pages',
      draft,
      limit: 1,
      pagination: false,
      overrideAccess: draft,
      where: {
        slug: {
          equals: decodeSlug, //slug,
        },
      },
    })

    return result.docs?.[0] || null
  })

In this code snippet, we've added the line const decodeSlug = decodeURI(slug). This line takes the slug and decodes any URI components, ensuring that non-English characters are correctly interpreted. By using decodeSlug in the where clause of the query, we make sure the database is queried with the correct slug.

Step 2: Encoding Slugs in generatePreviewPath.ts

Next, we need to adjust the generatePreviewPath.ts file. This file is responsible for generating the preview URLs, so it’s crucial to encode the slug here to ensure the URLs are correctly formed.

  ...  
  export const generatePreviewPath = ({ collection, slug }: Props) => {
    // Allow empty strings, e.g. for the homepage
    if (slug === undefined || slug === null) {
      return null
    }
    const encodeSlug = encodeURIComponent(slug) // Add this line
    const encodedParams = new URLSearchParams({
      slug: encodeSlug, // replace `slug` with `encodeSlug`
      collection,
      path: `${collectionPrefixMap[collection]}/${encodeSlug}`, // replace `slug` with `encodeSlug`
      previewSecret: process.env.PREVIEW_SECRET || '',
    })

    const url = `/next/preview?${encodedParams.toString()}`

    return url
  }

Here, we've added the line const encodeSlug = encodeURIComponent(slug). This encodes the slug using encodeURIComponent, which is more comprehensive than encodeURI and handles a wider range of characters. We then use encodeSlug in the URL parameters, ensuring the generated preview URL is valid and correctly includes the non-English characters.

Why These Functions?

decodeURI() and encodeURIComponent() are essential for handling URLs with special characters. decodeURI() decodes a URI component, converting encoded characters back to their original form. encodeURIComponent(), on the other hand, encodes special characters in a URL, making it safe to use in a web address. By using these functions, we ensure our slugs are correctly processed, no matter the language.

Reproducing the Bug and Verifying the Fix

To really understand the fix, it’s helpful to see the bug in action and then verify that our changes resolve it. Let’s walk through how to reproduce the issue and confirm the fix.

Reproducing the Bug

  1. Set up a Payload CMS project: If you haven’t already, set up a Payload CMS project and make sure you’re running version 3.59.1.
  2. Create content with non-English slugs: Create a new page or post and use a non-English slug, like a Thai word or phrase. For example, you might use “สวัสดี” as the slug.
  3. Try to preview or access the page: Go to the preview mode or try to access the page using the generated URL. You’ll likely see a blank page or a 404 error.

This confirms the bug: the non-English slug isn’t being correctly processed, and the page can’t be found.

Verifying the Fix

  1. Implement the code changes: Apply the decodeURI() and encodeURIComponent() changes to your page.tsx and generatePreviewPath.ts files, as described in the solution.
  2. Restart your development server: Make sure to restart your development server to apply the changes.
  3. Try to preview or access the page again: Go back to the preview mode or try to access the page using the generated URL. This time, you should see the page loading correctly.

If the page loads without any issues, congratulations! You’ve successfully fixed the non-English slug bug. This verification process ensures that the fix works as expected and gives you confidence in your solution.

Affected Areas and Environment Info

This bug primarily affects areas of Payload CMS that deal with URL generation and content querying, specifically the preview mode and frontend page rendering. It’s most noticeable when working with non-English languages, but it’s a good idea to implement the fix regardless, to ensure your site is future-proof.

The provided environment info gives us a snapshot of a typical setup where this bug might occur:

> cross-env NODE_OPTIONS=--no-deprecation payload info

npm warn Unknown env config "verify-deps-before-run". This will stop working in the next major version of npm.
npm warn Unknown env config "_jsr-registry". This will stop working in the next major version of npm.
npm warn Unknown env config "enable-pre-post-scripts". This will stop working in the next major version of npm.
npm warn Unknown project config "enable-pre-post-scripts". This will stop working in the next major version of npm.
This project is configured to use pnpm because /Users/junmacbookpro/Documents/Projects/Test/payload/kc-interpress/package.json has a "packageManager" field

Binaries:
  Node: 22.15.0
  npm: 11.4.1
  Yarn: N/A
  pnpm: 10.18.2
Relevant Packages:
  payload: 3.59.1
  next: 15.4.4
  @payloadcms/db-sqlite: 3.59.1
  @payloadcms/drizzle: 3.59.1
  @payloadcms/email-nodemailer: 3.59.1
  @payloadcms/graphql: 3.59.1
  @payloadcms/live-preview: 3.59.1
  @payloadcms/live-preview-react: 3.59.1
  @payloadcms/next/utilities: 3.59.1
  @payloadcms/payload-cloud: 3.59.1
  @payloadcms/plugin-form-builder: 3.59.1
  @payloadcms/plugin-nested-docs: 3.59.1
  @payloadcms/plugin-redirects: 3.59.1
  @payloadcms/plugin-search: 3.59.1
  @payloadcms/plugin-seo: 3.59.1
  @payloadcms/richtext-lexical: 3.59.1
  @payloadcms/translations: 3.59.1
  @payloadcms/ui/shared: 3.59.1
  react: 19.1.0
  react-dom: 19.1.0
Operating System:
  Platform: darwin
  Arch: x64
  Version: Darwin Kernel Version 21.6.0: Mon Jun 24 00:56:10 PDT 2024; root:xnu-8020.240.18.709.2~1/RELEASE_X86_64
  Available memory (MB): 8192
  Available CPU cores: 4

This setup includes Payload CMS version 3.59.1, Next.js 15.4.4, and various Payload CMS plugins. If you’re running a similar environment, you might encounter this bug. The key is to ensure you're using the correct encoding and decoding functions, as we’ve discussed.

Conclusion

Dealing with non-English slugs can be tricky, but with the right approach, you can ensure your Payload CMS site works seamlessly across all languages. By implementing the decodeURI() and encodeURIComponent() fixes in your page.tsx and generatePreviewPath.ts files, you can resolve the linking issues and provide a better user experience. So go ahead, give it a try, and make your multilingual site shine!

Remember, a smooth multilingual experience not only benefits your users but also boosts your site's SEO and overall credibility. Keep coding, keep creating, and keep making the web a more inclusive place!