Evite el bucle AJAX infinito al usar su propia API

5 minutos de lectura

avatar de usuario
Chris O’Kelly

Actualmente estoy tratando de encontrar la integración entre 2 complementos de WordPress: el complemento de correos electrónicos de seguimiento de WooCommerce y el complemento de formularios Ninja (con el objetivo final de que podamos enviar una plantilla de correo electrónico de seguimiento de tipo manual como una acción en respuesta al envío de formularios ninja ). Estamos usando Ninja Forms 3, por lo que vale.

Al definir las opciones para el Clase de acción Estoy proporcionando una lista de las plantillas al usuario, para que al definir la acción pueda elegir la plantilla para enviar. Para obtener las plantillas de correo electrónico del complemento de correos electrónicos de seguimiento, estoy usando su cliente APIespecíficamente el get_emails() (que, a su vez, se traduce en una llamada GET al /emails endpoint bajo su URL de API).

El problema es este: en cada página carga el ninja_forms_register_actions se llama a la acción, durante la cual ejemplifico mi clase de acción. Durante el __construct call, completamos la configuración para la acción y, para hacerlo, llamamos a la API de correos electrónicos de seguimiento. Esto inicia una carga de página, durante la cual el ninja_forms_register_actions la accion se llama…

Aunque anticipé este problema, mi solución planificada no ayudó: es decir, había planeado usar transitorios para almacenar el resultado de la llamada a la API, así:

private static function _get_templates()
    {
        error_log('_get_templates() started - ' . microtime(true));
        if (false === ($templates = get_transient(self::TEMPLATE_TRANSIENT))) {
            error_log('_get_templates() fetching - ' . microtime(true));
            $fue_api = self::fue_api();
            $templates = $fue_api->get_emails();
            set_transient(self::TEMPLATE_TRANSIENT, $templates, self::TEMPLATE_TRANSIENT_EXPIRY);
            error_log('_get_templates() fetched - ' . microtime(true));
        }
        error_log('_get_templates() done - ' . microtime(true));

        return $templates;
    }

Sin embargo, el resultado en mis registros es el siguiente:

[22-May-2016 23:53:33 UTC] _get_templates() started - 1463961213.692187
[22-May-2016 23:53:33 UTC] _get_templates() fetching - 1463961213.694222
[22-May-2016 23:53:34 UTC] _get_templates() started - 1463961214.05998
[22-May-2016 23:53:34 UTC] _get_templates() fetching - 1463961214.061054
[22-May-2016 23:53:38 UTC] _get_templates() started - 1463961218.660683
[22-May-2016 23:53:38 UTC] _get_templates() fetching - 1463961218.661265
[22-May-2016 23:53:40 UTC] _get_templates() started - 1463961220.772228
[22-May-2016 23:53:40 UTC] _get_templates() fetching - 1463961220.774142
[22-May-2016 23:53:41 UTC] _get_templates() started - 1463961221.150277
[22-May-2016 23:53:41 UTC] _get_templates() fetching - 1463961221.654757
[22-May-2016 23:53:45 UTC] _get_templates() started - 1463961225.306565
[22-May-2016 23:53:45 UTC] _get_templates() fetching - 1463961225.308898
[22-May-2016 23:53:46 UTC] _get_templates() started - 1463961226.281794
[22-May-2016 23:53:46 UTC] _get_templates() fetching - 1463961226.283803

Lo que continúa hasta que elimino el proceso del servidor web o algo más drástico como eliminar/cambiar el nombre de la carpeta del complemento, momento en el que el transitorio se llena con un código de error HTTP (que, en sí mismo, no es sorprendente). Claramente, mi solución transitoria no funciona ya que el transitorio aún no está configurado hasta después de la solicitud.

En algunas situaciones como esta, agregaría un cheque para DOING_AJAXsin embargo, esto no encaja por dos razones: todavía necesito que estos datos estén disponibles para los procesos AJAX de Ninja Forms, y tampoco estoy seguro de si DOING_AJAX realmente se configuraría aquí, ya que la API FUE no usa admin-ajax.php. Estaba considerando cambiar a algo como lo siguiente:

private static function _get_templates()
        {
            error_log('_get_templates() started - ' . microtime(true));
            if (false === get_option(self::TEMPLATE_LOCK_OPTION, false) && false === ($templates = get_transient(self::TEMPLATE_TRANSIENT))) {
                delete_option(self::TEMPLATE_LOCK_OPTION);
                add_option(self::TEMPLATE_LOCK_OPTION, true, '', 'no');
                error_log('_get_templates() fetching - ' . microtime(true));
                $fue_api = self::fue_api();
                $templates = $fue_api->get_emails();
                delete_option(self::TEMPLATE_LOCK_OPTION);
                set_transient(self::TEMPLATE_TRANSIENT, $templates, self::TEMPLATE_TRANSIENT_EXPIRY);
                error_log('_get_templates() fetched - ' . microtime(true));
            }
            error_log('_get_templates() done - ' . microtime(true));

            return $templates;
        }

Pero usar opciones como bloqueos se siente sucio e incorrecto, y siento que deja espacio para errores cuando se usa el almacenamiento en caché de objetos (por ejemplo, WPEngine et al). ¿Hay una forma mejor/normal de lidiar con esto o, alternativamente, no hay ningún problema real con lo anterior?

Editar: Entonces, la solución de bloqueo tampoco funciona al 100%; terminé haciendo esto con un trabajo WP Cron: cada diez minutos obtenemos la lista de plantillas, en lugar de según sea necesario, y la almacenamos en una opción. No me gusta especialmente esta solución, pero todavía no he podido encontrar una mejor. Todavía estoy interesado si hay una solución común para este problema.

  • ¿Has probado a actualizar wordpress? sigue teniendo el problema?

    –Kelvin Mariano

    31 de octubre de 2019 a las 8:28

Uno de los métodos/funciones entre el último error_log impreso y el primero esperado está llamando a su método nuevamente. Para obtener una pista de dónde comienza el bucle/recursión, puede usar debug_backtrace() para obtener la pila de llamadas y, por lo tanto, el punto donde comienza su bucle/recursión.

El mejor lugar para comenzar es colocar debug_backtrace justo después de su último error_log de trabajo.

Algunas de las siguientes funciones están llamando _get_templates()

$fue_api = self::fue_api();
$templates = $fue_api->get_emails();
delete_option(self::TEMPLATE_LOCK_OPTION);
set_transient(self::TEMPLATE_TRANSIENT, $templates, self::TEMPLATE_TRANSIENT_EXPIRY);

¿Ha sido útil esta solución?