Blog posts under the Tutorial category https://webdevstudios.com/category/tutorial/ WordPress Design and Development Agency Mon, 15 Apr 2024 15:56:23 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.2 https://webdevstudios.com/wp-content/uploads/2022/07/cropped-wds-icon.white-on-dark-60x60.png Blog posts under the Tutorial category https://webdevstudios.com/category/tutorial/ 32 32 58379230 Having Fun with Query Loop Block https://webdevstudios.com/2023/05/16/query-loop-block/ https://webdevstudios.com/2023/05/16/query-loop-block/#comments Tue, 16 May 2023 16:00:59 +0000 https://webdevstudios.com/?p=25658 The Query Loop block is a powerful tool that brings the WP Loop, a core WordPress function, to the block editor. Introduced in WordPress version 5.8 and continually updated and improved since then, the Query Loop block is a useful way to display a list of posts or other content in the block editor. In Read More Having Fun with Query Loop Block

The post Having Fun with Query Loop Block appeared first on WebDevStudios.

]]>
The Query Loop block is a powerful tool that brings the WP Loop, a core WordPress function, to the block editor. Introduced in WordPress version 5.8 and continually updated and improved since then, the Query Loop block is a useful way to display a list of posts or other content in the block editor. In this article, we will explore the usefulness of the Query Loop block and how to extend its capabilities.

To get started, we will create a plugin to store our code. The quickest way to create a plugin scaffold is by using the WP-CLI command npx @wordpress/create-block loop-patterns, which will generate the necessary files for us.

If you want more information on the create-block script, you can check out the WordPress documentation.

Query Loop Variations

WordPress provides block variations as a way for developers to create custom versions of core blocks. To get started, we will need to create some directories to store our code. We can do this by running a few commands in the terminal.

We begin by creating a simple block variation called simple-query, and adding a CSS folder to store minimal styles. We don’t want to change the theme styles already declared in the theme.json file. To add our code, we will edit the simple-query/index.js file.

We will use the registerBlockVariation() function to register our block variation. If you are unfamiliar with block variations, you can learn more about them here.

This code defines a constant called SIMPLE_QUERY, which is set to the string 'loop-patterns/simple-query'. This constant represents the name of a block variation that is being registered.

The wp.domReady() function is a WordPress function that is called when the DOM (Document Object Model) is fully loaded and ready for manipulation. Inside the wp.domReady() function, the wp.blocks.registerBlockVariation() function is called with two arguments: 'core/query' and an empty object {}.

The wp.blocks.registerBlockVariation() function is used to register a block variation. The first argument is the name of the parent block (in this case, 'core/query'), and the second argument is an object that specifies the properties of the block variation being registered. In this case, the object is empty, so no additional properties are being set for the block variation.

As previously mentioned, the registerBlockVariation() function takes two arguments: the first argument is the name of the parent block, and the second argument is an object that specifies the properties of the block variation being registered. Let’s review the properties of the object.

  1. name: This property specifies the name of the block variation being registered. In this case, the value of the name property is the constant SIMPLE_QUERY, which represents the string 'loop-patterns/simple-query'.
  2. title: This property specifies the title of the block variation. This title will be displayed to the user in the block editor. In this case, the value of the title property is 'Simple Query'.
  3. description: This property specifies a description of the block variation. This description will be displayed to the user in the block editor. In this case, the value of the description property is 'Displays a Simple Query'.
  4. return: This property is a function that specifies the conditions under which the block variation should be displayed to the user. In this case, the function returns true if the namespace variable is equal to SIMPLE_QUERY and the query.postType variable is equal to 'post'. Otherwise, the function returns false.
  5. icon: This property specifies the icon that should be displayed for the block variation in the block editor. In this case, the value of the icon property is 'edit-large', which represents a pencil icon.
  6. attributes: This property is an object that specifies the attributes (i.e., data values) that the block variation should have. In this case, the object is empty, so no attributes are being set for the block variation.

Block Attributes

The next step will be adding our block attributes. Let’s take a look at the Query Loop block attributes.

 

Based on the screenshots, we can add the following to the attributes object in our script:

The attributes object in this code defines the query parameters that will be used to retrieve posts from the WordPress database.

Here is what each attribute does:

  • perPage: The number of posts to be displayed on each page.
  • pages: The number of pages to be displayed.
  • offset: The number of posts to skip before starting to display posts.
  • postType: The type of post to be displayed (e.g., post, page, etc.).
  • order: The order in which the posts will be displayed (either asc for ascending or desc for descending).
  • orderBy: The criteria used to order the posts (e.g., date, title, etc.).
  • author: The ID of the author whose posts will be displayed.
  • search: A search term used to filter the posts that are displayed.
  • exclude: An array of post IDs to exclude from the query.
  • sticky: A value used to include or exclude sticky posts from the query.
  • inherit: A boolean value indicating whether the query should inherit the context of the current page.

These attributes can be used to customize the behavior of the query and fine-tune which posts are displayed.

Finally, we will build our template. We can use the innerBlocks property to build our template by creating nested blocks within the parent block.

In this case, the innerBlocks array has three nested blocks:

  1. The first nested block is an instance of the core/post-template block, which is a template block that can be used to display a single post. The second element of the array is an empty object {}, which represents the attributes of the block. The third element of the array is another array, which represents the content of the block. In this case, the content of the core/post-template block consists of two blocks: the core/post-title block and the core/post-excerpt block.
  2. The second nested block is an instance of the core/query-pagination block, which is used to display pagination links for a list of posts.
  3. The third nested block is an instance of the core/query-no-results block, which is displayed when a query returns no results.

This is what our final code will look like::

Register Our Scripts

Now let’s test our simple query to make sure it is reading our code correctly. To do this, we need to change how we register our scripts in the **loop-patterns.php**file. Replace the existing content with the following:

To make sure you are calling the script correctly, add the following to the src/index.js file:

And make sure that you’re calling the script correctly on src/index.js. Add this:

Let’s visit the block editor and check out our new block variation. See how it appears in the block editor and on the frontend of the site.

While our custom variation is simple, it’s a good starting point. Now that we have a better understanding of how to register a query loop variation let’s create a flip cards variation for the Query Loop block. To create a new flip-cards variation, we can follow the same steps we used to create the previous variation.

This code registers a new block variation for the core/query block calledflip-cards. The variation has a name, title, and description and is only active if the namespace is FLIP_CARDS and the postType attribute of the query object is 'post'. The variation also has a set of attributes, including a className, tagName, and queryobject.

The variation is scoped to the block inserter and does not contain any inner blocks.

Inner Blocks

For our inner blocks, let’s do the following:

This code defines an array of inner blocks for the flip-cards variation of the core/query block. The inner blocks include a core/post-template block, which is locked and has a specific className. The core/post-template block also contains a core/group block, which in turn contains a core/columns block. The core/columns block contains two core/column blocks, which each contain various blocks such as core/post-title, core/post-date, core/post-author, and core/post-excerpt.

The structure of the inner blocks creates a layout with flip cards, where each card has a front and backside. The front side of the card contains a featured image, and the back side contains the post title, date, author, and excerpt. The blocks are nested inside each other to create the desired layout and functionality.

If you’re having trouble understanding how to access the block’s attributes, a helpful resource is the block library on GitHub. Alternatively, you can view the block’s attributes by clicking the Code editor option under the Editor toolbar, or by referring to the attributes we registered earlier.

The same applies to all blocks, I found it very helpful when looking for the attributes.

Adding Styles

The finishing touch will be adding our styles, which are the following:

With all the pieces in place, we can now see the results of our custom query loop variation. In the block editor and on the frontend of the site, we should see:

I hope you’ve enjoyed this tutorial and have learned how to create custom query loop variations in the block editor. With these skills, you can give your content a unique look and feel and customize the Query Loop block to meet your needs. Thanks for following along, and I look forward to seeing what you create!

