Skip to content

Instantly share code, notes, and snippets.

@rmpel
Last active February 12, 2020 07:25
Show Gist options
  • Save rmpel/5672b2b943a4a015fe1777c0a31fac59 to your computer and use it in GitHub Desktop.
Save rmpel/5672b2b943a4a015fe1777c0a31fac59 to your computer and use it in GitHub Desktop.
Translated POSTS urls in WPML WordPress website with a "Page for Posts" as POST-URL-base
<?php
/**
* Notes on the following section
*
* Correct set-up is:
*
* Set your page-for-posts to a certain WordPress Posts, for example /nl/nieuws/
* Set your permalink structure to the same; /nieuws/%postname%/
*
* WordPress will generate links for "some-article-in-german" as /de/nieuws/some-article-in-german
* Code below will rewrite /(any-language)/(any-translation-of-/nieuws)/ to /the-language/the-translated-page/the-post/,
* like /de/neuigkeiten/some-article-in-german
*
* If you have problems;
*
* Re-save permalinks
*
* If you changed the languages in your site;
*
* Re-save permalinks
*
* If you change the "Page for Posts" for your site;
*
* Re-save permalinks
*
*/
add_filter( 'post_link', function ( $permalink, $post, $leavename ) {
static $shortcircuit, $languages, $patch;
if ( ! $shortcircuit ) {
if ( 'post' === get_post_type( $post ) ) {
if ( ! $languages ) {
$languages = apply_filters( 'wpml_active_languages', array(), 'skip_missing=0' );
$languages = array_keys( $languages );
$languages = implode( '|', $languages );
$languages = "($languages)";
}
if ( ! $patch ) {
$patch = get_option( 'page_for_posts_patch' );
// do nothing if there is no patch available
if (!$patch) {
return $permalink;
}
}
$post_page = get_option( 'page_for_posts' );
$post_page = apply_filters( 'wpml_object_id', $post_page, 'post', true );
$shortcircuit = true;
$link = get_permalink( $post_page );
$shortcircuit = false;
// this is an elaborate replacement to make absolutely sure this changes the FIRST and ONLY the first occurrence
$permalink = preg_replace( '/\/' . $languages . '\/' . $patch . '\//', '/' . ICL_LANGUAGE_CODE . '/%page_for_posts%/', $permalink, 1 );
$permalink = explode( '/' . ICL_LANGUAGE_CODE . '/%page_for_posts%/', $permalink, 2 );
$permalink = $link . $permalink[1];
}
}
return $permalink;
}, PHP_INT_MAX, 3 );
add_filter( 'term_link', function( $permalink, $term, $taxonomy ) {
static $shortcircuit, $languages, $patch;
if ( ! $shortcircuit ) {
$shortcircuit = true;
if ( ! $languages ) {
$languages = apply_filters( 'wpml_active_languages', array(), 'skip_missing=0' );
$languages = array_keys( $languages );
$languages = implode( '|', $languages );
$languages = "($languages)";
}
if ( ! $patch ) {
$patch = get_option( 'page_for_posts_patch' );
// do nothing if there is no patch available
if (!$patch) {
return $permalink;
}
}
$post_page = get_option( 'page_for_posts' );
$post_page = apply_filters( 'wpml_object_id', $post_page, 'post', true );
$link = get_permalink( $post_page );
// this is an elaborate replacement to make absolutely sure this changes the FIRST and ONLY the first occurrence
$permalink = preg_replace( '/\/' . $languages . '\/' . $patch . '\//', '/' . ICL_LANGUAGE_CODE . '/%page_for_posts%/', $permalink, 1 );
$permalink = explode( '/' . ICL_LANGUAGE_CODE . '/%page_for_posts%/', $permalink, 2 );
$permalink = $link . $permalink[1];
$shortcircuit = false;
}
return $permalink;
}, PHP_INT_MAX, 3 );
add_filter( 'icl_ls_languages', function ( $languages ) {
global $sitepress;
$current_language = $sitepress->get_current_language();
$post_page = get_option( 'page_for_posts' );
$patch = get_option( 'page_for_posts_patch' );
foreach ( $languages as $language_code => &$language ) {
if (preg_match( '@/' . $patch . '/@', $language['url'] )) {
$post_page = apply_filters( 'wpml_object_id', $post_page, 'post', true, $language['code'] );
$sitepress->switch_lang($language['code']);
$link = get_permalink( $post_page );
$language['url'] = preg_replace( '@/' . $patch . '/@', '/****/', $language['url'] );
$language['url'] = explode('****/', $language['url']);
$language['url'] = $link . $language['url'][1];
}
}
$sitepress->switch_lang($current_language);
return $languages;
} );
/**
* Purpose of this filter:
*
* 1. rewrite the rewrite rules.
*
* WordPress generates rules based on the Permalink structure.
* Example: /nieuws/%postname%/
* Will generate rules starting with 'nieuws/' but then will fail to detect urls that should be translated;
* /de/neuigkeiten/ for example.
* The code below makes the rule '(?:nieuws|neuigkeiten|news|....) based on all translations of the "Page for Posts".
* This fix is called the "patch", and will be stored for later use
*
* 2. Store the patch so the code-block above can use it.
*
* Because of this piece of caching;
*
* If you have problems;
*
* Re-save permalinks
*
* If you changed the languages in your site;
*
* Re-save permalinks
*
* If you change the "Page for Posts" for your site;
*
* Re-save permalinks
*
*/
add_filter('rewrite_rules_array', function($rules) {
$patch = false;
$post_page = get_option( 'page_for_posts' );
// do nothing if we don't have this setting.
if (!$post_page) {
update_option('page_for_posts_patch', false);
return $rules;
}
$keys = array_keys($rules);
$values = array_values($rules);
$has_one = false;
foreach ($keys as &$key) {
if ( ! $patch ) {
$languages = apply_filters( 'wpml_active_languages', array(), 'skip_missing=0' );
foreach ( $languages as $language_code => $data ) {
$id = apply_filters( 'wpml_object_id', $post_page, 'post', true, $language_code );
$all_permalinks_for_all_languages[ $language_code ] = explode('/'. $language_code .'/', get_permalink( $id ), 2);
$all_permalinks_for_all_languages[ $language_code ] = trim($all_permalinks_for_all_languages[ $language_code ][1], '/');
}
$patch = '(?:'. implode('|', $all_permalinks_for_all_languages) .')';
update_option('page_for_posts_patch', $patch);
}
$_key = preg_replace('/^'. $patch .'\//', $patch.'/', $key);
if ($key != $_key) {
$has_one = true;
}
$key = $_key;
}
if (!$has_one) {
update_option('page_for_posts_patch', false);
return $rules;
}
$rules = array_combine($keys, $values);
return $rules;
});

With WPML you can localize the "page for posts", this will localize the post-URL-base according to the actual page URL.

With WPML you can localize the slug of your CPT single, but not your CPT archive, if you give it a different content. You can fix the translations with https://gist.github.com/rmpel/d9989da79956fb0eafe81e49331b84b6 .

While this will fix all URLs on the front-end, you will still need to fix the Sitemap links, in case you use Yoast SEO (Basic or Premium), or SEO by Rank Math. You van do this with https://gist.github.com/rmpel/b00997f2504c39c718028dfa7e79b87c .

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment