我有一个使用 cron 的 wordpress 插件,当没有人访问该页面时,cron 不会运行

问题描述 投票:0回答:1

上下文:我正在制作一个 WordPress 插件,它接收两个参数,一个标题和一个提示,并生成一篇应该在 120 到 180 秒之间的随机时间发布的文章。可以提出多个请求。数据保存在txt中,其中包含数据标题、提示、随机时间和记录时间。

插件部分有一个表格,显示了用 javascript 制作的倒计时,指示距离文章发布还剩多少时间,当达到 0 时就应该发布。请记住,js 中的倒计时只是视觉上的。文章的发布时间在 cron 和 get_article_y_publish() 函数中管理

理论上,crons 的执行无需用户交互。但由于某种原因,这并没有发生。

代码:

<?php
/**
 * Plugin Name: Psychologist article generator
 * Description: Este plugin genera un artículo apartir de un título usando la API de OpenAI.
 * Version: 2.1 B
 * Author: Toni cipher
 * Author URI: https://cipher.icu
 */




// Ubicación del archivo
$filename = plugin_dir_path(__FILE__) . 'titulos_y_prompts.txt';



// Activación del plugin
function mi_plugin_activado() {
    // Agregar el horario de cron personalizado (si no existe)
    if ( ! wp_next_scheduled( 'my_custom_function' ) ) {
        wp_schedule_event( time(), 'per_minute', 'my_custom_function' );
    }
}
register_activation_hook( __FILE__, 'mi_plugin_activado' );

// Desactivación del plugin
function mi_plugin_desactivado() {
    wp_clear_scheduled_hook( 'my_custom_function' );
}
register_deactivation_hook( __FILE__, 'mi_plugin_desactivado' );


// Función para crear la página de ajustes
function ammd_admin_menu() {
    add_options_page(
        'Administrar Títulos',
        'Automatización Artículos',
        'manage_options',
        'ammd-settings',
        'ammd_settings_page'
    );
}
add_action('admin_menu', 'ammd_admin_menu');

