<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Bhanu Singh - Web developer working mainly on WordPress.]]></title><description><![CDATA[Hello,
I’m a software engineer by trade; and fitness enthusiast by hobby. I majorly work with JS, Typescript & VueJS. I am growing myself to become a full-stack]]></description><link>https://bhanusingh.in</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1626795224868/u4cpNRMsB.png</url><title>Bhanu Singh - Web developer working mainly on WordPress.</title><link>https://bhanusingh.in</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Apr 2026 04:55:14 GMT</lastBuildDate><atom:link href="https://bhanusingh.in/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[🕷️ ScrapeWave: Web Scraping using Puppeteer in a Docker container with a UI dashboard and database.]]></title><description><![CDATA[https://github.com/git-bhanu/scrapewave
 
🕷️ ScrapeWave project was created to help me accomplish some scraping tasks.
The requirements of the task I was building were:

To be able to access a particular link.

Parse the content of the page and save...]]></description><link>https://bhanusingh.in/scrapewave-web-scraping-using-puppeteer-in-a-docker-container-with-a-ui-dashboard-and-database</link><guid isPermaLink="true">https://bhanusingh.in/scrapewave-web-scraping-using-puppeteer-in-a-docker-container-with-a-ui-dashboard-and-database</guid><category><![CDATA[Docker]]></category><category><![CDATA[puppeteer]]></category><category><![CDATA[Express]]></category><category><![CDATA[Vue.js]]></category><dc:creator><![CDATA[Bhanu Singh]]></dc:creator><pubDate>Sat, 11 May 2024 08:01:50 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1715417312918/15972e06-0356-4655-ae83-51759dc8275f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715412647828/5c764f07-7099-4e05-93cc-5e60a540f400.png" alt="ScrapeWave - first run" class="image--center mx-auto" /></p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/git-bhanu/scrapewave">https://github.com/git-bhanu/scrapewave</a></div>
<p> </p>
<p>🕷️ <strong>ScrapeWave</strong> project was created to help me accomplish some scraping tasks.</p>
<p>The requirements of the task I was building were:</p>
<ol>
<li><p>To be able to access a particular link.</p>
</li>
<li><p>Parse the content of the page and save it somewhere.</p>
</li>
<li><p>Log error in case something unexpected happens.</p>
</li>
<li><p>Ability to start and stop the scarping.</p>
</li>
<li><p>Ability to add more data into the tool.</p>
</li>
<li><p>Ability to import and export data into and from the tool.</p>
</li>
<li><p>And, provide a UI for the person who is administering the tool to be able to see the progress.</p>
</li>
<li><p>Easy &amp; quick to deploy multiple instances of it.</p>
</li>
</ol>
<p>This project uses multiple technologies to achieve the requirement.</p>
<ol>
<li><p>Server</p>
<ol>
<li><p><a target="_blank" href="https://github.com/szymmis/vite-express">ViteExpress</a> - @vitejs integration module for @expressjs.</p>
</li>
<li><p><a target="_blank" href="https://github.com/kriasoft/node-sqlite">SQlite</a> - SQLite client wrapper around sqlite3 for Node.js applications with SQL-based migrations API written in Typescript.</p>
</li>
<li><p><a target="_blank" href="https://github.com/puppeteer/puppeteer">Puppeteer</a> - Node.js API for Chrome</p>
</li>
<li><p><a target="_blank" href="https://github.com/socketio/socket.io">https://github.com/socketio/socket.io</a> - Realtime application framework (Node.JS server).</p>
</li>
<li><p>Other packages worth mentioning are:-</p>
<ul>
<li><p>axios</p>
</li>
<li><p>fast-csv</p>
</li>
</ul>
</li>
</ol>
</li>
<li><p>UI</p>
<ol>
<li><p><a target="_blank" href="https://vuejs.org/">VueJs</a> - Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web</p>
</li>
<li><p><a target="_blank" href="https://pinia.vuejs.org/">Pinia</a> - Intuitive, type safe, light and flexible Store for Vue using the composition api with DevTools support.</p>
</li>
<li><p><a target="_blank" href="https://vuetifyjs.com/en/getting-started/installation/">Vuetify</a> - Vue Component Framework</p>
</li>
</ol>
</li>
<li><p><a target="_blank" href="https://www.docker.com/">Docker</a> - Accelerated Container Application Development</p>
</li>
</ol>
<h2 id="heading-scrapewave-in-action">ScrapeWave in action</h2>
<h3 id="heading-adding-data-to-your-tool">Adding data to your tool</h3>
<p>Using CSV import you can add data to your scarper.</p>
<p>Head over to <code>upload</code> the page and upload the data.</p>
<p>You can use the sample.csv file attached to the repository.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://github.com/git-bhanu/scrapewave/blob/main/sample.csv">https://github.com/git-bhanu/scrapewave/blob/main/sample.csv</a></div>
<p> </p>
<p>As you can see we have three data which can be seen in the table at home.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715413005102/2edb988d-7921-4c62-afe3-2adeaf06baca.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-starting-the-script">Starting the script</h3>
<p>You can start the scraping process by clicking on the start button on the home page.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715413221962/10aaf8ce-5db9-4285-923f-0e21a21c287f.png" alt class="image--center mx-auto" /></p>
<p>As you can see from the image above scraping for the first two entries is done. We also nice logs in your terminal which shows the current status of the software.</p>
<h2 id="heading-deploying-scrapewave-in-cloud">Deploying ScrapeWave in Cloud</h2>
<p>Once you have created the changes as per your liking in the project (learn how to do that from the readme file of the repo) you can create a docker image.</p>
<p>You can name the image whatever you want.</p>
<pre><code class="lang-bash">docker build -t bhanu/scrapewave:latest .
</code></pre>
<p>Here, <code>bhanu</code> would be the docker hub username and <code>scrapewave</code> is the name of the image.</p>
<p>You can push the image to your docker hub using the following command.</p>
<p><em>Make sure you are logged in your dokcer hub account.</em></p>
<pre><code class="lang-bash">dokcer push bhanu/scrapewave:latest
</code></pre>
<p>Once it is done, go to the server using ssh and install two software, docker and Nginx.</p>
<ul>
<li>To install Docker follow the steps here:</li>
</ul>
<p><a target="_blank" href="https://www.digitalocean.com/community/questions/how-to-install-and-run-docker-on-digitalocean-dorplet">https://www.digitalocean.com/community/questions/how-to-install-and-run-docker-on-digitalocean-dorplet</a></p>
<ul>
<li>To install Nginx follow the steps here:</li>
</ul>
<p><a target="_blank" href="https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-18-04">https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-18-04</a></p>
<p>Once you have successfully installed both,</p>
<p>You can use <code>docker run -dit --name &lt;instance-name&gt; -p &lt;port&gt;:3000 krenovate/data-validator:latest</code> to create a container.</p>
<p>For eg.</p>
<pre><code class="lang-bash">docker run -dit -v instance-1:/usr/src/app/db --name instance-1 -p 8080:3000 --restart on-failure bhanu/scrapewave:latest
</code></pre>
<p>This command does quite a few things:</p>
<ol>
<li><p>Creates a container using <code>latest</code> tag of <code>bhanu/scrapewave</code></p>
</li>
<li><p>Mounts the SQlite database in your host filesystem, ensuring even if you recreate the the container with <code>instance-1</code> volume your data would still be persistent.</p>
</li>
<li><p>For any scenario if the container exists, it will try to restart the container so that your scraping doesn't stop.</p>
</li>
</ol>
<p>I plan to keep on improving this project so that it helps me and other folks to use it as the base to get up and running with there scraping task.</p>
<p>Feel free to raise issues if you see anything which is broken - <a target="_blank" href="https://github.com/git-bhanu/scrapewave/issues">https://github.com/git-bhanu/scrapewave/issues</a></p>
<p>Also any kind of contribution is appreciated.</p>
]]></content:encoded></item><item><title><![CDATA[How to Upgrade to a non-LTS Ubuntu [23.10] ?]]></title><description><![CDATA[You can do the following to upgrade your Ubuntu version to 23.04 version.
First, we have to change the Prompt from lts to normal.
Run > sudo nano /etc/update-manager/release-upgrades and find Prompt and switch it to normal from lts.
Now to update use...]]></description><link>https://bhanusingh.in/how-to-upgrade-to-a-non-lts-ubuntu-2310</link><guid isPermaLink="true">https://bhanusingh.in/how-to-upgrade-to-a-non-lts-ubuntu-2310</guid><category><![CDATA[Ubuntu]]></category><category><![CDATA[Ubuntu 23.10]]></category><dc:creator><![CDATA[Bhanu Singh]]></dc:creator><pubDate>Thu, 11 Apr 2024 14:33:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1712845921509/0d9f625a-85da-4e09-939e-121780145fd5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You can do the following to upgrade your Ubuntu version to 23.04 version.</p>
<p>First, we have to change the Prompt from <code>lts</code> to normal.</p>
<p>Run <code>&gt; sudo nano /etc/update-manager/release-upgrades</code> and find <code>Prompt</code> and switch it to <code>normal</code> from <code>lts</code>.</p>
<p>Now to update use <code>do-release-upgrade -c</code></p>
<p>Follow the steps as prompted and you should be good to update your Ubuntu version to version <code>23.10</code></p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">Do remember this is not an LTS (long-term support) version.</div>
</div>]]></content:encoded></item><item><title><![CDATA[Must Read's]]></title><description><![CDATA[Hello everyone, When I am not working at my day job, I usually surf internet and stumble upon some really good articles about tech, productivity, life and other varied topics.
I would like to use this space to share them.

Writing Down What I Do — In...]]></description><link>https://bhanusingh.in/must-reads</link><guid isPermaLink="true">https://bhanusingh.in/must-reads</guid><category><![CDATA[recommendations]]></category><dc:creator><![CDATA[Bhanu Singh]]></dc:creator><pubDate>Thu, 10 Nov 2022 17:26:25 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1668101749271/k-gA-AT8w.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hello everyone, When I am not working at my day job, I usually surf internet and stumble upon some really good articles about tech, productivity, life and other varied topics.</p>
<h3 id="heading-i-would-like-to-use-this-space-to-share-them">I would like to use this space to share them.</h3>
<ol>
<li><p><a target="_blank" href="https://v5.chriskrycho.com/journal/writing-down-what-i-do-in-obsidian/">Writing Down What I Do — In Obsidian [by Chris Krycho]</a> [<em>Productivity</em>]</p>
</li>
<li><p><a target="_blank" href="https://www.simplethread.com/taming-names-in-software-development/">Taming Names in Software Development</a> [<strong>by Joseph Glass</strong>] [Development]</p>
</li>
<li><p><a target="_blank" href="https://withblue.ink/2019/03/11/why-you-need-to-normalize-unicode-strings.html">When "Zoë" !== "Zoë". Or why you need to normalize Unicode strings</a> <strong>[by Alessandro Segala]</strong> [Development]</p>
</li>
</ol>
<p><em>Last Updated: 24 Dec, 2022</em></p>
]]></content:encoded></item><item><title><![CDATA[ACF : Reset all WYSIWYG inside a field group using JS]]></title><description><![CDATA[You can find the JS code below if you are just looking for them. If you are interested in the explanation continue reading.
function bks_add_custom_js()
{
    ?>
    <script type="text/javascript">
        (function($) {
            acf.add_action('r...]]></description><link>https://bhanusingh.in/acf-reset-all-wysiwyg-inside-a-field-group-using-js</link><guid isPermaLink="true">https://bhanusingh.in/acf-reset-all-wysiwyg-inside-a-field-group-using-js</guid><category><![CDATA[WordPress]]></category><category><![CDATA[plugins]]></category><category><![CDATA[wordpress plugins]]></category><category><![CDATA[wordpress themes]]></category><dc:creator><![CDATA[Bhanu Singh]]></dc:creator><pubDate>Wed, 23 Jun 2021 18:56:58 GMT</pubDate><content:encoded><![CDATA[<p>You can find the JS code below if you are just looking for them. If you are interested in the explanation continue reading.</p>
<pre><code class="lang-js"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bks_add_custom_js</span>(<span class="hljs-params"></span>)
</span>{
    ?&gt;
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/javascript"</span>&gt;</span><span class="javascript">
        (<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">$</span>) </span>{
            acf.add_action(<span class="hljs-string">'ready'</span>, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params"> $el </span>)</span>{

                <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">resetWYSIWYG</span>(<span class="hljs-params">fieldGroup</span>) </span>{
                    <span class="hljs-keyword">const</span> parent = $(fieldGroup);

                    <span class="hljs-keyword">const</span> wysiwygs = parent.find(<span class="hljs-string">'[data-type="wysiwyg"]'</span>);

                    $(wysiwygs).each(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">index, wysiwyg</span>) </span>{
                        <span class="hljs-keyword">let</span> tinyID = $(<span class="hljs-built_in">this</span>).find(<span class="hljs-string">"textarea"</span>).attr(<span class="hljs-string">"id"</span>);
                        <span class="hljs-keyword">let</span> tinyInstance = tinyMCE.editors[tinyID];
                        <span class="hljs-keyword">if</span>(tinyInstance) {
                            tinyInstance.setContent(<span class="hljs-string">''</span>);
                        }
                    });
                }

            <span class="hljs-comment">// Reset all WYSIWYG for Field group haivng 'group_60d191ab7f442' id</span>
            resetWYSIWYG(<span class="hljs-string">'#acf-group_60d191ab7f442'</span>);
            });
        })(jQuery);
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>
    &lt;?php
}

add_action(<span class="hljs-string">'acf/input/admin_footer'</span>, <span class="hljs-string">'bks_add_custom_js'</span>);
</code></pre>
<p>We have used <code>acf/input/admin_footer</code> action from acf to add the custom code on the footer of our page, wherever the acf fields are shown.</p>
<p>Inside the function we have written our code inlined. Once the dom is ready we use  <a target="_blank" href="https://www.advancedcustomfields.com/resources/javascript-api/#actions-ready">action ready</a>  from <a target="_blank" href="https://www.advancedcustomfields.com/resources/javascript-api">ACF JS Api</a> .</p>
<p>After that we define our <code>resetWYSIWYG</code> function. I have commented what each line does.</p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">resetWYSIWYG</span>(<span class="hljs-params">fieldGroup</span>) </span>{
     <span class="hljs-comment">// Get main field group.</span>
    <span class="hljs-keyword">const</span> parent = $(fieldGroup);

    <span class="hljs-comment">// Find all the items where data-type attribute has value of wysiwyg</span>
    <span class="hljs-keyword">const</span> wysiwygs = parent.find(<span class="hljs-string">'[data-type="wysiwyg"]'</span>);

    <span class="hljs-comment">// Loop around the found wysiwygs</span>
    $(wysiwygs).each(<span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">index, wysiwyg</span>) </span>{
        <span class="hljs-comment">// Find ID of the wysiwyg</span>
        <span class="hljs-keyword">let</span> tinyID = $(<span class="hljs-built_in">this</span>).find(<span class="hljs-string">"textarea"</span>).attr(<span class="hljs-string">"id"</span>);
        <span class="hljs-comment">// Get instance of tinyMCE</span>
        <span class="hljs-keyword">let</span> tinyInstance = tinyMCE.editors[tinyID]; 
        <span class="hljs-comment">// If you get instance then use setContent to set the vaule empty.</span>
        <span class="hljs-keyword">if</span>(tinyInstance) {
            tinyInstance.setContent(<span class="hljs-string">''</span>);
        }
    });
}
</code></pre><p>Finally you can call the function with your group field id like so. As we are targeting id ACF adds <code>acf-</code> before group_key, so make sure you add that when you are specifying selector for the group.</p>
<pre><code><span class="hljs-selector-tag">resetWYSIWYG</span>(<span class="hljs-string">"#acf-group_60d191ab7f442"</span>);
</code></pre><p>I hope this snippet helped you. 😊</p>
<p>Let me know if you have any question below in the comment and I will try my best to answer them.</p>
]]></content:encoded></item><item><title><![CDATA[Creating a custom webhook in WordPress to get data from third part services]]></title><description><![CDATA[Before setting up a webhook lets understand what a webhook is.
A webhook (also called a web callback or HTTP push API) is a way for an app to provide other applications with real-time information.
In simpler terms, they are a great way for applicatio...]]></description><link>https://bhanusingh.in/creating-a-custom-webhook-in-wordpress-to-get-data-from-third-part-services</link><guid isPermaLink="true">https://bhanusingh.in/creating-a-custom-webhook-in-wordpress-to-get-data-from-third-part-services</guid><category><![CDATA[WordPress]]></category><category><![CDATA[woocommerce]]></category><category><![CDATA[wordpress themes]]></category><category><![CDATA[wordpress plugins]]></category><dc:creator><![CDATA[Bhanu Singh]]></dc:creator><pubDate>Sun, 13 Jun 2021 18:24:47 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1623608631395/v6GZTGFHq.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Before setting up a webhook lets understand what a webhook is.</p>
<p>A webhook (also called a web callback or HTTP push API) is a way for an app to provide other applications with real-time information.</p>
<p>In simpler terms, they are a great way for applications to speak to each other.</p>
<p><strong>For example </strong>: You have a form which you have created on typeform, and you would like to do something on your website when the form is submitted. You can use webhook to achieve this. Typeform  <a target="_blank" href="https://developer.typeform.com/webhooks/">supports webhook</a>.</p>
<p>You have to add a webhook URL in your typeform form. When someone fills up the form typeform will send the data to the URL which you have entered. To recieve that data you have to setup a webhook on your wordpress website and get that data.</p>
<h3 id="setting-up-webhook">Setting up Webhook</h3>
<p>We will use <code>do_action( "admin_post_nopriv_{$action}" )</code>   <a target="_blank" href="https://developer.wordpress.org/reference/hooks/admin_post_nopriv_action/">provided by wordpress</a> .
This action "<em>fires on a non-authenticated admin post request for the given action.</em>" </p>
<pre><code><span class="hljs-selector-tag">add_action</span>(<span class="hljs-string">'admin_post_nopriv_get_typeform_data'</span>,  <span class="hljs-string">'process_data_form_tyepform_webhook'</span>, <span class="hljs-number">10</span>);
</code></pre><p>Here, the action name is <code>get_typeform_data</code>. Which means your webhook url will be </p>
<pre><code>https://yourwebsite.com/wp-<span class="hljs-keyword">admin</span>/<span class="hljs-keyword">admin</span>-post.php?action=get_typeform_data
</code></pre><h3 id="processing-incoming-data">Processing Incoming data</h3>
<p>Now we will define a function which would accept the data and process it.</p>
<pre><code><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">process_data_form_tyepform_webhook</span>(<span class="hljs-params"></span>) </span>{

   $request = file_get_contents(<span class="hljs-string">'php://input'</span>); <span class="hljs-comment">// get data from webhoook</span>

   $data = json_decode($request, <span class="hljs-literal">true</span>); <span class="hljs-comment">// decode the data is you are getting data in JSON format</span>
   <span class="hljs-comment">// log it in debug.log</span>
  error_log( $request );
}
</code></pre><p>Here we have used <code>file_get_contents</code> to store the value in the variable. Most of the time the data you will get is in the form of json, so we have decoded the data and logged it. ( Make sure your debugging is set to true. )</p>
<p>Now you can use the <code>$data</code> variable and process in any way you like. Create a post, create a user etc.</p>
<h3 id="caveat">Caveat</h3>
<p>When testing your funtionality make sure that you are not using your local development environment. You must have hosted your website somewhere it can be visited by other server. If you are interested in testing it locally you should look into https://ngrok.com/.</p>
<p>I hope you enjoyed reading this blog, as much as I enjoyed writing it. 😊</p>
<p>Let me know if you have any question below in the comment and I will try my best to answer them.</p>
]]></content:encoded></item><item><title><![CDATA[Efficient debugging workflow for WordPress  developers]]></title><description><![CDATA[When I started developing on wordpress with php I would always reach for var_dump() which would show me information about the variable. It did what it promised, it dumped the information of the variable.
For example.
$variable = array( 1, 2, 3 );
var...]]></description><link>https://bhanusingh.in/efficient-debugging-workflow-for-wordpress-developers</link><guid isPermaLink="true">https://bhanusingh.in/efficient-debugging-workflow-for-wordpress-developers</guid><category><![CDATA[WordPress]]></category><category><![CDATA[wordpress plugins]]></category><category><![CDATA[wordpress themes]]></category><category><![CDATA[debugging]]></category><category><![CDATA[PHP]]></category><dc:creator><![CDATA[Bhanu Singh]]></dc:creator><pubDate>Sat, 12 Jun 2021 21:33:58 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1623533778744/bMdDckXNK.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I started developing on wordpress with php I would always reach for <code>var_dump()</code> which would show me information about the variable. It did what it promised, it dumped the information of the variable.</p>
<p>For example.</p>
<pre><code>$variable = <span class="hljs-keyword">array</span>( <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span> );
var_dump( $variable );
<span class="hljs-keyword">die</span>(); <span class="hljs-comment">// Stop the code. I will come back to this later.</span>
</code></pre><p>This is rendered like this on the frontend.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623529026155/I9KHTGNLA.png" alt="image.png" /></p>
<p>This looked good enough for a simple array, if it was a multidimensional array like below</p>
<pre><code>$cars = <span class="hljs-keyword">array</span> (
  <span class="hljs-keyword">array</span>(<span class="hljs-string">"Volvo"</span>,<span class="hljs-number">22</span>,<span class="hljs-number">18</span>),
  <span class="hljs-keyword">array</span>(<span class="hljs-string">"BMW"</span>,<span class="hljs-number">15</span>,<span class="hljs-number">13</span>),
  <span class="hljs-keyword">array</span>(<span class="hljs-string">"Saab"</span>,<span class="hljs-number">5</span>,<span class="hljs-number">2</span>),
  <span class="hljs-keyword">array</span>(<span class="hljs-string">"Land Rover"</span>,<span class="hljs-number">17</span>,<span class="hljs-number">15</span>)
); <span class="hljs-comment">// This array is taken from the popular website w3schools 😜</span>
var_dump( $cars );
<span class="hljs-keyword">die</span>(); <span class="hljs-comment">// Stop the code. I will come back to this later.</span>
</code></pre><p>Okay let's look at the output.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623529265816/FquVk2GJl.png" alt="image.png" /></p>
<p>I am very sure that this is very difficult for most developers to scan and make sense out of 😑. </p>
<p>In my pursuit to make my life easier I found other solution to my problem, "Pretty printing arrays".</p>
<pre><code>$cars = <span class="hljs-keyword">array</span> (
  <span class="hljs-keyword">array</span>(<span class="hljs-string">"Volvo"</span>,<span class="hljs-number">22</span>,<span class="hljs-number">18</span>),
  <span class="hljs-keyword">array</span>(<span class="hljs-string">"BMW"</span>,<span class="hljs-number">15</span>,<span class="hljs-number">13</span>),
  <span class="hljs-keyword">array</span>(<span class="hljs-string">"Saab"</span>,<span class="hljs-number">5</span>,<span class="hljs-number">2</span>),
  <span class="hljs-keyword">array</span>(<span class="hljs-string">"Land Rover"</span>,<span class="hljs-number">17</span>,<span class="hljs-number">15</span>)
); 
<span class="hljs-keyword">print</span>(<span class="hljs-string">"&lt;pre&gt;"</span>.print_r($cars,<span class="hljs-literal">true</span>).<span class="hljs-string">"&lt;/pre&gt;"</span>);
<span class="hljs-keyword">die</span>(); <span class="hljs-comment">// Stop the code. I will come back to this later.</span>
</code></pre><p>Output :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623529562048/tMty3NHTy.png" alt="image.png" /></p>
<p>This is already much better. I can scan the array in a format, its easier to understand. </p>
<p>But my happiness didn't last for too long, when I started working with classes and objects.</p>
<p>I will use global variable of woocommerce to depict the issue which I faced.</p>
<pre><code><span class="hljs-keyword">global</span> $woocommerce;
<span class="hljs-keyword">print</span>(<span class="hljs-string">"&lt;pre&gt;"</span>.print_r($woocommerce,<span class="hljs-literal">true</span>).<span class="hljs-string">"&lt;/pre&gt;"</span>);
<span class="hljs-keyword">die</span>();
</code></pre><p>Output :</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623529783318/OZZHsGh4R.png" alt="image.png" /></p>
<p>Okay that is readable but its very long. To give you a prespective.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623529867512/KfxDr8Mf_.png" alt="image.png" />
This is in the lowest zoom of 25% and there is still a lot of scrolling left.</p>
<p>That's a lot about the problem, lets get into the solution. 😁</p>
<h2 id="solution-debug-toolkit">Solution - Debug Toolkit</h2>
<p>The solution is a plugin called Debug Toolkit by author  <a target="_blank" href="https://profiles.wordpress.org/hellofromtonya/">hellofromTonya</a> .</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623530097337/eFoa2UuXW.png" alt="image.png" /></p>
<p>This plugin is available on wordpress plugin directory. You can download it <a target="_blank" href="https://wordpress.org/plugins/debug-toolkit/">here</a>.</p>
<h3 id="how-is-it-a-solution">How is it a solution?</h3>
<p>It comes with three very awesome tools.</p>
<ol>
<li><a target="_blank" href="http://filp.github.io/whoops/">Whoops </a> - whoops is a nice little library that helps you develop and maintain your projects better, by helping you deal with errors and exceptions in a less painful way.</li>
<li><a target="_blank" href="https://kint-php.github.io/kint/">Kint</a> - Zero-setup replacement for var_dump(), print_r(), and debug_backtrace().</li>
<li><a target="_blank" href="https://symfony.com/doc/current/components/var_dumper.html">VarDumper</a> - The VarDumper component provides mechanisms for extracting the state out of any PHP variables. Built on top, it provides a better dump() function that you can use instead of var_dump.</li>
</ol>
<h3 id="how-to-use-it">How to use it ?</h3>
<p>Once you have installed the  <a target="_blank" href="https://wordpress.org/plugins/debug-toolkit/">plugin</a> 
activate it and you are ready. Nothing else is needed. You can start using it.</p>
<blockquote>
<p>It is advised to use this plugin only on development and staging servers.</p>
</blockquote>
<p>Let's use this plugin to dump our  <code>$wocommerce</code>  variable.</p>
<p>This plugin provides us with two type of dumper </p>
<ol>
<li><code>vd()</code> - from VariableDumper</li>
<li><code>d()</code> - from Kint</li>
</ol>
<p>Lets test both of them.</p>
<h4 id="testing-vd">Testing <code>vd()</code></h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623531043032/ABXEWur8Z.png" alt="image.png" /></p>
<p>So much better, we get color coding and toggles, we can use toggle open only those which we want. Let's try to find what our WC_Cart looks like it.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623531143461/5nBFhOX-e.png" alt="image.png" /></p>
<p>I can keep toggling on and off to read the output.</p>
<h4 id="testing-d">Testing <code>d()</code></h4>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623531231419/_kDCrLR8q.png" alt="image.png" /></p>
<p>This may looks similar to <code>vd();</code> but its not. You can toggle parts of output in here as well.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623531301279/SR6QAhoiT.png" alt="image.png" /></p>
<p>But it also has an <code>Available methods</code> tab which shows all the methods that are applicable on that particular variable.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623531393811/sZPBleGPs.png" alt="image.png" /></p>
<p>And not only for the variable but you can also see Available methods for children values. For example we can see available methods for our cart.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623531496406/YC2XmJIbW.png" alt="image.png" /></p>
<p>This becomes so handy that I have discovered so many methods using this that I couldn't find on stackoverflow and wordpress support forum. This is like a crisp doc with variable information. And if code has a docbloc you can see that information here.</p>
<p>Example
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623531608964/zImzwsIvT.png" alt="image.png" /></p>
<p>It doesn't end at <code>vd</code> and <code>d</code>. You can use</p>
<ol>
<li><code>vd()</code> is an alias for <code>vdump()</code></li>
<li><code>vdd()</code> and <code>vdd()</code> are aliases for <code>vdump_and_die()</code></li>
<li><code>d()</code> is an alias for <code>dump()</code></li>
<li><code>dd()</code> and <code>ddd()</code> are aliases <code>for dump_and_die()</code></li>
</ol>
<p>What number 2 and 4 does is that it will halt the code at the dumping line and won't run it further.</p>
<h3 id="tracing">Tracing</h3>
<p>Generates a backtrace for a code is called tracing.</p>
<ol>
<li><code>tracevd();</code> – Combines trace() and vd()</li>
<li><code>traced();</code> – Combines trace() and d()</li>
<li><code>tracevdd();</code> – Combines trace() and vdd()</li>
<li><code>tracedd();</code> – Combines trace() and dd()</li>
<li><code>tracevddd();</code> – Combines trace() and vddd()</li>
<li><code>traceddd();</code> – Combines trace() and ddd()</li>
</ol>
<p>Output of  <code>tracevdd();</code>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623532011344/4GmuPjACI.png" alt="image.png" /></p>
<p>Apart from dumping the the variable information it also gives you the traceback.</p>
<h4 id="what-power-it-gives-you-you-ask">What power it gives you, you ask ?</h4>
<p>You can see the line of code it hit before at every trace.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623532136307/r-X2lDYgr.png" alt="image.png" /></p>
<p>You can see what was the value of the arguments at that time.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623532453578/8etcNNp0S.png" alt="image.png" /></p>
<p>And, also Callee object whenever possible.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623532325142/VIYxXLHc4.png" alt="image.png" /></p>
<h3 id="errors-and-exception">Errors and exception.</h3>
<p>Whoops extenstion of this plugin makes your life a lot better by giving you a clean look when you hit an error.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623532585057/sS-rHlufs.png" alt="image.png" /></p>
<p>On the top left hand side it gives you the error.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623532636964/e4FORVOc4.png" alt="image.png" /></p>
<p>You get a view of code on which the error occured.</p>
<p>Befow that are stack frames which you can click on and see the trace of code.</p>
<p>You can test Whoops live here. http://filp.github.io/whoops/demo/</p>
<h3 id="my-opinion-on-xdebug">My opinion on XDebug</h3>
<p><a target="_blank" href="https://xdebug.org/">Xdebug</a> is said to be the defacto for php development and help with a lot of things.</p>
<ul>
<li>Step Debugging</li>
<li>Better var_dump()</li>
<li>Tracing</li>
<li>Profiling</li>
<li>Code Coverage Analysis</li>
</ul>
<p>I think its a great tool and helps with improving developers development experience. But it can be very tough to setup for a lot of developers. I myself have tried to install and use it and haven't been very successful in doing so.</p>
<p>I also think that Debug Toolkit is a plugin which gives a lot of tools to developers in 0 configuration. The reason I wanted to write this blog is because of the low number of download of this plugin.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1623533122391/2mPG5RfG2.png" alt="image.png" /></p>
<p>I hope you will start using it and make your life a lot easier. 😍</p>
<p>Please share your experience of using Debug toolkit in the comments below. You can also ask questions you may have. I will try my best to answer them.</p>
]]></content:encoded></item><item><title><![CDATA[WooCommerce : Update order automatically based on meta key]]></title><description><![CDATA[Its a common request of woocommerce store owners to be able to change the state  of order automatically when the order meta gets updated.
We will see how can be use  WP Cron and  wc_get_query  to update order status autmatically.
1. Setting up the CR...]]></description><link>https://bhanusingh.in/woocommerce-update-order-automatically-based-on-meta-key</link><guid isPermaLink="true">https://bhanusingh.in/woocommerce-update-order-automatically-based-on-meta-key</guid><category><![CDATA[woocommerce]]></category><category><![CDATA[WordPress]]></category><dc:creator><![CDATA[Bhanu Singh]]></dc:creator><pubDate>Sat, 12 Jun 2021 12:55:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1623502495129/qi9Kvy4il.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Its a common request of woocommerce store owners to be able to change the state  of order automatically when the order meta gets updated.</p>
<p>We will see how can be use  <a target="_blank" href="https://developer.wordpress.org/plugins/cron/">WP Cron</a> and  <a target="_blank" href="https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query">wc_get_query</a>  to update order status autmatically.</p>
<h4 id="1-setting-up-the-cron-job">1. Setting up the CRON Job.</h4>
<pre><code class="lang-php"><span class="hljs-comment">/*
 * Trigger the code when everything is loaded.
 * */</span>