The post Having Fun with Query Loop Block appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2023/05/16/query-loop-block/feed/ 2 25658
Integrating WP Search with Algolia: Autocomplete and Instantsearch Customization https://webdevstudios.com/2022/10/11/wp-search-with-algolia-autocomplete-instantsearch-customization/ https://webdevstudios.com/2022/10/11/wp-search-with-algolia-autocomplete-instantsearch-customization/#comments Tue, 11 Oct 2022 16:00:53 +0000 https://webdevstudios.com/?p=25467 In the first part of my three-part series, Integrating WP Search with Algolia, I covered settings and index management for a WordPress install. There, I shared details like managing indices settings, as well as controlling when products may or may not get indexed alongside what product data is included. I also covered the results to Read More Integrating WP Search with Algolia: Autocomplete and Instantsearch Customization

The post Integrating WP Search with Algolia: Autocomplete and Instantsearch Customization appeared first on WebDevStudios.

]]>
In the first part of my three-part series, Integrating WP Search with Algolia, I covered settings and index management for a WordPress install. There, I shared details like managing indices settings, as well as controlling when products may or may not get indexed alongside what product data is included.

I also covered the results to be shown for both autocomplete suggestions and instant search, among some other elements. It’s worth reading if you haven’t yet.

Today, however, we are going to focus on template customization for WooCommerce. Specifically, I am referring to the display of your Algolia data on your WordPress website and how to customize the display of returned results.

We will be using the product data discussed in part one of this series.

WP Search with Algolia: Autocomplete and Instantsearch Template Files

When you download WP Search with Algolia, it comes with a couple of template files for both autocomplete and instantsearch. These make for solid defaults with minimal display, but we need to make them more robust and fit our needs.

In order to customize these files safely, we need to copy the autocomplete.php and instantsearch.php files out of /plugins/wp-search-with-algolia/templates/ and into a folder named algolia in your currently active theme.

The plugin will automatically detect their existence from the theme and use those copies instead of the prepackaged versions. This allows you to customize and still update the plugin without losing customization.

Autocomplete

Below is a screenshot of the default autocomplete search when using the TwentyTwenty theme. Here, we can see a heading mentioning the content types being shown, followed by five different products matching our search term.

Each result includes a thumbnail for their product image, product name, and product description.

Picture of the TwentyTwenty theme search field before Algolia autocomplete customization.

We are going to change the listings to include both the price and SKU number next to the product name, and use the short description if available, or else the current description.

For this, we need to edit the autocomplete.php template file, specifically, the section found at Autocomplete.php line 21-33.

Here, we will have a JavaScript variable data that will hold information for each suggestion hit, meaning an individual product. Now, we start making use of all that information we indexed.

The bundled template files make use of the wp.template functionality that ships with WordPress. It uses underscore.js for its templating, and has a mustache-like syntax. Luke Woodward has a great general tutorial for making use of this on your own.

<div class="suggestion-post-attributes">
	<span class="suggestion-post-title">{{{ data._highlightResult.post_title.value }}} - {{ data.sku }} - {{ data.price }}</span>
	<# if ( data.short_desc ) { #>
		<span class="suggestion-post-content">{{ data.short_desc }}</span>
	<# } else if ( data._snippetResult['content'] ) { #>
		<span class="suggestion-post-content">{{{ data._snippetResult['content'].value }}}</span>
	<# } #>
</div>

In the snippet above, I have amended the markup for the “suggestion-post-attributes” wrapper div, starting on line 26, to include a few more things. These values are all on the top level of your product index when looking at the item in the Algolia dashboard.

First, we output the SKU property, followed by the price property. Both are included in the span wrapping of the original post title value, which is getting some extra highlighting from Algolia.

Next, we can use some standard “if statement” logic on the properties to check if we have a value before acting. Here, I have checked to see if we have a short description to show, otherwise it falls back to the original snippet version coming from the full product description.

Below is a screenshot of the final result.

Picture of the TwentyTwenty theme search field after Algolia autocomplete customization.

Other areas of the autocomplete.php template file has spots for customizing details like the autocomplete header, term suggestions, user suggestions, autocomplete footer, and no results template. We are not going to worry about those at the moment.

Towards the very bottom is the JavaScript that is powering everything. For the sake of this post, I won’t be going into details there. What we’ve been concerned about is the display of data coming back from a given query.

Instantsearch

Now that we’ve added some content to the autocomplete suggestions, we will add the same information to our Algolia hits output before we click into a specific result.

Picture of an Algolia InstantSearch hit result, before customization

For this portion, we need to edit the instantsearch.php template file.

The section for this one can be found at Instantsearch.php line 48-68. We are going to insert a new paragraph tag above the excerpt, to conditionally show both the SKU and the current price if we have a value.

<h2><a class="ais-hits--title-link" title="{{ data.post_title }}" href="{{ data.permalink }}">{{{ data._highlightResult.post_title.value }}}</a></h2>
<# if ( data.sku || data.price ) { #>
	<# if ( data.sku ) { #>
		<span class="is-hit-sku">SKU: {{data.sku}}</span> |
	<# } #>

	<# if ( data.price ) { #>
		<span class="is-hit-price">Price: {{data.price}}</span>
	<# } #>
<# } #>

<# if ( data.taxonomies.product_cat ) { #>
	{{{data.taxonomies.product_cat}}}
<# } #>
<div class="excerpt">

To help keep our markup clean, we are only going to output anything if we have either a SKU or a price value. Once we know we have something, we output some span markup for each data item we have.

For easier styling, we have included some custom classes. To top off our instantsearch customizations, we’re going to output the product category for each.

Picture of an Algolia InstantSearch hit result, after customization

Template Summary

These template edit examples are definitely minor but show how to take a given Algolia hit and modify the output for each. The data object variable is going to be the key here.

As a reminder, when viewing your index in the Algolia Dashboard and index explorer, each part of a given object is available via that data variable. Some parts may be top level like data.post_title, while others may be a bit more nested like you see in the images. For example, data.images.thumbnail found in use in the template files, but not as part of our code examples above.

Our journey through integrating WP Search with Algolia is not complete. Coming up next in this series, I’ll discuss facet widget customization. Be sure to come back to this blog.

The post Integrating WP Search with Algolia: Autocomplete and Instantsearch Customization appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2022/10/11/wp-search-with-algolia-autocomplete-instantsearch-customization/feed/ 2 25467
Debugging WordPress Using Xdebug, Local, and VS Code https://webdevstudios.com/2022/10/06/debugging-wordpress/ https://webdevstudios.com/2022/10/06/debugging-wordpress/#comments Thu, 06 Oct 2022 16:00:51 +0000 https://webdevstudios.com/?p=25376 This post covers debugging WordPress using Xdebug, Local, and VS Code. This approach to debugging is far superior to logging variables to the error log or to the screen. Getting things set up correctly can be tricky. That’s where this tutorial helps. Xdebug Xdebug is a powerful tool for debugging PHP applications. It conveniently comes Read More Debugging WordPress Using Xdebug, Local, and VS Code

The post Debugging WordPress Using Xdebug, Local, and VS Code appeared first on WebDevStudios.

]]>
This post covers debugging WordPress using Xdebug, Local, and VS Code. This approach to debugging is far superior to logging variables to the error log or to the screen.

Getting things set up correctly can be tricky. That’s where this tutorial helps.

Xdebug in action

Xdebug

Xdebug is a powerful tool for debugging PHP applications. It conveniently comes bundled with Local.

We’re using VS Code for our code editor in this tutorial, as well as some other tools I’ve listed below. Everything included here is the current release and version numbers are noted just in case it might be helpful since things change.

Prerequisites

  • Local v6.4.2+6012: A local WordPress development environment, formally known as Local by Flywheel
      • PHP v7.4.1/v7.3.5/v8.0: Selectable via the Local UI. Choose v7.4.1 or v 7.3.5 for now because PHP 8 has a different Xdebug setup we’ll cover at the end of the article.
  • VS Code v1.70.2: Code editor
  • PHP Debug by Xdebug for VS code v1.27.0: VS Code extension which allows VS Code to talk to Xdebug
  • Xdebug Helper browser extension: Used for explicitly enabling or disabling debugging sessions