// HTML para la página de ajustes
function ammd_settings_page() {
    

    global $filename;
    /*
    Este codigo es para mostrar cuando es el proximo tiempo en el cual se ejecutará obtener_articulo y publicar. Descomentar en caso de querer ver esa informacion.
    $next_cron = wp_next_scheduled('my_custom_function');
    if ($next_cron !== false) {
        // Formatear la fecha y hora de la próxima ejecución
        $next_cron_formatted = date('Y-m-d H:i:s', $next_cron);
    
        // Imprimir la próxima fecha y hora de ejecución
        echo "<h1>La próxima ejecución de 'my_custom_function' está programada para: $next_cron_formatted </h1>";
    } else {
        echo "<h1>La tarea cron 'my_custom_function' no está programada.</h1>";
    }*/
   
        if (isset($_POST['submit'])) {
            if (empty($_POST['titulo']) || empty($_POST['prompt'])) { 
                return; // Sale del script si uno de los campos está vacío
            }
            

        
    }
    if (isset($_POST['titulo']) && !empty($_POST['titulo']) && isset($_POST['prompt']) && !empty($_POST['prompt'])) {
        // Limpiar el título y el prompt
        $titulo_clean = sanitize_text_field($_POST['titulo']);
        $prompt_clean = sanitize_textarea_field($_POST['prompt']);
    
        // Generar un valor aleatorio en horas entre 8 y 20
        $valor_en_segundos = rand(120, 240); // Valor en horas
    
        // Pasar a horas
        $valor_en_horas = $valor_en_segundos;// * 3600;
      
        // Calcular el tiempo de espera para este artículo
        $tiempo_espera = $valor_en_horas;
    
        // Obtener el tiempo actual en formato Unix (time())
        $tiempo_actual = time();

        // Ruta del archivo de tu script que se ejecutará periódicamente
        $script_a_ejecutar = __DIR__ . '/auto-post-v2.php';
        $tiempo_unix = time()+$valor_en_horas;

        // Convierte el valor Unix a un formato cron
        $minutos = date('i', $tiempo_unix); // Minutos (30)
        $horas = date('G', $tiempo_unix);    // Horas (10)

        // Configura el comando de cron con los valores obtenidos
        $comando_cron = "$minutos $horas * * * /usr/bin/php $script_a_ejecutar";

        // Ejecutar el comando para agregar el Cron Job
        shell_exec('(crontab -l ; echo "' . $comando_cron . '") | crontab -');

        // Crear la línea de contenido a agregar al archivo
        $nuevo_contenido = "\n" . $tiempo_espera . '||' . $tiempo_actual . '||' . str_replace("\n", ' ', $titulo_clean) . '||' . str_replace("\n", ' ', $prompt_clean) . "\n";
        file_put_contents($filename, $nuevo_contenido, FILE_APPEND);
        
        
        echo '<div class="updated"><p>Título, Prompt agregados con éxito!</p></div>';
    }

    // El código HTML para la página de ajustes
    echo '<div class="wrap">';
    echo '<h2>Automatizador de artículos</h2>';
    echo '<form method="post" action="" autocomplete="off">';
    echo '<table class="form-table">';
    echo '<tr>';
    echo '<th scope="row"><label for="titulo">Agregar Título</label></th>';
    echo '<td><input name="titulo" type="text" id="titulo" value="" class="regular-text" required></td>';
    echo '</tr>';
    echo '<tr>';
    echo '<th scope="row"><label for="prompt">Agregar Prompt</label></th>';
    echo '<td><textarea name="prompt" id="prompt" rows="5" cols="50" required></textarea></td>';
    echo '</tr>';
    echo '</table>';
    echo '<p class="submit"><input type="submit" name="submit" id="submit" class="button button-primary" value="Guardar Título y Prompt"></p>';
    echo '</form>';

    // Nueva sección para mostrar los artículos y prompts en cola
    echo '<h2>Cola de Artículos y Prompts</h2>';
    echo '<table class="form-table">';
    echo '<thead>';
    echo '<tr>';
    echo '<th scope="col">Título</th>';
    echo '<th scope="col">Prompt</th>';
    echo '<th scope="col">Tiempo de espera</th>';
    echo '</tr>';
    echo '</thead>';
    echo '<tbody>';



    // Leer el archivo y separarlo en líneas
    $lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
    $flag = True;
    if (!empty($lines)) {
        $acumulado_tiempo_espera = 0; // Inicializa el tiempo acumulado en 0

        foreach ($lines as $line) {
            list($horas2, $tiempo_registro, $titulo, $prompt) = explode('||', $line, 4);

            // Calcula el tiempo de espera para este artículo
            $tiempo_espera = $horas2 + $acumulado_tiempo_espera;

            // Actualiza el tiempo acumulado
            $acumulado_tiempo_espera += $horas2;

            // Resta el tiempo transcurrido desde el registro
            $tiempo_resta = time() - $tiempo_registro;
            


            $tiempo_espera -= $tiempo_resta;

         

          // Separar cada línea en título y prompt
            echo '<tr>';
            echo '<td>' . esc_html($titulo) . '</td>';
            echo '<td>' . esc_html($prompt) . '</td>';
            echo '<td><span class="countdown" data-tiempo="' . esc_attr($tiempo_espera) . '"></span></td>';
            echo '</tr>';
        }

            
            
            

        }
     else {
        echo '<tr><td colspan="2">No hay artículos o prompts en la cola.</td></tr>';

    }
    echo '</tbody>';
    echo '</table>';
    echo '</div>';  // Cierre del div "wrap"
    echo '<script>
    function startCountdown(element, totalSeconds) {
        var interval = setInterval(function() {
            var hours = Math.floor(totalSeconds / 3600);
            var minutes = Math.floor((totalSeconds % 3600) / 60);
            var seconds = totalSeconds % 60;
            var formattedTime = formatTime(hours, minutes, seconds);
            element.textContent = formattedTime;
            if (totalSeconds <= 0) {
                clearInterval(interval);
                element.textContent = "Cuenta regresiva finalizada.";
            }
            totalSeconds--;
        }, 1000);
    }

    function formatTime(hours, minutes, seconds) {
        return String(hours).padStart(2, "0") + ":" + String(minutes).padStart(2, "0") + ":" + String(seconds).padStart(2, "0");
    }

    var countdownElements = document.querySelectorAll(".countdown");
    countdownElements.forEach(function(element) {
        var totalSeconds = parseInt(element.getAttribute("data-tiempo"));
        startCountdown(element, totalSeconds);
    });
    </script>';

    }