add_action( <span class="hljs-string">'init'</span>, <span class="hljs-string">'bks_setup_cron_task'</span> );

<span class="hljs-comment">/*
 * Set a cron job for daily Midnight.
 * */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bks_setup_cron_task</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> ( ! wp_next_scheduled( <span class="hljs-string">'bks_update_order_status'</span> ) ) {
        wp_schedule_event( time() , <span class="hljs-string">'daily'</span>, <span class="hljs-string">'bks_update_order_status'</span> );
    }
}

<span class="hljs-comment">// Plug the cron job with function 'bks_mark_order_complete_if_delivered'</span>
add_action( <span class="hljs-string">'bks_update_order_status'</span>, <span class="hljs-string">'bks_mark_order_complete_if_delivered'</span> );
</code></pre>
<p>There are multiple things going on here. Let's take a look at them one by one.</p>
<p>We are using  <a target="_blank" href="https://developer.wordpress.org/reference/functions/add_action/"><code>add_action</code></a> function with  <a target="_blank" href="https://developer.wordpress.org/reference/hooks/init/"><code>init</code></a> hook which fires after WordPress has finished loading but before any headers are sent. We have passed a funtion in <code>bks_setup_cron_task</code> which would run when this hook is executed.</p>
<pre><code><span class="hljs-selector-tag">if</span> ( ! wp_next_scheduled( <span class="hljs-string">'bks_update_order_status'</span> ) ) { ... }
</code></pre><p>Inside this function we are checking if a cron job named <code>bks_update_order_status</code> is scheduled or not using <a target="_blank" href="https://developer.wordpress.org/reference/functions/wp_next_scheduled/"><code>wp_next_scheduled</code></a>  function.</p>
<pre><code>wp_schedule_event( <span class="hljs-type">time</span>() , <span class="hljs-string">'daily'</span>, <span class="hljs-string">'bks_update_order_status'</span> );
</code></pre><p>And then we use  <a target="_blank" href="https://developer.wordpress.org/reference/functions/wp_schedule_event/"><code>wp_schedule_event</code></a> function to set when it should run next.</p>
<p>The functions accepts 5 parameter but we are using only the 3 which are required ones.</p>
<ul>
<li><code>$timestamp (int)</code> - Unix timestamp (UTC) for when to next run the event.</li>
<li><code>$recurrence (string)</code> - This determines how often the event should subsequently recur. We have set it to daily. Default values you can set here are  ‘hourly’, ‘twicedaily’, ‘daily’, and ‘weekly’.</li>
<li><code>$hook (string)</code> Action hook to execute when the event is run. We have set it to a function called <code>bks_mark_order_complete_if_delivered</code>.</li>
</ul>
<pre><code><span class="hljs-selector-tag">add_action</span>( <span class="hljs-string">'bks_update_order_status'</span>, <span class="hljs-string">'bks_mark_order_complete_if_delivered'</span> );
</code></pre><p>And finally using the cron hook <code>bks_update_order_status</code> to execute a function </p>
<p>You can see in the screenshot below that we have successfully registered a cron job which would execute <code>bks_mark_order_complete_if_delivered()</code> function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1622926815454/d1hB74GEn.png" alt="image.png" /></p>
<blockquote>
<p>I have used  <a target="_blank" href="https://wordpress.org/plugins/wp-crontrol/">WP Crontrol plugin</a> 
 to monitor my cron job.</p>
