Localización de "slugs" en el tema (tipos de contenido personalizados, taxonomías)
en mi tema quiero definir una serie de tipos de contenido personalizados y taxonomías personalizadas, cada una con su propio slug personalizado; el idioma base de mi tema es inglés, por lo tanto los slugs estarán en inglés
por ejemplo, al definir el slug de un tipo de contenido personalizado "product" en los argumentos:
'rewrite' => array( 'slug' => 'producto' ),
¿hay alguna manera de traducir el "slug" a través de archivos po/mo? ¿puedo ponerlo como:
'rewrite' => array( 'slug' => __('producto', 'mytextdomain') )
¿o no funcionará? ¿cuál es la práctica actual para localizar slugs?
No intentaría localizar tus slugs. En su lugar, ¿por qué no darles a tus usuarios la opción de cambiarlos agregando otro campo a la página de configuración de enlaces permanentes?
Conéctate a load-options-permalink.php
y configura algunos elementos para capturar los datos de $_POST
y guardar tu slug. También añade un campo de configuración a la página.
<?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'] ) );
}
// Añade un campo de configuración a la página de enlaces permanentes
add_settings_field( 'wpse30021_cpt_base', __( 'Base CPT' ), 'wpse30021_field_callback', 'permalink', 'optional' );
}
Luego, la función de retorno para el campo de configuración:
<?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" />';
}
Cuando registres tu tipo de contenido, obtén el slug con get_option
. Si no está, usa tu valor predeterminado.
<?php
add_action( 'init', 'wpse30021_register_post_type' );
function wpse30021_register_post_type()
{
$slug = get_option( 'wpse30021_cpt_base' );
if( ! $slug ) $slug = 'tu-slug-predeterminado';
// registra tu tipo de contenido, referencia $slug para la reescritura
$args['rewrite'] = array( 'slug' => $slug );
// Obviamente probablemente necesites más $args que uno...
register_post_type( 'wpse30021_pt', $args );
}
Aquí está la parte del campo de configuración como un plugin https://gist.github.com/1275867
EDITAR: Otra Opción
También podrías cambiar el slug basado en lo que está definido en la constante WPLANG
.
Solo escribe una función rápida que contenga datos...
<?php
function wpse30021_get_slug()
{
// retorna un slug predeterminado
if( ! defined( 'WPLANG' ) || ! WPLANG || 'en_US' == WPLANG ) return 'prensa';
// array de datos de slugs
$slugs = array(
'fr_FR' => 'presse',
'es_ES' => 'prensa'
// etc.
);
return $slugs[WPLANG];
}
Luego obtén el slug donde registres tu tipo de contenido personalizado.
<?php
add_action( 'init', 'wpse30021_register_post_type' );
function wpse30021_register_post_type()
{
$slug = wpse30021_get_slug();
// registra tu tipo de contenido, referencia $slug para la reescritura
$args['rewrite'] = array( 'slug' => $slug );
// Obviamente probablemente necesites más $args que uno...
register_post_type( 'wpse30021_pt', $args );
}
La mejor opción, en mi opinión, sería tanto darle al usuario una opción como proporcionar valores predeterminados sólidos:
<?php
add_action( 'init', 'wpse30021_register_post_type' );
function wpse30021_register_post_type()
{
$slug = get_option( 'wpse30021_cpt_base' );
// No configuraron una opción, obtén el predeterminado
if( ! $slug ) $slug = wpse30021_get_slug();
// registra tu tipo de contenido, referencia $slug para la reescritura
$args['rewrite'] = array( 'slug' => $slug );
// Obviamente probablemente necesites más $args que uno...
register_post_type( 'wpse30021_pt', $args );
}

+1 por el plugin en gist y el código bien documentado. En mi caso, sin embargo, pierde el propósito, que es no dar poder al usuario sino crear URLs conscientes de la localización (amigables para SEO) para tipos de posts personalizados

No estoy seguro de entender por qué querrías eliminar una opción de tu usuario. Además, pasar un slug por un filtro de traducción les da la misma opción: cambiar el slug. Solo que no con un bonito campo de formulario para rellenar.

Parece que esta opción es para una localización basada en WPLANG. Pero, ¿qué pasa si estás trabajando con un sitio multilingüe? (por ejemplo, el plugin WPML). La pregunta es más acerca de mostrar un slug diferente dependiendo de la localización del cliente, que de poder establecer un slug de tipo de entrada personalizado desde las opciones del servidor.

wpse = WordPress stack exchange. 30021 es el número de la URL. Buena suerte en tu búsqueda; he dado mi respuesta. La complejidad adicional que estás añadiendo, y el aparente cambio completo de la pregunta original — originalmente sobre slugs de CPT— solo refuerza el caso para permitir que el usuario final elija su propio slug.

La pregunta es si la función __()
puede usarse con slugs, y "cuál es la práctica para localizar slugs". Eso podría interpretarse como tener un slug traducido como lo hace una cadena cuando ves un tema en un idioma determinado, independientemente de que se use en un CPT. Por eso se colocó la recompensa en primer lugar.

Teniendo en cuenta que desde WordPress 4.7 los usuarios pueden establecer un idioma preferido para su perfil, usar una opción de la base de datos es en realidad la solución preferida. Si un usuario ha seleccionado un idioma diferente al del sitio y desencadena un reinicio de los enlaces permanentes, por ejemplo al visitar la configuración de enlaces permanentes, entonces la traducción del slug de la publicación cambiará a la del usuario, lo cual no es deseable que ocurra.

