From 62b3b880c14267708cc8b018c5e8f4926e868766 Mon Sep 17 00:00:00 2001
From: ale <ale@incal.net>
Date: Thu, 24 Nov 2022 22:16:31 +0000
Subject: [PATCH] Handle unsafe (plugin) cron events by spawning wp-cli

---
 lib/cron.php | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/lib/cron.php b/lib/cron.php
index 5981b79..55630ee 100644
--- a/lib/cron.php
+++ b/lib/cron.php
@@ -1,12 +1,34 @@
 <?php
 
+function is_hook_safe($hook) {
+    if (strlen($hook) > 2 && substr($hook, 0, 3) == "wp_") {
+        return true;
+    }
+    if ($hook == "delete_expired_transients") {
+        return true;
+    }
+    return false;
+}
+
 // Run cron jobs for the current blog.
-// (Use switch_to_blog() before calling this). 
+// (Use switch_to_blog() before calling this).
+//
+// We can deal with core Wordpress events inline, but not with events
+// associated with plugins, as they aren't properly loaded when
+// switch_to_blog() is called. So we detect when "unsafe" events
+// should be scheduled, and only for those blogs we spawn a wp-cli
+// process (much slower) to run them in the specific context of the
+// blog.
 function noblogs_run_cron_for_current_blog() {
   $crons = wp_get_ready_cron_jobs();
 
+  $has_unsafe_hooks = false;
   foreach ($crons as $timestamp => $cronhooks) {
     foreach ($cronhooks as $hook => $keys) {
+      if (!is_hook_safe($hook)) {
+        $has_unsafe_hooks = true;
+        continue;
+      }
       foreach ($keys as $k => $v) {
         echo "  {$k} -> {$hook}()\n";
         $schedule = $v['schedule'];
@@ -28,4 +50,10 @@ function noblogs_run_cron_for_current_blog() {
       }
     }
   }
+
+  if ($has_unsafe_hooks) {
+    $domain = get_option('domain');
+    echo "  executing wp-cli for unsafe hooks ({$domain})";
+    system("wp cron event run --due-now --url={$domain}");
+  }
 }
-- 
GitLab