</blockquote>
<h4 id="2-writing-the-logic-to-actually-update-the-order-status">2. Writing the logic to actually update the order status</h4>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bks_mark_order_complete_if_delivered</span>(<span class="hljs-params"></span>)</span>{
    $args = <span class="hljs-keyword">array</span>(
        <span class="hljs-string">'status'</span> =&gt; <span class="hljs-keyword">array</span>( <span class="hljs-string">'wc-processing'</span>),
        <span class="hljs-string">'limit'</span>  =&gt; <span class="hljs-number">-1</span>,
        <span class="hljs-string">'date_created'</span> =&gt; <span class="hljs-string">'&gt;'</span> . ( time() - <span class="hljs-number">864000</span> ),
        <span class="hljs-string">'delivery_status'</span> =&gt; <span class="hljs-string">'delivered'</span>
    );


    $orders = wc_get_orders( $args );

    <span class="hljs-keyword">foreach</span> ($orders <span class="hljs-keyword">as</span> $order){
        $order-&gt;update_status( <span class="hljs-string">'completed'</span> );
        $order-&gt;save();
    }
};
</code></pre>
<p>Here we are using <a target="_blank" href="https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query"><code>wc_get_orders</code></a>  function where we pass 4 parameters.</p>
<ol>
<li>status : <code>array( 'wc-processing')</code> - we only want order which has the status of wc-processing</li>
<li>limit : <code>-1</code> - No limit, we want all the orders without any limit</li>
<li>date_created : <code>'&gt;' . ( time() - 864000 )</code> - orders whose date is greater than time() [ current time ] - 864000 seconds (  = 10 days ). ie. in last 10 days.</li>
<li>delivery_satus ; <code>delivered</code> : This is a  <a target="_blank" href="https://github.com/woocommerce/woocommerce/wiki/wc_get_orders-and-WC_Order_Query#adding-custom-parameter-support">custom paramater</a> created which checks if the value of <code>deliver_status</code> order meta is delivery or not and only those orders are returned which satisfy the condition.</li>
</ol>
<p>You can add Custom parameter like this.</p>
<pre><code class="lang-php"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bks_handle_custom_query_var</span>(<span class="hljs-params"> $query, $query_vars </span>) </span>{
    <span class="hljs-keyword">if</span> ( ! <span class="hljs-keyword">empty</span>( $query_vars[<span class="hljs-string">'delivery_status'</span>] ) ) {
        $query[<span class="hljs-string">'meta_query'</span>][] = <span class="hljs-keyword">array</span>(
            <span class="hljs-string">'key'</span> =&gt; <span class="hljs-string">'delivery_status'</span>,
            <span class="hljs-string">'value'</span> =&gt; esc_attr( $query_vars[<span class="hljs-string">'delivery_status'</span>] ),
        );
    }

    <span class="hljs-keyword">return</span> $query;
}

