{"id":4579,"date":"2021-08-19T11:58:00","date_gmt":"2021-08-19T09:58:00","guid":{"rendered":"https:\/\/florianbrinkmann.com\/en\/?p=4579"},"modified":"2021-08-19T12:23:21","modified_gmt":"2021-08-19T10:23:21","slug":"background-processes-wordpress","status":"publish","type":"post","link":"https:\/\/florianbrinkmann.com\/en\/background-processes-wordpress-4579\/","title":{"rendered":"Creating background processes in WordPress"},"content":{"rendered":"\n<p>If a PHP script runs, the page loads typically as long as the script needs to finish (or throws an error). That is fine for many cases, but if the script needs to process complex and\/or many tasks, that take a few minutes or even hours, it would be nice to put that tasks in the background. This post shows you how to create background processes in WordPress.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">Advantages of running background processes<\/h2>\n\n\n\n<p>Using background processes has various advantages, for example:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Better user experience, because no tab needs to stay open while a slow task is running.<\/li><li>Tasks can be split into smaller parts to prevent timeouts.<\/li><\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Background processes in WordPress with \u00bbAction Scheduler\u00ab<\/h2>\n\n\n\n<p><em><a href=\"https:\/\/actionscheduler.org\">Action Scheduler<\/a><\/em> is a background process solution that can be installed as a plugin or used as a library as part of a plugin. Action Scheduler uses the WordPress hook system and makes it possible to run an action hook:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>once as soon as possible,<\/li><li>once on a defined time,<\/li><li>recurring in a specified seconds interval or<\/li><li>recurring in a cron interval.<\/li><\/ul>\n\n\n\n<p>Additionally, it brings an admin interface under <em>Tools<\/em> \u203a <em>Scheduled Actions<\/em> that lists the planned and processed actions with its parameters and, if there are any, errors.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Installation<\/h3>\n\n\n\n<p>The tool can be installed in different ways, at first you need to decide if you want to use it <a href=\"https:\/\/wordpress.org\/plugins\/action-scheduler\/\">as a WordPress plugin<\/a> or as part of another plugin. I show you the usage as part of another plugin and install Action Scheduler via <a href=\"https:\/\/getcomposer.org\/\">Composer<\/a>:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">composer require woocommerce\/action-scheduler<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The normal way of loading composer packages would be to include the Composer autoloader, but Action Scheduler has its own loading mechanism, so we need to include the <code>action-scheduler.php<\/code> file manually:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Load action scheduler.<\/span>\n$action_scheduler = <span class=\"hljs-keyword\">require_once<\/span> dirname( <span class=\"hljs-keyword\">__FILE__<\/span> ) . <span class=\"hljs-string\">'\/vendor\/woocommerce\/action-scheduler\/action-scheduler.php'<\/span>;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>That is is, now we can create our first background process.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Create a background process<\/h3>\n\n\n\n<p>I will show the usage of Action Scheduler with an action that is processed only once and as fast as possible. All other options and the required parameters are listed on the <a href=\"https:\/\/actionscheduler.org\/api\/\">API page of Action Scheduler<\/a>.<\/p>\n\n\n\n<p>To run an action once and as soon as possible, we use the function <code>as_enqueue_async_action()<\/code> that gets the action hook name to run as the first and only required parameter.<\/p>\n\n\n\n<p>The following code would schedule the <code>one_time_action_asap<\/code> hook for a one-time run at the next possible time, if the GET parameter <code>one_time_action<\/code> is present. And because we added the function <code>one_time_function_asap()<\/code> to the action hook, that function will run in the background.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">add_action( <span class=\"hljs-string\">'init'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n\tadd_action( <span class=\"hljs-string\">'one_time_action_asap'<\/span>, <span class=\"hljs-string\">'one_time_function_asap'<\/span> );\n\n\t<span class=\"hljs-keyword\">if<\/span> ( <span class=\"hljs-keyword\">isset<\/span>( $_GET&#91;<span class=\"hljs-string\">'one_time_action'<\/span>] ) ) {\n\t\tas_enqueue_async_action( <span class=\"hljs-string\">'one_time_action_asap'<\/span> );\n\t}\n} );\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">one_time_function_asap<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n\t<span class=\"hljs-comment\">\/\/ Some time-consuming task.<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The second parameter of <code>as_enqueue_async_action()<\/code> can be used to pass an array of parameters to the function that is run by the hook. So, let\u2019s imagine a user enters a value into a text field that is added as <code>one_time_action<\/code> parameter in the URL and should be passed to the background process:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">add_action( <span class=\"hljs-string\">'init'<\/span>, <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n\tadd_action( <span class=\"hljs-string\">'one_time_action_asap'<\/span>, <span class=\"hljs-string\">'one_time_function_asap'<\/span> );\n\n\t<span class=\"hljs-keyword\">if<\/span> ( <span class=\"hljs-keyword\">isset<\/span>( $_GET&#91;<span class=\"hljs-string\">'one_time_action'<\/span>] ) ) {\n\t\tas_enqueue_async_action(\n\t\t\t<span class=\"hljs-string\">'one_time_action_asap'<\/span>,\n\t\t\t&#91; $_GET&#91;<span class=\"hljs-string\">'one_time_action'<\/span>] ]\n\t\t);\n\t}\n} );\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">one_time_function_asap<\/span><span class=\"hljs-params\">( $value )<\/span> <\/span>{\n\t<span class=\"hljs-comment\">\/\/ Some time-consuming task.<\/span>\n\terror_log( $value );\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The example code would write the value of <code>one_time_action<\/code> to the error log if it is enabled. If you pass an array with multiple values, the function gets multiple parameters. Those params are shown in the admin interface of Action Scheduler, which is nice if you need to debug issues with background processes.<\/p>\n\n\n\n<p>And with that, we have our first (slightly silly, but\u2026) action that runs in the background.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Action Scheduler is quickly ready to use and not much complicated to use because it can be used via known WordPress mechanisms.<\/p>\n\n\n\n<p>Compared to <em><a href=\"https:\/\/github.com\/A5hleyRich\/wp-background-processing\">WP Background Processing<\/a><\/em>, which was the subject of the first version of this post, I like that Action Scheduler is easier to integrate and, at least for the time of development, that it comes with a user interface where you see the actions with its parameters and can if needed, cancel an action before it is started.<\/p>\n\n\n\n<p><em>The original version of this post was published on April 14, 2018.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>If a PHP script runs, the page loads typically as long as the script needs to finish (or throws an error). That is fine for many cases, but if the script needs to process complex and\/or many tasks, that take a few minutes or even hours, it would be nice to put that tasks in [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"wpf_show_in_dewp_planet_feed":false,"flobn_post_versions":"4580:5966","webmentions_disabled_pings":false,"webmentions_disabled":false,"lazy_load_responsive_images_disabled":false,"footnotes":""},"categories":[115],"tags":[],"class_list":["post-4579","post","type-post","status-publish","format-standard","hentry","category-wordpress-snippets"],"wp-worthy-pixel":{"ignored":false,"public":"5ba83d0a2bb546089b85a9ddc4d19fcf","server":"vg07.met.vgwort.de","url":"https:\/\/vg07.met.vgwort.de\/na\/5ba83d0a2bb546089b85a9ddc4d19fcf"},"wp-worthy-type":"normal","_links":{"self":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/4579","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/comments?post=4579"}],"version-history":[{"count":5,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/4579\/revisions"}],"predecessor-version":[{"id":6171,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/4579\/revisions\/6171"}],"wp:attachment":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/media?parent=4579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/categories?post=4579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/tags?post=4579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}