Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
Lauri Kallioniemi committed Jun 22, 2021
0 parents commit 397e0ad
Show file tree
Hide file tree
Showing 5 changed files with 650 additions and 0 deletions.
46 changes: 46 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
Polylang - Translate URL Rewrite Slugs
===============================================================================
WordPress plugin that add rewrite url slugs translation feature to Polylang.

Work in progress ;)

Upgrade notice < 0.3.0
-------------------------------------------------------------------------------
If you used a version prior to 0.3.0, the plugin will probably crash as the structure of the param for the "pll_translated_post_type_rewrite_slugs" filter has changed.

Translate Post Type URLs
-------------------------------------------------------------------------------
Translate rewrite slugs for post types by doing 5 things:
- Remove original extra rewrite rules and permastruct for these post types;
- Translate the extra rewrite rules and permastruct for these post types;
- Stop Polylang from translating rewrite rules for these post types;
- Fix "get_permalink" for these post types.
- Fix "get_post_type_archive_link" for these post types.

To translate a post type rewrite slug, add the filter "pll_translated_post_type_rewrite_slugs" to your functions.php file or your plugin and add the "has_archive" and "rewrite" key has you normally do for the params of the "register_post_type" Wordpress function but add it for each post type and language you want.

Example
~~~php
<?php
add_filter('pll_translated_post_type_rewrite_slugs', function($post_type_translated_slugs) {
// Add translation for "product" post type.
$post_type_translated_slugs = array(
'product' => array(
'fr' => array(
'has_archive' => true,
'rewrite' => array(
'slug' => 'produit',
),
),
'en' => array(
'has_archive' => true,
'rewrite' => array(
'slug' => 'product',
),
),
),
);
return $post_type_translated_slugs;
});
?>
~~~
6 changes: 6 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"name": "jussikinnula/wp-polylang-translate-rewrite-slugs",
"description": "Polylang - Translate URL Rewrite Slugs",
"homepage": "https://github.com/jussikinnula/wp-polylang-translate-rewrite-slugs",
"type": "wordpress-plugin"
}
156 changes: 156 additions & 0 deletions include/post-type.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
<?php
/**
* Post type related object.
*
* @todo Filter "extra_rules_top" after Polylang has create his translated version
* of them. See $this->replace_extra_rules_top.
*/
class PLL_TRS_Post_Type {
// The post type object.
public $post_type_object;
// The translated rewrite slugs.
public $translated_slugs;

/**
* Contructor.
*/
public function __construct($post_type_object, $translated_slugs) {
$this->post_type_object = $post_type_object;
$this->translated_slugs = $this->sanitize_translated_slugs($translated_slugs);

// Replace "extra_rules_top", for archive.
$this->replace_extra_rules_top();
// Replace "permastruct", for single.
$this->replace_permastruct();
}

private function sanitize_translated_slugs($translated_slugs) {
$post_type = $this->post_type_object->name;

// Add defaults to translated_slugs.
$defaults = array(
'has_archive' => false,
'rewrite' => true,
);

foreach ($translated_slugs as $lang => $translated_slug) {
$args = wp_parse_args( $translated_slug, $defaults );
$args = (object) $args;

if ( false !== $args->rewrite && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
if ( ! is_array( $args->rewrite ) )
$args->rewrite = array();
if ( empty( $args->rewrite['slug'] ) )
$args->rewrite['slug'] = $post_type;
if ( ! isset( $args->rewrite['with_front'] ) )
$args->rewrite['with_front'] = true;
if ( ! isset( $args->rewrite['pages'] ) )
$args->rewrite['pages'] = true;
if ( ! isset( $args->rewrite['feeds'] ) || ! $args->has_archive )
$args->rewrite['feeds'] = (bool) $args->has_archive;
if ( ! isset( $args->rewrite['ep_mask'] ) ) {
if ( isset( $args->permalink_epmask ) )
$args->rewrite['ep_mask'] = $args->permalink_epmask;
else
$args->rewrite['ep_mask'] = EP_PERMALINK;
}
}

$translated_slugs[$lang] = $args;
}

return $translated_slugs;
}

/**
* Replace "extra_rules_top", for archive.
*
* This code simulate the code used in WordPress function "register_post_type"
* and execute it for each language. After that, Polylang will consider these
* rules like "individual" post types (one by lang) and will create the appropriated
* rules.
*
* @see Extra rules from WordPress (wp-include/post.php, register_post_type()).
*/
private function replace_extra_rules_top() {
global $polylang, $wp_rewrite;

$post_type = $this->post_type_object->name;

// Remove the original extra rules.
if ( $this->post_type_object->has_archive ) {
$archive_slug = $this->post_type_object->has_archive === true ? $this->post_type_object->rewrite['slug'] : $this->post_type_object->has_archive;
if ( $this->post_type_object->rewrite['with_front'] )
$archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
else
$archive_slug = $wp_rewrite->root . $archive_slug;

unset($wp_rewrite->extra_rules_top["{$archive_slug}/?$"]);
if ( $this->post_type_object->rewrite['feeds'] && $wp_rewrite->feeds ) {
$feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
unset($wp_rewrite->extra_rules_top["{$archive_slug}/feed/$feeds/?$"]);
unset($wp_rewrite->extra_rules_top["{$archive_slug}/$feeds/?$"]);
}
if ( $this->post_type_object->rewrite['pages'] )
unset($wp_rewrite->extra_rules_top["{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$"]);
}

// Add the translated extra rules for each languages.
foreach ($this->translated_slugs as $lang => $translated_slug) {
if ($translated_slug->has_archive) {
$archive_slug = $translated_slug->has_archive === true ? $translated_slug->rewrite['slug'] : $translated_slug->has_archive;
if ( $translated_slug->rewrite['with_front'] )
$archive_slug = substr( $wp_rewrite->front, 1 ) . $archive_slug;
else
$archive_slug = $wp_rewrite->root . $archive_slug;

add_rewrite_rule( "{$archive_slug}/?$", "index.php?post_type=$post_type", 'top' );
if ( $translated_slug->rewrite['feeds'] && $wp_rewrite->feeds ) {
$feeds = '(' . trim( implode( '|', $wp_rewrite->feeds ) ) . ')';
add_rewrite_rule( "{$archive_slug}/feed/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
add_rewrite_rule( "{$archive_slug}/$feeds/?$", "index.php?post_type=$post_type" . '&feed=$matches[1]', 'top' );
}
if ( $translated_slug->rewrite['pages'] )
add_rewrite_rule( "{$archive_slug}/{$wp_rewrite->pagination_base}/([0-9]{1,})/?$", "index.php?post_type=$post_type" . '&paged=$matches[1]', 'top' );
}
}
}

/**
* Replace "permastruct", for single.
*
* This code simulate the code used in WordPress function "register_post_type"
* and execute it for each language.
*
* @see Permstruct from WordPress (wp-include/post.php, register_post_type()).
*/
private function replace_permastruct() {
global $polylang, $wp_rewrite;

$post_type = $this->post_type_object->name;

// Remove the original permastructs.
unset($wp_rewrite->extra_permastructs[$post_type]);

// Add the translated permastructs for each languages.
foreach ($this->translated_slugs as $lang => $translated_slug) {
$args = $translated_slug;

if ( false !== $args->rewrite && ( is_admin() || '' != get_option( 'permalink_structure' ) ) ) {
$permastruct_args = $args->rewrite;
$permastruct_args['feed'] = $permastruct_args['feeds'];
// Set the walk_dirs to false to avoid conflict with has_archive = false and the %language%
// in the rewrite directive. Without it the archive page redirect to the frontpage if has_archive is false.
$permastruct_args['walk_dirs'] = false;

// If "Hide URL language information for default language" option is
// set to true the rules has to be different for the default language.
if ($polylang->options['hide_default'] && $lang == pll_default_language()) {
add_permastruct( $post_type.'_'.$lang, "{$args->rewrite['slug']}/%$post_type%", $permastruct_args );
} else {
add_permastruct( $post_type.'_'.$lang, "%language%/{$args->rewrite['slug']}/%$post_type%", $permastruct_args );
}
}
}
}
}
66 changes: 66 additions & 0 deletions include/taxonomy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* Taxonomy related object.
*/
class PLL_TRS_Taxonomy {
// The post type object.
public $taxonomy_object;
// The translated rewrite slugs.
public $translated_slugs;
// The translated object struct.
public $translated_struct;

/**
* Contructor.
*/
public function __construct($taxonomy_object, $translated_slugs, $translated_struct) {
$this->taxonomy_object = $taxonomy_object;
$this->translated_slugs = $translated_slugs;
$this->translated_struct = $translated_struct;

// Translate the rewrite rules of the post type.
add_filter($this->taxonomy_object->name.'_rewrite_rules', array($this, 'taxonomy_rewrite_rules_filter'));
}

/**
* Translate the rewrite rules.
*/
public function taxonomy_rewrite_rules_filter($rewrite_rules) {
global $polylang, $wp_rewrite;

$translated_rules = array();

// For each lang.
foreach ($this->translated_slugs as $lang => $translated_slug) {
// If "Hide URL language information for default language" option is
// set to true the rules has to be different for the default language.
if ($polylang->options['hide_default'] && $lang == pll_default_language()) {
// For each rule.
foreach ($rewrite_rules as $rule_key => $rule_value) {
// Only translate the rewrite slug.
$translated_rules[str_replace(trim($this->taxonomy_object->rewrite['slug'], '/'), $translated_slug, $rule_key)] = $rule_value;
}
} else {
// For each rule.
foreach ($rewrite_rules as $rule_key => $rule_value) {
$taxonomy_rewrite_slug = $this->taxonomy_object->rewrite['slug'];

// Replace the rewrite tags in slugs.
foreach ($wp_rewrite->rewritecode as $position => $code) {
$taxonomy_rewrite_slug = str_replace($code, $wp_rewrite->rewritereplace[$position], $taxonomy_rewrite_slug);
$translated_slug = str_replace($code, $wp_rewrite->rewritereplace[$position], $translated_slug);
}

// Shift the matches up cause "lang" will be the first.
$translated_rules['('.$lang.')/'.str_replace(trim($taxonomy_rewrite_slug, '/'), $translated_slug, $rule_key)] = str_replace(
array('[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]', '[1]'),
array('[9]', '[8]', '[7]', '[6]', '[5]', '[4]', '[3]', '[2]'),
$rule_value
);
}
}
}

return $translated_rules;
}
}
Loading

0 comments on commit 397e0ad

Please sign in to comment.