add_filter( <span class="hljs-string">'woocommerce_order_data_store_cpt_get_orders_query'</span>, <span class="hljs-string">'bks_handle_custom_query_var'</span>, <span class="hljs-number">10</span>, <span class="hljs-number">2</span> );
</code></pre>
<p>Once the args is done we get </p>
<ol>
<li>all the orders </li>
<li>with processing status</li>
<li>in last 10 days</li>
<li>having <code>delivery_status</code> meta as <code>delivered</code>.</li>
</ol>
<p>We the loop through the order, update the status and save.</p>
<pre><code class="lang-php">$order-&gt;update_status( <span class="hljs-string">'completed'</span> );
$order-&gt;save();
</code></pre>
<h4 id="summary">Summary</h4>
<p>So you have to finally add this combined code in your <code>functions.php</code> of your child theme.</p>
<pre><code class="lang-php"><span class="hljs-comment">/*
 * Trigger the code when everything is loaded.
 * */</span>
add_action( <span class="hljs-string">'init'</span>, <span class="hljs-string">'bks_setup_cron_task'</span> );

<span class="hljs-comment">/*
 * Set a cron job for daily Midnight.
 * */</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bks_setup_cron_task</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">if</span> ( ! wp_next_scheduled( <span class="hljs-string">'bks_update_order_status'</span> ) ) {
        wp_schedule_event( time() , <span class="hljs-string">'daily'</span>, <span class="hljs-string">'bks_update_order_status'</span> );
    }
}

