¿Dónde, Cuándo y Cómo Vaciar Correctamente las Reglas de Reescritura Dentro del Ámbito de un Plugin?
Estoy teniendo un problema extraño con las reglas de reescritura que no se vacían correctamente.
He intentado usar flush_rewrite_rules();
y flush_rewrite_rules(true);
.
También he intentado globalizar $wp_rewrite
usando $wp_rewrite->flush_rules();
y $wp_rewrite->flush_rules(true);
Ninguno de estos métodos parece estar vaciando las reglas de reescritura correctamente. Estas llamadas efectivamente están vaciando las reglas de reescritura cuando se llaman. ¿Cómo lo sé? Usando la solución para depurar el vaciado de reglas de reescritura.
Actualmente, tengo las reglas de reescritura vaciándose en la activación y desactivación del plugin. No hay problemas allí.
Tengo una página de configuración de administración del plugin para que los usuarios lo configuren. Algunas de las configuraciones ajustan la estructura de enlaces permanentes, por lo que las reglas de reescritura deben vaciarse en la página de configuración de administración del plugin al "Guardar Configuración". (Usa el estándar update_option();
para guardar la configuración).
Me gustaría señalar que dependiendo de la configuración especificada, se crean tipos de contenido personalizados para coincidir con la configuración especificada por el usuario. Por lo tanto, las reglas de reescritura deben vaciarse inmediatamente después de guardar la configuración. Aquí es donde las cosas no funcionan apropiadamente.
La solución de depuración de reglas de reescritura proporcionada por @toscho
muestra que está vaciando toneladas de reglas de reescritura. Sin embargo, al visitar el elemento singular del tipo de contenido personalizado, o incluso el archivo del tipo de contenido personalizado, cada uno devuelve errores 404.
El tipo de contenido personalizado está registrado correcta y apropiadamente. Sé con certeza que ese no es el problema.
Inmediatamente después de guardar la configuración en la página de administración del plugin, se crean los tipos de contenido personalizados, se ajusta la estructura de enlaces permanentes y se intenta vaciar todas las reglas de reescritura.
Los tipos de contenido personalizados se cargan siempre, y se cargan en init
como es normal.
Por alguna razón, las reglas de reescritura no se están vaciando correctamente, porque como dije antes, visitar secciones singulares o de archivo del tipo de contenido personalizado devuelve errores 404.
Ahora la parte extraña, si todo lo que hago es simplemente visitar la página de configuración de enlaces permanentes en la administración, y luego volver al front-end para ver las secciones singulares o de archivo del tipo de contenido personalizado, mágicamente funcionan como se espera.
¿Qué hace esa página de configuración de enlaces permanentes de administración que yo no estoy haciendo que permite que las reglas de reescritura se vacíen apropiadamente y las mías no?
Como solución temporal, estoy redirigiendo al usuario a la página de configuración de enlaces permanentes de administración después de guardar la página de configuración del plugin, pero esta no es una solución ideal. Preferiría que las reglas de reescritura se vacíen correctamente dentro del código de mi plugin.
¿Hay algún punto en WordPress donde vaciar las reglas de reescritura simplemente deja de vaciar TODAS las reglas?
admin_menu
- La página de configuración del plugin se agrega a la administración de WordPress.
add_options_page()
- La página de configuración del plugin se agrega bajo el menú de Configuración.
La página de configuración se renderiza en el callback para add_options_page()
. Aquí es también donde se procesa $_POST
para actualizar la configuración del plugin y vaciar las reglas de reescritura.
Dado que esta ya es una pregunta larga, estaría dispuesto a proporcionar bloques de código (si ayuda) en un enlace externo para ayudar a producir una respuesta válida.
El mejor lugar para vaciar las reglas de reescritura es durante la activación/desactivación del plugin.
function myplugin_activate() {
// registrar taxonomías/tipos de contenido aquí
flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'myplugin_activate' );
function myplugin_deactivate() {
flush_rewrite_rules();
}
register_deactivation_hook( __FILE__, 'myplugin_deactivate' );
Disculpas de antemano, no pude leer completamente tu pregunta, así que esta es una respuesta bastante genérica.