Estoy haciendo exactamente eso en un tema que estamos desarrollando. Está disponible en 5 idiomas distintos, y cada idioma tiene un conjunto de categorías traducidas. El primer componente de la URL en el tema se analiza para determinar qué idioma se usa, en formato país-idioma:
/uk-en
/fr-fr
/it-it
Y luego las categorías traducidas se analizan como componentes adicionales de la URL.
La URL se analiza en la fase parse_request
:
function my_parse_request( $wp ) {
$path = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );
$components = preg_split('|/|', $path, null, PREG_SPLIT_NO_EMPTY );
// Determinar el idioma desde $components[0]
$language = array_shift( $components );
...
// Cargar archivo de traducciones...
$mofile = get_stylesheet_directory()."/$language.mo";
load_textdomain( 'mydomain', $mofile );
...
// Determinar categoría desde $components[0]
if( __( 'some-category', 'mydomain' ) == $components[0] )
$wp->query_vars['category'] = 'some-category';
...
}
add_action( 'parse_request', 'my_parse_request' );
Este ejemplo carece de las comprobaciones necesarias, pero solo pretende ser un ejemplo.
Hay desventajas en este enfoque, por supuesto, pero permite URLs naturales en todos los idiomas. Las principales desventajas que veo son:
1) No hace uso del mecanismo de enlaces permanentes. Esto probablemente podría extenderse para que se generen las reglas de enlaces permanentes adecuadas para todos los idiomas y parse_request
no sea necesario, pero hacerlo para todos los idiomas implicaría cargar un archivo MO tras otro en un bucle, y no sé qué tan bien soportado está eso.
2) Si un traductor cambia un slug, entonces los enlaces se invalidan.

¿Has añadido el dominio de texto correcto? <?php load_theme_textdomain(my_text_domain);?> ?

¡Ten cuidado con esto! Desde WordPress 4.7, los usuarios pueden establecer un idioma preferido para su perfil. Si un usuario tiene un idioma diferente al del sitio y provoca un vaciado de los enlaces permanentes, por ejemplo, al visitar la configuración de enlaces permanentes, ¡la traducción del slug de la publicación cambiará a la del usuario! Por eso la respuesta aceptada, que utiliza una opción que se carga desde la base de datos, es en realidad una solución mucho mejor y a prueba de fallos.

Yo tuve este problema y aquí está mi solución, que funciona cuando conoces los idiomas de tu sitio web de antemano. Digamos que tienes un CPT llamado "movie", y tu sitio web tiene 3 idiomas. Necesitas reescribir el permalink de tu CPT, para cada idioma. También podrías hacer esto de forma dinámica.
add_action("init", "rewrite_cpt", 10, 0);
function rewrite_cpt(){
add_rewrite_rule('^movie/([^/]*)/?', 'index.php?post_type=movie&name=$matches[1]', 'top'); // Inglés
add_rewrite_rule('^film/([^/]*)/?', 'index.php?post_type=movie&name=$matches[1]', 'top'); // Italiano
add_rewrite_rule('^фильм/([^/]*)/?', 'index.php?post_type=movie&name=$matches[1]', 'top'); // Ruso
}
Ahora solo necesitas reconstruir tus permalinks: ve a Ajustes > Enlaces permanentes y simplemente presiona "Guardar"
La siguiente parte es reescribir las URLs para tu CPT, si tienes un CPT traducido necesitas obtener el idioma del post, en mi caso uso Polylang. Es importante codificar caracteres extranjeros en las 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;
}

Podrías probar esto en tu archivo functions.php
<?php
add_filter('rewrite_slugs', function($translated_slugs) {
// las posibles traducciones para tu 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;
});
?>
como se ve aquí

Recomendaría no hacer traducibles los slugs.
La traducción es para el contenido del sitio orientado al usuario. Los slugs se usan internamente, y solo son marginalmente "visibles públicamente" mediante reescrituras de URL - y las URLs tampoco deberían ser traducibles.
Por lo tanto: deja tus slugs como los defines originalmente. Solo haz traducibles las cadenas destinadas para consumo público.

los slugs traducidos, tanto desde una perspectiva de SEO como de experiencia de usuario, tienen mucho sentido...

No estoy de acuerdo en que los slugs afecten de alguna manera la experiencia de usuario. Si un slug se utiliza como parte de un enlace, el texto de anclaje del enlace estará traducido, por lo que el usuario no notará la diferencia. Y cuando la gente empieza a mencionar "SEO", generalmente pienso "pseudociencia". No soy un experto en SEO, pero no creo en el impacto del SEO con respecto a los slugs traducidos.

Discrepo basado en la experiencia. Tenemos gestores de contenido extranjeros internos que son explícitos en que los slugs de las URL deben localizarse. Se trata de crear una experiencia completa/mente local para el usuario extranjero. Para algunos países, como Japón, es literalmente esencial para establecer un tipo de confianza auténtica e indicar que realmente estás serio sobre hacer negocios allí.

Las URLs deben ser claras. Por lo tanto, si el slug es (como suele ocurrir) el nombre de la entidad o la taxonomía, la reescritura debe tener en cuenta tanto los plurales como las traducciones. Esto no es opcional, tanto para SEO como por simple buena práctica hacia los usuarios finales.