<span class="hljs-comment">// Plug the cron job with function 'bks_mark_order_complete_if_delivered'</span>
add_action( <span class="hljs-string">'bks_update_order_status'</span>, <span class="hljs-string">'bks_mark_order_complete_if_delivered'</span> );

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bks_mark_order_complete_if_delivered</span>(<span class="hljs-params"></span>)</span>{
    $args = <span class="hljs-keyword">array</span>(
        <span class="hljs-string">'status'</span> =&gt; <span class="hljs-keyword">array</span>( <span class="hljs-string">'wc-processing'</span>),
        <span class="hljs-string">'limit'</span>  =&gt; <span class="hljs-number">-1</span>,
        <span class="hljs-string">'date_created'</span> =&gt; <span class="hljs-string">'&gt;'</span> . ( time() - <span class="hljs-number">864000</span> ),
        <span class="hljs-string">'delivery_status'</span> =&gt; <span class="hljs-string">'delivered'</span>
    );


    $orders = wc_get_orders( $args );

    <span class="hljs-keyword">foreach</span> ($orders <span class="hljs-keyword">as</span> $order){
        $order-&gt;update_status( <span class="hljs-string">'completed'</span> );
        $order-&gt;save();
    }
};

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">bks_handle_custom_query_var</span>(<span class="hljs-params"> $query, $query_vars </span>) </span>{
    <span class="hljs-keyword">if</span> ( ! <span class="hljs-keyword">empty</span>( $query_vars[<span class="hljs-string">'delivery_status'</span>] ) ) {
        $query[<span class="hljs-string">'meta_query'</span>][] = <span class="hljs-keyword">array</span>(
            <span class="hljs-string">'key'</span> =&gt; <span class="hljs-string">'delivery_status'</span>,
            <span class="hljs-string">'value'</span> =&gt; esc_attr( $query_vars[<span class="hljs-string">'delivery_status'</span>] ),
        );
    }

    <span class="hljs-keyword">return</span> $query;
}

