|
<?php |
|
|
|
/** |
|
* Translate post-type-archive-slug when different from post-type-slug. |
|
* |
|
* You can have your archive slug set to, for example /books and the singles on /book/title by setting |
|
* $args['rewrite'] => [ 'slug' => 'book', ... ]; |
|
* $args['has_archive'] => 'books'; |
|
* when registering your post_type |
|
* |
|
* WPML supports translating the single-slug, but not the archive-slug. |
|
* |
|
* Following code allows that. It's a 3-part solution, all 3 parts are needed. |
|
* |
|
* After implementation: |
|
* |
|
* 1. save permalinks (will register the strings with WPML) |
|
* 2. use WPML string translation to translate the strings, found in text-domain "post-type-archive-slug" |
|
* You may need to set the correct source-language for the text-domain using the WPML String Translation tools. |
|
* 3. save permalinks (will update rewrite rules for tanslations) |
|
* |
|
* If you don't want to use WPML String Translation, change the text-domain post-type-archive-slug to that of your theme |
|
* or plugin and register the strings by putting a line like this: |
|
* $not_used = __('archive-slug', 'text-domain'); |
|
* in your theme or plugin and scan the files with your favorite POMO-editor. |
|
* |
|
* For more information: |
|
* @see https://developer.wordpress.org/apis/handbook/internationalization/localization/#translating-themes-and-plugins |
|
* |
|
* |
|
* Part 1: filter the link generation. This works on the page. |
|
*/ |
|
|
|
add_filter( 'post_type_archive_link', function ( $permalink, $post_type ) { |
|
$post_type_object = get_post_type_object( $post_type ); |
|
|
|
// dont do anything if |
|
// - not a valid post_type |
|
// - rewrite not enabled |
|
// - slug not defined |
|
// - archive-slug not defined |
|
// - archive-slug not different from post-slug |
|
if ( ! $post_type_object || ! is_array( $post_type_object->rewrite ) || ! isset( $post_type_object->rewrite['slug'] ) || ! is_a( $post_type_object, WP_Post_Type::class ) || ! is_string( $post_type_object->has_archive ) || $post_type_object->rewrite['slug'] == $post_type_object->has_archive ) { |
|
return $permalink; |
|
} |
|
|
|
// use a cached version written after permalink resave, so we don't have to do grunt work every time. |
|
$match = get_option( '__wpml_post_type_archive_slug_match', [] ); |
|
$match = $match && isset( $match[ $post_type ] ) ? $match[ $post_type ] : false; |
|
if ( ! $match ) { |
|
// sorry, need to save permalinks first. |
|
// silently fail. |
|
return $permalink; |
|
} |
|
|
|
/** |
|
* @action wpml_register_single_string |
|
* @var string $context the text-domain |
|
* This should be $text_domain, not $context |
|
* @var string $name a description of the string. |
|
* because this is the actual Context for the string |
|
* @var string $value the text to translate |
|
* @var bool $allow_empty_value , default = false |
|
* @var string $source_lang_code , default to system-default-language. |
|
*/ |
|
do_action( 'wpml_register_single_string', 'post-type-archive-slug', '', $post_type_object->has_archive ); |
|
$permalink = preg_replace( '@/' . implode('|', $match) . '/@', '/' . __( $post_type_object->has_archive, 'post-type-archive-slug' ) . '/', $permalink ); |
|
/** |
|
* Why? sometimes url's come with dual slashes after the website domain. |
|
* replace all // with / except when it is :// |
|
*/ |
|
$permalink = preg_replace('@([^:]/)/@', '\1', $permalink); |
|
|
|
return $permalink; |
|
}, PHP_INT_MAX, 2 ); |
|
|
|
// above works for "current language" but fails for the language switcher. hence the following hook |
|
|
|
/** |
|
* Part 2: filter the link generation. This works in the language switch. |
|
* Warning: this is done multiple times during a page generation, but only once for the actual language-switcher |
|
* This is detected by the code by checking the post_Type being defined. ... ugly, but it works. |
|
*/ |
|
|
|
add_filter( 'icl_ls_languages', function ( $languages ) { |
|
$patch = get_option( '__wpml_post_type_archive_slug_match', [] ); |
|
if ( is_admin() || ! $patch || ! is_array( $patch ) ) { |
|
return $languages; |
|
} |
|
|
|
foreach ( $patch as $post_type => $_patches ) { |
|
$post_type_object = get_post_type_object( $post_type ); |
|
if ($post_type_object && is_a($post_type_object, 'WP_Post_Type')) { |
|
foreach ( $languages as $language_code => &$language ) { |
|
$language['url'] = preg_replace( '@/(' . implode('|', $_patches) . ')/@', '/' . ($_patches[$language_code] ?: $post_type_object->has_archive) . '/', $language['url'] ); |
|
/** |
|
* Why? sometimes url's come with dual slashes after the website domain. |
|
* replace all // with / except when it is :// |
|
*/ |
|
$language['url'] = preg_replace('@([^:]/)/@', '\1', $language['url']); |
|
} |
|
} |
|
} |
|
|
|
return $languages; |
|
} ); |
|
|
|
/** |
|
* Part 3: make the url's work. |
|
* This step also caches the list of post-types and their possible slugs |
|
* Effort is mate to only do work when there is actually an archive-slug that is different from the post-type-slug and rewrite is enabled. |
|
*/ |
|
|
|
add_filter( 'rewrite_rules_array', function ( $rules ) { |
|
|
|
global $sitepress; |
|
|
|
$current_language = $sitepress->get_current_language(); |
|
|
|
$post_types = get_post_types(); |
|
$post_types = array_filter( $post_types, function ( $post_type ) { |
|
$post_type_object = get_post_type_object( $post_type ); |
|
|
|
return ! ( ! $post_type_object || ! is_array( $post_type_object->rewrite ) || ! isset( $post_type_object->rewrite['slug'] ) || ! is_a( $post_type_object, WP_Post_Type::class ) || ! is_string( $post_type_object->has_archive ) || $post_type_object->rewrite['slug'] == $post_type_object->has_archive ); |
|
} ); |
|
if ( ! $post_types ) { |
|
return $rules; |
|
} |
|
|
|
$languages = apply_filters( 'wpml_active_languages', array(), 'skip_missing=0' ); |
|
|
|
$match = array_map( function ( $post_type ) use ( $languages, $sitepress ) { |
|
$post_type_object = get_post_type_object( $post_type ); |
|
|
|
return $post_type_object->has_archive; |
|
}, $post_types ); |
|
|
|
$patch = array_map( function ( $post_type ) use ( $languages, $sitepress ) { |
|
$post_type_object = get_post_type_object( $post_type ); |
|
$strings = []; |
|
foreach ( $languages as $language_code => $language ) { |
|
$sitepress->switch_lang( $language_code ); |
|
$strings[ $language_code ] = __( $post_type_object->has_archive, 'post-type-archive-slug' ); |
|
} |
|
|
|
return $strings; |
|
}, $post_types ); |
|
|
|
$sitepress->switch_lang( $current_language ); |
|
|
|
update_option( '__wpml_post_type_archive_slug_match', $patch ); |
|
|
|
$patch = array_map(function($strings){ |
|
return implode('|', $strings); |
|
}, $patch); |
|
$match = '@^(' . implode( '|', $match ) . ')/@'; |
|
$patch = '(?:' . implode( '|', $patch ) . ')'; |
|
|
|
|
|
$keys = array_keys( $rules ); |
|
$values = array_values( $rules ); |
|
|
|
foreach ( $keys as &$key ) { |
|
$key = preg_replace( $match, $patch, $key ); |
|
} |
|
|
|
$rules = array_combine( $keys, $values ); |
|
|
|
return $rules; |
|
} ); |