// Al activar el plugin, crea el archivo si no existe
function ammd_activate() {
    global $filename;
    if(!file_exists($filename)) {
        touch($filename);
    }

}
register_activation_hook(__FILE__, 'ammd_activate');



function reemplazar_primera_linea_no_vacia($archivo, $nuevaLinea) {
    // Leer el contenido actual del archivo
    $contenido = file($archivo);

    // Iterar a través de las líneas y encontrar la primera no vacía
    foreach ($contenido as $indice => $linea) {
        $linea = trim($linea); // Eliminar espacios en blanco al principio y al final
        if (!empty($linea)) {
            // Reemplazar la primera línea no vacía con la nueva línea
            $contenido[$indice] = $nuevaLinea . PHP_EOL;
            break; // Salir del bucle después de reemplazar la primera línea
        }
    }

    if (!is_array($contenido)) {
        // Handle the case where $contenido is not an array, possibly by initializing it as an empty array.
        $contenido = [];
    }
    
    // Now you can safely use implode on $contenido
    file_put_contents($archivo, implode('', $contenido));
    
}
function obtener_acumulado_tiempo_espera($filename) {
    $lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

    $acumulado_tiempo_espera = 0;

    if (!empty($lines)) {
        foreach ($lines as $line) {
            list($horas, $tiempo_registro, $titulo, $prompt) = explode('||', $line, 4);
            $acumulado_tiempo_espera += $horas;
        }
    }

    return $acumulado_tiempo_espera /** 3600*/; // Convertir a segundos
}
function obtener_articulo_y_publicar() {
    global $filename;
 


    $lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

    if (empty($lines)) {
        // No hay artículos en la cola, detener la ejecución
        return;
    }

    // Obtener el primer artículo de la cola
    list($horas2, $tiempo_registro, $titulo, $prompt) = explode('||', $lines[0], 4);

    // Calcular el tiempo de espera para este artículo
    $tiempo_espera = $horas2;

    // Restar el tiempo transcurrido desde el registro 
 
    $tiempo_espera -= 60;

    
    if ($tiempo_espera <= 0) {   
        
        //Esta funcion es solo para registrar en un archivo si paso por acá el codigo. Si se usa descomentar la funcion crear_archivo_pase()
        //crear_archivo_pase();
        
        
        
        $tiempo_resta = 0;
        // Obtener el artículo, título y prompt desde el archivo .txt
        list($titulo, $articulo) = obtener_articulo_y_titulo();

        // Si no hay título o artículo, detener la ejecución
        if (empty($titulo) || empty($articulo)) {
            // Detiene la ejecución si no hay títulos
            return;
        }

        // Obtener fotos relacionadas con el título del artículo
        $foto_url_inicio = obtener_foto_unsplash('marketing'); // Ajusta el término según tus necesidades
        $foto_url_medio = obtener_foto_unsplash('business');  // Ajusta el término según tus necesidades

        // Generar el código HTML para las fotos
        $foto_html_inicio = "<!-- wp:image -->\n<figure class=\"wp-block-image\"><img src=\"$foto_url_inicio\" alt=\"\"/></figure>\n<!-- /wp:image -->";
        $foto_html_medio = "<!-- wp:image -->\n<figure class=\"wp-block-image\"><img src=\"$foto_url_medio\" alt=\"\"/></figure>\n<!-- /wp:image -->";

        // Dividir el artículo en dos partes
        $article_parts = explode("\n", $articulo);
        $halfway_point = floor(count($article_parts) / 2);

        $first_half = array_slice($article_parts, 0, $halfway_point);
        $second_half = array_slice($article_parts, $halfway_point);

        $first_half_content = '<p>' . implode('</p><p>', $first_half) . '</p>';
        $second_half_content = '<p>' . implode('</p><p>', $second_half) . '</p>';

        // Combinar las fotos y el artículo en el contenido del post
        $post_content = $foto_html_inicio . "\n\n" . $first_half_content . "\n\n" . $foto_html_medio . "\n\n" . $second_half_content;

        // Argumentos del post
        $post_args = array(
            'post_title'    => $titulo,
            'post_content'  => $post_content,
            'post_status'   => 'publish',
            'post_author'   => 1,
            'post_type'     => 'post'
        );

        // Insertar el post
        $id_post = wp_insert_post($post_args);
        
        asignar_imagen_destacada($id_post, $foto_url_inicio);

        // Después de publicar, eliminar el artículo de la cola
        $lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        if (!empty($lines)) {
            unset($lines[0]);
            file_put_contents($filename, implode(PHP_EOL, $lines));
        }
        
       
        
    }
    else{
        $linea_de_texto = implode('||', [$tiempo_espera, time(), $titulo, $prompt]);
        reemplazar_primera_linea_no_vacia(__DIR__.'/titulos_y_prompts.txt',$linea_de_texto);
    }
}