I use Windows because that’s what makes me happy, but this guide applies to other environments as well. I just wanted to note that, since the paths I’ll be referencing are Windows-y.

Create a Site in Local

Once all of the prerequisites have been installed and activated, you’ll need to create a new WP site in Local if you don’t have one already. When PHP Versions 7.3.x or 7.4.x are selected in Local, Xdebug Version 2 is used.

When PHP Version 8 is selected, Xdebug Version 3 is used. We’re going to use PHP Version 7.4.1 to start off with and will cover PHP Version 8 at the end of the article.

I’ve named my site xdebugvscode.test. Here are its settings:

Local site settings

Set Up php.ini.hbs Directives

Now that the site has been created, let’s double-check the Xdebug configuration directives in the site’s php.ini.hbs file. This file is located under your site’s conf/php directory.

For me, the path is D:devlocal-sitesxdebugvscodeconfphpphp.ini.hbs. Scroll to the bottom of the file under the [xdebug] section, and verify that you have the directives below set accordingly. If you need to make any changes, be sure to restart your Local site.

; Enable remote debugging.
xdebug.remote_enable=1

; If enabled, the xdebug.remote_host setting is ignored and
; Xdebug will try to connect to the client that made the HTTP request.
; It checks the $_SERVER['HTTP_X_FORWARDED_FOR'] and $_SERVER['REMOTE_ADDR'] variables to find out remote IP
xdebug.remote_connect_back=Off

; Set the port that Xdebug connects to.
xdebug.remote_port="9000"

; Disable the profiler.
xdebug.profiler_enable=0

; Set the profiler's output directory for when we're profiling.
xdebug.profiler_output_dir = "D:/dev/xdebug-profiler-output"

A Note About the php.ini.hbs File When Switching PHP Versions

If you ever change the PHP version for your Local site, Local will save the settings for the previous install of PHP under the {local-site-dir}/conf/php/php-{version-number}directory.

For example, I started out with PHP Version 7.4.1 installed, then switched to PHP Version 7.3.5. Local made a copy of my PHP Version 7.4.1 settings under D:devlocal-sitesxdebugvscodeconfphp-7.4.1.

If you change PHP versions and made any modifications to Local’s php.ini.hbs file, you’ll need to make the changes again, if this is the first time the PHP version has been activated. After that, if you swap between PHP versions, your setting changes will be preserved.

Ensure Xdebug Is Running

To make sure that Xdebug is running, create a file named pi.php in the root of your site and add the following code to it:

<?php
// Output information about PHP's configuration.
phpinfo();

location of the ph.php file

Now load up https://yoursite.test/pi.php and make sure that Xdebug is running. Find the Xdebug section; it will look something like this:
php_info() output
If you’re not seeing this, then Xdebug is not running. Double-check the php.ini.hbs file to ensure that Xdebug is enabled.

Activate Xdebug Helper Browser Extension

Once you’ve installed and activated the Xdebug Helper extension for your preferred browser, make sure to enable debugging by clicking on the icon and selecting Debug. The little bug icon will turn green letting you know that the browser extension will set the appropriate flag to turn on debugging.

Enable the Xdebug helper extension

Open Local Site in VS Code and Save a Workspace

Once the site has been created, go to File > Open Folder in VS Code, then navigate to the site’s directory. Now, save the workspace by going to File > Save Workspace As… and then give the workspace a name.

Install and Activate PHP Debug Extension for VS Code

The PHP Debug extension for VS Code helps to bring everything together. Locate the extension in VS Code’s Extension Browser, and activate it. Make sure to select the one published by the Xdebug team, since there are a few extensions with the same name.

PHP debug extension for VS Code

 

Create a launch.json File for Your Workspace

Next, we will create a launch.json file for our workspace. Click on VS Code’s debugging icon to open the debugging panel, then click on the create a launch.json file link.

Create launch.json step 1

Now select the name of your workspace which you created earlier.

Create launch.json step 2

VS Code will populate the launch.json file with defaults, but we’re going to replace them.

Create launch.json step 3

Go ahead and delete the entire contents of the default launch.json, replace the contents with the settings below, then save the file.

The launch.jsonwill be stored at {local-site-name}/.vscode/launch.json. So, mine is saved at D:devlocal-sitesxdebugvscode.vscodelaunch.json.

 

{
  // Use IntelliSense to learn about possible attributes.
  // Hover to view descriptions of existing attributes.
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Listen for Xdebug",
      "type": "php",
      "request": "launch",
      "port": 9000,
      "log": false,
      "maxConnections": 1, // @see  https://github.com/xdebug/vscode-php-debug/issues/604
      "xdebugSettings": {
        "resolved_breakpoints": "0", // @see https://github.com/xdebug/vscode-php-debug/issues/629 and https://stackoverflow.com/a/69925257/3059883
        "max_data": 512,
        "show_hidden": 1,
        "max_children": 128
      }
    }
  ]
}

When using Local’s PHP Version 7.3.x or 7.4.x, the version of Xdebug in use will be 2.9.0, which had a bug that caused some weirdness with breakpoints. I’ve added some links to the config file above which go into some more detail if you’re interested.

Check out the PHP Debug extension’s Github page for more information about supported settings.

Add a Breakpoint to Your Code

For the purposes of this debugging WordPress demo, I’m going to add a breakpoint to line 48 of  Twenty Twenty-Two’s functions.php file.

To add a breakpoint, hover over the gutter (just to the left of a line number) and a little orange dot will appear. Click it to add a breakpoint.

Click it again to remove it. You can add multiple breakpoints, and the debugger will stop on each one. To keep things simple here, I’ll just add the one.

Adding a breakpoint

Once your breakpoint has been added, you will see it listed in the lower left-hand corner of  VS Code’s debugger panel. It’s also possible to set breakpoints on Notices, Warnings, Errors, etc., but we’ll uncheck all of those for this example.

Debugger breakpoints

Start Debugging WordPress

We’re finally ready to start debugging WordPress! Open VS Code’s debugger panel and click the green triangle to start listening for Xdebug. Use the F5 shortcut.
Start debugging
Once VS Code is listening for Xdebug, the Debugger Controls window will be displayed. The bottom of the VS Code window will turn orange.

Listening for debugger

Now Xdebug is waiting to start the session. To kick things off, just load a page that will hit the breakpoint.

I’m just going to load the homepage of the test site I created. Once I hit refresh on the homepage of the test site, VS Code will be highlighted in the taskbar and the debugger will stop executing code on the breakpoint that I had previously set.

Once a debugging session has started, additional controls will be active on the Debugger Control Panel, and variables will be listed under the VARIABLES section of the Debugging Panel.

Inside a debugging session

We can now use the Debugger Controls to navigate through the codebase:

Debugger Controls

  • Pause/Run (F6): Resumes code execution. Debugger will stop on the next breakpoint if set.
  • Step Over (F10): Steps over a block of code.
  • Step Into (F11): Steps into a block of code.
  • Step Out (Shift + F11): Steps out of a block of code that was previously stepped into.
  • Restart (Ctrl + Shift + F5): Restarts the debugging session.
  • Stop (Shift+F5): Halts execution of the script.

The GIF at the top of this article demonstrates some basic usage of these controls.

Exploring Variables

We can also explore the values of local and global variables using the VS Code’s VARIABLES section within the Debugging Panel.

Exploring variables

PHP Version 8 + Xdebug Version 3 Set Up

When a Local site is configured to use PHP Version 8.X, the bundled version of Xdebug will be Version 3, and there are many changes from Versions 2 to 3.

These changes are covered thoroughly in this guide. Notably, Xdebug Version 3 defaults to port 9003 instead of 9000. I’m going to switch my Xdebug Version 3 setup to use port 9000 for consistency, so I don’t have to change anything in my launch.json file.

