WP Cron ne s'exécute pas lorsque le temps s'est écoulé

16

Le but

Je souhaite utiliser wp_schedule_single_event( )pour exécuter un événement unique qui m'envoie un e-mail 8 minutes après que l'utilisateur a soumis un formulaire.

Le problème

Le code suivant est dans mon functions.php:

function nkapi_send_to_system( $args ) {
  wp_mail( 'xxx', 'xxx', $args );
}

add_action( 'nkapi_send', 'nkapi_send_to_system' );

function schedule_event( $id ) {
  wp_schedule_single_event( current_time( 'timestamp' ) + 480, 'nkapi_send', array( $id ) );
}

Et le code suivant est utilisé pour appeler schedule-event:

schedule_event( $_SESSION['insert_id'] ); // the $_SESSION var contains an INT

Après avoir attendu plus de 8 minutes, il n'y avait pas d'e-mail dans ma boîte de réception.

Ce que j'ai essayé

Avec le plugin Core Control, il est possible de voir quels travaux cron sont planifiés.

Écran de contrôle de base

Après quelques changements, j'ai réussi à les obtenir tout à fait correctement, et mieux, lorsque je clique sur "Exécuter maintenant", je reçois en fait un e-mail dans ma boîte de réception.

Mais pourquoi le cron ne s'exécute pas lorsque je visite mon site après 8 minutes. Qu'est-ce qui ne va peut-être pas avec ce code? Je dois dire que c'est la première fois que j'utilise WP Cron.

J'ai essayé plus

Après le commentaire de vancoder, j'ai décidé de tester si le code fonctionne si je mets le code suivant directement dans le functions.php:

function schedule_event( $id ) {
  wp_schedule_single_event( time(), 'nkapi_send', array( $id ) );
}

if ( isset( $_SESSION['insert_id'] ) ) {
  if ( ! array_key_exists( 'insert_scheduled', $_SESSION ) || $_SESSION['insert_scheduled'] != $_SESSION['insert_id'] ) {
    schedule_event( $_SESSION['insert_id'] );
    $_SESSION['insert_scheduled'] = $_SESSION['insert_id'];
  }
}

L'inconvénient de ce code est que l'utilisateur doit aller sur une autre page avant l'exécution de ce code. Mais d'un autre côté, cela ne fonctionne pas non plus, ce ne serait donc pas mon premier problème ...

Mike Madern
la source
1
Où et comment est schedule_event( $_SESSION['insert_id'] );tiré?
vancoder
Un shortcode inclut un fichier séparé (avec un formulaire dedans) dans une page, lorsque ce formulaire est publié, la page se recharge, le même fichier exécute ensuite le schedule_event( ), disons en haut du fichier inclus chargé par le shortcode.
Mike Madern
Faites tout travail de crons? wp_version_check etc?
vancoder
Je n'ai pas mis de cron au travail. Quel pourrait être le problème de cela?
Mike Madern
Pour confirmer - même les tâches cron de base échouent?
vancoder

Réponses:

8

Pouvez-vous d'abord confirmer que vous n'avez activé aucun plug-in de mise en cache? Les plugins de mise en cache peuvent interférer avec les tâches cron car vos visiteurs ne reçoivent pas une page en direct mais une version mise en cache de votre page.

Si un plugin de mise en cache est activé, vous pouvez choisir l'une de vos pages, ajouter une exclussion aux paramètres de votre plugin de mise en cache pour cette page afin qu'elle ne soit jamais mise en cache.

Ensuite, vous devrez créer manuellement un travail cron (en utilisant cpanel si vous êtes dans un environnement d'hébergement partagé ou depuis le terminal s'il s'agit d'un serveur VPS / dédié) qui visitera cette page toutes les quelques minutes.

J'espère que ça aide!

WPMU-DEV Ari
la source
J'ai un plugin de mise en cache activé! W3 Total Cache pour être précis
Mike Madern
14

Tout d'abord, définissez vos plannings de tâches cron personnalisés.

add_filter('cron_schedules', array($this, 'cron_schedules'));