Gracias por tu sugerencia, pero ya lo sé. El problema no tiene que ver con la activación/desactivación del plugin. Tiene que ver con usuarios que cambian la configuración del plugin ya activo, lo que ajusta las reglas de reescritura y por lo tanto requiere un flush.

Es difícil saber qué está mal sin ver tu código. Pero después de guardar algunas configuraciones, es práctico engancharse a admin_init
como se muestra a continuación para limpiar tus reglas de reescritura.
Código:
add_action('admin_init', 'wpse_123401_plugin_settings_flush_rewrite');
function wpse_123401_plugin_settings_flush_rewrite() {
if ( get_option('plugin_settings_have_changed') == true ) {
flush_rewrite_rules();
update_option('plugin_settings_have_changed', false);
}
}
Tienes que establecer la opción en algún lugar de tu página de configuraciones o, para ser exacto, en algún lugar del proceso de guardado de configuraciones. Hacerlo sin la opción es malo, porque no quieres limpiar las reglas cada vez.
Nota: no probado

¿O tal vez podrías usar un transitorio? Pero definitivamente +1 por no reiniciar las reglas en cada admin_init.

Por supuesto que tienes razón sobre el transitorio, supongo que opté por *_option()
por la página de configuración. @helgatheviking

Esto fue muy útil. Tenía una situación similar a la de Michael. Terminé incorporando la sugerencia de helga sobre usar un transitorio y lo configuré en la función de validación para los ajustes. Terminé necesitando establecer el transitorio en falso después de reiniciar, de lo contrario seguía reiniciando en cada carga de página de administración hasta que el transitorio expiraba. Así que funcionalmente usar una opción o un transitorio era lo mismo. Supongo que el transitorio podría ser bueno solo para mantener la tabla de opciones un poco más limpia. Pero es un punto menor.

Tenía un archivo de clase para tipos de post que era responsable de leer las configuraciones de opciones del plugin y crear los tipos de post personalizados necesarios basados en los ajustes especificados por el usuario.
Este archivo de clase para tipos de post se cargaba en el hook init
.
Pensé que todo lo que necesitaría hacer sería actualizar las configuraciones del plugin y luego limpiar las reglas de reescritura. Dado que la clase de tipos de post ya se cargaba basándose en las configuraciones del plugin. Pero con las páginas de administración, estas se cargan DESPUÉS del hook init
.
Los tipos de post nunca se registraron realmente porque los ajustes no estaban configurados todavía. La clase de registro de tipos de post terminó prematuramente sin registrar ningún tipo de post.
La solución fue:
- Actualizar las configuraciones del plugin.
- Cargar el archivo de clase de tipos de post SOLO una vez aquí para que se creen las nuevas reglas de reescritura.
- Limpiar las reglas de reescritura.
(Anteriormente... faltaba el paso 2 -- Como mencioné arriba...)
De ahora en adelante, los tipos de post se cargarán en el hook init
y tendrán las configuraciones ya especificadas, permitiendo que los tipos de post se creen y se emparejen con las reglas de reescritura apropiadas.
Por alguna razón, tuve que agregar una llamada JavaScript para redirigir a la página actual después de realizar los tres pasos anteriores.
También tuve que agregar una llamada a flush_rewrite_rules();
en la página de configuraciones de administración del plugin.
Así que para asegurar que todo se limpie...
Paso 1) Navegar a la página de configuraciones de administración del plugin. -- Limpieza inicial.
Paso 2) Actualizar configuraciones del plugin. -- Segunda limpieza.
Paso 3) La página redirige a la página de configuraciones del plugin. Causando la... Tercera y última limpieza (igual que la limpieza inicial -- Se hace automáticamente cuando se visita la página de configuraciones del plugin)
No digo que esta sea una solución práctica, pero funcionó para mí. Un problema muy extraño y probablemente tiene que ver con mi infraestructura de código.