Here are the Xdebug directives in my PHP Version 8 site’s php.ini.hbs file. Note that I’ve commented out the line xdebug.start_with_request.

xdebug.mode=debug
xdebug.client_port="9000"
; xdebug.start_with_request=yes
xdebug.discover_client_host=yes

Now that we’ve switched our site to PHP Version 8 if we check the output of our pi.php file that we created earlier, we can see that Xdebug Version 3 is now loaded, where Version 2.9.0 was being used under our PHP Versions 7.3 and 7.4 sites.

Xdebug version 3

One of the cool features that comes bundled with Xdebug Version 3 is the addition of the xdebug_info() function. This is similar to the php_info() function, but it provides more detailed diagnostics for about the Xdebug setup.

To use it, simply add a file to your site’s web root. For example, xdebug-info.php , then add the following contents:

<?php
xdebug_info();

Load that file up in your browser, and you’ll see something like this:

xdebug_info output - debugger not listening

In the screenshot above, the diagnostics log is indicating a problem connecting to the host on port 9000. The reason for this is that I have not enabled VS Code to listen for debugging.

So, I tap F5 to enable debugging, and now when I reload my xdebug-info.php, the Diagnostics Log is clean, and I’m ready to debug. Thanks to fellow WebDevStudios Backend Engineer, Biplav Subedi, for this tip!

xdebug_info output - debugger is listening

Troubleshooting

One common issue that comes up when you’re debugging WordPress is that the debugger does not stop on the breakpoint that you’ve set. This is typically caused by a port conflict—some other process is already using the port that you’ve configured for debugging.

Make sure that no other application is using the port that was configured in the php.ini.hbs and launch.json file. If an application is already using the port you’ve specified, make sure to change your port to something that’s not in use.

To check for a port conflict, end your debugging session in VS Code then run the following command:

Windows CMD: netstat -an | find "9000"

Linux/Mac: sudo netstat -nap | grep ":9000"

You should not see any output after entering these commands. If you do, that means that a process is already using the port you’ve configured for Xdebug (9000) in our example. So you should either configure a different port in your php.ini.hbs and launch.json files, or locate the process that is tying up the port, and stop it/configure it to use a different port.

Bonus: Quick and Dirty Debugging

Sometimes, instead of using Xdebug, I prefer to simply log variables to WP’s error.log file using PHP’s error_log().

I find this handy for real quick stuff, though it’s really not the best way to debug WordPress when things get serious. For this setup, first, add the following statements to your site’s wp-config.php file:

define( 'WP_DEBUG', true ); // Debugging mode activated.
define( 'WP_DEBUG_LOG', true ); // Logs to wp-content/debug.log
define( 'WP_DEBUG_DISPLAY', false ); // Don't add errors to the output.
define( 'SCRIPT_DEBUG', true ); // Load un-minified scripts.

Now, errors will be logged to your site’s wp-content/debug.log file. I typically keep this file open in a side panel of VS Code.

error logging to debug.log

I usually use this one-liner to output values to the debug.log file:  error_log( '$variable_name ' . var_export( $variable_name, true ) );

To make things easier, I trigger this one-liner using a VS Code User Snippet with the trigger logv. Here’s a copy of the debugging-related snippets I use. These are configured in VS Code under File > Preferences >  Configure User Snippets > PHP.

{
// Place your snippets for php here. Each snippet is defined under a snippet name and has a prefix, body and
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the
// same ids are connected.
// Example:
// "Print to console": {
// "prefix": "log",
// "body": [
// "console.log('$1');",
// "$2"
// ],
// "description": "Log output to console"
// }
"Log var_export()": {
"prefix": "logv",
"body": ["error_log( '$1 ' . var_export( $2, true ) );"],
"description": "Do a var_export( $variable ) to PHP error log."
},
"Log print_r()": {
"prefix": "logp",
"body": ["error_log( print_r( $0, true ) );"],
"description": "Do a print_r( $variable ) to PHP error log."
},
"Exit with var_dump()": {
"prefix": "xvd",
"body": ["exit( var_dump( $0 ) );"],
"description": "Exit with var_dump()"
},
"Exit with print_r()": {
"prefix": "xpr",
"body": ["exit( print_r( $0 ) );"],
"description": "Exit with print_r()"
},
"Detailed Error Log": {
"prefix": "logd",
"body": [
"error_log( print_r( (object)",
"t[",
"tt'line' => __LINE__,",
"tt'file' => __FILE__,",
"tt'dump' => [",
"ttt$0,",
"tt],",
"t], true ) );"
],
"description": "Detailed error logging"
},
"Log gettype()": {
"prefix": "logt",
"body": ["error_log( gettype( $0 ) );"],
"description": "Do a gettype( $variable ) to PHP error log."
},
"Debug Filters": {
"prefix": "logf",
"body": ["add_action( 'all', function() { error_log( var_export( current_filter(), true ) ); } );"],
"description": "Logs current filter."
}
}

Conclusion

That’s about it for this post on debugging WordPress using Xdebug, Local, and VS Code. Using Xdebug, you’ll be able to more efficiently and effectively debug code. If you’ve never used it before, I’m sure you will find that Xdebug is a helpful tool in your development arsenal.

The post Debugging WordPress Using Xdebug, Local, and VS Code appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2022/10/06/debugging-wordpress/feed/ 6 25376
Adding Custom Notices for the Gutenberg Editor https://webdevstudios.com/2022/07/19/custom-notices-gutenberg/ https://webdevstudios.com/2022/07/19/custom-notices-gutenberg/#respond Tue, 19 Jul 2022 16:00:13 +0000 https://webdevstudios.com/?p=25219 WordPress admin notices have changed and the good old PHP-based hooks no longer work for Gutenberg. This post covers the easy way to add admin notices when a post gets added or updated.

The post Adding Custom Notices for the Gutenberg Editor appeared first on WebDevStudios.

]]>
Change is the only constant, and developers all know it. WordPress admin notices have changed and the good old PHP-based hooks no longer work for Gutenberg.

This blog post covers the easy way to add admin notices when a post gets added or updated, focusing mainly on the Gutenberg notices.

Gutenberg Notices

Let’s start with this working example and customize it to your needs.

Hook into save action.

Here we are using the publish_post action to add our callback after every time a post gets saved. Add a did_action check to make sure this callback executes on the first time and doesn’t repeat.

Other plugins or customizations may also use this action hook, so it is recommended to perform this did_action check.

View the code on Gist.

Set the message on the callback.

Here is an example of a typical editorial workflow:

  • Author submits a blog post
  • Saved as Draft
  • Editor approves and publishes

The background action is sending email notifications to the author when the post gets published. Let your callback process the data and return the message you want to show in the notice. To keep this data easily accessible, we are using post meta.

View the code on Gist.

Create a custom endpoint.

Register an endpoint using register_rest_route. We will be using the namespace and route during the AJAX call.

View the code on Gist.

AJAX call

Now that we have an error message on meta, we have to fetch it via an AJAX request. To keep this simple, the admin script is added directly along with the PHP code. You can make it a separate file and enqueue it.

We need ‘subscribe’ and ‘select’ from WP data module.

const { subscribe,select } = wp.data;

Subscribe allows you to listen to changes in the state. By subscribing to isSavingPost(), you can call the AJAX request.

We are sending the post ID to the custom REST endpoint and displaying the message via createNotice.

View the code on Gist.

Get the error and render it.

Now we have the error, custom endpoint, and the AJAX callback. Retrieve the message from post_meta and send it to the response.

View the code on Gist.

Here is the plugin with the complete code in the repo. I hope you find this quick tip useful. Follow our blog for more WordPress tutorials.