public function cron_schedules($schedules){
    $prefix = 'cron_';// Avoid conflict with other crons. Example Reference: cron_30_mins
    $schedule_options = array(
        '30_mins' => array(
            'display' => '30 Minutes',
            'interval' => '1800'
        ),
        '1_hours' => array(
            'display' => 'Hour',
            'interval' => '3600'
        ),
        '2_hours' => array(
            'display' => '2 Hours',
            'interval' => '7200'
        )
    );
    /* Add each custom schedule into the cron job system. */
    foreach($schedule_options as $schedule_key => $schedule){
        $schedules[$prefix.$schedule_key] = array(
            'interval' => $schedule['interval'],
            'display' => __('Every '.$schedule['display'])
        );
     }
     return $schedules;
}

Vous devez décider où et quand planifier réellement l'événement.

Voici juste un exemple d'extrait de code, qui effectue un appel à une méthode de classe personnalisée:

$schedule = $this->schedule_task(array(
    'timestamp' => current_time('timestamp'), // Determine when to schedule the task.
    'recurrence' => 'cron_30_mins',// Pick one of the schedules set earlier.
    'hook' => 'custom_imap_import'// Set the name of your cron task.
));

Voici le code qui planifie réellement l'événement:

private function schedule_task($task){
    /* Must have task information. */
    if(!$task){
        return false;
    }
    /* Set list of required task keys. */
    $required_keys = array(
        'timestamp',
        'recurrence',
        'hook'
    );
    /* Verify the necessary task information exists. */
    $missing_keys = array();
    foreach($required_keys as $key){
        if(!array_key_exists($key, $task)){
            $missing_keys[] = $key;
        }
    }
    /* Check for missing keys. */
    if(!empty($missing_keys)){
        return false;
    }
    /* Task must not already be scheduled. */
    if(wp_next_scheduled($task['hook'])){
        wp_clear_scheduled_hook($task['hook']);
    }
    /* Schedule the task to run. */
    wp_schedule_event($task['timestamp'], $task['recurrence'], $task['hook']);
    return true;
}

Maintenant, tout ce que vous devez faire est d'appeler le nom de votre tâche cron personnalisée. Dans cet exemple, le nom de la tâche cron est custom_imap_import.

add_action('custom_imap_import', array($this, 'do_imap_import'));

public function do_imap_import(){
    // .... Do stuff when cron is fired ....
}

Donc, dans cet exemple, $this->do_imap_import(); est appelé toutes les 30 minutes (en supposant que vous avez suffisamment de trafic vers votre site Web).


Remarques

Nécessite une visite de la page pour que votre cron se déclenche aux bons moments.

Exemple: si vous avez planifié une tâche à des intervalles de 30 minutes, mais que personne ne visite votre site pendant 4 heures, votre tâche cron ne sera pas déclenchée tant que ce visiteur ne viendra pas sur votre site 4 heures plus tard. Si vous avez vraiment vraiment besoin que votre tâche soit exécutée toutes les 30 minutes, il est conseillé de configurer un travail cron légitime via votre fournisseur d'hébergement Web pour visiter votre site Web aux intervalles souhaités.

Les tâches cron WordPress ne ralentissent pas votre site Web!

Peut-être que vous pensez que si le cron-script prend beaucoup de temps pour être exécuté, les visiteurs devront-ils attendre que le script soit exécuté. Nan! Comment est-ce possible? Si vous regardez le wp-cron.phpfichier, vous trouverez une ligne

ignore_user_abort(true);

C'est un php.ini configuration qui définit que si vous arrêtez de charger le site / script, le script ne cessera pas de s'exécuter.

Si vous regardez le wp-includes/cron.phpfichier, vous trouverez une ligne comme celle-ci:

wp_remote_post( $cron_url, 
array('timeout' => 0.01,
 'blocking' => false, 
 'sslverify' => apply_filters('https_local_ssl_verify', true)) );

Cela signifie que WordPress attendra que 0,01 seconde pour déclencher l'exécution alors il abandonnera , mais que vous avez défini ignore_user_abortau truescript sera l' exécution. Cette fonctionnalité est un énorme avantage pour exécuter de gros scripts dans des tâches cron WordPress.

Fonctions disponibles pour l'aide:

