{"id":4555,"date":"2018-03-28T14:17:00","date_gmt":"2018-03-28T12:17:00","guid":{"rendered":"https:\/\/florianbrinkmann.com\/en\/?p=4555"},"modified":"2020-02-09T11:25:35","modified_gmt":"2020-02-09T10:25:35","slug":"parallel-requests-woocommerce-api-php-requests-library","status":"publish","type":"post","link":"https:\/\/florianbrinkmann.com\/en\/parallel-requests-woocommerce-api-php-requests-library-4555\/","title":{"rendered":"Parallel requests against the WooCommerce API with the PHP Requests library"},"content":{"rendered":"\n<p>Two of my recent articles are about the WooCommerce REST API and the official PHP library from Automattic, which makes the usage of the API with PHP easier. This post describes a way to run multiple requests against a shop at the same time.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h2 class=\"wp-block-heading\">The problem when using the API with the official PHP library<\/h2>\n\n\n\n<p>If the API is used as I described in my recent posts, then every request pauses the program until the request was finished. If there are only a few requests or requests that depend on each other, that is not that bad, or the wanted behavior.<\/p>\n\n\n\n<p>But if you want to fire API requests that could be bundled, for example, because they should add multiple products, then it would be cool to run those requests parallel. With that, the runtime could be reduced, but that is \u2013 as far as I know \u2013 not possible with the official PHP lib for the REST API.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The solution: the Requests library<\/h2>\n\n\n\n<p>The post \u00bb<a href=\"https:\/\/torquemag.io\/2017\/09\/guide-async-http-requests-wordpress\">A Guide to Async HTTP Requests for WordPress<\/a>\u00ab by Josh Pollock made me aware of <a href=\"https:\/\/github.com\/rmccue\/Requests\">the Requests library by Ryan McCue<\/a>, that is part of WordPress core for some time now. With its <code class=\"lang-php\">requests_multiple()<\/code> method, it is possible to run multiple requests at once \u2013 exactly what we want.<\/p>\n\n\n\n<p>For example, to make two parallel GET requests, the code could look something like that:<\/p>\n\n\n<pre class=\"wp-block-code lang-php\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">$requests_array = &#91;\n\t&#91;\n\t\t<span class=\"hljs-string\">'url'<\/span>  =&gt; <span class=\"hljs-string\">'https:\/\/example.com\/api-endpoint-1'<\/span>,\n\t\t<span class=\"hljs-string\">'type'<\/span> =&gt; <span class=\"hljs-string\">'GET'<\/span>,\n\t],\n\t&#91;\n\t\t<span class=\"hljs-string\">'url'<\/span>  =&gt; <span class=\"hljs-string\">'https:\/\/example.com\/api-endpoint-2'<\/span>,\n\t\t<span class=\"hljs-string\">'type'<\/span> =&gt; <span class=\"hljs-string\">'GET'<\/span>,\n\t],\n];\n\n$responses = Requests::request_multiple( $requests_array );<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><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><code class=\"lang-php\">$responses<\/code> safes the result of both requests.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Usage of the Requests library with the WooCommerce API<\/h2>\n\n\n\n<p>A note to the following steps: I did not get it working locally, because <code class=\"lang-php\">request_multiple()<\/code> currently does not work with self-signed SSL certs (there is an option to deactivate the cert check, but it is not working with the method), and I failed with using OAuth 1 authentication. So the easiest way is to test it on a real server with a valid SSL certificate.<\/p>\n\n\n\n<p>To communicate with the WooCommerce API, we need a URL of the following format (I think it is also possible to provide <code class=\"lang-php\">consumer_key<\/code> and <code class=\"lang-php\">consumer_secret<\/code> as HTTP headers, but I did not try that):<\/p>\n\n\n<pre class=\"wp-block-code lang-bash\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">https:&#47;&#47;example.com\/wp-json\/wc\/v2\/products\/categories?consumer_key=ck_000&amp;consumer_secret=cs_000<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><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 first part until the <code class=\"lang-php\">products\/categories<\/code> endpoint does not change while running requests against one shop; the same goes for both params <code class=\"lang-php\">consumer_key<\/code> and <code class=\"lang-php\">consumer_secret<\/code>.<\/p>\n\n\n\n<p>We create a little helper function that returns a API URL for a provided endpoint:<\/p>\n\n\n<pre class=\"wp-block-code lang-php\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/**\n * Returns URL for accessing the provided WooCommerce REST API endpoint.\n *\n * <span class=\"hljs-doctag\">@param<\/span> string $endpoint   API endpoint.\n * <span class=\"hljs-doctag\">@param<\/span> array  $parameters Optional parameters.\n *\n * <span class=\"hljs-doctag\">@return<\/span> string\n *\/<\/span>\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">build_api_url<\/span><span class=\"hljs-params\">( $endpoint, $parameters = &#91;] )<\/span> <\/span>{\n\t<span class=\"hljs-comment\">\/\/ Add trailing slash to URL.<\/span>\n\t$url     = trailingslashit( <span class=\"hljs-string\">'https:\/\/example.com\/wp-json\/wc\/v2\/'<\/span> ) . $endpoint;\n\t$api_url = add_query_arg( \\array_merge( $parameters, &#91;\n\t\t<span class=\"hljs-string\">'consumer_key'<\/span>    =&gt; <span class=\"hljs-string\">'ck_000'<\/span>,\n\t\t<span class=\"hljs-string\">'consumer_secret'<\/span> =&gt; <span class=\"hljs-string\">'cs_000'<\/span>,\n\t] ), $url );\n\n\t<span class=\"hljs-keyword\">return<\/span> $api_url;\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>And now it is possible, for example to retrieve the product categories and attributes, with the following code:<\/p>\n\n\n<pre class=\"wp-block-code lang-php\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Make requests to get existing categories and attributes.<\/span>\n$requests = &#91;\n\t&#91;\n\t\t<span class=\"hljs-string\">'url'<\/span>  =&gt; build_api_url( <span class=\"hljs-string\">'products\/categories'<\/span> ),\n\t\t<span class=\"hljs-string\">'type'<\/span> =&gt; <span class=\"hljs-string\">'GET'<\/span>,\n\t],\n\t&#91;\n\t\t<span class=\"hljs-string\">'url'<\/span>  =&gt; build_api_url( <span class=\"hljs-string\">'products\/attributes'<\/span> ),\n\t\t<span class=\"hljs-string\">'type'<\/span> =&gt; <span class=\"hljs-string\">'GET'<\/span>,\n\t]\n];\n\n$responses = Requests::request_multiple( $requests );<\/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>To create multiple products, the product data could be looped and put into a temporary array, along with the request data. That array could look like that:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">$tmp_requests_array&#91;] = &#91;\n\t<span class=\"hljs-string\">'url'<\/span>     =&gt; build_api_url( <span class=\"hljs-string\">\"products\"<\/span> ),\n\t<span class=\"hljs-string\">'type'<\/span>    =&gt; <span class=\"hljs-string\">'POST'<\/span>,\n\t<span class=\"hljs-string\">'data'<\/span>    =&gt; $prod_data,\n];<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><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>Where <code class=\"lang-php\">$prod_data<\/code> is the array of the product data like described in my article \u00bb<a href=\"https:\/\/florianbrinkmann.com\/en\/4520\/creating-woocommerce-product-rest-api\/\">Creating a WooCommerce product with PHP via the REST API<\/a>\u00ab. After the products were looped and all requests are in the array, we run <code class=\"lang-php\">request_multiple()<\/code> with the array as the parameter. Maybe you should be a little careful not to send too many requests to the server at the same time.<\/p>\n\n\n\n<p>One thing that currently does not work with <code class=\"lang-php\">requests_multiple()<\/code> too is providing user and password to access the API of a shop that is saved via .htaccess basic auth.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Two of my recent articles are about the WooCommerce REST API and the official PHP library from Automattic, which makes the usage of the API with PHP easier. This post describes a way to run multiple requests against a shop at the same time.<\/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":"","webmentions_disabled_pings":false,"webmentions_disabled":false,"lazy_load_responsive_images_disabled":false,"footnotes":""},"categories":[115],"tags":[],"class_list":["post-4555","post","type-post","status-publish","format-standard","hentry","category-wordpress-snippets"],"wp-worthy-pixel":{"ignored":false,"public":"ce72bb8fc0cb46429f4e95ed6fd41405","server":"vg04.met.vgwort.de","url":"https:\/\/vg04.met.vgwort.de\/na\/ce72bb8fc0cb46429f4e95ed6fd41405"},"wp-worthy-type":"normal","_links":{"self":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/4555","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=4555"}],"version-history":[{"count":3,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/4555\/revisions"}],"predecessor-version":[{"id":5969,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/posts\/4555\/revisions\/5969"}],"wp:attachment":[{"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/media?parent=4555"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/categories?post=4555"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/florianbrinkmann.com\/en\/wp-json\/wp\/v2\/tags?post=4555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}