in my theme I want to define a series of custom post types and custom taxonomies, each one having its own customized slug; the base language of my theme is english, therefore the slugs will be in English language
for example while defining the slug of custom post type "product" args:
'rewrite' => array( 'slug' => 'product' ),
is there any way to translate the "slug" through po/mo files? can I put it as:
'rewrite' => array( 'slug' => __('product', 'mytextdomain') )
or it won't work? what's the current practice to localize slugs?
in my theme I want to define a series of custom post types and custom taxonomies, each one having its own customized slug; the base language of my theme is english, therefore the slugs will be in English language
for example while defining the slug of custom post type "product" args:
'rewrite' => array( 'slug' => 'product' ),
is there any way to translate the "slug" through po/mo files? can I put it as:
'rewrite' => array( 'slug' => __('product', 'mytextdomain') )
or it won't work? what's the current practice to localize slugs?
Share Improve this question asked Oct 2, 2011 at 11:02 unfulviounfulvio 1,8347 gold badges32 silver badges63 bronze badges 4 |6 Answers
Reset to default 21 +25I wouldn't try to localize your slugs. Instead, why not give your users the option to change them by adding another field to the permalink settings page?
Hook into load-options-permalink.php
and set up some things to catch the $_POST
data to save your slug. Also add a settings field to the page.
<?php
add_action( 'load-options-permalink.php', 'wpse30021_load_permalinks' );
function wpse30021_load_permalinks()
{
if( isset( $_POST['wpse30021_cpt_base'] ) )
{
update_option( 'wpse30021_cpt_base', sanitize_title_with_dashes( $_POST['wpse30021_cpt_base'] ) );
}
// Add a settings field to the permalink page
add_settings_field( 'wpse30021_cpt_base', __( 'CPT Base' ), 'wpse30021_field_callback', 'permalink', 'optional' );
}
Then the call back function for the settings field:
<?php
function wpse30021_field_callback()
{
$value = get_option( 'wpse30021_cpt_base' );
echo '<input type="text" value="' . esc_attr( $value ) . '" name="wpse30021_cpt_base" id="wpse30021_cpt_base" class="regular-text" />';
}
Then when you register your post type, grab the slug with get_option
. If it's not there, use your default.
<?php
add_action( 'init', 'wpse30021_register_post_type' );
function wpse30021_register_post_type()
{
$slug = get_option( 'wpse30021_cpt_base' );
if( ! $slug ) $slug = 'your-default-slug';
// register your post type, reference $slug for the rewrite
$args['rewrite'] = array( 'slug' => $slug );
// Obviously you probably need more $args than one....
register_post_type( 'wpse30021_pt', $args );
}
Here's the settings field portion as a plugin https://gist.github/1275867
EDIT: Another Option
You could also change the slug based on what's defined in the WPLANG
constant.
Just write a quick function that holds data...
<?php
function wpse30021_get_slug()
{
// return a default slug
if( ! defined( 'WPLANG' ) || ! WPLANG || 'en_US' == WPLANG ) return 'press';
// array of slug data
$slugs = array(
'fr_FR' => 'presse',
'es_ES' => 'prensa'
// etc.
);
return $slugs[WPLANG];
}
Then get the slug where you register your custom post type.
<?php
add_action( 'init', 'wpse30021_register_post_type' );
function wpse30021_register_post_type()
{
$slug = wpse30021_get_slug();
// register your post type, reference $slug for the rewrite
$args['rewrite'] = array( 'slug' => $slug );
// Obviously you probably need more $args than one....
register_post_type( 'wpse30021_pt', $args );
}
The best option, IMO, would be to both give the user an option and provide solid defaults:
<?php
add_action( 'init', 'wpse30021_register_post_type' );
function wpse30021_register_post_type()
{
$slug = get_option( 'wpse30021_cpt_base' );
// They didn't set up an option, get the default
if( ! $slug ) $slug = wpse30021_get_slug();
// register your post type, reference $slug for the rewrite
$args['rewrite'] = array( 'slug' => $slug );
// Obviously you probably need more $args than one....
register_post_type( 'wpse30021_pt', $args );
}
I am doing exactly that in a theme we are developing. It is available in 5 distinct languages, and each language has a translated set of categories. The first component of the URL in the theme is parsed to determine which language is used, in country-language format:
/uk-en
/fr-fr
/it-it
And then translated categories are parsed as further components of the URL.
The URL is parsed in the parse_request
phase:
function my_parse_request( $wp ) {
$path = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
$components = preg_split('|/|', $path, null, PREG_SPLIT_NO_EMPTY );
// Determine language from $components[0]
$language = array_shift( $components );
...
// Load translations file...
$mofile = get_stylesheet_directory()."/$language.mo";
load_textdomain( 'mydomain', $mofile );
...
// Determine category from $components[0]
if( __( 'some-category', 'mydomain' ) == $components[0] )
$wp->query_vars['category'] = 'some-category';
...
}
add_action( 'parse_request', 'my_parse_request' );
This example is devoid of requisite checks, but is meant only as an example.
There are drawbacks to this approach, of course, but it allows natural URLs in all languages. The main drawbacks I see are:
1) It doesn't make use of the permalink mechanism. This could likely be extended so that the proper permalink rules for all languages are generated and parse_request won't be necessary, but to do it for all of the languages would involve loading one MO file after another in a loop, and I don't know how well supported that is.
2) If a translator changes a slug, then the links get invalidated.
If that doest not work Why not you just simple do:
$post_slug= __('product', 'mytextdomain');
'rewrite' => array( 'slug' => $post_slug );
I actually had this problem, here's my solution, which works when you know the languages of your website beforehand. Let's say you have a CPT called "movie", and your website has 3 languages. You need to rewrite your CPT permalink, for each language. You could do this dynamically too.
add_action("init", "rewrite_cpt", 10, 0);
function rewrite_cpt(){
add_rewrite_rule('^movie/([^/]*)/?', 'index.php?post_type=movie&name=$matches[1]', 'top'); // English
add_rewrite_rule('^film/([^/]*)/?', 'index.php?post_type=movie&name=$matches[1]', 'top'); // Italian
add_rewrite_rule('^фильм/([^/]*)/?', 'index.php?post_type=movie&name=$matches[1]', 'top'); // Russian
}
Now you just need to rebuild your permalinks: go to Settings > Permalinks and just press "Save"
The next part is rewriting URLs for your CPT, if you have a translated CPT you need to get the language of the post, in my case I use Polylang. It's important to encode foreign characters in URLs
add_filter("post_type_link", "x_tours_postlink", 10, 2);
function x_tours_postlink($post_link, $post){
$urls = array(
"en" => "movie",
"it" => "film",
"ru" => "фильм"
);
if(get_post_type($post) == "movie")
$post_link = str_replace("movie", urlencode($urls[pll_get_post_language($post->ID)]), $post_link);
return $post_link;
}
You could try this in your functions.php
<?php
add_filter('rewrite_slugs', function($translated_slugs) {
// the possible translations for your slug 'product'
$translated_slugs = array(
'product' => array(
'pt' => array(
'has_archive' => true,'rewrite' => array('slug' => 'produto'),
),
'es' => array(
'has_archive' => true,'rewrite' => array('slug' => 'producto'),
),
),
);
return $translated_slugs;
});
?>
as seen here
I would recommend not making slugs translatable.
Translation is for user-facing site content. Slugs are used internally, and are only marginally "public-facing" via URL rewrites - and URLs should not be translatable, either.
So: leave your slugs alone, as you define them. Only make translatable strings that are intended for public consumption.
prensa
with a slug set toprensa
. Using WPML the translated's page slug ispress
as it can't beprensa
again: /en/press/ which doesn't display anything (note that now clicking the ES link doesn't bring you back to /prensa/). BUT, if you visit /en/prensa/ it does work... – Naoise Golden Commented Oct 10, 2011 at 16:45