The post Adding Custom Notices for the Gutenberg Editor appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2022/07/19/custom-notices-gutenberg/feed/ 0 25219
Let’s Create an FSE Theme https://webdevstudios.com/2022/07/05/create-fse-theme/ https://webdevstudios.com/2022/07/05/create-fse-theme/#comments Tue, 05 Jul 2022 16:00:43 +0000 https://webdevstudios.com/?p=24474 A lot has changed since the last time I wrote about Full Site Editor. With the arrival of WordPress 6.0, the Full Site Editor (FSE) has matured for the better. Perhaps the most obvious update is the UI, along with a new set of blocks, on top of other improvements. The minimum requirements to create Read More Let’s Create an FSE Theme

The post Let’s Create an FSE Theme appeared first on WebDevStudios.

]]>
A lot has changed since the last time I wrote about Full Site Editor. With the arrival of WordPress 6.0, the Full Site Editor (FSE) has matured for the better. Perhaps the most obvious update is the UI, along with a new set of blocks, on top of other improvements.

The minimum requirements to create a custom theme and how some of the new blocks work for the page creation have also been tweaked. Before 6.0, we needed to have the Gutenberg plugin installed and a block-based theme. Now, we only need a block-based theme.

You can start downloading an empty starter. Begin with this GitHub repo. This starter theme was made by Carolina Nymark. She has really great material on FSE. Check out her other work.

Open your favorite IDE and open your theme files. If you use localWP, you can spin up a local WordPress install. Now, add your theme and activate it.

We are going to build a simple home page for our theme, with a minimum amount of code. Thanks to theme.json and the Full Site Editor, let’s look at what we are going to build. This is a basic mockup I made with Figma:

We have a Header, a Footer, and some common sections that we will turn into Template Parts and  Block Patterns, as well as our colors, font sizes, and font family—all of which we are going to add to our theme.json.

theme.json

The first step, once we got our blank theme up and running, is to set our global styles. Let’s add some colors and font styles.

If it’s your first time working with theme.json, I encourage you, before you continue, to check the official documentation and get a grasp of what you can do.

Our color palette will look like this:

 

So on our theme.json, we do the following: on the settings object, we have our colors object. Let’s add our primary color:

This results in the generation of the CSS variable in the body of the website: --wp--preset--color--black: #D63E4B;.  Follow the same pattern and add the rest of the colors ( Secondary: #48655E, Tertiary: #59BDB4, Black: #333333, and White: #FFFFFF ).

This will generate our color palette. Go to your dashboard and open your Full Site Editor. Open the styles toolbar and click on the colors tab. There is our theme color palette:

We can also disable the default and custom colors by adding this  "defaultPalette": false,"custom":false, to the colors object.  Setting up our font sizes and styles is similar to how we add our colors. We will update the typography object on our theme file.

As with the colors, WordPress programmatically will create --wp--preset--font-family--helvetica-arial: Helvetica Neue, Helvetica, Arial, sans-serif; will generate the CSS Variable on the body of our website, and on the Full Site Editor, our typography is registered.

Follow the same pattern and add these sizes: 14, 18, 20, 24, 28, and 40px. When ready, save your theme.json file and open your Full Site Editor. Open the styles bar, and you will get your font family and font sizes.

Let’s take a look what theme.json has created for us. On your website, open the inspector tool. On the Styles Panel, take a look on your body element properties.

inspector controls

Excellent! We now have CSS variables with our values, globally available,  fonts and colors, and there are more settings for gradients, duotones, line-heights, borders, etc.

For the sake of this article, we are going to keep it simple. Lets’s take a look at how we can apply these styles to our elements and blocks.

First, we go back to our theme.json file on our IDE. We will add some properties to the styles, some spacing to our blocks, our typography, and default font sizes.

If we go back to our inspector tools, we can see the body has now our properties. You can use theme.json to adjust the styles to elements and blocks. Don’t forget to check the documentation to better understand what you can do with it.

Styling Blocks

Applying these styles to our blocks can also be done using the FSE editor. Open the styles tab, and let’s add some global styles to our buttons.

Here, we can set the typography, colors, and layout that the buttons will use. Follow the example below. Once you’re ready, hit save. It will let you know you’re adding a custom style. Save again.

So now, our default button is styled and looking like this on the backend/frontend. Using the inspector tool on our website, we can check the generated styles and our CSS Variables:

You can apply these styles to your blocks also on your theme.json. Following the same pattern, open your IDE,  and on the styles object:

Now that we get to know better theme.json ,  we can now focus on our Block Patterns.

Block Patterns

Our Hero, the Latest Post section, and our Call To Action section can be patterns. So, first of all, what are patterns?

Block Patterns are predefined block layouts available from the patterns tab of the block inserter. Once inserted into content, the blocks are ready for additional or modified content and configuration.

This feature in WordPress is super handy and it also has its own library. So, you can grab and use it, similar to how you add a theme or a plugin.

To build the Hero, we are going to use the cover block. With an inner group block, add a Heading (H1) a Paragraph, and a Button. Remember, we already set up all our styles via theme.json. All the settings can be added using the Full Site Editor. It should look similar to this:

Hero Block

Our pattern looks like the one on our mockup. There is no way we can add the patterns via the editor, similar to how we add template parts or reusable blocks.

You can use a plugin There are a few on the plugin repo  or you can create your own programmatically.

Once your block is ready, select the block. Open the sidebar options on the block options and select copy. This will copy the block markup. Go back to your IDE and open your  theme. Create a directory, name it patterns, add a new file hero.php and paste the markup.

Notice that we not only need to add the markup, but we also need to declare our pattern to let WordPress know what to do with this file. Similar to how we declare our templates, we declare the title, the slug, and categories. You can get more details on the official documentation. Click the Block Inserter, and there is our Hero Pattern:

Awesome! There is also one other pretty neat feature on theme.json. You can also declare patterns from the block pattern library. The patterns field is an array of pattern slugs and you can get the pattern slug from the URL in a single pattern view at the Pattern Directory. For example:

Sweet. Now, that we know how to create patterns, it is time to create the Latest Posts pattern. We are going to use the query loop block to show our three latest posts, with post image, post title, and the excerpt.

To get more on this super handy block, what do we do? Head to the official documentation.

Go ahead and do it yourself with what you learn in our previous example, but here is the gist in case you need it. I’m pretty sure you won’t. Our Latest Posts pattern looks like this:

Query Block PAttern Example

Go ahead and create the final pattern. Again, you can build it yourself with what you learn so far. In case you need it, here is the gist for our final pattern.

Creating a Template

Now that we have our patterns, the next step will be to glue them to our templates. Open your Full Site Editor. Under templates, we have the index from our theme files.

We are going to create a new template by clicking on the Add New button. It will display a list of options that follows the WordPress Template Hierarchy. Select Front Page.

The first thing we are going to do is add our Template Parts, our Heading, and Footer. We have these parts already on our theme files, and most importantly, the Post Content Block.

Following our mockup design, click on the Block Inserter. On Patterns, add our own. It will look like this:

Now, we need to add some content to our homepage for the Subject of the page. Open a page and add your content. Copy what we have on the mockup.

Once that is ready, save it. Go to the dashboard, click on SettingsReading > then select your new page as Homepage. Save it and open your website.

We are getting closer… really close. I will say, we need to add a few styles here and there, but we manage to get really close to the mockup without a single line of CSS.

With the help of theme.json we add global styles, colors, fonts. And with the help of the Full Site Editor and the Block Patterns, we create our template and some patterns that we can use across our site—not only when templating, but also when creating posts and pages.

So far, we have just created the Front Page template, but is up to you to create the rest of the templates needed for your theme.

Exporting My Theme

Yes, you can build themes locally with the help of the Full Site Editor and also export it and ship it. Since we are creating a theme, before exporting, we still need to enqueue some custom styles that we need for our theme.

From here, there are many options. You can add wp-scripts or any task runner to your theme. For now, I will only enqueue a basic stylesheet.

Back to your IDE. Create a new directory for our styles. Name it css. Create a CSS file (named as you like) and paste these styles. To enqueue styles on a block-based theme, use the traditional way and add it to your theme’s functions.php file.

Now, here is our theme with the styles. Pretty good.