add_filter( <span class="hljs-string">'woocommerce_order_data_store_cpt_get_orders_query'</span>, <span class="hljs-string">'bks_handle_custom_query_var'</span>, <span class="hljs-number">10</span>, <span class="hljs-number">2</span> );
</code></pre>
<h4 id="this-comes-from-the-two-different-question-which-i-answered-on-stackoverflow">This comes from the two different question which I answered on stackoverflow :</h4>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://stackoverflow.com/questions/67838546/update-order-status-from-custom-statuses-to-completed-in-woocommerce-everyday-at/67844705#67844705">https://stackoverflow.com/questions/67838546/update-order-status-from-custom-statuses-to-completed-in-woocommerce-everyday-at/67844705#67844705</a></div>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://stackoverflow.com/questions/67689647/woocommerce-change-order-status-based-on-custom-meta-value/67755204#67755204">https://stackoverflow.com/questions/67689647/woocommerce-change-order-status-based-on-custom-meta-value/67755204#67755204</a></div>
]]></content:encoded></item><item><title><![CDATA[Deploying Sage(WordPress Starter theme) to your host using Github Actions]]></title><description><![CDATA[I had recently started using sage for theme development of a new design upgrade for an old WordPress website. This website was hosted on Digital Ocean droplet having OpenLiteSpeed server installed on it. 
If you look at the roots ecosystem, you will ...]]></description><link>https://bhanusingh.in/deploying-sagewordpress-starter-theme-to-your-host-using-github-actions</link><guid isPermaLink="true">https://bhanusingh.in/deploying-sagewordpress-starter-theme-to-your-host-using-github-actions</guid><category><![CDATA[WordPress]]></category><category><![CDATA[wordpress themes]]></category><dc:creator><![CDATA[Bhanu Singh]]></dc:creator><pubDate>Wed, 05 Aug 2020 05:40:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1621029532443/JOsFaKjJJ.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I had recently started using <a target="_blank" href="https://roots.io/sage/">sage</a> for theme development of a new design upgrade for an old WordPress website. This website was hosted on Digital Ocean droplet having <a target="_blank" href="https://marketplace.digitalocean.com/apps/openlitespeed-wordpress">OpenLiteSpeed server</a> installed on it. </p>
<p>If you look at the <a target="_blank" href="https://roots.io">roots</a> ecosystem, you will see that they Trellis project which take care of Production, Staging and Development environments. But in my case I couldn't change the host. To solve this problem I used <a target="_blank" href="https://github.com/features/actions">Github Actions</a> to setup continuous deployment.</p>
<p>#Steps Involved</p>
<ol>
<li>Setting up Github Repository</li>
<li>Setting up your host machine</li>
<li>Command to push code to Host from local</li>
</ol>
<h1 id="setting-up-github-repository">Setting up Github Repository</h1>
<p>I am considering that you have your sage code pushed to your remote github repository.</p>
<p>We will start by adding actions. </p>
<ol>
<li>Click on the "Actions" tab in your repository.</li>
<li>Click on the button "Skip this and set up a workflow yourself -&gt;" next. You will find it in the top section.</li>
<li>You will be taken to a page where which would be at <code>your-repo/.github/workflows/main.yml</code>. Change the name of the file to <code>deployment.yml</code> as we are creating actions to deploy our code.</li>
<li>Copy the code from below and paste it in your <code>deployment.yml</code> file.</li>
</ol>
<pre><code><span class="hljs-attribute">name</span>: Deployment

<span class="yaml"><span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">production</span> ]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>

    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v1.1.0</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">version:</span> <span class="hljs-number">12.</span><span class="hljs-string">x</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">dependencies</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">|
        composer install -o
        yarn
</span>    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">yarn</span> <span class="hljs-string">build</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Sync</span>
      <span class="hljs-attr">env:</span>
        <span class="hljs-attr">dest:</span> <span class="hljs-string">'root@111.11.111.111:/var/www/html/wp-content/themes/theme-name'</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">|
        echo "${{secrets.DEPLOY_KEY}}" &gt; deploy_key
        chmod 600 ./deploy_key
        rsync -chav --delete \
          -e 'ssh -i ./deploy_key -o StrictHostKeyChecking=no' \
          --exclude /deploy_key \
          --exclude /.git/ \
          --exclude /.github/ \
          --exclude /node_modules/ \
          ./ ${{env.dest}}</span></span>
</code></pre><ol>
<li>In line no. 27 you will have to change the value of <code>dest</code>. This is what the value of dist will be for you <code>&lt;user&gt;@&lt;host ip&gt;:&lt;path-to-your-theme&gt;</code>. So for example <code>bhanu@111.11.111.111:/var/www/html/wp-content/themes/theme-name</code></li>
<li>After this is done you have to on "<em>Start Commit</em>" button and merge it into your master branch.</li>
<li>You will have to add a secret <code>DEPLOY_KEY</code> which we will revisit after setting up our host.</li>
</ol>
<h1 id="setting-up-your-host-machine">Setting up your host machine</h1>
<p><code>ssh</code> into your machine. We will create a SSH key and add it our github repository in order for our give our github repository access to our host machine.</p>
<p>We do this in the following steps.</p>
<pre><code class="lang-bash">ssh-keygen -t rsa -b 4096 -C <span class="hljs-string">"your_email@example.com"</span>
</code></pre>
<p>Don't forget to change the email ID to yours. 
This will give you some prompts.</p>
<pre><code class="lang-bash">&gt; Generating public/private rsa key pair.
&gt; Enter a file <span class="hljs-keyword">in</span> <span class="hljs-built_in">which</span> to save the key (/home/you/.ssh/id_rsa): [Press enter]
&gt; Enter passphrase (empty <span class="hljs-keyword">for</span> no passphrase): [Type a passphrase]
&gt; Enter same passphrase again: [Type passphrase again]
</code></pre>
<p>You have to press enter and skip all of the above. In some cases you may already have an SSH key and you can overwrite it in order to create a fresh one.</p>
<p>You have now created a new ssh at <code>~/.ssh/id_rsa</code>.</p>
<p>###Adding SSH key to the ssh-agent</p>
<p>Enter the following command.</p>
<pre><code class="lang-bash"><span class="hljs-built_in">eval</span> $(ssh-agent -s)
&gt; Agent pid 59566
ssh-add ~/.ssh/id_rsa
</code></pre>
<p>Now we need to add our public key <code>id_rsa.pub</code> to the authorized_keys. </p>
<p>You can do this by.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Getting inside SSH file</span>
$ <span class="hljs-built_in">cd</span> ~/.ssh/

