How to use Polylang and Frontity

Hi to everyone, i’m happy to in announcing that, i found a way to work with frontity and polylang. There is not great documentation about it, i hope that can help someone.

Okay let’s start.
I set up my polylang plugin and i have two url for homepage “/” → It, “/en/home” → eng. Unfortunately the homepage doesn’t work with same slug “/” but other pages working fine.

I setup my frontity.settings.js like as

const settings = [
  {
    "name": "frontity-react-ita",
    "match": [".*localhost:3000\/it(\/.*)?$"],
    "state": {
      "frontity": {
        "url": "",
        "title": "Test Frontity Blog",
        "description": "WordPress installation for Frontity development"
      }
    },
    "packages": [
      {
        "name": "name-of-your-theme",
        "state": {
          "lang": "it",
          "theme": {
            "menu": [],
            "featured": {
              "showOnList": false,
              "showOnPost": false
            }
          }
        }
      },
      {
        "name": "@frontity/wp-source",
        "state": {
          "source": {
            "url": "https://your-website-url.com",
            // "api": "",
            "homepage": "/",  // -> SET YOUR FIRST LANG HOME PAGE
            "postsPage": "bacheca", // -> SET YOUR FIRST LANG POSTS PAGE
            "params": {
              "lang": "it",
            },
            "postTypes":[
              {
                type: "eventi",
                endpoint: "eventi",
                archive: "/eventi"
              }
            ]
          }
        }
      },
      "@frontity/tiny-router",
      "@frontity/html2react"
    ]
  },
  {
    "name": "frontity-react-eng",
    "match": [".*localhost:3000\/en(\/.*)?$"],
    "state": {
      "frontity": {
        "url": "",
        "title": "Test Frontity Blog",
        "description": "WordPress installation for Frontity development"
      }
    },
    "packages": [
      {
        "name": "name-of-your-theme",
        "state": {
          "lang": "en",
          "theme": {
            "menu": [],
            "featured": {
              "showOnList": false,
              "showOnPost": false
            }
          }
        }
      },
      {
        "name": "@frontity/wp-source",
        "state": {
          "source": {
            "url": "http://abarcalreact.local",
            // "api": "",
            "homepage": "/home", //-> SET YOUR SECOND LANG HOMEPAGE
            "postsPage": "/en/news", //-> SET YOUR SECOND LANG POSTS PAGE
            "params": {
              "lang": "en",
            },
            "postTypes":[
              {
                type: "eventi",
                endpoint: "eventi",
                archive: "/en/eventi" // -> SET THE SECOND LANG URL OF YOUR CPT ARCHIVE
              }
            ]
          }
        }
      },
      "@frontity/tiny-router",
      "@frontity/html2react"
    ]
  }
  ]
  export default settings;

Set up my index.js like as

import Root from "./components"
import link from "@frontity/html2react/processors/link";

//handlers
import menuHandler from "./components/handlers/menu-handler";

const themeName = {
  name: "theme-name",
  roots: {
    theme: Root,
  },
  state: {
    theme: {
      isUrlVisible:false,
      menu: [],
      lang: "it",
      rapidNavIta:'navigazione-rapida', // -> If you use the menu handler this is a primary lang slug of menu
      rapidNavEng:'rapid-navigation', // -> If you use the menu handler this is a secondary lang slug of menu
      relativePathEng:'', // -> This is for the switch from first and second lang, if for example you're on "/bacheca/post-name", and you want to switch to "en/news/post-name" you can store here your other language post slug
      relativePathIta:'', // -> See under
    },
  },
  actions: {
    theme: {
      toggleLang:({state}) => {
        state.theme.lang = state.lang
      },
      toggleUrl:({state}) => {
        state.theme.isUrlVisible = !state.theme.isUrlVisible
      },
      beforeSSR: async ({ state, actions }) => {
        await actions.source.fetch("/pages");
        await actions.source.fetch("/posts")
        await actions.source.fetch("/eventi");
        await actions.source.fetch(`/menu/${state.theme.rapidNavIta}`);
        await actions.source.fetch(`/menu/${state.theme.rapidNavEng}`);
      },
    },
  },
  libraries: {
    html2react: {
      processors: [link]
    },
    source: {
      handlers: [menuHandler],
    },
  }
}


export default themeName

Ok, now see how to set the index.js (Root) file.

import React from "react"
import { connect, Global, css, Head } from 'frontity'
[... your imports]

//components
import Post from './Post'
import LangSwitch from './LangSwitch'
[... your components ...]


const Root = ({state, actions}) => {
  const data = state.source.get(state.router.link)

  return (
    <>
    <Head>
      <html lang="no" />
    </Head>
    <LanguageSwitch/>
    [.... your index.js file contine here]
    </>
  )
}