Great! We just completed our task, created our landing page, and it is also responsive by default. Now, let’s export our theme.

On the Full Site Editor, click on the three dots on the top bar to open the settings bar. Click on the option to export your site:

This will generate a .zip file ready to ship. Go ahead and add your theme and try it out. Here is the repo of the generated theme.

This is just a basic example of what you can do with the new Full Site Editor. I’m really excited about this new way of building themes. There are a lot of documentation, tutorials, and humans that are doing really great things with WordPress.

Thank you for taking the time to read this article. See you next time!

The post Let’s Create an FSE Theme appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2022/07/05/create-fse-theme/feed/ 2 24474
Quick Tip: Change PHP Versions with Homebrew on Apple Silicon Powered Macs https://webdevstudios.com/2022/02/03/change-php-versions-with-homebrew/ https://webdevstudios.com/2022/02/03/change-php-versions-with-homebrew/#comments Thu, 03 Feb 2022 17:00:52 +0000 https://webdevstudios.com/?p=24659 When you change PHP versions with Homebrew, it makes managing packages on macOS easier. However, Apple’s new silicon is based on ARM64 architecture. This means that not every package or app can run natively (yet). Thankfully, Rosetta 2 helps bridge the gap by “translating software” so it can run on this new architecture. First, let’s Read More Quick Tip: Change PHP Versions with Homebrew on Apple Silicon Powered Macs

The post Quick Tip: Change PHP Versions with Homebrew on Apple Silicon Powered Macs appeared first on WebDevStudios.

]]>
When you change PHP versions with Homebrew, it makes managing packages on macOS easier. However, Apple’s new silicon is based on ARM64 architecture. This means that not every package or app can run natively (yet). Thankfully, Rosetta 2 helps bridge the gap by “translating software” so it can run on this new architecture.

First, let’s talk about the importance of updating PHP.

Keeping the version of PHP updated in your development environment is of paramount importance for several compelling reasons:

  • Security: Outdated PHP versions are more vulnerable to security threats.
  • Performance: Newer PHP versions often come with performance improvements and optimizations.
  • Compatibility: As PHP evolves, new features and functions are introduced. By using the latest version, you can benefit from these improvements.
  • Bug Fixes: PHP updates include bug fixes that address issues present in earlier releases.
  • Long-Term Support: PHP versions are typically supported for several years. Staying up to date ensures access to supported releases.
  • Community Support: A community of developers and experts actively contributes to the PHP ecosystem.
  • Future-Proofing: By adopting the latest PHP versions, you prepare your codebase for future technologies and trends.

Ready to change PHP versions with Homebrew? Keep reading to see how I did it.

Using Homebrew

While setting up my new MacBook Pro, I ran into this error while trying to install PHP 7.4:

brew install php@7.4
Error: Cannot install under Rosetta 2 in ARM default prefix (/opt/homebrew)!
To rerun under ARM use: arch -arm64 brew install ...

Turns out, PHP 7.4 wanted nothing to do with Rosetta, so I needed to specify the architecture first:

arch -arm64 brew install php@7.4

Then I updated the PATH in my .zshconfig , so the terminal can find PHP 7.4:

echo 'export PATH="/opt/homebrew/opt/php@7.4/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/opt/homebrew/opt/php@7.4/sbin:$PATH"' >> ~/.zshrc

I restarted my terminal and verified the PHP version:

php -v

Now I see PHP 7.4:

PHP 7.4.27 (cli) (built: Dec 16 2021 18:02:37) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Zend OPcache v7.4.27, Copyright (c), by Zend Technologies

Switch Between PHP Versions

Switching between versions of PHP is the same process: install (you only have to install once) and then update the PATH. Here are some examples:

PHP 8.1

brew install php

Update the path:

echo 'export PATH="/opt/homebrew/opt/php/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/opt/homebrew/opt/php/sbin:$PATH"' >> ~/.zshrc

PHP 8.0

brew install php@8.0

Update the path:

echo 'export PATH="/opt/homebrew/opt/php@8.0/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/opt/homebrew/opt/php@8.0/sbin:$PATH"' >> ~/.zshrc

PHP 7.4

arch -arm64 brew install php@7.4

Update the path:

echo 'export PATH="/opt/homebrew/opt/php@7.4/bin:$PATH"' >> ~/.zshrc
echo 'export PATH="/opt/homebrew/opt/php@7.4/sbin:$PATH"' >> ~/.zshrc

Because PHP 7.3 and below are no longer supported, Homebrew won’t let you install:

arch -arm64 brew install php@7.3

Will throw an error:

Error: php@7.3 has been disabled because it is a versioned formula!

Gotchas

You may need to unlink/link PHP version using Homebrew if you see an error like:

Error: Could not symlink include/php/TSRM/TSRM.h
Target /usr/local/include/php/TSRM/TSRM.h is a symlink belonging to php. You can unlink it: brew unlink php

You could solve for this by trying:

brew unlink php
brew link php@7.4

I hope you found this quick tip helpful, and if you have anything to add, please drop a comment below. WebDevStudios offers a monthly retainer for ongoing website development and support services that include keeping your PHP updated and your website performant. Contact us when you need a team of experts behind your website.

The post Quick Tip: Change PHP Versions with Homebrew on Apple Silicon Powered Macs appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2022/02/03/change-php-versions-with-homebrew/feed/ 1 24659
Local Development with Node and Express https://webdevstudios.com/2021/05/06/local-development-with-node-and-express/ https://webdevstudios.com/2021/05/06/local-development-with-node-and-express/#respond Thu, 06 May 2021 16:00:51 +0000 https://webdevstudios.com/?p=23770 Create your Server If you are working with React and webpack, you probably or mostly never have to create your own local server. If you ever wonder how it works under the hood, here is a simple way to get a local server up and running in no time. Install Node First we need Node. Read More Local Development with Node and Express

The post Local Development with Node and Express appeared first on WebDevStudios.

]]>
Create your Server

If you are working with React and webpack, you probably or mostly never have to create your own local server. If you ever wonder how it works under the hood, here is a simple way to get a local server up and running in no time.

Install Node

First we need Node. You probably have node installed. If not, and you’re on a Mac use Homebrew:

View the code on Gist.

Your First Server

Create a index.js file:

View the code on Gist.

Then on our index.js :

View the code on Gist.

To learn more about the Node http package, use the following link to learn all about http.

Finally, run index.js with:

View the code on Gist.

Go to your browser and enter http://localhost:3000/ in your browser. You should see the text, ‘Hello Node.js.’

Request and Response

To have different responses based on different URLs, we now change our respond:

View the code on Gist.

Let’s restart Node: CTRL + C. Run  node index.js. Go to localhost:3000 and navigate the routes:

To see your request information, open developer tools/network/status. It will show the status code from the request.

What about adding HTML Files to our routes? In the same directory of index.js, create:

View the code on Gist.

With Emmet, it is as easy as typing ! or doc and hit the ENTER KEY. Your file will have the HTML code necessary to run. If you use Visual Code like me, support for Emmet snippets and expansion is built right into Visual Studio Code; no extension required.

Emmet takes the snippets idea to a whole new level. You can type CSS-like expressions that can be dynamically parsed, and produce output depending on what you type in the abbreviation. Emmet is developed and optimized for web developers whose workflow depends on HTML/XML and CSS but can be used with programming languages too. Bookmark this: Emmet Cheat Sheet.

Now, add a navigation. Let’s use Emmet one more time.

Between the body tags, go ahead and type ul>li*3>a and hit enter. This will create an unordered list with three items and a tags. Add your links, as seen in this screenshot, and then add a h1 tag on each of the pages named Homepage, About, Contact, and Page Not Found. Your files should look like this:

Let’s update index.js.

View the code on Gist.

Restart the server with CTRL + C and run  node index.js . Go to: http://localhost:3000; you’re now navigating your HTML files.

 

Express

Express is a minimal and flexible NodeJS web application framework that provides a robust set of features for web and mobile applications. Express provides a layer of abstraction to make handling web traffic and APIs easier. In short, Express did for NodeJS what Bootstrap did for HTML/CSS and responsive web design.

Some of the advantages of using Express are:

  • Almost the standard for Node.js web middleware
  • Simple, minimalistic, flexible, and scalable
  • Fast app development
  • Fully customizable
  • Low learning curve
  • Majorly focused on browsers, making templating and rendering an almost out-of-the-box feature

Before we install Express, we need to create a package.json file. On your root directory, run:

View the code on Gist.

If you’re not familiar with npm init and its flags, I recommend running npm help init for definitive documentation on these fields and exactly what they do.

Now that we have our package.json in our project. Let’s go ahead and install Express:

View the code on Gist.

Let’s refactor our index.js to work with Express:

View the code on Gist.

Previously we create a server and started with:

View the code on Gist.

We have to take care of importing http, fs , other packages, and also the request and response object; but with Express, we achieve the same thing.

Run CTRL + C and  node index.js . Check your terminal. It should now log from Express, your routes are probably broken.  We’ll take care of that next.

View the code on Gist.

Routing with Express

You define routing using methods of the Express app object that correspond to HTTP methods—for example, app.get() to handle GET requests and app.post() to handle POST requests.

The following code is an example of a very basic route.

View the code on Gist.

To learn more about Express routing click here. For now, let’s add routing to our app go to index.js.

View the code on Gist.

Express adds things like the sendFile method which makes it easier to write request handler functions.

That’s it! Run CTRL + C and node index.js and navigate within your app.

 

Serving Static Files

Express has this special function, app.use(), which mounts the specified middleware function or functions at the specified path. The middleware function is executed when the base of the requested path matches path. This special function, express.static(), is a built-in middleware function in Express. It serves static files and is based on serve-static.

What is middleware? Middleware is a software that bridges gaps between other applications, tools, and databases in order to provide unified services to users. It is commonly characterized as the glue that connects different software platforms and devices together.

View the code on Gist.

Create a directory:

View the code on Gist.

Add this code on your index.js file in the root of your app:

View the code on Gist.

To reference styles.css in index.html, add in index.html and on all your HTML files between the <head> in the following lines:

View the code on Gist.

Let’s make sure we are reading the styles and script; on your style.css add:

View the code on Gist.

In your index.js, be sure that this is the new index.js the one on our public folder on the js directory, and is not our root index.js.

View the code on Gist.

That’s it! You have an app running locally with Node and Express.

We learned how to install and run a Node application locally and leverage it with Express. We also learned how to serve static files with express.static().

Automatic Server Restart with Nodemon

Nodemon is a utility that will monitor for any changes in your source and automatically restart your server, making it perfect for development. We have been starting and stopping our server each time we make a change on index.js, but with Nodemon, we don’t have to that anymore.

Let’s install Nodemon: npm i nodemon --save-dev. Now update your package.json.

View the code on Gist.

So instead of node index.js, we now run our app with npm start.

I hope this article helps you understand what happens under the hood on some of the most popular JavaScript bundlers.

The post Local Development with Node and Express appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2021/05/06/local-development-with-node-and-express/feed/ 0 23770
Quick Tip: Gutenberg Blocks as JSON https://webdevstudios.com/2021/04/20/quick-tip-gutenberg-blocks-as-json/ https://webdevstudios.com/2021/04/20/quick-tip-gutenberg-blocks-as-json/#respond Tue, 20 Apr 2021 16:00:22 +0000 https://webdevstudios.com/?p=23404 Big Ugly Blobs When WordPress saves Gutenberg blocks to the database, it smashes them together as a string of markup. When you query that via the REST-API or WPGraphQL? You get this big ugly blob of HTML: The screenshot above isn’t that bad, but what happens when you have a 2,000 word blog post with Read More Quick Tip: Gutenberg Blocks as JSON

The post Quick Tip: Gutenberg Blocks as JSON appeared first on WebDevStudios.

]]>
Big Ugly Blobs

When WordPress saves Gutenberg blocks to the database, it smashes them together as a string of markup. When you query that via the REST-API or WPGraphQL? You get this big ugly blob of HTML:

This is a screenshot of a string of HTML in GraphQL that looks like a blob of code.

The screenshot above isn’t that bad, but what happens when you have a 2,000 word blog post with images, block quotes and Twitter embeds? When working on a headless frontend, how are you going to create a layout to match your client’s design, when you’re stuck with a big string of HTML?

Maybe reach for regular expressions to pluck out the data? Try using CSS to drill down and style HTML tags? You could totally YOLO that blob of HTML right into a component with dangerouslySetInnerHTML

This is a screenshot of what the previous blob of HTML could look like when using dangerously Set Inner HTML, which is React’s replacement for using inner HTML in the browser DOM.

…but the reality is, losing control over the decision making process for handling data makes for a poor developer experience.

There’s already a standard way to work with APIs that have structured data. To quote the MDN:

JavaScript Object Notation (JSON) is a standard text-based format for representing structured data based on JavaScript object syntax. It is commonly used for transmitting data in web applications (e.g., sending some data from the server to the client, so it can be displayed on a web page, or vice versa).

After reading that definition, you might be asking, “If JSON is a standard way to transmit structured data, why isn’t WordPress doing this with Gutenberg blocks?”

That’s the million dollar question.

WPGraphQL Gutenberg to the Rescue

You’re in luck because the WPGraphQL Gutenberg plugin from Peter Pristas converts Gutenberg blocks to JSON!

Using WPGraphQL, you can query for blocksJSON on a page or post and receive a big ugly blob of JSON instead!

This is a screenshot of a big ugly blob of JSON.

Thanks to both the JSON.parse() and .map() methods, you can convert the JSON response from WPGraphQL into an array of objects, and then .map() over it (kind of like the WordPress Loop). This is standard practice when working with JSON in JavaScript.

The following code snippet parses the JSON response, starts a loop, plucks out the ‘core/paragraph’ block, then passes in the data as props:

This is a screenshot of a code snippet that parses the JSON response.

Thanks to the structure JSON provides, you now have full control over content coming from Gutenberg. Now that’s a good developer experience!

The post Quick Tip: Gutenberg Blocks as JSON appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2021/04/20/quick-tip-gutenberg-blocks-as-json/feed/ 0 23404
Quick Tip: Add Custom Meta Fields to GraphQL https://webdevstudios.com/2021/04/15/add-custom-meta-fields-to-graphql/ https://webdevstudios.com/2021/04/15/add-custom-meta-fields-to-graphql/#respond Thu, 15 Apr 2021 16:00:38 +0000 https://webdevstudios.com/?p=23462 One of WordPress’ greatest strengths, at least in my opinion, is its ability to function as a general-purpose content management system. This is usually done through custom post types and custom meta fields. Putting them onto the website is as easy as adding a few pages to your theme. But what about making a headless Read More Quick Tip: Add Custom Meta Fields to GraphQL

The post Quick Tip: Add Custom Meta Fields to GraphQL appeared first on WebDevStudios.

]]>
One of WordPress’ greatest strengths, at least in my opinion, is its ability to function as a general-purpose content management system. This is usually done through custom post types and custom meta fields. Putting them onto the website is as easy as adding a few pages to your theme.

But what about making a headless WordPress site with GraphQL? How do you add your custom post types and custom meta fields to the GraphQL API?

It’s worth noting that our plugin for creating custom post types, Custom Post Type UI, now does this automatically! But if you’re not using a plugin to create your custom post types, read on to see the code behind the scenes.

I ran into this issue working on a personal website and using the WP GraphQL plugin. This website would be for my music, so I need a custom post type called “Album.”

View the code on Gist.

There are three extra arguments being passed to the register_post_type function: show_in_graphql, graphql_single_name, and graphql_plural_name. The first enables the custom post type to be added to the GraphQL API, and the last two give the name for the object:

GraphiQL IDE showing the album and albums objects