<span class="hljs-comment"># Copying pub key into your clipboard</span>
$ cat id_rsa.pub
<span class="hljs-comment"># This would print the content on the screen which you have to copy</span>

<span class="hljs-comment"># paste the content inside authorized_keys</span>
$ nano authorized_keys
<span class="hljs-comment"># To save press Ctrl+X -&gt; y -&gt; Press Enter</span>

<span class="hljs-comment"># Copy the content of public key</span>
$ cat id_rsa
<span class="hljs-comment"># This will paste the content of the public key which you have to copy starting from Start here till the end.</span>
</code></pre>
<h3 id="this-is-the-point-where-we-go-back-to-point-7-of-setting-up-github-repository"><strong>This is the point where we go back to point 7 of Setting up Github Repository</strong></h3>
<p>In your Github repository you go 
-&gt; settings tab
-&gt; Secrets
-&gt; Click on <code>New secret</code>button
-&gt; Type the name of the secret as <code>DEPLOY_KEY</code>
-&gt; Paste the content of public key copied above here and hit <code>Add secret</code>.</p>
<p>We are almost done. We just have to test if everything is working fine or not.</p>
<p>Go to your local development and git push all the changes you want to deploy. When you are satisfied with the changes and you have pushed those in your master branch use this command.</p>
<pre><code class="lang-bash">git push origin master:production
</code></pre>
<p>This will push all the contents of master branch to production branch.</p>
<p>Now if you look closely at our <code>deployment.yml</code> file you can see these lines of code.</p>
<pre><code class="lang-yml"><span class="hljs-attr">name:</span> <span class="hljs-string">Deployment</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
    <span class="hljs-attr">branches:</span> [ <span class="hljs-string">production</span> ]
</code></pre>
<p>These lines tells that this action gets triggered when there is a push in the production branch.</p>
<p>You can look at your progress by going to the <code>Actions</code> tab. You would see an action is running. You can click on deploy to check the status and log of the same.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1621068069991/YmypBXCt7.png" alt="Github action.png" /></p>
<p>Let me know if you have any questions regarding this method, or you are stuck somewhere in the process.</p>
]]></content:encoded></item></channel></rss>