// Agregar el horario de cron personalizado
add_filter( 'cron_schedules', function ( $schedules ) {
    $schedules['every_minute'] = array(
    'interval' => 60,
    'display' => __( 'Every Minute' )
);
    return $schedules;
 } );
 
 // Programar la función que se ejecutará cada minuto
 add_action( 'my_custom_function', 'obtener_articulo_y_publicar' );


// Programar la tarea cron
if ( ! wp_next_scheduled( 'my_custom_function' ) ) {
    wp_schedule_event( time(), 'every_minute', 'my_custom_function' );
}
?>
php wordpress cron
1个回答
0
投票

WP_Cron,正如评论者所指出的,只能在 WordPress 收到请求时运行。请求可以来自

  1. 由用户发起的综合浏览量。
  2. 对您网站上的任何 REST 或其他 API 的点击。
  3. 点击
    https://example.com/wp-cron.php?doing_wp_cron
    (当然使用您的主机名而不是
    example.com
    )。

因此,您可以让 Javascript 倒计时代码在倒计时到期时对 /wp-cron.php?doing_wp_cron 执行

fetch()
操作。你的 Javascript 中有这样的东西,没有调试!.

    function startCountdown(element, totalSeconds) {
        var interval = setInterval(function() {
            var hours = Math.floor(totalSeconds / 3600);
            var minutes = Math.floor((totalSeconds % 3600) / 60);
            var seconds = totalSeconds % 60;
            var formattedTime = formatTime(hours, minutes, seconds);
            element.textContent = formattedTime;
            if (totalSeconds <= 0) {
                clearInterval(interval);
                element.textContent = "Cuenta regresiva finalizada.";
                fetch('/wp-cron.php?doing_wp_cron')
                  .then ( response => return response.text())
                  .then ();
            }
            totalSeconds--;
        }, 1000);
    }

fetch()
序列不会返回任何有用的数据,但它确实为 WP_Cron 提供了工作所需的动力。

小心!过于频繁地激活 cron 会降低站点性能。而且,这个东西很难调试。

话虽如此,最好避免依赖实时 WP_Cron 操作。

© www.soinside.com 2019 - 2024. All rights reserved.