That takes care of our custom post type! But what about the custom meta field?

View the code on Gist.

This code is a little more complicated, so we’ll step through it:

  1. We hook into the graphql_register_types action. This will make sure that our next code is called at the right time.
  2. We call the register_graphql_field field with:
    1. The name of the object we are creating the field on (“Album”)
    2. The name of the field we are creating (externalLinks)
    3. Extra arguments for the function
  3. The extra arguments include a callback function that returns the value of the field.

For our callback function, we’re cheating a little bit. The meta field, find_links, can have multiple values. The purist approach would be to create a new GraphQL object and allow the links to be individually queryable. The pragmatic approach is to instead make our GraphQL field a String and encode the full meta field into a JSON object.

The GraphiQL IDE showing the results of the new custom field

The end result here is that we get the data out of WordPress and into our Next.js frontend where we can use it.

Displaying the contents of the custom meta field on the final website

You can see the full Next.js source code for my website on GitHub.

With a few tricks, it’s not hard to get the full power of WordPress into your Headless WordPress site. Using a decoupled frontend like Next.js means that the final website can be as complicated or as simple as it needs to be. And when it comes time to update or make new content, it’s as easy as… well, as easy as WordPress.

Want to see what we can do for you? Get in touch!

The post Quick Tip: Add Custom Meta Fields to GraphQL appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2021/04/15/add-custom-meta-fields-to-graphql/feed/ 0 23462
Using Constants and Input Fields to Store User Information https://webdevstudios.com/2021/04/13/using-constants-and-input-fields/ https://webdevstudios.com/2021/04/13/using-constants-and-input-fields/#respond Tue, 13 Apr 2021 16:00:29 +0000 https://webdevstudios.com/?p=23477 One of the advantages of using wp-config.php is how it allows us to add configuration options for our theme or plugin in a central place accessible throughout the entire site or web application; but using wp-config.php assumes a level of technical prowess some don’t have or some don’t want. Developers, engineers, and the like are Read More Using Constants and Input Fields to Store User Information

The post Using Constants and Input Fields to Store User Information appeared first on WebDevStudios.

]]>
One of the advantages of using wp-config.php is how it allows us to add configuration options for our theme or plugin in a central place accessible throughout the entire site or web application; but using wp-config.php assumes a level of technical prowess some don’t have or some don’t want.

Developers, engineers, and the like are used to working with the file to configure all sorts of things:

Option pages, on the other hand, are great if you’re a user who wants to add configuration without having to read any code. Assume for a moment that you’re building something tailored for both the developer-types and those who are used to filling out options pages, clicking buttons, and setting values in text fields. The latter is obviously the more common approach among most users. It’s often easier, if implemented correctly, but what if you want to support both?

Using Constants and Input Fields

Given the situation outlined above, there are a couple of architectural design decisions to make:

  1. Determine what takes priority. Is it the values set in WordPress’ configuration file or the values set in the options page?
  2. If there are values set in the wp-config.php file, do you automatically populate the options page with those values?
  3. How do you store these options in a way that’s universally readable regardless of how they are defined?

Let’s look at each of these before arriving at a final solution.

Universally Acceptable Values

In most cases, we’re going to want to access to the values throughout the site in such a way that we can easily read them using the WordPress API. Having values that can defined by constants or defined by form values implies that there are two places from which to read the input. But why? Centralize the data in a single place, thus making it easily accessible.

To do this, I recommend using the options table. (Yes, you could go with transients, but that’s outside the scope of this article and has technical implications that aren’t relevant to the point I’m trying to make.) If users can define values in both constants and forms, how do we get them into the options table? Specifically, how do we get constants defined in a file into the database that can be read on the frontend and in the administration area of the site?

Let’s start with constants. PHP offers a function called get_defined_constants and it accepts a boolean as an argument such that you can have it organize the constants defined in the application by unique IDs. In the case of WordPress, all user-defined constants look something like this:

A screenshot of an example of user-defined constants.

From there, we can then determine if the given constant is set and, if so, save it to the options table.

  1. This allows us to store the constants in a place that’s readable throughout the site.
  2. It also allows us to override the options either via input forms or constants (depending on what you choose).

Here’s a function that does just that:

View the code on Gist.

First, it forces the incoming constant to be uppercased since that’s how constants should be defined. Secondly, the reads user-defined constants into an array. After that, if the constant is defined and it’s set in the $constants['user'] array, then it will write it to the options table.

The full function looks like this:

View the code on Gist.

So this covers the case of making our constants universally acceptable. That is, it reads them, writes them to the database, and then allows us to access them through the get_option function.

But what about working with form fields in a settings page?

Populating the Options Page with Constant Values

This particular section of the article assumes you’ve followed everything above. That is, if something is defined in the constants and it is written in the options table, then it will be accessible in the options page.

This article isn’t focused on writing an options page; so I’m assuming you have familiarity with how they are created through something like:

I’m also assuming that you have a view of sorts set up to read a value. Additionally, let’s assume for a moment that we have a constant, as defined earlier, such as WDS_HOMEPAGE_URL with the value of https://webdevstudios.com. From the function above, we know that if the constant is set and as a value, it will be written into the database using a key such as wds_homepage_url.

This means we can easily access it using the Options API by simply calling get_option( 'acme-homepage-url' ); so our form field may look something like this (assuming you’re using an input element and proper escaping functions):

View the code on Gist.

Thus, if a constant is set, then the value will be added to the input field’s value attribute. Otherwise, it will be empty.

Working with Input Field Values

If, on the other hand, constants aren’t defined and you want to allow the user to specify the options using an administration screen, then you’ll need to implement functionality that will do the following:

  1. Enforce security around the page using nonce values and permissions
  2. Sanitize the information and serialize it properly
  3. Delete the option if it’s an empty string (as we don’t want to clutter the database with empty values)
  4. Reload the page once the serialization has happened which should, in turn, also show the value that was just saved

To do this, let’s first add an options page that will introduce the field. This should add a submenu item to the Settings menu that renders a page titled “Theme Settings.”

View the code on Gist.

Next, we’ll need a function that will render the page. This is as easy an calling require_once on a single file (as it’s a good idea to keep templates separate from backend logic):

View the code on Gist.

After that, we’ll populate a basic options page that includes a form element, the input field, and two native WordPress API functions that will allow us to enforce security and save the values. This includes wp_nonce_field and submit_button.

View the code on Gist.

An Important Note

There’s a very important distinction to make here, though, and it should not be missed:

If the value of the option is defined in a constant, it will automatically populate the value of the input field. 

Furthermore, if the constant is defined, it will overwrite whatever you attempt to save. So, in this example, you opt to go with the constants or you opt to go with the input field on the settings page.

Back to Work

From here, we have to:

  • Validate the nonce and make sure the user has the proper permissions
  • Save (or delete) the data

This can all be achieved through the following functions:

View the code on Gist.

After all of that, we’ll redirect the user back to the page that will include the option they just created.

View the code on Gist.

Note here that although the gist of what we’re doing is captured and described, there are a few functions that I recommend you fully understand not just for this work but for future work, too. These include:

Each of these can serve you well in your custom backend WordPress development.

Conclusion

When you’re faced with working with user-defined constants and with user-defined input both of which are stored as values in the database, there are considerations to be made, some of which are outlined in this article. For example:

  1. What are you going to prioritize—constants or user input?
  2. Will the user input override the constants or, as long as constants are present, will the form be available for use?
  3. If the latter is the case, what happens to the constant values defined in wp-config.php?

I’m not attempting to provide a solution on how you should prioritize these things but how to work with each of these methods of input such that you’re enabled to make a decision for your own project. Ultimately, that’s a call that you or you and your team will have to make. But the ability to offer constants for more technical users and form input for other users is not something that has to be a competing goal.

And that’s the goal of what’s outlined above.

The post Using Constants and Input Fields to Store User Information appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2021/04/13/using-constants-and-input-fields/feed/ 0 23477