<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Carlos Guzman</title>
	<atom:link href="https://carlosguzman.dev/feed/" rel="self" type="application/rss+xml" />
	<link>https://carlosguzman.dev/</link>
	<description>Web developer</description>
	<lastBuildDate>Tue, 03 Mar 2026 03:57:12 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.1</generator>

<image>
	<url>https://carlosguzman.dev/wp-content/uploads/2019/06/favicon.ico</url>
	<title>Carlos Guzman</title>
	<link>https://carlosguzman.dev/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Building a WordPress plugin with modern architecture</title>
		<link>https://carlosguzman.dev/building-a-wordpress-plugin-with-modern-architecture/</link>
		
		<dc:creator><![CDATA[Carlos Guzmán]]></dc:creator>
		<pubDate>Thu, 15 Jan 2026 21:03:36 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[phpunit]]></category>
		<category><![CDATA[React.js]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://carlosguzman.dev/?p=281</guid>

					<description><![CDATA[<p>The Motivation: Why Build Another Crypto Plugin? When building a portfolio project, the &#8220;what&#8221; is often less important than the &#8220;how&#8221;. I decided building a WordPress plugin with modern architecture and I chose to build a Multi-Crypto Price Converter not because the market lacked one, but because it provided the perfect sandbox to demonstrate and [&#8230;]</p>
<p>The post <a href="https://carlosguzman.dev/building-a-wordpress-plugin-with-modern-architecture/">Building a WordPress plugin with modern architecture</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading"><strong>The Motivation: Why Build Another Crypto Plugin?</strong></h2>



<p class="wp-block-paragraph">When building a portfolio project, the &#8220;what&#8221; is often less important than the &#8220;how&#8221;. I decided building a WordPress plugin with modern architecture and I chose to build a <strong>Multi-Crypto Price Converter</strong> not because the market lacked one, but because it provided the perfect sandbox to demonstrate and include in my portfolio how <strong>WordPress engineering</strong> looks like. While the feature set is straightforward, the architecture behind it is designed for scale, stability, and maintainability.</p>



<p class="wp-block-paragraph">The goal was simple: Create a lightweight, robust, and highly maintainable plugin using modern tools like <strong>TypeScript, React, and SOLID PHP principles.</strong></p>



<h2 class="wp-block-heading"><strong>1. A Decoupled Architecture</strong></h2>



<p class="wp-block-paragraph">Most WordPress plugins suffer from &#8220;hook fatigue,&#8221; where logic is scattered and hard to test. I approached this project with a clear separation of concerns:</p>



<ul class="wp-block-list">
<li><strong>The Backend (PHP):</strong> I implemented a <strong>Service Container</strong> and used <strong>Dependency Injection</strong> to manage my classes. The backend’s primary responsibility is data orchestration—fetching crypto prices from external APIs and managing a custom <strong>caching layer</strong>. By using a dedicated service for caching, I ensure that visitors hit my local REST API rather than exhausting external API limits. By coding to interfaces rather than concrete classes, the system is prepared for future-proofing (e.g., swapping out a price API without touching the core logic).</li>



<li><strong>The Frontend (React):</strong> To keep the experience snappy, the actual currency conversion happens on the client side. Once the React component fetches the cached prices from the WordPress REST API, it handles all calculations locally. This reduces server overhead and provides an instantaneous UI for the user.</li>
</ul>



<h2 class="wp-block-heading"><strong>2. Building &#8220;Bulletproof&#8221; Software with PHP-Scoper</strong></h2>



<p class="wp-block-paragraph">In the WordPress ecosystem, dependency conflicts are a silent killer (e.g., your plugin uses Guzzle 7, but another plugin loads Guzzle 6). To prevent this, I used <strong>PHP-Scoper</strong>.</p>



<p class="wp-block-paragraph">I’ve ensured that the plugin uses prefixes for third-party namespaces to make it completely isolated. It doesn&#8217;t matter what other plugins are installed; my dependencies will never conflict. This is a standard I believe should be used in all high-level WordPress development.</p>



<h2 class="wp-block-heading"><strong>3. Modern Frontend &amp; Gutenberg Integration</strong></h2>



<p class="wp-block-paragraph">I wanted to showcase my experience with the modern WordPress block editor. The plugin includes a custom <strong>Gutenberg Block</strong> built with <strong>TypeScript</strong> and <strong>React</strong>.</p>



<ul class="wp-block-list">
<li><strong>Editor Experience:</strong> A custom Gutenberg block built with React and TypeScript for a native editing experience.</li>



<li><strong>Frontend Performance:</strong>  While I initially considered Vanilla JS, I pivoted to a <strong>React-based frontend component</strong> to handle the state of price conversions more elegantly and provide a smoother UX but mainly to showcase my experience creating React components. By moving the conversion math to React, I avoided unnecessary admin-ajax or REST calls during user interaction.</li>



<li><strong>REST API Integration:</strong> I built custom REST endpoints to handle data fetching, this decouples the frontend from the backend logic.</li>
</ul>



<h2 class="wp-block-heading"><strong>4. AI-Augmented Engineering</strong></h2>



<p class="wp-block-paragraph">I used an AI coding assistant as a co-pilot for this project. My goal was to see how much it could accelerate my workflow.</p>



<ul class="wp-block-list">
<li><strong>The Result:</strong> It significantly sped up boilerplate and initial implementations.</li>



<li><strong>The Caveat:</strong> It requires a human hand. I found that while the AI is fast, I had to refactor its output to meet my architectural standards, fix edge-case validations, or pivot when I realized a design needed to change (such as switching from a Vanilla JS table to a full React component). I remained the architect; the AI was the builder. By maintaining a strict &#8220;Human-in-the-loop&#8221; approach—including detailed code reviews and manual refactoring—I was able to code faster without sacrificing the integrity of the architecture or losing control and knowledge of the details of the architecture.</li>
</ul>



<h2 class="wp-block-heading"><strong>5. Quality Assurance &amp; Tooling</strong></h2>



<p class="wp-block-paragraph">Even for a portfolio piece, code quality is non-negotiable.</p>



<ul class="wp-block-list">
<li><strong>Unit Testing:</strong> I implemented tests for the core PHP logic, specifically focusing on the external API requests and the caching mechanism.</li>



<li><strong>Static Analysis &amp; Type Safety:</strong> To reduce bugs in the codebase, I utilized <strong>PHP 8</strong> features with <strong>strict typing</strong> throughout the plugin. I integrated <strong>PHPStan</strong> into my workflow to catch potential edge cases and type mismatches before the code ever reached execution, ensuring a level of type safety rarely seen in traditional WordPress development.</li>



<li><strong>Coding Standards:</strong> The project enforces <strong>PHPCS</strong> (WordPress standards) and <strong>ESLint</strong> to ensure the code is clean and readable for any developer who touches it next.</li>



<li><strong>Build Automation:</strong> Using <code>package.json</code> and <code>composer</code>, I created a streamlined local build process that orchestrates <code>tsc</code>, <code>wp-scripts</code>, and dependency scoping into a production-ready ZIP file.</li>
</ul>



<ul class="wp-block-list"></ul>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<h2 class="wp-block-heading"><strong>Summary</strong></h2>



<p class="wp-block-paragraph">This project was a great way to combine my interest in Web3 with my experience in modern software design. It’s not just a price converter—it’s a demonstration of <strong>SOLID principles</strong>, <strong>dependency isolation</strong>, and a <strong>modern React-to-REST workflow</strong>.</p>



<p class="wp-block-paragraph"><strong><a target="_blank" rel="noreferrer noopener" href="https://github.com/c24o/wp-multi-crypto-price-converter">View the Source Code on GitHub</a></strong></p>



<h3 class="wp-block-heading">Multi Crypto Price Converter in Action</h3>


		<div class="wp-block-multi-crypto-price-converter-converter" data-coins="btc,eth,sol,trx,xrp,bnb,doge,ada,xmr,xlm,ltc,zec,hype">
							<div class="mcpc-converter-container"></div>
						<p>Data provided by <a href="https://www.coingecko.com/" target="_blank" rel="noopener noreferrer">CoinGecko</a></p>
							</div>
		<p>The post <a href="https://carlosguzman.dev/building-a-wordpress-plugin-with-modern-architecture/">Building a WordPress plugin with modern architecture</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>How to update meta fields of multiple posts in WordPress using a single REST request</title>
		<link>https://carlosguzman.dev/update-meta-fields-of-multiple-posts-in-wordpress-with-the-rest-api/</link>
					<comments>https://carlosguzman.dev/update-meta-fields-of-multiple-posts-in-wordpress-with-the-rest-api/#respond</comments>
		
		<dc:creator><![CDATA[Carlos Guzmán]]></dc:creator>
		<pubDate>Sat, 05 Oct 2024 17:10:51 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[Web Development]]></category>
		<category><![CDATA[WordPress Batch Framework]]></category>
		<guid isPermaLink="false">https://carlosguzman.dev/?p=239</guid>

					<description><![CDATA[<p>Building a custom settings page in WordPress using React, I faced the situation where I wanted to update meta fields of multiple posts at once. I want to share the approach I used with the WordPress REST API. The WordPress REST API has a framework for making a series of REST API calls at once. [&#8230;]</p>
<p>The post <a href="https://carlosguzman.dev/update-meta-fields-of-multiple-posts-in-wordpress-with-the-rest-api/">How to update meta fields of multiple posts in WordPress using a single REST request</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Building a custom settings page in WordPress using React, I faced the situation where I wanted to update meta fields of multiple posts at once. I want to share the approach I used with the WordPress REST API.</p>



<p class="wp-block-paragraph">The WordPress REST API has a framework for making a series of REST API calls at once. It is handy to update meta fields of multiple posts using a single REST request. The framework name is <a href="https://make.wordpress.org/core/2020/11/20/rest-api-batch-framework-in-wordpress-5-6/" target="_blank" rel="noreferrer noopener">REST API Batch Framework</a>. Next are the steps I took to use it.</p>



<h2 class="wp-block-heading">Registration of the meta fields in the REST API</h2>



<p class="wp-block-paragraph">First I registered the custom meta field in the REST API using the <a href="https://developer.wordpress.org/reference/functions/register_post_meta/" target="_blank" rel="noreferrer noopener">register_post_meta</a> function.</p>



<pre class="wp-block-code"><code lang="php" class="language-php line-numbers">add_action( 'init', function() {
	register_post_meta(
		'post',
		'my_custom_field_name',
		[
			'single'       =&gt; true,
			'type'         =&gt; 'string',
			'show_in_rest' =&gt;  true,
		]
	);
} );</code></pre>



<ul class="wp-block-list">
<li>The first argument I used here is <code>'post'</code>, which means that the custom field is applied for items saved in the posts table (posts, pages and custom post types). Here you can use other entities like <code>'comment'</code>, <code>'term'</code> or <code>'user'</code>. If the meta field is used in a custom post type, then the custom post type should support custom fields. During the <a href="https://developer.wordpress.org/reference/functions/register_post_type/" target="_blank" rel="noreferrer noopener">custom post type registration</a>, you can use the <code>supports</code> field to add <code>custom-fields</code>.</li>



<li>The second argument is <code>'my_custom_field_name'</code> which is the key name used for the meta field.</li>



<li>The last argument describes the meta field. In this example, the meta field has one value per post only, its type is string and its value is accessible via the REST API. Indeed, the value of the <code>'show_in_rest'</code> key can be an array with the key <code>'schema'</code> to describe its data structure in the REST API.</li>
</ul>



<h2 class="wp-block-heading">Using the Batch Framework to update meta fields of multiple posts in WordPress</h2>



<p class="wp-block-paragraph">The React component uses the Batch Framework and it is in charge of doing the request to update the posts. It has a function to update the meta fields of multiple posts in WordPress using a single request. The request looks like this:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript line-numbers">const requests = [
	{
		path: '/wp/v2/posts/10',
		method: 'POST',
		body: {
			meta: {
				my_custom_field_name: 'hello world',
			},
		},
	},
	{
		path: '/wp/v2/posts/11',
		method: 'POST',
		body: {
			meta: {
				my_custom_field_name: 'lorem ipsum...',
			},
		},
	},
	{
		path: '/wp/v2/posts/12',
		method: 'POST',
		body: {
			meta: {
				my_custom_field_name: '123abc',
			},
		},
	}
];
apiFetch( {
	path: 'batch/v1',
	method: 'POST',
	data: { requests },
} )
	.then( response =&gt; handleBatchResponse( response, requests ) )
	.catch( err =&gt; console.log( err ) );</code></pre>



<p class="wp-block-paragraph">The <code><a href="https://developer.wordpress.org/block-editor/reference-guides/packages/packages-api-fetch/">apiFetch</a></code> call use the next config object:</p>



<ul class="wp-block-list">
<li>The <code>path</code> and the <code>method</code> properties of the Batch Framework endpoint, <code>batch/v1</code> and <code>POST</code> respectively.</li>



<li>The <code>data</code> property is an object with the property <code>requests</code> which contains an array with the configuration of each one of the requests we want to execute. Each configuration is an object with the required property <code>path</code> and optionally the properties <code>method</code>, <code>headers</code> and <code>body</code>. In this case, these are the configuration to make the requests to <a href="https://developer.wordpress.org/rest-api/reference/posts/#update-a-post" target="_blank" rel="noreferrer noopener">the WordPress endpoint <code>POST /wp/v2/posts/&lt;id&gt;</code></a> to update the posts.</li>
</ul>



<h2 class="wp-block-heading">Handling the response</h2>



<p class="wp-block-paragraph">Finally here is how to handle the response of the request to update meta fields of multiple posts in WordPress. In the React component, I defined the next function:</p>



<pre class="wp-block-code"><code lang="typescript" class="language-typescript line-numbers">const handleBatchResponse = ( batchResponse, requests ) =&gt; {
	batchResponse.responses.forEach( ( requestResponse, idx ) =&gt; {
		// Get the data of the request related to the current response.
		const requestData = requests[ idx ];

		// Check if the response was not successful.
		if ( 200 !== requestResponse.status ) {
			// Show error message here.
		}
	} );
} );</code></pre>



<p class="wp-block-paragraph">The custom function <code>handleBatchResponse</code> expects 2 parameters, the response of the batch request and the array of requests sent in the batch request. This function is called when the response of the request is received and parsed by the <code>apiFetch</code> call. The response of the batch requests is an object with the property <code>responses</code> which is an array of enveloped responses objects for each one of the requests sent in the batch request. Each enveloped response has the properties <code>status</code>, <code>headers</code> and <code>body</code>. The order of the items in the <code>responses</code> array corresponds to the order of the items in the <code>requests</code> array sent in the batch request, so the first object in <code>batchResponses.responses</code> is the response of the first object in the <code>requests</code> array.</p>



<h2 class="wp-block-heading">Conclusion</h2>



<p class="wp-block-paragraph">It is possible to update meta fields of multiple posts in WordPress using a single REST requests. The REST API Batch Framework allows to run multiple requests at once in WordPress. However, take into account that it accepts up to 25 requests in a single batch. Additionally, the framework doesn&#8217;t support GET requests. Using parallel requests or <a href="https://developer.wordpress.org/rest-api/using-the-rest-api/linking-and-embedding/" target="_blank" rel="noreferrer noopener">linking and embedding</a> are the recommendation in this case.</p>
<p>The post <a href="https://carlosguzman.dev/update-meta-fields-of-multiple-posts-in-wordpress-with-the-rest-api/">How to update meta fields of multiple posts in WordPress using a single REST request</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://carlosguzman.dev/update-meta-fields-of-multiple-posts-in-wordpress-with-the-rest-api/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Prevent access to WooCommerce downloadable products in WPEngine</title>
		<link>https://carlosguzman.dev/prevent-access-to-woocommerce-downloadable-products-in-wpengine/</link>
					<comments>https://carlosguzman.dev/prevent-access-to-woocommerce-downloadable-products-in-wpengine/#respond</comments>
		
		<dc:creator><![CDATA[Carlos Guzmán]]></dc:creator>
		<pubDate>Fri, 08 Oct 2021 13:20:07 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[woocommerce]]></category>
		<category><![CDATA[wpengine]]></category>
		<guid isPermaLink="false">https://carlosguzman.dev/?p=215</guid>

					<description><![CDATA[<p>If you are using WPEngine, WooCommerce and you sell digital products, then you might have realized that your downloadable products are public to anyone. You can use redirect rules to protect access to WooCommerce downloadable products in WPEngine. But now it has a feature called web rules that allows you to block access in a [&#8230;]</p>
<p>The post <a href="https://carlosguzman.dev/prevent-access-to-woocommerce-downloadable-products-in-wpengine/">Prevent access to WooCommerce downloadable products in WPEngine</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">If you are using WPEngine, WooCommerce and you sell digital products, then you might have realized that your downloadable products are public to anyone. You can use <a href="https://anchor.host/protecting-static-files-with-php-script-and-wp-engine/" target="_blank" rel="noreferrer noopener">redirect rules to protect access</a> to WooCommerce downloadable products in WPEngine. But now it has a feature called <a href="https://wpengine.com/support/web-rules/" target="_blank" rel="noreferrer noopener">web rules</a> that allows you to block access in a similar way that .htaccess does.</p>



<p class="wp-block-paragraph">First go to the dashboard of your site in WPEngine. Then click on the <strong>Web rules</strong> option at the bottom in the sidebar menu:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img fetchpriority="high" decoding="async" width="250" height="621" src="https://carlosguzman.dev/wp-content/uploads/2021/09/wpengine-site-sidebar-menu.jpg" alt="WPEngine site sidebar menu" class="wp-image-216" srcset="https://carlosguzman.dev/wp-content/uploads/2021/09/wpengine-site-sidebar-menu.jpg 250w, https://carlosguzman.dev/wp-content/uploads/2021/09/wpengine-site-sidebar-menu-121x300.jpg 121w" sizes="(max-width: 250px) 100vw, 250px" /></figure></div>



<p class="wp-block-paragraph">Then you just need to create an access rule to block direct access to the WooCommerce downloadable products in WPEngine:</p>



<div class="wp-block-image"><figure class="aligncenter size-full"><img decoding="async" width="958" height="587" src="https://carlosguzman.dev/wp-content/uploads/2021/09/protect-woocommerce-downloadable-products-in-wpengine.jpg" alt="Protect WooCommerce downloadable products in wpengine" class="wp-image-219" srcset="https://carlosguzman.dev/wp-content/uploads/2021/09/protect-woocommerce-downloadable-products-in-wpengine.jpg 958w, https://carlosguzman.dev/wp-content/uploads/2021/09/protect-woocommerce-downloadable-products-in-wpengine-300x184.jpg 300w, https://carlosguzman.dev/wp-content/uploads/2021/09/protect-woocommerce-downloadable-products-in-wpengine-768x471.jpg 768w" sizes="(max-width: 958px) 100vw, 958px" /></figure></div>



<p class="wp-block-paragraph">When you are creating the new rule, use the next configuration:</p>



<pre class="wp-block-preformatted">Order: 1 (or a lower value order than any rule that could interfere)<br>Action: Deny<br>IP: All<br>Condition type: URI<br>Condition Operator: Regex matches (~)<br>Condition value: wp-content/uploads/woocommerce_uploads/</pre>



<p class="wp-block-paragraph">This configuration blocks the direct access to the files in the WooCommerce uploads folder. When your downloadable products is bought, then WooCommerce gives a link to the customer. Then the customer uses this link to download the product.</p>



<p class="wp-block-paragraph">Do you need help with the configuration of your website? Don&#8217;t hesitate into <a href="https://www.webilop.com/hire-a-wordpress-developer-now/" target="_blank" rel="noreferrer noopener">hire me now</a>.</p>



<p class="wp-block-paragraph">Now that you have protected your files, let&#8217;s see what is the &#8220;issue&#8221;. The summarized explanation is that WPEngine uses <a rel="noreferrer noopener" href="https://www.nginx.com/" target="_blank">Nginx</a> instead Apache as web server. WooCommerce creates an .htaccess file in its upload folder. Apache uses it to block the access to the content in the folder. However, the .htaccess file doesn&#8217;t work in Nginx. This web server works in another way and it is configured in other way. Unfortunately, WooCommerce doesn&#8217;t have a way to make this configuration and only the administrator of the web server can setup the configuration and block the access. Before it was possible to <a rel="noreferrer noopener" href="https://docs.easydigitaldownloads.com/article/683-protecting-file-downloads-on-wp-engine" target="_blank">prevent direct downloads in WPEngine</a> using redirect rules. <a href="https://wpengine.com/support/web-rules/" target="_blank" rel="noreferrer noopener">Now WPEngine has a feature named <strong>web rules</strong></a> that allows us to make this configuration and block the access to some sections in our website easily.</p>
<p>The post <a href="https://carlosguzman.dev/prevent-access-to-woocommerce-downloadable-products-in-wpengine/">Prevent access to WooCommerce downloadable products in WPEngine</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://carlosguzman.dev/prevent-access-to-woocommerce-downloadable-products-in-wpengine/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Responsive dynamic background images in WordPress</title>
		<link>https://carlosguzman.dev/responsive-dynamic-background-images-in-wordpress/</link>
					<comments>https://carlosguzman.dev/responsive-dynamic-background-images-in-wordpress/#respond</comments>
		
		<dc:creator><![CDATA[Carlos Guzmán]]></dc:creator>
		<pubDate>Mon, 19 Oct 2020 12:46:32 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[background-image]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://carlosguzman.dev/?p=177</guid>

					<description><![CDATA[<p>The most common ways to show images in a website are using the HTML tags &#60;img&#62; and &#60;picture&#62; or using the CSS property background-image. There are attributes in the HTML tags to show different images based on the browser viewport. Or you can use media queries to show different images with background-image. You could find [&#8230;]</p>
<p>The post <a href="https://carlosguzman.dev/responsive-dynamic-background-images-in-wordpress/">Responsive dynamic background images in WordPress</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The most common ways to show images in a website are using the HTML tags <code>&lt;img&gt;</code> and <code>&lt;picture&gt;</code> or using the CSS property <code>background-image</code>. There are <a aria-label="undefined (opens in a new tab)" rel="noreferrer noopener" href="https://developer.mozilla.org/en-US/docs/Learn/HTML/Multimedia_and_embedding/Responsive_images" target="_blank" class="yoast-seo-link">attributes in the HTML tags to show different images</a> based on the browser viewport. Or you can use <a aria-label="undefined (opens in a new tab)" rel="noreferrer noopener" href="https://cloudfour.com/thinks/responsive-images-101-part-8-css-images/" target="_blank" class="yoast-seo-link">media queries to show different images</a> with background-image. You could find the article <em><a aria-label="undefined (opens in a new tab)" rel="noreferrer noopener" href="https://nystudio107.com/blog/the-css-background-image-property-as-an-anti-pattern" target="_blank" class="yoast-seo-link">The CSS background-image property as an anti-pattern</a></em> very interesting. If you are using background-image anyway, this article describe how to use it to have a responsive dynamic background images in WordPress.</p>



<p class="wp-block-paragraph">Nowadays one trend is to use eye-catching images at the top of articles and news in websites to draw the attention of visitors. Downloading images in a website is one of the main factors in the speed loading. Large images increase the quantity of data to download. Most of the traffic of websites is done through mobile devices. Optimize the loading of these images is important.</p>



<p class="wp-block-paragraph">WordPress has the field <a aria-label="undefined (opens in a new tab)" rel="noreferrer noopener" href="https://developer.wordpress.org/themes/functionality/featured-images-post-thumbnails/" target="_blank" class="yoast-seo-link">featured image</a> in to link a representative image with an article. Some websites use this image in the header of the article.<mark class="annotation-text annotation-text-yoast" id="annotation-text-c96964d3-be1c-4f5f-91a1-384682d24687"></mark> The next solution also works if the image is not in the featured image field but in a custom field of the article.</p>



<h2 class="wp-block-heading">1. Define the CSS breakpoints</h2>



<p class="wp-block-paragraph">CSS breakpoints define the ranges of device screen width where the content responds in a certain way. In example, the framework <a aria-label="undefined (opens in a new tab)" rel="noreferrer noopener" href="https://getbootstrap.com/docs/4.5/layout/overview/#responsive-breakpoints" target="_blank" class="yoast-seo-link">Twitter Bootstrap defines 4 breakpoints and 5 ranges</a>: extra small, small, medium, large and extra large.</p>



<ul class="wp-block-list">
<li>Extra small screens: &lt;576px</li>



<li>Small screens: ≥576px</li>



<li>Medium screens: ≥768px</li>



<li>Large screens: ≥992px</li>



<li>Extra large screens: ≥1200px</li>
</ul>



<h2 class="wp-block-heading">2. Register image sizes for each screen width range</h2>



<p class="wp-block-paragraph">Each screen width range defined by the CSS breakpoints requires to define the dimensions to show the image in the range. Let’s continue with the example of Twitter Bootstrap. We are using its <a aria-label="undefined (opens in a new tab)" rel="noreferrer noopener" href="https://getbootstrap.com/docs/4.5/layout/overview/#containers" target="_blank" class="yoast-seo-link">containers</a> and we are displaying the image using the full width of the container, then we could define the next dimensions(WxH):</p>



<ul class="wp-block-list">
<li>576&#215;350 for containers in extra small screens</li>



<li>540&#215;350 for containers in small screens</li>



<li>720&#215;350 for containers in medium screens</li>



<li>960&#215;400 for containers in large screens</li>



<li>1140&#215;400 for containers in extra large screens</li>
</ul>



<p class="wp-block-paragraph">The WordPress function <a aria-label="undefined (opens in a new tab)" rel="noreferrer noopener" href="https://developer.wordpress.org/reference/functions/add_image_size/" target="_blank" class="yoast-seo-link">add_image_size</a> registers images dimensions. WordPress creates a cropped version of the image for each registered dimension when an image is uploaded.</p>



<pre class="wp-block-code"><code lang="php" class="language-php">// register image sizes
add_image_size('header-image-xs', 576, 350);
add_image_size('header-image-sm', 540, 350);
add_image_size('header-image-md', 720, 350);
add_image_size('header-image-lg', 960, 400);
add_image_size('header-image-xl', 1140, 400);</code></pre>



<h2 class="wp-block-heading" id="include-image-in-theme">3. Include the image in the theme template</h2>



<p class="wp-block-paragraph">A WordPress theme has different templates for different kind of pages. In this example, we are displaying the images for the articles. Thus we edit the <em>single-post.php</em> template to include the image.</p>



<pre class="wp-block-code"><code lang="markup" class="language-markup">// ... content before the background image

&lt;div class="site-content"&gt;
  &lt;div class="header-image-container"&gt;
    // ... some content over the background image
  &lt;/div&gt;
&lt;/div&gt;

// ... content after the background image</code></pre>



<h2 class="wp-block-heading">4. Include the media queries</h2>



<p class="wp-block-paragraph">When we show the image using background-image, then we need to use CSS media queries to display the images in a responsive way. We can use the WordPress hook <a aria-label="undefined (opens in a new tab)" class="yoast-seo-link" rel="noreferrer noopener" href="https://developer.wordpress.org/reference/hooks/wp_head/" target="_blank">wp_head</a> to include the CSS code in the head of the HTML document. In the function attached to the hook, then we get the featured image of the article and build the media queries. At this point, we have defined the <a href="#include-image-in-theme">HTML structure</a> and we know the CSS selector required to point to the element where the background-image is used.</p>



<pre class="wp-block-code"><code lang="php" class="language-php">// print the background CSS rules
add_action('wp_head', function(){
  // link breakpoints and image sizes
  $images = [
    '0' =&gt; 'header-image-xs',
    '576' =&gt; 'header-image-sm',
    '768' =&gt; 'header-image-md',
    '992' =&gt; 'header-image-lg',
    '1200' =&gt; 'header-image-xl',
  ];
  
  // check if the post/page has a featured image
  if (has_post_thumbnail()) {
    // get the thumbnail images
    array_walk($images, function(&amp;$item) {
        $item = get_the_post_thumbnail_url(get_the_ID(), $item);
    });
    ?&gt;
    &lt;style&gt;
    &lt;?php foreach($args['images'] as $breakpoint =&gt; $image_url): ?&gt;
      &lt;?php if ('0' == $breakpoint): ?&gt;
      .site-content .header-image-container {
        background-image: url("&lt;?= $image_url ?&gt;");
      }
      &lt;?php else; ?&gt;
      @media (min-width: &lt;?= $breakpoint ?&gt;px) {
        .site-content .header-image-container {
          background-image: url("&lt;?= $image_url ?&gt;");
        }
      }
      &lt;?php endif; ?&gt;
    &lt;?php endforeach; ?&gt;
    &lt;/style&gt;
    &lt;?php
  }
});</code></pre>



<p class="wp-block-paragraph">And that’s all. You can find <a aria-label="undefined (opens in a new tab)" class="yoast-seo-link" rel="noreferrer noopener" href="https://wpexperiments.carlosguzman.dev/responsive-background-images/" target="_blank">here</a> a demo of this approach:</p>



<figure class="wp-block-image aligncenter size-large"><a href="https://wpexperiments.carlosguzman.dev/responsive-background-images/" target="_blank" rel="noopener noreferrer"><img decoding="async" width="1024" height="1002" src="https://carlosguzman.dev/wp-content/uploads/2020/10/responsive-bg-images-demo-1024x1002.jpg" alt="Responsive dynamic background images in WordPress" class="wp-image-203" srcset="https://carlosguzman.dev/wp-content/uploads/2020/10/responsive-bg-images-demo-1024x1002.jpg 1024w, https://carlosguzman.dev/wp-content/uploads/2020/10/responsive-bg-images-demo-300x294.jpg 300w, https://carlosguzman.dev/wp-content/uploads/2020/10/responsive-bg-images-demo-768x752.jpg 768w, https://carlosguzman.dev/wp-content/uploads/2020/10/responsive-bg-images-demo.jpg 1280w" sizes="(max-width: 1024px) 100vw, 1024px" /></a><figcaption class="wp-element-caption">Demo of responsive dynamic background images in WordPress</figcaption></figure>



<p class="wp-block-paragraph">You might found useful the library <a aria-label="undefined (opens in a new tab)" rel="noreferrer noopener" href="https://github.com/c24o/wp-responsive-background-image" target="_blank" class="yoast-seo-link">wp-responsive-background-image</a>. I created this library which offer an interface with a couple of methods to allow add the background rules easily. It uses the approach mentioned before to insert responsive dynamic background images in WordPress.</p>
<p>The post <a href="https://carlosguzman.dev/responsive-dynamic-background-images-in-wordpress/">Responsive dynamic background images in WordPress</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://carlosguzman.dev/responsive-dynamic-background-images-in-wordpress/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Datetime or Timestamp: readability matters</title>
		<link>https://carlosguzman.dev/datetime-or-timestamp-readability-matters/</link>
					<comments>https://carlosguzman.dev/datetime-or-timestamp-readability-matters/#respond</comments>
		
		<dc:creator><![CDATA[Carlos Guzmán]]></dc:creator>
		<pubDate>Fri, 12 Jun 2020 20:39:48 +0000</pubDate>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[databases]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://carlosguzman.dev/?p=153</guid>

					<description><![CDATA[<p>When you are designing the schema of the database for your project and you need to store dates and times, then the question about what data type to use appears. Recently, I started a project to build a REST API and I used timestamps, a total mistake. Later, I was applying to a job and [&#8230;]</p>
<p>The post <a href="https://carlosguzman.dev/datetime-or-timestamp-readability-matters/">Datetime or Timestamp: readability matters</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">When you are designing the schema of the database for your project and you need to store dates and times, then the question about what data type to use appears. Recently, I started a project to build a REST API and I used timestamps, a total mistake. Later, I was applying to a job and again I decided to use timestamps in the project to show my skills. During the interview, the recruiter asked me why I decided to use timestamps and I realized that I didn’t make any analysis for this decision. I just wanted to try it…what a mistake.</p>



<p class="wp-block-paragraph">After this, I decided to investigate the pros and cons for the different options to store dates in a database. There are multiple articles about this topic. I want to highlight this <a rel="noreferrer noopener" aria-label="article where it is explained with details, examples and benchmarks using MySQL (opens in a new tab)" href="https://www.vertabelo.com/blog/what-datatype-should-you-use-to-represent-time-in-mysql-we-compare-datetime-timestamp-and-int/" target="_blank">article where it is explained with details, examples and benchmarks using MySQL</a>. Next is a too short summary about the article:</p>



<ul class="wp-block-list"><li>Using <em>DATETIME</em> allows to make SQL queries using functions related to dates(i.e: WEEKDAY in MySQL) in the SQL server. It allows to use dates from year 1000 to 9999. Queries over <em>DATETIME</em> are faster than queries over <em>TIMESTAMP</em>. The format used to print the <em>DATETIME</em> is user friendly and legible.</li><li>Using <em>TIMESTAMP</em> also allows to make SQL queries using functions related to dates. It allows dates until 2038 only. <em>TIMESTAMP</em> is lighter and it saves 1 byte of storage compared with <em>DATETIME</em>. The format used to print the <em>TIMESTAMP</em> is user friendly and legible.</li><li>Using <em>UNSIGNED INT</em> allows dates until 2106. It is not possible to use CURRENT_TIMESTAMP with this data type. SQL queries over INT are much faster than <em>DATETIME</em> and <em>TIMESTAMP</em>. To use date functions, the integer should be converted to a date(using function FROM_UNIXTIME in MySQL). In this case the SQL queries are slower than <em>DATETIME</em>.</li></ul>



<p class="wp-block-paragraph">One of the disadvantages with <em>TIMESTAMP</em> is the limit of 2038. Personally, I think that the SQL servers will change this in order to preserve compatibility with existing software using this datatype. It is not the same with <em>INT</em> because it is a datatype not intended to be used for dates. However there are integer types using more bytes of storage like <em>BIGINT</em> in MySQL.</p>



<p class="wp-block-paragraph">After my experience using timestamps in a REST API, definitely I will use <em>DATETIME</em> in next projects unless performance and storage are critical. When you are debugging, readability matters. When you see a bunch of numbers that not make sense, then you need to expend time converting those numbers to readable dates. Also working in the frontend, sometimes I needed to understand why I was getting those dates and then again it was stressful to see unintelligible numbers in the API response.</p>



<div class="wp-block-image"><figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="322" height="277" src="https://carlosguzman.dev/wp-content/uploads/2020/06/timestamps-in-api-response.png" alt="datetime or timestamp: readability matters" class="wp-image-155" srcset="https://carlosguzman.dev/wp-content/uploads/2020/06/timestamps-in-api-response.png 322w, https://carlosguzman.dev/wp-content/uploads/2020/06/timestamps-in-api-response-300x258.png 300w" sizes="auto, (max-width: 322px) 100vw, 322px" /><figcaption>Timestamps in a REST API response</figcaption></figure></div>



<p class="wp-block-paragraph">In my opinion, using <em>UNSIGNED INT</em> has sense if the performance of the app is critical <strong>AND</strong> you have one or multiple queries that doesn’t require to use date functions and they are in processes that run frequently in the app.</p>
<p>The post <a href="https://carlosguzman.dev/datetime-or-timestamp-readability-matters/">Datetime or Timestamp: readability matters</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://carlosguzman.dev/datetime-or-timestamp-readability-matters/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Running PHPUnit tests in a WordPress plugin with Docker</title>
		<link>https://carlosguzman.dev/running-phpunit-tests-in-a-wordpress-plugin-with-docker/</link>
					<comments>https://carlosguzman.dev/running-phpunit-tests-in-a-wordpress-plugin-with-docker/#comments</comments>
		
		<dc:creator><![CDATA[Carlos Guzmán]]></dc:creator>
		<pubDate>Sat, 25 Apr 2020 15:16:24 +0000</pubDate>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[phpunit]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://carlosguzman.dev/?p=99</guid>

					<description><![CDATA[<p>There are several resource about running PHPUnit tests in a WordPress plugin with Docker. Here I want to share how I do it. You can find the configuration files in Github. I explain how to create the development instance in 5 steps: The folder structure Build a docker image to host the WordPress site Configure [&#8230;]</p>
<p>The post <a href="https://carlosguzman.dev/running-phpunit-tests-in-a-wordpress-plugin-with-docker/">Running PHPUnit tests in a WordPress plugin with Docker</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">There are several resource about running PHPUnit tests in a WordPress plugin with Docker. Here I want to share how I do it. You can find <a href="https://github.com/c4rlosguzm4n/wordpress-docker-dev-environment" target="_blank" rel="noreferrer noopener" aria-label="the configuration files in Github (opens in a new tab)">the configuration files in Github</a>.</p>



<p class="wp-block-paragraph">I explain how to create the development instance in 5 steps:</p>



<ol class="wp-block-list"><li><a href="#the-folder-structure">The folder structure</a></li><li><a href="#build-docker-image-for-wordpress-site">Build a docker image to host the WordPress site</a></li><li><a href="#configure-testing-environment-in-container">Configure the testing environment in your WordPress container</a></li><li><a href="#docker-compose">Docker compose to launch the containers</a></li><li><a href="#run-tests-while-coding">Run tests while coding</a></li></ol>



<h2 class="wp-block-heading" id="the-folder-structure">1. The folder structure</h2>



<p class="wp-block-paragraph">Let&#8217;s start creating a folder to host all the docker configuration files and the WordPress code including the plugin source files.</p>



<figure class="wp-block-image size-large"><a href="https://carlosguzman.dev/wp-content/uploads/2020/04/console-project-wp-docker.png"><img loading="lazy" decoding="async" width="1024" height="404" src="https://carlosguzman.dev/wp-content/uploads/2020/04/console-project-wp-docker-1024x404.png" alt="project folder structure with configuration of wordpress and docker" class="wp-image-110" srcset="https://carlosguzman.dev/wp-content/uploads/2020/04/console-project-wp-docker-1024x404.png 1024w, https://carlosguzman.dev/wp-content/uploads/2020/04/console-project-wp-docker-300x118.png 300w, https://carlosguzman.dev/wp-content/uploads/2020/04/console-project-wp-docker-768x303.png 768w, https://carlosguzman.dev/wp-content/uploads/2020/04/console-project-wp-docker.png 1256w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>How the folder will look at the end</figcaption></figure>



<p class="wp-block-paragraph">This is a picture of how the folder will look at the end. <em>my-project</em> is the root folder of the project. The <em>wordpress-image</em> folder contains the Dockerfile and an the entry point script for the WordPress environment. The <em>wordpress</em> folder contains the files of WordPress and the plugin to work on.</p>



<p class="wp-block-paragraph">I use to run the wp-cli tool as the www-data user instead as root. So I assign www-data as group and my user as owner of the <em>wp-content</em> folder inside the <em>wordpress</em> folder. Then I give write access to the group to the <em>wp-content</em> folder. In this way, www-data is able to write on those files without problem and I can edit the files from outside Docker with my user.</p>



<h2 class="wp-block-heading" id="build-docker-image-for-wordpress-site">2. Build a docker image to host the WordPress site</h2>



<p class="wp-block-paragraph">I built a custom Docker image based on <a rel="noreferrer noopener" aria-label="the official Docker image for WordPress (opens in a new tab)" href="https://hub.docker.com/_/wordpress/" target="_blank">the official Docker image for WordPress</a>. The purpose of this custom image is to setup the development instance to run the unit tests automatically. This file is placed inside the <em>wordpress-image</em> folder. Next is the Dockerfile of the image:</p>



<pre class="wp-block-code"><code>#1. Docker base image
FROM wordpress:php7.4-apache

#2. Install WP-cli and dependencies to run it
RUN apt-get update \
    &amp;&amp; apt-get install -y \
      less \
      subversion \
      sudo \
      default-mysql-client-core \
    &amp;&amp; curl https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar -o /usr/local/bin/wp \
    &amp;&amp; chmod +x /usr/local/bin/wp

#3. Create the files for the testing environment
RUN \
    #3.1 Install phpunit
    curl -L https://phar.phpunit.de/phpunit-7.phar -o /tmp/phpunit \
    &amp;&amp; chmod a+x /tmp/phpunit \
    #3.2 Install wordpress
    &amp;&amp; cp -r /usr/src/wordpress /tmp/wordpress \
    &amp;&amp; curl https://raw.github.com/markoheijnen/wp-mysqli/master/db.php -o /tmp/wordpress/wp-content/db.php \
    #3.3 Install the testing libraries
    &amp;&amp; svn co --quiet https://develop.svn.wordpress.org/tags/5.3.2/tests/phpunit/includes/ /tmp/wordpress-tests-lib/includes \
    &amp;&amp; svn co --quiet https://develop.svn.wordpress.org/tags/5.3.2/tests/phpunit/data/ /tmp/wordpress-tests-lib/data \
    #3.4 set owner and permissions
    &amp;&amp; chown -R www-data:www-data /tmp/wordpress \
    &amp;&amp; chown -R www-data:www-data /tmp/wordpress-tests-lib

#4. Copy the script to create the testing environment when the container is started
COPY init-testing-environment.sh /usr/local/bin/

#5. Run the script and send as an argument the command to run the apache service
ENTRYPOINT &#091;"init-testing-environment.sh"]
CMD &#091;"apache2-foreground"]
</code></pre>



<p class="wp-block-paragraph">The section #1 in the Dockerfile shows the base image used. In this case the container will run WordPress in a Apache web server running PHP 7.4. You can see other options of <a rel="noreferrer noopener" aria-label="images for WordPress in Docker Hub (opens in a new tab)" href="https://hub.docker.com/_/wordpress/" target="_blank">images for WordPress in Docker Hub</a>.</p>



<p class="wp-block-paragraph">The script installs <a rel="noreferrer noopener" aria-label="wp-cli (opens in a new tab)" href="https://wp-cli.org/" target="_blank">wp-cli</a> in the section #2 . This tool is required to create the testing environment to run unit tests with WordPress easily. I run the wp-cli as the www-data user using the sudo package. Subversion downloads the testing libraries in the next section of the script. The mysql client package is used to check the connection to the database in the configuration of the testing environment later.</p>



<p class="wp-block-paragraph">The section #3 creates the files for the testing environment. It is not required to download these files again when the container is started. In this way, there is a saving of data downloaded but mainly the container starts faster. It creates the WordPress instance for testing and download the libraries used by WordPress to run PHPUnit. This section does part of the job of <code>wp scaffold plugin-tests</code> which will be invoked when the container is launched.</p>



<p class="wp-block-paragraph">In sections #4 and #5, the entry point script is copied and its parameters are configured. More about this script follows in the next section.</p>



<h2 class="wp-block-heading" id="configure-testing-environment-in-container">3. Configure the testing environment in your WordPress container</h2>



<p class="wp-block-paragraph">In the Dockerfile above, when the container starts, it runs a custom script instead running the Apache service. This script basically finishes the testing environment if it is not complete yet before launching the Apache service. This script is based on the steps to create <a rel="noreferrer noopener" aria-label="a testing environment in WordPress (opens in a new tab)" href="https://make.wordpress.org/cli/handbook/plugin-unit-tests/" target="_blank">a testing environment in WordPress</a> and it is placed inside the <em>wordpress-image</em> folder.</p>



<pre class="wp-block-code"><code>#!/bin/bash

cd /var/www/html/

#1. check if wordpress is already installed/configured
if (sudo -u www-data -- wp core is-installed)
then

	#2. check if the database is ready
	if ! (sudo -u www-data -- wp db check)
	then
		# wait a moment for the database container
		sleep 1
		exit 1;
	fi

	#3. init the testing instance
	sudo -u www-data -- wp scaffold plugin-tests $WP_PLUGIN_FOLDER --force
	cd wp-content/plugins/$WP_PLUGIN_FOLDER &amp;&amp; sudo -u www-data -- bash -c "./bin/install-wp-tests.sh $WP_TESTS_DB_NAME $WORDPRESS_DB_USER $WORDPRESS_DB_PASSWORD $WORDPRESS_DB_HOST latest true"	
fi

#4. back to the root WP folder
cd /var/www/html/

#5. execute the entrypoint of the parent image
bash docker-entrypoint.sh "$@"</code></pre>



<p class="wp-block-paragraph">The script checks if the WordPress instance is already configured in the section #1. The configuration of the testing environment requires the WordPress site to be already installed. If it is not active, then it skips the sections #2 and #3 and launches the container.</p>



<p class="wp-block-paragraph">In the section #2 of the script, it checks if the WordPress instance have connection to the database. If it is not the case, then it finish with error core but it sleeps for a bit first to give some time to the database to be ready.</p>



<p class="wp-block-paragraph">The section #3 uses <code>wp scaffold plugin-tests</code> to create the configuration for the environment to run PHPUnit. One of the configuration files is install-wp-tests.sh. The install-wp-tests.sh script creates the WordPress instance in the tmp folder by default. I already created this instance in that folder in <a href="#build-docker-image-for-wordpress-site">the previous step</a>. The script doesn’t download the WordPress files again because the WordPress files are already in the folder. The docker compose file, explained in the next step, passes the values for the variables like <em>WP_TEST_DB_NAME</em>  or <em>WORDPRESS_DB_USER</em>.</p>



<p class="wp-block-paragraph">The last 2 sections in the script just move back to the main folder and executes the default entry point of the WordPress Docker image.</p>



<h2 class="wp-block-heading" id="docker-compose">4. Docker compose to launch the containers</h2>



<p class="wp-block-paragraph">The next step is to create a docker file to run easily the backend and the database containers.</p>



<pre class="wp-block-code"><code>version: '3'

services:
    db:
        image: mysql:5.7
        volumes:
            - db-data:/var/lib/mysql
        ports:
            - "3360:3306"
        environment:
            MYSQL_ROOT_PASSWORD: password
            MYSQL_DATABASE: wordpress
            MYSQL_USER: wordpress
            MYSQL_PASSWORD: password

    wordpress:
        depends_on:
            - db
        build: ./wordpress-image
        ports:
            - 8080:80
        restart: on-failure
        volumes:
            - ./wordpress:/var/www/html
        environment:
            WORDPRESS_DB_HOST: db:3306
            WORDPRESS_DB_USER: wordpress
            WORDPRESS_DB_PASSWORD: password
            WORDPRESS_DB_NAME: wordpres
            WP_TESTS_DB_NAME: wptests
            WP_PLUGIN_FOLDER: my-plugin-folder

volumes:
    db-data:</code></pre>



<p class="wp-block-paragraph">The first service in the docker compose file launches the container for the database. It is based on the MySQL Docker image. The values for passwords, database and user names are values that you configure at your wish.</p>



<p class="wp-block-paragraph">The second service is used for the WordPress container. It is based on the custom WordPress image that I created in <a href="#build-docker-image-for-wordpress-site">the step 2 explained previously</a>. This container uses a volume for the root folder of the WordPress instance. The values used to configure the database connection of the WordPress instance should match the values used for the database container. The official WordPress Docker image doesn&#8217;t use the variables <em>WP_TEST_DB_NAME</em> and <em>WP_PLUGIN_FOLDER</em>. <a href="#configure-testing-environment-in-container">The script explained in the step 3</a> uses these custom variables. The first variable is the database name used to run the PHPUnit tests. The second variable is the name of the plugin folder under development and testing.</p>



<p class="wp-block-paragraph">Last to highlight is the directive <em>restart</em> with value on-failure that allows this container to try to be launched again if the script to create the testing instance fails or if there is another problem starting the container. In example, if the database is not ready as we saw in <a href="#configure-testing-environment-in-container">the previous step</a>.</p>



<h2 class="wp-block-heading" id="run-tests-while-coding">5. Run tests while coding</h2>



<p class="wp-block-paragraph">The development and testing environment is ready after all this configuration. First go to the project folder and lunch the containers using <code>docker-composer up</code>. The testing environment will not be configured until you have configured the WordPress site. After lunching the containers by first time, you would need to visit <em>localhost:8080</em> in your browser to setup the WordPress site.</p>



<p class="wp-block-paragraph">The next time you lunch your container, if you have already setup the WordPress site, then the testing environment will be configured automatically. Then you need a bash session in the WordPress container to run the tests:</p>



<figure class="wp-block-image size-large"><a href="https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-bash.png"><img loading="lazy" decoding="async" width="1024" height="556" src="https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-bash-1024x556.png" alt="bash session in the docker container" class="wp-image-134" srcset="https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-bash-1024x556.png 1024w, https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-bash-300x163.png 300w, https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-bash-768x417.png 768w, https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-bash.png 1274w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>Bash session in the WordPress container</figcaption></figure>



<p class="wp-block-paragraph">An alternative is to use composer and install PHPUnit in the plugin&#8217;s source code. In the <a href="#build-docker-image-for-wordpress-site">step 2</a>, I already downloaded it and place it in the <em>tmp</em> folder:</p>



<figure class="wp-block-image size-large"><a href="https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-run-tests.png"><img loading="lazy" decoding="async" width="1024" height="556" src="https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-run-tests-1024x556.png" alt="PHPUnit tests in a WordPress plugin with Docker" class="wp-image-136" srcset="https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-run-tests-1024x556.png 1024w, https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-run-tests-300x163.png 300w, https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-run-tests-768x417.png 768w, https://carlosguzman.dev/wp-content/uploads/2020/04/docker-wp-plugin-environment-run-tests.png 1274w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>PHPUnit tests results</figcaption></figure>



<p class="wp-block-paragraph">If you want to run your tests automatically while you are coding, you could take a look to a previous article where I explain <a href="https://carlosguzman.dev/running-phpunit-tests-automatically/">how to run tests automatically using the bash script watch-and-do</a>.</p>



<p class="wp-block-paragraph">So this is the way I run PHPUnit tests in a WordPress plugin with Docker. You can find <a rel="noreferrer noopener" aria-label="these configuration files in Github (opens in a new tab)" href="https://github.com/c4rlosguzm4n/wordpress-docker-dev-environment" target="_blank">these configuration files in Github</a>.</p>



<p class="wp-block-paragraph"><em>UPDATE(2020-06-17): Change on <a href="#configure-testing-environment-in-container">step 3</a> with a fix in the script.</em></p>
<p>The post <a href="https://carlosguzman.dev/running-phpunit-tests-in-a-wordpress-plugin-with-docker/">Running PHPUnit tests in a WordPress plugin with Docker</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://carlosguzman.dev/running-phpunit-tests-in-a-wordpress-plugin-with-docker/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Running PHPUnit tests automatically</title>
		<link>https://carlosguzman.dev/running-phpunit-tests-automatically/</link>
					<comments>https://carlosguzman.dev/running-phpunit-tests-automatically/#respond</comments>
		
		<dc:creator><![CDATA[Carlos Guzmán]]></dc:creator>
		<pubDate>Sun, 01 Mar 2020 17:30:52 +0000</pubDate>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[phpunit]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://carlosguzman.dev/?p=88</guid>

					<description><![CDATA[<p>I have found test-driven development(TDD) a very interesting development methodology. Just recently I have been applying this in the development of a WordPress plugin. One of the issues during the development was wasting time launching tests manually after making changes to the code. You don’t know what you could do and achieve in those few [&#8230;]</p>
<p>The post <a href="https://carlosguzman.dev/running-phpunit-tests-automatically/">Running PHPUnit tests automatically</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I have found test-driven development(TDD) a very interesting development methodology. Just recently I have been applying this in the development of a WordPress plugin. One of the issues during the development was wasting time launching tests manually after making changes to the code. You don’t know what you could do and achieve in those few seconds. Running PHPUnit tests automatically became important to save those precious seconds. In this post I want to share how to run tests automatically when a change in code is detected.</p>



<p class="wp-block-paragraph">There are multiple options that you could use for running phpunit tests automatically. In example, <a rel="noreferrer noopener" aria-label="phpunit-watcher (opens in a new tab)" href="https://github.com/spatie/phpunit-watcher" target="_blank">phpunit-watcher</a> is a PHP script that you can install in your project easily through composer. In my case, I created <a href="https://github.com/c4rlosguzm4n/watch-and-do">watch-and-do</a>, a bash script and it is now hosted in Github. Honestly I think I didn’t google it well and I didn’t find phpunit-watcher before. But let’s say that I wanted to learn and create a bash script.</p>



<figure class="wp-block-image"><a href="https://carlosguzman.dev/wp-content/uploads/2020/02/console-running-phpunit-automatically.jpg"><img loading="lazy" decoding="async" width="1024" height="610" src="https://carlosguzman.dev/wp-content/uploads/2020/02/console-running-phpunit-automatically-1024x610.jpg" alt="console running phpunit automatically" class="wp-image-90" srcset="https://carlosguzman.dev/wp-content/uploads/2020/02/console-running-phpunit-automatically-1024x610.jpg 1024w, https://carlosguzman.dev/wp-content/uploads/2020/02/console-running-phpunit-automatically-300x179.jpg 300w, https://carlosguzman.dev/wp-content/uploads/2020/02/console-running-phpunit-automatically-768x457.jpg 768w, https://carlosguzman.dev/wp-content/uploads/2020/02/console-running-phpunit-automatically.jpg 1280w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></a><figcaption>Running PHPUnit tests automatically with watch-and-do</figcaption></figure>



<p class="wp-block-paragraph">A testing environment with WordPress configured and running is required in order to run tests for the WordPress plugin. In the official documentation of WordPress, you can find <a href="https://make.wordpress.org/cli/handbook/plugin-unit-tests/">how to create the testing environment for your WordPress plugin</a>.</p>



<p class="wp-block-paragraph">The bash script is based on <a href="https://linux.die.net/man/1/inotifywait">inotifywait</a> to watch and detect changes in the code. This tool can use some filters to notify when a file is created, modified, deleted or moved only:</p>



<pre class="wp-block-code"><code># listen for changes
inotifywait -m -r -q -e modify -e create -e delete -e move --format "%w%f %e" $WATCHDIR</code></pre>



<p class="wp-block-paragraph">When a change is detected, then the script waits for a couple of seconds before launching the tests. Sometimes I am editing multiple files and then I save all of them. With a delay in the script, the test are launched after the last saving instead launching the tests after saving each file:</p>



<pre class="wp-block-code"><code># increase the stock
echo $(( $(cat $STOCK_FILE) + 1 )) &gt; $STOCK_FILE

# sleep for a moment while more changes are detected
sleep $CHANGES_DETECTION_SLEEP

# decrease stock
echo $(( $(cat $STOCK_FILE) - 1 )) &gt; $STOCK_FILE

# if stock is empty (this discard multiple execution)
if [ $(cat $STOCK_FILE) -eq 0 ]
then
    # run tests
    run_tests $@
fi</code></pre>



<p class="wp-block-paragraph">It is important to run the tests in a new process and store its PID because it is used to stop the process if required. Before launching the tests, it is possible that the tests are under execution due to a previous modification of a file. In order to not get conflicts and to not get a mess in the console, it is a good idea to stop the current execution of the tests. We stop the tests using the PID of the process and the kill command with signal SIGTERM. The tests are not stopped immediately, so it is important to wait until they have been stopped:</p>



<pre class="wp-block-code"><code>while [ $LASTPID ] &amp;&amp; [ $LASTPID -gt 0 ] &amp;&amp; (ps -p $LASTPID &gt; /dev/null)
do
    # kill previous testing
    if [ $KILLING -eq 0 ]
    then
        KILLING=1    
        kill -SIGTERM $LASTPID
    fi

    # wait until previous tests are finished
    echo "Wait while current tests are stopped..."
    sleep $TESTS_KILLING_SLEEP
done</code></pre>



<p class="wp-block-paragraph">Finally, when previous tests have been stopped, the new tests are lunched and the PID of its process is stored. The command to run the tests is passed as an argument to the script. In this way the script is not attached to how phpunit is configured in the system:</p>



<pre class="wp-block-code"><code># execute tests
echo "Running command: $@"
$@ &amp;

# store the pid of the thread running the tests
echo $! &gt; $PID_FILE</code></pre>



<p class="wp-block-paragraph">Using the script requires as arguments the folder to watch and the command to run the tests:</p>



<pre class="wp-block-code"><code>$ ./watch-and-do my-base-folder phpunit -v</code></pre>



<p class="wp-block-paragraph">As mentioned before, this script is just an alternative to other tools to watch for changes in your code and run the tests automatically. This bash script is open source and you can find it in Github as <a href="https://github.com/c4rlosguzm4n/watch-and-do">watch-and-do</a>.</p>
<p>The post <a href="https://carlosguzman.dev/running-phpunit-tests-automatically/">Running PHPUnit tests automatically</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://carlosguzman.dev/running-phpunit-tests-automatically/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to see the error logs in WordPress with Docker in Linux</title>
		<link>https://carlosguzman.dev/how-to-see-the-error-logs-in-wordpress-with-docker-in-linux/</link>
					<comments>https://carlosguzman.dev/how-to-see-the-error-logs-in-wordpress-with-docker-in-linux/#comments</comments>
		
		<dc:creator><![CDATA[Carlos Guzmán]]></dc:creator>
		<pubDate>Fri, 24 Jan 2020 17:47:42 +0000</pubDate>
				<category><![CDATA[WordPress]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Web Development]]></category>
		<guid isPermaLink="false">https://carlosguzman.dev/?p=48</guid>

					<description><![CDATA[<p>Recently I was working in the development of a WordPress plugin and I didn&#8217;t find an easy way to see the error logs in WordPress with Docker. I started to read and learn about Docker some few time ago. I created a WordPress development instance using the official Docker image for WordPress in Docker Hub. [&#8230;]</p>
<p>The post <a href="https://carlosguzman.dev/how-to-see-the-error-logs-in-wordpress-with-docker-in-linux/">How to see the error logs in WordPress with Docker in Linux</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Recently I was working in the development of a WordPress plugin and I didn&#8217;t find an easy way to see the error logs in WordPress with Docker. I started to read and learn about Docker some few time ago. I created a WordPress development instance using <a rel="noreferrer noopener" aria-label="the official Docker image for WordPress in DockerHub (opens in a new tab)" href="https://hub.docker.com/_/wordpress" target="_blank">the official Docker image for WordPress in Docker Hub</a>. In some cases, you want to see the log of errors and do not activate the debug mode in WordPress. In example, a plugin can generate warnings that make difficult to debug and that could break responses for Ajax requests in your site.</p>



<p class="wp-block-paragraph">My first attempt to see the error logs was to login in a bash session it the Docker container. Then I searched for the error log file but the errors are sent to the I/O stream STDERR by default.<mark class="annotation-text annotation-text-yoast" id="annotation-text-4058d5b7-636c-4a18-bcd5-ab1e309368af"></mark></p>



<figure class="wp-block-image"><a href="https://carlosguzman.dev/wp-content/uploads/2020/01/default-error-logs-wordpress-docker.jpg"><img loading="lazy" decoding="async" width="892" height="134" src="https://carlosguzman.dev/wp-content/uploads/2020/01/default-error-logs-wordpress-docker.jpg" alt="Default configuration of error logs for WordPress with Docker" class="wp-image-60" srcset="https://carlosguzman.dev/wp-content/uploads/2020/01/default-error-logs-wordpress-docker.jpg 892w, https://carlosguzman.dev/wp-content/uploads/2020/01/default-error-logs-wordpress-docker-300x45.jpg 300w, https://carlosguzman.dev/wp-content/uploads/2020/01/default-error-logs-wordpress-docker-768x115.jpg 768w" sizes="auto, (max-width: 892px) 100vw, 892px" /></a><figcaption>Default configuration of error logs for WordPress with Docker</figcaption></figure>



<p class="wp-block-paragraph">Instead to create a custom image to change this configuration, I tried with the <a rel="noreferrer noopener" aria-label="Docker cli tool to access to the logs of the container (opens in a new tab)" href="https://docs.docker.com/engine/reference/commandline/logs/" target="_blank">Docker cli tool to access to the logs of the container</a>. Using <code>docker logs ID_CONTAINER</code>, I was able to see the logs of the web server. It was progress but it wasn&#8217;t what I want. I got all logs entries of the web server including access and warning entries. It would be difficult to spot the error entries easily in a website loading multiple resources and doing multiple Ajax requests.</p>



<figure class="wp-block-image"><a href="https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs.jpg"><img loading="lazy" decoding="async" width="824" height="500" src="https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs.jpg" alt="Show logs of the Docker WordPress image container." class="wp-image-54" srcset="https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs.jpg 824w, https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-300x182.jpg 300w, https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-768x466.jpg 768w" sizes="auto, (max-width: 824px) 100vw, 824px" /></a><figcaption>Show logs of the Docker WordPress image container.</figcaption></figure>



<h2 class="wp-block-heading">The solution</h2>



<p class="wp-block-paragraph">If we discard the output sent to the standard stream, then the access entries are gone. So using <code>docker logs -f ID_CONTAINER &gt;/dev/null</code>, we get only the entries sent to the error stream. Most of the entries here are the useful entries for debugging, they are the warning and error messages. The option -f in docker logs command is to follow and refresh automatically the logs in the console.</p>



<figure class="wp-block-image"><a href="https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-without-access-entries.jpg"><img loading="lazy" decoding="async" width="828" height="478" src="https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-without-access-entries.jpg" alt="" class="wp-image-56" srcset="https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-without-access-entries.jpg 828w, https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-without-access-entries-300x173.jpg 300w, https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-without-access-entries-768x443.jpg 768w" sizes="auto, (max-width: 828px) 100vw, 828px" /></a><figcaption>Show entries sent to the error stream only</figcaption></figure>



<h3 class="wp-block-heading">Extra tip</h3>



<p class="wp-block-paragraph">If you want to see the error messages only without changing the error reporting directive, you can use the <em>grep</em> tool to filter the other entries. Using <code>docker logs -f ID_CONTAINER 2&gt;&amp;1 &gt;/dev/null | grep -i error</code>, the entries are filtered to display only the lines with the error word in them. This command replaces the output of the standard stream with the output of the error stream. Then <em>grep</em> filters the content. The option -i in the <em>grep</em> command is to be case insensitive in the search.</p>



<figure class="wp-block-image"><a href="https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-only-errors.jpg"><img loading="lazy" decoding="async" width="828" height="341" src="https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-only-errors.jpg" alt="Show only error logs of WordPress with Docker" class="wp-image-57" srcset="https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-only-errors.jpg 828w, https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-only-errors-300x124.jpg 300w, https://carlosguzman.dev/wp-content/uploads/2020/01/console-wordpress-docker-logs-only-errors-768x316.jpg 768w" sizes="auto, (max-width: 828px) 100vw, 828px" /></a><figcaption>Show only error logs of WordPress with Docker</figcaption></figure>



<p class="wp-block-paragraph">Maybe it isn&#8217;t the most elegant but at least it is an effective way to see the error logs in WordPress with Docker.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://carlosguzman.dev/how-to-see-the-error-logs-in-wordpress-with-docker-in-linux/">How to see the error logs in WordPress with Docker in Linux</a> appeared first on <a href="https://carlosguzman.dev">Carlos Guzman</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://carlosguzman.dev/how-to-see-the-error-logs-in-wordpress-with-docker-in-linux/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 
Minified using Disk
Database Caching 48/57 queries in 0.230 seconds using Disk

Served from: carlosguzman.dev @ 2026-07-12 12:31:43 by W3 Total Cache
-->