Yo estaba teniendo exactamente el mismo problema. En mi plugin, tengo tipos de post que se crean dinámicamente. Por lo tanto, no pueden registrarse mediante register_post_type()
en un método estático durante el activation_hook
y, por lo tanto, aún no están activos cuando se ejecuta flush_rewrite_rules()
durante este hook (que normalmente es la forma recomendada de vaciar las reglas de reescritura).
La solución más limpia que se me ocurrió al final fue vaciar las reglas de reescritura después del registro de los tipos de post, pero por supuesto solo si dicho vaciado era realmente necesario (porque la operación es lenta). En mi caso, tengo varios tipos de post personalizados que heredan de una única clase base, por lo que era deseable implementar el código que realiza el vaciado allí.
Si es necesario vaciar las reglas se puede decidir mirando la salida de get_option( 'rewrite_rules' )
:
class MyPostTypeClass {
public final function register_as_custom_post_type() {
... //haz toda la configuración de tu tipo de post aquí
$args = array(
... //rellena los otros argumentos como consideres apropiado
'rewrite' => array('slug' => 'slug-de-tu-tipo-de-post')
);
register_post_type('nombre-del-tipo-de-post', $args );
$rewrite_rules_must_be_fluhed = true;
foreach( get_option( 'rewrite_rules' ) as $key => $rule)
if(strpos($key, $args['rewrite']['slug'] ) === 0)
{
$rewrite_rules_must_be_fluhed = false;
break;
}
if($rewrite_rules_must_be_fluhed)
flush_rewrite_rules(true);
}
}
Desventajas:
- Depende en cierta medida de qué reglas exactas de reescritura genera WP durante
register_post_type()
. - Verificar si es necesario vaciar durante cada carga de página también genera algo de sobrecarga.
Ventajas:
- Completamente encapsulado en la clase que representa el tipo de post.
- Solo vacía las reglas de reescritura si realmente es necesario.
¡Usa esto solo si no puedes registrar tu tipo de post en una función estática que pueda llamarse tanto durante init
como durante el activation_hook
!
La dependencia de cómo se ven las reglas de reescritura generadas durante register_post_type()
puede mitigarse reemplazando la prueba if(strpos($key, $args['rewrite']['slug'] ) === 0)
con algo más elaborado, es decir, una expresión regular.

@tazo-todua esto también me funcionó cuando usé multisitio.
add_action( 'wpmu_new_blog', 'set_my_permalink_structure', 11, 2 );
function set_my_permalink_structure( $blog_id ) {
switch_to_blog( $blog_id );
global $wp_rewrite;
$wp_rewrite->set_permalink_structure( '/%postname%/' );
$wp_rewrite->flush_rules();
$wp_rewrite->init();
restore_current_blog();
}

Si quieres ejecutar flush_rewrite_rules cuando CUALQUIER plugin se activa o desactiva
add_action('init', function(){
// Obtener la ruta de todos los plugins instalados
$pluginsInstalledPaths = glob(WP_PLUGIN_DIR . '/*', GLOB_ONLYDIR);
foreach ($pluginsInstalledPaths as $pluginPath) {
// Obtener todos los archivos PHP disponibles en el directorio raíz del plugin
$files = glob($pluginPath . '/*.php');
foreach ($files as $file) {
$contents = file_get_contents($file);
// Si el archivo contiene "Plugin Name" es el archivo principal del plugin
if (preg_match('/\/\*\*[^\/]*?Plugin Name:/', $contents)) {
add_action('activate_' . plugin_basename($file), function(){
flush_rewrite_rules();
});
add_action('deactivate_' . plugin_basename($file), function(){
flush_rewrite_rules();
});
}
}
}
});