Michael Ecklund
la source
6
Il s'agit d'une réponse remarquablement complète qui, à ma connaissance, ne répond pas à la question réelle - c'est pourquoi toutes les tâches planifiées (y compris les tâches principales) échouent.
vancoder
Cette réponse est de guider l'utilisateur dans la bonne direction pour comprendre et planifier correctement les tâches cron WordPress.
Michael Ecklund
4
Cela m'a beaucoup aidé à comprendre les horaires cron avec WordPress
Mike Madern
2
Michael, tu devrais répondre plus souvent. Grand +1
kaiser
1
Je pense qu'il WP_Cronutilise GMT sous le capot, comme le reste de WP, il serait donc préférable de planifier le premier événement au time()lieu de current_time().
Ian Dunn
3

WordPress Cron vous permet de planifier des tâches, mais elles ne s'exécuteront qu'en cas de demande adressée au site. Pour chaque demande reçue par WordPress, il vérifiera s'il y a des tâches cron à traiter et, si tel est le cas, déclenche une demande /wp-cron.php?doing_wp_cronde traitement asynchrone de la tâche. Si le démarrage planifié d'un travail passe sans demande, le processus cron ne sera pas démarré.

Comme vous pouvez voir et exécuter vos travaux planifiés, il est possible qu'aucune demande ne déclenche le démarrage du travail cron, surtout si vous utilisez un plug-in de mise en cache. La meilleure option pour décharger cela sur un calendrier plus régulier est de désactiver la vérification par défaut dans WordPress et de l'utiliser crontab.

Tout d'abord pour désactiver la vérification par défaut (ce qui peut aider un peu avec les performances côté client), ajoutez ce qui suit à wp-config.php:

// Disable default check for WordPress cron jobs on page loads
define( 'DISABLE_WP_CRON', true );

Ensuite, vous créez une tâche pour récupérer la wp-cron.phppage une fois par minute pour traiter les travaux sur le back-end, à partir de la ligne de commande, entrez crontab -e, puis ajoutez une ligne qui ressemble à ceci:

*/1 * * * * /usr/bin/curl --silent http://example.com/wp-cron.php?doing_wp_cron=$(date +\%s.\%N) >/dev/null 
doubleharp
la source
2
Si vous ne donnez pas de valeur à doing_wp_cron, il est fort probable que les travaux soient parfois exécutés deux fois. Utilisez doing_wp_cron=$(date +\%s.\%N)pour empêcher cela.
Alexander Garden
0

Vérifiez que DISABLE_WP_CRON n'est pas défini dans votre configuration.

À défaut, essayez de désactiver tous les plugins (sauf le contrôle du cœur - bien que j'utiliserais wp-crontrol) et voyez si vos travaux principaux fonctionnent. S'ils le font, vous rencontrez des interférences de plugins quelque part.

De même, essayez de passer à un thème standard de vingt ans.

Si aucun de ces éléments ne fait la différence, il est probable que ce soit un problème d'hébergement.

vancoder
la source
Je n'ai pas DISABLE_WP_CRONinstallé mon wp-config.php, je vais essayer plus de choses et je reviendrai plus tard
Mike Madern
0

Vérifiez tout plugin qui cache Wordpress.

Comment voir si c'est le problème?

  1. Accédez à http (s): //votresite.com/wp-cron.php Vous devriez voir une page vide. Un complètement vide.
  2. En outre, vous devez voir dans un gestionnaire de tâches cron une heure sous "Prochaine exécution": Travail Cron planifié - si wp-cron.php fonctionne correctement (non seulement le texte "En file d'attente" - mais une heure donnée - pour certaines entrées "En file d'attente" est OK parfois, mais si c'est la seule chose vous voyez -> votre cron ne fonctionne pas.)

+1. Ne croyez pas les plugins qui "vérifient si cron fonctionne" - par exemple, le plugin WP Cron status checker a montré que cron fonctionne. Mais en fait, ce n'était pas le cas. Quoi qu'il montre - croyez vos yeux et pas ce plugin!

Conclusion: s'il s'agit d'une erreur 404 - désactivez a) non seulement la mise en cache des plugins comme d'autres le suggèrent b) mais également tous les plugins qui cachent Wordpress.

Peter Cz
la source