export default connect(Root)

Now see how to set langswitch.js

import React from "react";
import { connect, styled } from "frontity";


const LanguageSwitch = ({ actions, state }) => {
    const { lang } = state.theme;
    return (
        <>
            <Box>      
                <a 
                    href={state.theme.relativePathEng !== '' ? `${state.theme.relativePathEng}` : '/en/home'}
                    className="toggleicon"  
                    onClick={actions.theme.toggleLang}
                >EN</a>
                <a 
                href={state.theme.relativePathIta !== '' ? `${state.theme.relativePathIta}` : '/'}
                className="toggleicon">
                    IT
                </a>
            </Box>
        </>
    )
}

export default connect(LanguageSwitch);

const Box = styled.div`
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 1rem;
    cursor: pointer;
    z-index: 5;

    img {
        height: 25px;
        width: 25px;
    }
`;

And in the end we see how to set the useEffect to manage the related post slug of current post, the code below is for "Posts.js"

import React, {useEffect} from "react"
import { connect } from "frontity"
import dayjs from "dayjs"

const Post = ({ state, libraries }) => {
  const data = state.source.get(state.router.link)
  const post = state.source[data.type][data.id]
  const formattedDate = dayjs(post.date).format("DD MMMM YYYY")
  const Html2React = libraries.html2react.Component

  useEffect(() => {
   /// BE CAREFOUL! I SET MY CUSTOM API KEY FOR POSTS WHERE STORE THE RELATIVE SLUG FOR EACH POST.
   // SEE THE NEXT CODE SECTION FOR READ HOW TO SET CUSTOM API KEY
    post['translate_id'].map(translate => {
        if(translate.key === 'en') {
          state.theme.relativePathEng=translate.path
        }
        if(translate.key === 'it') {
          state.theme.relativePathIta=translate.path
        }
    })
  },[])

  return (
    <div>
        <p>
            <strong>Posted: </strong>
            {formattedDate}
        </p>
        <h2>{post.title.rendered}</h2>
        <Html2React html={post.content.rendered} />
    </div>
  )
}

export default connect(Post)

How to set in wordpress function.php custom API key to store current post slug in other language



  add_action( 'rest_api_init', function () {
	register_rest_field( 'post', 'translate_id', my_related_translation() );
    

function my_related_translation() {
	return array(
		'methods'         => 'GET',
		'get_callback'    => 'related_translate_id',
		'schema'          => null,
	);
}

function related_translate_id( $data ) {
	$post_id = $data['id'];
    $defaultLanguage = pll_default_language();
    $translationId = pll_get_post_translations($post_id);
    $singlePostId = get_post($translationId);
    $langArray = array();

    foreach ($translationId as $post => $key) {
        $postDataArray = array(
            'key' => $post,
            'id' => $key,
            'slug' => get_post($key)->post_name,
            'path' => wp_make_link_relative(get_the_permalink($key))
        );
        $langData = array(
                $postDataArray
        );
        array_push($langArray,$postDataArray);

    }
    return $langArray;
}

And now you find related_translate_id key in each post api.
You can add the “related_transalte_id” function to all website post-type.

It’s not very easy to explain, i hope it’s helpfull.

Bye :wink:

2 Likes

Wow, thanks for this! I only managed to connect Qtranslate XT and WPML and I had given up Polylang as impossible. Will be really helpful :slight_smile:

Hey @Hussein, it’s very hard but it’s possible…for example the second language custom taxonomy does not work like as archive, if you want to display in archive a list of post with certain taxonomy you need to create a dynamic filter while preserv the post type archive url…
For now i just create the filter and it’s work for filter posts but if i want to show all the posts after filtering it doesen’t work…if i find solution will publish thath :slight_smile:

It’s easy connect wpml to frontity? Qtranslate it’s very outdated

Thanks!

@matteo.lcd with WPML really works out of the box. No extra configuration is needed a part from setting up the frontity settings correctly. WPML gives you a json path for each language like yourdomain.com/es/wp-json and yourdomain.com/en/wp-json

About Qtranslate, I don’t mean the old version of Qtranslate, but the new one that is currently under development (Qtranslate XT). They always keep it updated, I will leave you the link in case you are interested. It also works out of the box: GitHub - qtranslate/qtranslate-xt: qTranslate-XT (eXTended) - reviving qTranslate-X. A new community-driven plugin soon. GUTENBERG initial support now available! Built-in modules for WooCommerce, ACF, All in one SEO, Events Made Easy, Gravity Forms.

Ah ok, it’s fantastic…i think i’ll use Wpml next time :slight_smile:

Thanks a lot!

I find interesting the work you did, I have a doubt, with the static content created, how can I translate it or how can I manage it?

Hi, i think the best way is create a variables and display it depends on the language :slight_smile: