WordPress cron钩子-完全不同操作的相同回调?

时间:2021-11-02 作者:Brian

我想更好地理解Wordpress 处理cron jobs 因此,我可以更好地了解如何创建一些自定义作业,这些作业可以基于单一事件发送电子邮件,例如lesson startedlesson webinar started.

In my case, I want to have emails sent to users when I have certain content that becomes available. 可用性基于一个日期字段,我将其作为自定义帖子类型的自定义元数据。

所以想象一下一系列的课程和课程。当课程打开时,我希望该事件触发向有权访问该课程的用户发送电子邮件。同样,当课程的网络研讨会开始时,我也想触发电子邮件。

现在,对于课程点播日期,我对save_post_membrepressrule 通过的挂钩$rule_id 并安排一个cron作业,在课程的drip发布日期发送电子邮件。我在钩子里这样做

    // save meta for lesson if this rule is \'single_sfwd-lessons\' and has fixed drip
function my_save_post_membrepressrule_hook ($rule_id)
{    
    // bunch of checks first
   if ( (isset($_POST[\'_mepr_rules_type\']) AND $_POST[\'_mepr_rules_type\'] == \'single_sfwd-lessons\')
        AND ( isset($_POST[\'_mepr_rules_drip_enabled\']) AND $_POST[\'_mepr_rules_drip_enabled\'] == \'on\')
        AND ( isset($_POST[\'_mepr_rules_drip_after_fixed\']) AND $_POST[\'_mepr_rules_drip_after_fixed\'] != \'\')  ) 
   {
      // we have fixed drip date for a given lesson
      $lesid = $_POST[\'_mepr_rules_content\'];
      $course_id = (int) learndash_get_course_id($lesid);

      // now set notification if rule is in future

      $lesdate = $_POST[\'_mepr_rules_drip_after_fixed\'];
      $lesdate = new DateTime($lesdate, new DateTimeZone(\'UTC\'));
      $current_date = new DateTime();
      $current_date->setTimeZone(new DateTimeZone( \'UTC\' ));
      
      if ($lesdate > $current_date) 
      {      
          $notifs = get_notifications( \'lesson_started\', $course_id, $lesson_id);
          if ( ! $notifs ) {
             return;
          }

          // what memberships are tied to this drip rule?
        
          global $wpdb;
          $memberships = $wpdb->get_results("SELECT access_condition FROM wp_mepr_rule_access_conditions WHERE access_type = \'membership\' AND access_operator = \'is\' AND rule_id = \'$rule_id\'");

          foreach ($memberships as $membership) {
              $membership_id = $membership->access_condition
              $wpdb->query("SET time_zone = \'UTC\'");
              $activeusers = $wpdb->get_results("SELECT DISTINCT user_id FROM wp_mepr_transactions WHERE status IN(\'confirmed\',\'complete\') AND (expires_at >= NOW() OR expires_at = \'0000-00-00 00:00:00\') AND product_id = \'$membership_id\'");

              // likely just one notification post for a given notification type, but use loop just in case
              foreach ($notifs as $notif)
              {
                 foreach ($activeusers as $activeuser) 
                 {
                    if ((int) $activeuser->user_id != 0)
                    {
                       // delete what currently is set for these users for this lesson/membership combo
                    
                       delete_user_meta($activeuser->user_id, \'ld_sent_notification_lesson_started\'.$notif->ID . \'_\' . $lesson_id . \'_\'. $membership_id);
                    }
                 }
                       
                 // see if we already have cron job to send email for this lesson drip, so we can remove in case we changed the drip date
                 if ( wp_next_scheduled( \'my_custom_crons\', [ $notif->ID, \'lesson_started\', $membership_id, $course_id, $lesson_id ] ) )             
                 {
                    wp_clear_scheduled_hook( \'my_custom_crons\', [ $notif->ID, \'lesson_started\', $membership_id, $course_id, $lesson_id ] );
                 }
                 wp_schedule_single_event( $lesdate->getTimeStamp(), \'my_custom_crons\', [ $notif->ID, \'lesson_started\', $membership_id, $course_id, $lesson_id ] );
              } // end notif loop
           } // end memberships loop
        } // if date in future
    } // if drip rule for lesson
}
因此,这在名为my_custom_crons. 我对webinar_started 事件,以及webinat_starts_in_onehour 给定课程的事件。

要对这个钩子做出反应,我必须

add_action( \'my_custom_crons\',\'my_custom_crons\', 99, 5 );
function my_custom_crons( $notif, $notification_type, $membership_id, $course_id, $lesson_id) {

    global $wpdb;
    $wpdb->query("SET time_zone = \'UTC\'");
    $activeusers = $wpdb->get_results("SELECT DISTINCT user_id FROM wp_mepr_transactions WHERE status IN(\'confirmed\',\'complete\') AND (expires_at >= NOW() OR expires_at = \'0000-00-00 00:00:00\') AND product_id = \'$membership_id\'");
    if ( empty( $activeusers ) ) {
        return;
    }

    // ok, we have users that are active
    foreach ( $activeusers as $activeuser ) {
        $user_id = absint( $activeuser->user_id );
        if ($user_id != 0) {
            // bunch of checking
            // get notification message for notification type (lessons tarted, or webinar started)
            // then send the emails

        }
    }

    // clear the job (but this not needed?)
    wp_clear_scheduled_hook(\'my_custom_crons\', array(
                $notif->ID,
                $notification_type, 
                $course_id,
                $membership_id,
                $lesson_id,
    ));
}
就cron的设置而言,一切似乎都在起作用。如果我跑步wp cron event list 在为课程添加Membrepress滴水规则后,我看到my_custom_crons 计划的作业:

my_custom_crons| 2021-11-03 20:01:00 |16 hours 1 minute| Non-repeating

But what happens if I have multiple lessons and multiple events I want to use for email triggers, all with various dates? As mentioned, I might have lesson_started and lesson_webinar_started event for various lessons. So will my current approach work, or will various events for various lessons all triggered at different times, all using my one cron hook\'s logic, interfere with one another?

只是没有看到我应该怎么做的大局。。。

谢谢

1 个回复
最合适的回答,由SO网友:Tom J Nowell 整理而成

不,不完全是。

当你这么说的时候:

wp_schedule_single_event( $sent_on, \'my_custom_cron\', [ $notif_id, $notif_name, $membership_id, $lesson_id ] );
你的意思是当当前时间过去时$sent_on, 执行:

do_action( \'my_custom_cron\', [ $notif_id, $notif_name, $membership_id, $lesson_id ] );
Cron作业只是一个待办事项,用于在将来启动带有一些参数的操作。这就是它们的全部,这个动作与任何其他动作/钩子的作用完全相同。

因此:

但是,如果我有多节课和多个事件要用于电子邮件触发器,并且都有不同的日期,会发生什么呢?

然后,您将有多个具有不同参数的预定cron作业。

如果您构建了一个发送所有课程电子邮件的功能并将其添加到该挂钩中,那么它只会发送所有课程的电子邮件。这是一件非常明显和深思熟虑的事情,我想你会知道,如果你这样做了,因为你需要特别努力来获取所有课程和发送电子邮件。

如前所述,我可能已经启动了lesson\\u,并且lesson\\u webinar\\u启动了各种课程的活动。那么,我当前的方法会起作用吗?或者,各种课程的各种事件都会在不同的时间触发,都会使用我的一个cron钩子的逻辑,相互干扰吗?

你建造它们是为了互相干涉吗?如果是,是!如果不是,则为否。

如果您为挂钩安排了5次cron作业,则该挂钩将被触发5次。如果每次都给它不同的参数,钩子每次都会用不同的参数触发。这是一个队列。我理解人们对此的焦虑和不确定性,但一点调查和常识表明这是毫无根据的。同样,一些快速测试将证明情况并非如此。

但我要指出的一点是wp_clear_scheduled_hook 打电话,没什么意义。这就像宣布周一刚从商店回家就不去商店一样。cron作业已经启动,为时已晚,而且它是一个不重复的一次性单cron作业,因此将来没有什么需要清除的。

整个循环毫无意义,不是这样的wp_schedule_single_event 如果成功,它将与第一次匹配,那么在循环的后续迭代中就不会有任何内容,因为您已经清除了它。wp_schedule_single_event 安排单个事件,而不是重复事件。

相关推荐

如何确保WP-Cron工作循环通过所有帖子?

我正在使用WP Crontrol,每天运行一些CRON作业来检查帖子的年龄。如果帖子提前2天发布,则会被删除。这是可行的,但由于某种原因,只有三天以上的帖子被删除了。还有一些仍在出版中。这一定是因为网站上大约有3000个帖子。有没有办法让我的CRON工作更有效率?以下是我运行的当前代码:class EventsWPCron { public function __construct() { if ( ! wp_next_scheduled( \'