Tag: Plugin

GSAP Flip Plugin for Animation

Greensock made the GSAP Flip plugin free in the 3.9 release. FLIP is an animation concept that helps make super performance state-change animations. Ryan Mulligan has a good blog post:

FLIP, coined by Paul Lewis, is an acronym for First, Last, Invert, and Play. The Flip plugin harnesses this technique so that web developers can effortlessly and smoothly transition elements between states.

GSAP Flip plugin logo.

Examples using the GSAP Flip plugin

Taking advantage of FLIP “by hand” is certainly possible, but tricky. It’s an absolutely perfect thing for an animation library to do for us. Greenstock nailed it, as Ryan says:

1. Get the current state
2. Make your state changes
3. Call Flip.from(state, options)

Deliciously simple. Ryan made an “add to cart” effect with it:

I used it just the other day to make a “mini photo gallery” that could rotate which image was the big one on top:

Which, coincidently, is exactly why I ended up blogging “How to Cycle Through Classes on an HTML Element” the other day.

To Shared LinkPermalink on CSS-Tricks


GSAP Flip Plugin for Animation originally published on CSS-Tricks. You should get the newsletter.

CSS-Tricks

, , ,

Using SVG in WordPress (2 Helpful Plugin Recommendations)

There is a little legwork to do if you plan on using SVG in WordPress. For fair-enough reasons, WordPress doesn’t allow SVG out of the box. SVG is a markup syntax that has lots of power, including the ability to load other resources and run JavaScript. So, if WordPress were to blanket-ly allow SVG by default, users even with quite limited roles could upload SVG and cause problems, like XSS vulnerabilities.

But say that’s not a problem for your site and you just use SVG gosh darn it. First, let’s be clear what we mean by using SVG in WordPress: uploading SVG through the media uploader and using the SVG images within post content and as featured images.

There is nothing stopping you from, say, using SVG in your templates. Meaning inline <svg> or SVG files you link up as images in your template from your CSS or whatnot. That’s completely fine and you don’t need to do anything special for that to work in WordPress.

Example of Using SVG in WordPress. the media library is open and shows tile previews of different SVG files.

Taking matters into your own hands

What prevents you from using SVG in WordPress is that the Media Library Uploader rejects the file’s MIME type. To allow SVG in WordPress, you really just need this filter. This would go in your functions.php or a functionality plugin:

function cc_mime_types($ mimes) {   $ mimes['svg'] = 'image/svg+xml';   return $ mimes; } add_filter('upload_mimes', 'cc_mime_types');

But the problem after that is that the SVG file usually won’t display correctly in the various places it needs to, like the Media Library’s image previews, the Featured Image widget, and possibly even the classic or Block Editor. I have a snippet of CSS that can be injected to fix this. But — and this is kinda why I’m writing this new post — that doesn’t seem to work for me anymore, which has got me thinking.

Plugins for using SVG in WordPress

I used to think, eh, why bother, it’s so little code to allow this might that I may as well just do it myself with the function. But WordPress, of course, has a way of shifting over time, and since supporting SVG isn’t something WordPress is going to do out of the box, this is actually a great idea for a plugin to handle. That way, the SVG plugin can evolve to handle quirks as WordPress evolves and, theoretically, if enough people use the SVG plugin, it will be maintained.

So, with that, here are a couple of plugin recommendations for using SVG in WordPress.

SVG Support

This is the one I’ve been using lately and it seems to work great for me.

Screenshot of the SVG Support plugin for WordPress in the WordPress Plugin Directory.

I just install it, activate it, and do nothing else. It does have a settings screen, but I don’t need any of those things. I really like how it asks you if it’s OK to load additional CSS on the front-end (for me, it’s not OK, so I leave it off) — although even better would be for the plugin to show you what it’s going to load so you can add it to your own CSS if you want.

The setting to restrict uploading SVG in WordPress to admins is smart, although if you want to be more serious about SVG safety, you could use this next plugin instead…

Safe SVG

This one hasn’t been updated in years, but it goes the extra mile for SVG safety in that it literally sanitizes SVG files as you upload them, and even optimizes them while it adds the SVG in WordPress.

Screenshot of the Safe SVG plugin in the WordPress Plugin Directory.

We have fairly tight editorial control over authors and such here on this site, so the security aspects of this SVG plugin aren’t a big worry to me. Plus, I like to be in charge of my own SVG optimization, so this one isn’t as perfect for me, though I’d probably recommend it to a site with less technical expertise at the site owner level.


Looks like there is Easy SVG Support as well, but it doesn’t seem to be as nice as the Support SVG plugin and hasn’t been updated recently, so I can’t recommend that.

What plugins have you successfully tried for using SVG in WordPress? Any recommendations you’d like to add?


Using SVG in WordPress (2 Helpful Plugin Recommendations) originally published on CSS-Tricks. You should get the newsletter and become a supporter.

CSS-Tricks

, , , ,
[Top]

Making a Site Work Offline Using the VitePWA Plugin

The VitePWA plugin from Anthony Fu is a fantastic tool for your Vite-powered sites. It helps you add a service worker that handles:

  • offline support
  • caching assets and content
  • prompting the user when new content is available
  • …and other goodies!

We’ll walk through the concept of service workers together, then jump right into making one with the VitePWA plugin.

New to Vite? Check out my prior post for an introduction.

Table of Contents

  1. Service workers, introduced
  2. Versioning and manifests
  3. Our first service worker
  4. What about offline functionality?
  5. How service workers update
  6. A better way to update content
  7. Runtime caching
  8. Adding your own service worker content
  9. Wrapping up

Service workers, introduced

Before getting into the VitePWA plugin, let’s briefly talk about the Service Worker itself.

A service worker is a background process that runs on a separate thread in your web application. Service workers have the ability to intercept network requests and do… anything. The possibilities are surprisingly wide. For example, you could intercept requests for TypeScript files and compile them on the fly. Or you could intercept requests for video files and perform an advanced transcoding that the browser doesn’t currently support. More commonly though, a service worker is used to cache assets, both to improve a site’s performance and enable it to do something when it’s offline.

When someone first lands on your site, the service worker the VitePWA plugin creates installs, and caches all of your HTML, CSS, and JavaScript files by leveraging the Cache Storage API. The result is that, on subsequent visits to your site, the browser will load those resources from cache, rather than needing to make network requests. And even on the first visit to your site, since the service worker just pre-cached everything, the next place your user clicks will probably be pre-cached already, allowing the browser to completely bypass a network request.

Versioning and manifests

You might be wondering what happens with a service worker when your code is updated. If your service worker is caching, say, a foo.js file, and you modify that file, you want the service worker to pull down the updated version, the next time a user visits the site.

But in practice you don’t have a foo.js file. Usually, a build system will create something like foo-ABC123.js, where “ABC123” is a hash of the file. If you update foo.js, the next deployment of your site may send over foo-XYZ987.js. How does the service worker handle this?

It turns out the Service Worker API is an extremely low-level primitive. If you’re looking for a native turnkey solution between it and the cache API, you’ll be disappointed. Basically, the creation of your service worker needs to be automated, in part, and connected to the build system. You’d need to see all the assets your build created, hard-code those file names into the service worker, have code to pre-cache them, and more importantly, keep track of the files that are cached.

If code updates, the service worker file also changes, containing the new filenames, complete with hashes. When a user makes their next visit to the app, the new service worker will need to install, and compare the new file manifest with the manifest that’s currently in cache, ejecting files that are no longer needed, while caching the new content.

This is an absurd amount of work and incredibly difficult to get right. While it can be a fun project, in practice you’ll want to use an established product to generate your service worker — and the best product around is Workbox, which is from the folks at Google.

Even Workbox is a bit of a low-level primitive. It needs detailed information about the files you’re pre-caching, which are buried in your build tool. This is why we use the VitePWA plugin. It uses Workbox under the hood, and configures it with all the info it needs about the bundles that Vite creates. Unsurprisingly, there are also webpack and Rollup plugins if you happen to prefer working with those bundlers.

Our first service worker

I’ll assume you already have a Vite-based site. If not, feel free to create one from any of the available templates.

First, we install the VitePWA plugin:

npm i vite-plugin-pwa

We’ll import the plugin in our Vite config:

import { VitePWA } from "vite-plugin-pwa"

Then we put it to use in the config as well:

plugins: [   VitePWA()

We’ll add more options in a bit, but that’s all we need to create a surprisingly useful service worker. Now let’s register it somewhere in the entry of our application with this code:

import { registerSW } from "virtual:pwa-register";  if ("serviceWorker" in navigator) {   // && !/localhost/.test(window.location)) {   registerSW(); }

Don’t let the code that’s commented out throw you for a loop. It’s extremely important, in fact, as it prevents the service worker from running in development. We only want to install the service worker anywhere that’s not on the localhost where we’re developing, that is, unless we’re developing the service worker itself, in which case we can comment out that check (and revert before pushing code to the main branch).

Let’s go ahead and open a fresh browser, launch DevTools, navigate to the Network tab, and run the web app. Everything should load as you’d normally expect. The difference is that you should see a whole slew of network requests in DevTools.

A screenshot of DevTools listing all of the network requests for the currant app using the VitePWA plugin. There are a total of 16 various JavaScript and CSS files.

That’s Workbox pre-caching the bundles. Things are working!

What about offline functionality?

So, our service worker is pre-caching all of our bundled assets. That means it will serve those assets from cache without even needing to hit the network. Does that mean our service worker could serve assets even when the user has no network access? Indeed, it does!

And, believe it or not, it’s already done. Give it a try by opening the Network tab in DevTools and telling Chrome to simulate offline mode, like this.

Screenshot of the DevTools UO to simulate an offline connection with the select menu open. The No throttling option is currently checked but the Offline option is highlighted in light blue.
The “No throttling” option is the default selection. Click that and select the “Offline” option to simulate an offline connection.

Let’s refresh the page. You should see everything load. Of course, if you’re running any network requests, you’ll see them hang forever since you’re offline. Even here, though, there are things you can do. Modern browsers ship with their own internal, persistent database called IndexedDB. There’s nothing stopping you from writing your own code to sync some data to there, then write some custom service worker code to intercept network requests, determine if the user is offline, and then serve equivalent content from IndexedDB if it’s in there.

But a much simpler option is to detect if the user is offline, show a message about being offline, and then bypass the data requests. This is a topic unto itself, which I’ve written about in much greater detail.

Before showing you how to write, and integrate your own service worker content, let’s take a closer look at our existing service worker. In particular, let’s see how it manages updating/changing content. This is surprisingly tricky and easy to mess up, even with the VitePWA plugin.

Before moving on, make sure you tell Chrome DevTools to put you back online.

How service workers update

Take a closer look at what happens to our site when we change the content. We’ll go ahead and remove our existing service worker, which we can do in the Application tab of DevTools, under Storage.

Screenshot showing the Storage panel of DevTools. The DevTools menu is a panel on the left and the app usage is displayed in a panel on the right, showing that 508 kilobytes of data total is used, where 392 kilobytes are cached and 16.4 are service workers. A button to clear site data is below the Usage stats with a deep blue label and a light gray background.

Click the “Clear site data” button to get a clean slate. While I’m at it, I’m going to remove most of the routes of my own site so there’s fewer resources, then let Vite rebuild the app.

Look in the generated sw.js to see the generated Workbox service worker. There should be a pre-cache manifest inside of it. Mine looks like this:

A dark mode screenshot showing a list of eight asset urls inside of a precacheAndRoute function.

If sw.js is minified, run it through Prettier to make it easier to read.

Now let’s run the site and see what’s in our cache:

Let’s focus on the settings.js file. Vite generated assets/settings.ccb080c2.js based on the hash of its contents. Workbox, being independent of Vite, generated its own hash of the same file. If that same file name were to be generated with different content, then a new service worker would be re-generated, with a different pre-cache manifest (same file, but different revision) and Workbox would know to cache the new version, and remove the old when it’s no longer needed.

Again, the filenames will always be different since we’re using a bundler that injects hash codes into our file names, but Workbox supports dev environments which don’t do that.

Since the time writing, the VitePWA plugin has been updated and no longer injects these revision hashes. If you’re attempting to follow along with the steps in this article, this specific step might be slightly different from your actual experience. See this GitHub issue for more context.

If we update our settings.js file, then Vite will create a new file in our build, with a new hash code, which Workbox will treat as a new file. Let’s see this in action. After changing the file and re-running the Vite build, our pre-cache manifest looks like this:

Now, when we refresh the page, the prior service worker is still running and loading the prior file. Then, the new service worker, with the new pre-cache manifest is downloaded and pre-cached.

A DevTools screenshot showing a table of pre-cached assets processed by the VitePWA plugin and Workbox.
The new pre-cached manifest is displayed in the list of cached assets. Notice that both versions of our settings file are there (and both versions of a few other assets were affected as well): the old version, since that’s what’s still being run, and the new version, since the new service worker has pre-cached it.

Note the corollary here: our old content is still being served to the user since the old service worker is still running. The user is unable to see the change we just made, even if they refresh because the service worker, by default, guarantees any and all tabs with this web app are running the same version. If you want the browser to show the updated version, close your tab (and any other tabs with the site), and re-open it.

The same DevTools screenshot of pre-cached assets, but now only displaying new assets instead of duplicates.
The cache should now only contain the new assets.

Workbox did all the legwork of making this all come out right! We did very little to get this going.

A better way to update content

It’s unlikely that you can get away with serving stale content to your users until they happen to close all their browser tabs. Fortunately, the VitePWA plugin offers a better way. The registerSW function accepts an object with an onNeedRefresh method. This method is called whenever there’s a new service worker waiting to take over. registerSW also returns a function that you can call to reload the page, activating the new service worker in the process.

That’s a lot, so let’s see some code:

if ("serviceWorker" in navigator) {   // && !/localhost/.test(window.location) && !/lvh.me/.test(window.location)) {   const updateSW = registerSW({     onNeedRefresh() {       Toastify({         text: `<h4 style='display: inline'>An update is available!</h4>                <br><br>                <a class='do-sw-update'>Click to update and reload</a>  `,         escapeMarkup: false,         gravity: "bottom",         onClick() {           updateSW(true);         }       }).showToast();     }   }); }

I’m using the toastify-js library to show a toast UI component to let users know when a new version of the service worker is available and waiting. If the user clicks the toast, I call the function VitePWA gives me to reload the page, with the new service worker running.

A toast component screenshot with white text and a slight background gradient that goes from light blue on the left to bright blue on the right. It reads: an update is available! Click to update and reload.
Now when we have pending updates, a nice toast component pops up on the front end. Clicking it reloads the page with the new content in there.

One thing to remember here is that, after you deploy the code to show the toast, the toast component won’t show up the next time you load your site. That’s because the old service worker (the one before we added the toast component) is still running. That requires manually closing all tabs and re-opening the web app for the new service worker to take over. Then, the next time you update some code, the service worker should show the toast, prompting you to update.

Why doesn’t the service worker update when the page is refreshed? I mentioned earlier that refreshing the page does not update or activate the waiting service worker, so why does this work? Calling this method doesn’t only refresh the page, but it calls some low-level Service Worker APIs (in particular skipWaiting) as well, giving us the outcome we want.

Runtime caching

We’ve seen the bundle pre-caching we get for free with VitePWA for our build assets. What about caching any other content we might request at runtime? Workbox supports this via its runtimeCaching feature.

Here’s how. The VitePWA plugin can take an object, one property of which is workbox, which takes Workbox properties.

const getCache = ({ name, pattern }: any) => ({   urlPattern: pattern,   handler: "CacheFirst" as const,   options: {     cacheName: name,     expiration: {       maxEntries: 500,       maxAgeSeconds: 60 * 60 * 24 * 365 * 2 // 2 years     },     cacheableResponse: {       statuses: [200]     }   } }); // ...    plugins: [     VitePWA({       workbox: {         runtimeCaching: [           getCache({              pattern: /^https://s3.amazonaws.com/my-library-cover-uploads/,              name: "local-images1"            }),           getCache({              pattern: /^https://my-library-cover-uploads.s3.amazonaws.com/,              name: "local-images2"            })         ]       }     })   ], // ...

I know, that’s a lot of code. But all it’s really doing is telling Workbox to cache anything it sees matching those URL patterns. The docs provide much more info if you want to get deep into specifics.

Now, after that update takes effect, we can see those resources being served by our service worker.

DevTools screenshot showing the resources that are loaded by the browser. There are four jpeg images.

And we can see the corresponding cache that was created.

DevTools screenshot showing the new cache instance that is stored in Cache Storage. It includes all of the cached images.

Adding your own service worker content

Let’s say you want to get advanced with your service worker. You want to add some code to sync data with IndexedDB, add fetch handlers, and respond with IndexedDB data when the user is offline (again, my prior post walks through the ins and outs of IndexedDB). But how do you put your own code into the service worker that Vite creates for us?

There’s another Workbox option we can use for this: importScripts.

VitePWA({   workbox: {     importScripts: ["sw-code.js"],

Here, the service worker will request sw-code.js at runtime. In that case, make sure there’s an sw-code.js file that can be served by your application. The easiest way to achieve that is to put it in the public folder (see the Vite docs for detailed instructions).

If this file starts to grow to a size such that you need to break things up with JavaScript imports, make sure you bundle it to prevent your service worker from trying to execute import statements (which it may or may not be able to do). You can create a separate Vite build instead.

Wrapping up

At the end of 2021, CSS-Tricks asked a bunch of front-end folks what one thing someone cans do to make their website better. Chris Ferdinandi suggested a service worker. Well, that’s exactly what we accomplished in this article and it was relatively simple, wasn’t it? That’s thanks to the VitePWA with hat tips to Workbox and the Cache API.

Service workers that leverage the Cache API are capable of greatly improving the perf of your web app. And while it might seem a little scary or confusing at first, it’s nice to know we have tools like the VitePWA plugin to simplify things a great deal. Install the plugin and let it do the heavy lifting. Sure, there are more advanced things that a service worker can do, and VitePWA can be used for more complex functionality, but an offline site is a fantastic starting point!


Making a Site Work Offline Using the VitePWA Plugin originally published on CSS-Tricks. You should get the newsletter and become a supporter.

CSS-Tricks

, , , , , ,
[Top]

A Look at the Cloudinary WordPress Plugin

(This is a sponsored post.)

Cloudinary (the media hosting and optimization service) has a brand new version (v3) of its WordPress plugin that has really nailed it. First, a high-level look at the biggest things this plugin does:

  • It takes over your media handling. Images and video are served by Cloudinary instead of your own server, which is good for a whole host of reasons. But don’t worry, your assets are also on your own server, so there is no lock-in.
  • It serves your images and video as performantly as possible. Everything is optimized, served in the best format, and use techniques like responsive images and lazy loading, all while providing a good loading experience. All together, those things are massive for performance.
  • It provides and image gallery block with lots of functionality.

Setting it up is as easy as copy and pasting from your Cloudinary account.

So, yes, you need a Cloudinary account. You can check out the programmable media plans here. There is a free tier that will likely work for many sites and paid plans that will cover sites that have heavy media needs, of which you’ll likely find the pricing amicable. Once you have your account, you pop the connection string (from your dashboard) into this quick onboarding wizard and you’re basically done. The default settings are good.

You could do literally nothing else and the plugin will work its magic, but it’s fun to look through all the settings.

Here are the general settings:

Those two (default) settings are important. Auto sync is nice in that all your images (even your entire existing media library) is synced up to Cloudinary and stays in sync. This is necessary to host your images (and do fancy optional stuff like “transforms”) but you could otherwise think of it as a backup. When you use “Cloudinary and WordPress” as the Storage setting, it means that media will be uploaded to your own server and Cloudinary. That’s what I would highly recommend, but if you’re in a situation where, say, you have very limited or no storage on your WordPress host, you could have the images go straight to Cloudinary (only).

In the Image settings, you can see two of Cloudinary’s most powerful weapons: f_auto and q_auto, standing for “auto image formatting” and “auto quality compression.” Those are defaults I’d highly recommend leaving alone. It means that any browser on any device gets the best possible format of the image, and Cloudinary adjusts the quality as appropriate for that image. Cloudinary has very good tech for doing this, so let it do it.

The “doing images right” checklist is a thing.

Remember, we blogged it just recently. Host them on a CDN. Optimze them. Serve them in the best possible format for the requesting browser. Use responsive images. Lazy load them. None of those things are trivial, and that’s just a partial list. The good news is: this plugin does all that stuff for you, does it well, and does it without you having to think too much about it.

Showing the source HTML code for an image block. It's a lot of code, starting with the image tag and all of the srcset attributes to make the image responsive.

I like seeing the output. This is where the rubber meets the road. From this I can see that responsive images are implemented correctly and lots of different sizes are available. I can see the the image sources are pointing at the Cloudinary CDN. I can see lazy loading is implemented and working. I can see the width and height attributes are there as they should be to ensure space is reserved for the images during loading. This is everything.

It goes the extra mile by hosting the images the used by the theme as well.

Heck, it replaces CSS background-images in your theme’s stylesheet with Cloudinary-hosted versions. That’s… amazing. There must be some real clever WordPress filter stuff going on.

I like seeing this in there:

Screenshot of a Cloudinary screen in the WordPress admin. It provides settings for the Gallery Block, including colors, main viewer options, carousel, and a toggle for advanced settings. A preview of the block is to the right of the settings.

Why? It shows that this plugin is part of modern WordPress. Block editor WordPress. The block itself is simple, but useful. It shows images in a variety of useful layouts with a “lightbox”-like effect (wow, it’s been a long time since I’ve typed the word lightbox). Hey, sometimes you just need a dang image gallery and you might as well use one that is well done.

Who am I to say?

Just a lowly blogger, I suppose. But I can tell you I’ve been watching this evolve for quite a while. A ways back, I had implemented a hand-rolled Cloudinary integration here on CSS-Tricks because I wanted all this stuff. I ultimately had to give up on it as it was more technical debt than I could maintain.

The previous versions of the WordPress plugin were better, but it’s not until now, v3, where this integration is truly nailed.

Shortly after that time I tore down my custom integration, I blogged “Workflow Considerations for Using an Image Management Service” and outlined what I thought the (rather high) bar would be for integrating a third-party image host. It was a lot to ask, and I wasn’t really sure if anyone would find the incentive and motivation to do it all. Well, Cloudinary has done it here. This is as perfect a media management plugin as I could imagine.


The post A Look at the Cloudinary WordPress Plugin appeared first on CSS-Tricks. You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,
[Top]

Using New Gatsby Source WordPress Plugin

In my previous article, I discussed how I learned to create a decoupled WordPress powered Gatsby site using the Gatsby Source WPGraphQL plugin. The project was done following the ongoing developmental version of WPGraphQL and an excellent tutorial by Henrik Wirth. Although WPGraphQL was used in some production sites at that time, there were lot of iterations that introduced breaking changes. Since the release of WPGraphQL v1.0 last November, the plugin is stable and available via the WordPress plugin directory.

The WPGraphQL plugin can be used to create a site that uses WordPress for content management, but with a front-end that’s driven by Gatsby. We call this a “decoupled” or “headless” CMS because the site’s back-end and front-end are separate entities that still talk to one another via APIs where components on the front end consume data from the CMS.

The WPGraphQL plugin site has solid step-by-step documentation for getting started, and the release announcement post lists nine examples of production-level sites using the plugin.

Selected screenshots of production level decoupled WordPress sites with WPGraphQL.
The Denver Post, The Twin Cities Pioneer Press, The San Jose Mercury News, and Credit Karma have a decoupled WordPress site with WPGraphQL.

In the true sense of a “decoupled” or “headless” site, WPGraphQL can be used to port WordPress data to other frameworks, like Next.js, Vue.js, among others. For the Gatsby framework, the Gatsby Source WordPress plugin is recommended, and it utilizes WPGraphQL to source data from WordPress.

Let’s set everything up together and tour the plugin.

Prerequisites

In my previous article, we covered the prerequisites needed for setting up WordPress and Gatsby sites, and porting back-end WordPress data to a Gatsby-powered front-end site with site deployment. I’m skipping a lot of those details here because the fundamental concepts are the same for this article, except that WordPress data is fetched by the Gatsby Source WordPress plugin this time.

If you are new to Gatsby and just now jumping into Gatsby’s generated static site generator bandwagon, I’d suggest reading “An Honest Review of Gatsby” by React expert David Cramer and “Gatsby vs Next.js” by Jared Palmer. What we’re going to cover isn‘t for everyone, and these articles may be helpful to evaluate for yourself whether it’s the right technology for you and your project.

WPGraphQL, or GraphQL is the primary query language API used in Gatsby’s framework. There are frequent updates in GraphQL and that often requires expert knowledge and keeping an eye out for breaking changes. After all, GraphQL is designed by React experts for other React experts. That said, there’s some troubleshooting instructions and a WPGraphQL Slack where both the WPGraphQL and Gatsby Source WordPress plugin authors actively participate and help answer questions.

This article is not a step-by-step guide on how to use Gatsby Source WordPress Plugin. Again, that’s already available in Gatsby’s documentation. Conversely, if you happen to be an expert in React, JavaScript, Node.js or GraphQL, then what we cover here is probably stuff you already know. This article is an opinion piece based on my personal experience, which I hope is useful for the average WordPress user with basic working knowledge on the subject.

And, before we get started, it’s worth mentioning that the Gatsby Source WordPress plugin was completely rewritten in version 4 and uses WPGraphQL as its data source. The previous release, version 3, was built with REST API as its data source. Since the stable version of the plugin was recently released, the number of starter themes and demos that support it are limited.

First, we need WordPress

For this project, I set up a fresh WordPress site with Local by Flywheel that uses the default Twenty Twenty theme. I imported theme unit test data for pages and posts, as described in the WordPress Codex. While this was the baseline I was working with, this could have just as easily been an existing WordPress site that’s either on a remote server or a local install.

Now that we have an established baseline, we can log into the WordPress admin and install the WPGraphQL and WPGatsby plugins we need and activate them.

As we covered in the previous article, what this does is expose GraphQL and WPGraphiQL API in the WordPress admin, allowing the GraphiQL API to create a “playground” for testing GraphQL queries based on WordPress data.

Screenshot of the GraphiQL UI in the WordPress admin, showing a three-panel UI.
The GraphiQL screen provides three panels: one to navigate between different objects (left), one to query data (center), and one to visualize the returned data (right).

Now we need a Gatsby front-end

Gatsby is well known for good documentation and solid starter templates. To create a new WordPress-powered site, Gatsby tutorials suggest that either using a starter or starting from scratch is just fine for what we’re doing.

Gatsby also offers a library of example websites for basic use cases that are built around a specific technology. There currently happens to be one that uses WordPress and one that uses WordPress with the Advanced Custom Fields plugin. Note that the example sites in the library still use gatsby-source-wordpress plugin 3 and have not yet updated to the version 4, as of this writing.

According to Gatsby tutorials, there are three options for creating a WordPress-powered Gatsby site. Let’s look at each one.

Option 1: Using the Gatsby starter

The docs have a step-by-step guide on how to set up a WordPress-Gatsby site, but here’s the gist.

Run the following in the command line to fetch the starter from GitHub repository and clone it into a my-wpstarter project folder:

#! clone starter repo gatsby new my-wpstarter https://github.com/gatsbyjs/gatsby-starter-wordpress-blog 

Then, install the npm packages

#! npm npm install  #! or yarn yarn install 

Now that the starter is cloned, let’s open the gatsby-config.js file in our code editor and update its URL option to fetch data from our WordPress endpoint (see above).

// gatsby-config.js {   resolve: gatsby-source-wordpress,     options: {      // WordPress is the GraphQL url.      url: process.env.WPGRAPHQL_URL || https://wpgatsbydemo.wpengine.com/graphql,   }, },

Now, we’ll replace the starter’s data source endpoint URL with our own WordPress site URL:

// gatsby-config.js file {   resolve: `gatsby-source-wordpress`,   options: {     url: `http://gatsbywpv4.local/graphql`,   }, },

Let’s make sure we are in the my-wpstarter project directory. From the project folder, we’ll run the gatsby develop command to build our new Gatsby site from our WordPress data source endpoint. In the terminal we should be able see the gatsby-source-wordpress plugin fetching data, including errors and successful site processes along the way.

If we see a success Building development bundle message at the end, that means the Gatsby site build process is complete and the site can be viewed at http://localhost:8000.

The homepage of our starting site, displaying posts pulled from WordPress data in a single column.

This is a bare-bone starter blog with basic files and a few components. It’s file structure is very similar to the gatsby-starter-blog, except this one has a templates folder that includes blog-post.js and blog-post-achive.js template files.

When we view the GraphiQL API explorer at http://localhost:8000/___graphql we can see all of the data from WordPress exposed by WPGraphQL, as well as query and retrieve specific data right from the UI.

The GraphiQL UI showing three panels, one for the Explorer, one for the GraphiQL query, and one that displays the returned data from the query.
This example shows a query for menu items in WordPress (middle panel) and the returned data of that query (right panel).

You got it! Gatsby assumes the rest is up to us to build, using Gatsby components that pull in WordPress data for the presentation.

Option 2: Building from scratch

Gatsby’s documentation offers a detailed step-by-step guide on how to create a new WordPress-Gatsby site from scratch using Gatsby’s default starter theme.

We’ll spin up a new project from the command line:

#! create a new Gatsby site gatsby new wpgatsby-from-scratch-demo

This gets us a wpgatsby-from-scratch-demo folder that includes the starter theme. From here, we’ll cd into that folder and start developing:

cd wpgatsby-from-scratch-demo gatsby develop

Now we can open up http://localhost:8000 in the browser and get the welcome page.

Now we are good to go to get start grabbing data from our WordPress site. Let’s install the Gatsby Source Plugin:

#! install with rpm npm install gatsby-source-wordpress  #! install with yarn yarn add Gatsby-source-wordpress

If we check our browser now, you’ll noticed that nothing happens — we still get the same Gatsby welcome. To fetch our WordPress site data, we need to add the plugin to the gatsby-config.js file. Open the file and insert the following:

// gatsby-config.js module.exports = {   siteMetadata: {     // ...   },   plugins: [   // Add Gatsby-source-wordpress plugin   {       resolve: `gatsby-source-wordpress`,       options: {         /*          * The full URL of the WordPress site's GraphQL API.          * Example : 'https://www.example-site.com/graphql'          */         url: `http://gatsbywpv4.local/graphql`,        },      },     // The following plugins are not required for gatsby-source-wordpress ....   ], }

Just like last time, we need to change the WordPress data endpoint source to the URL of our WordPress site. Let’s run gatsby develop in our terminal to start things up.

Two terminal windows, side-by-side. They are dark with light text.
Now we see that the createPages function is running successfully to build a development bundle (left), and that WordPress data for posts, pages, taxonomies, users, menus, and everything else are fetched (right).

However, when we open http://localhost:8000 in our browser, nothing seems to happen. We still see the same welcome screen. But if we examine GraphiQL in our browser (at http://localhost:8000/___graphql) then we see all WordPress data exposed to our Gatsby site that we can query and display as we want.

The three-panel GraphiQL UI.
GraphiQL shows that WordPress data is indeed exposed and we are able to create and execute queries.

Let’s test the following query I pulled straight from Gatsby’s tutorial, in the GraphiQL explorer:

query {   allWpPost {     nodes {       id       title       excerpt       slug       date(formatString: "MMMM DD, YYYY")     }   } }

When we run the above query, we will see the allWpPost.nodes property value, with sub properties for id, title, excerpt, and others.

Now, let’s open our src/components/pages/index.js component file and replace the code with this:

// src/components/pages/index.js import  React from "react" import { graphql } from "gatsby" import Layout from "../components/layout" import SEO from "../components/seo"  export default function Home({ data }) {   return (     <Layout>       <SEO title="home" />       <h1>My WordPress Blog</h1>       <h4>Posts</h4>       {data.allWpPost.nodes.map(node => (         <div>           <p>{node.title}</p>           <div dangerouslySetInnerHTML={{ __html: node.excerpt }} />         </div>       ))}     </Layout>   ) }  export const pageQuery = graphql`   query {     allWpPost(sort: { fields: [date] }) {       nodes {         title         excerpt         slug       }     }   } `

Save it, restart the server with gatsby develop, and refresh the page. If the build was successful, then our site’s homepage should display a list of sorted blog posts from WordPress!

Following the tutorial, let’s create pages for each blog post and link the post title from the list to the post page. The process of creating pages using Markdown data is described in detail in Part 7 of the Gatsby’s foundational tutorial, which we will follow here as well.

As described in the tutorial, Gatsby uses createPages API, or what it calls as its “workhorse” API, to programmatically create pages from data (from Markdown or WordPress). Unlike Markdown data, we don’t need to create a slug here because each WordPress post has its own unique slug which can be fetched from the WordPress data endpoint.

Creating pages for each post

Gatsby uses the gatsby-node.js file, located at the root of our project, to programmatically create blog post. Let’s open the gatsby-node.js file in our text editor add the following code from the tutorial.

// gatsby-node.js  const path = require(`path`)  exports.createPages = ({ graphql, actions }) => {   const { createPage } = actions   return graphql(`     {       allWpPost(sort: { fields: [date] }) {         nodes {           title           excerpt           content           slug         }       }     }   `).then(result => {     console.log(JSON.stringify(result, null, 4))     process.exit()   }) }

As noted in the Gatsby Part 7 tutorial, the above code is the first part of creating our post pages from WordPress data source. Following the guide, let’s restart our server and develop our site with gatsby develop.

We should see console.log output in our terminal as pages being build). However, our homepage still looks the same. To create single posts, Gatsby requires templates to build pages, which we will create in next step.. That’s what we’ll do next.

Creating blog post templates

Let’s create a src/components/templates folder in the src/ directory and create a blog-post.js file by pasting the following code snippets from the tutorial:

// src/templates/blog-post.js import React from "react" import Layout from "../components/layout" import { graphql } from "gatsby"  export default function BlogPost({ data }) {   const post = data.allWpPost.nodes[0]   console.log(post)   return (     <Layout>       <div>         <h1>{post.title}</h1>         <div dangerouslySetInnerHTML={{ __html: post.content }} />       </div>     </Layout>   ) } export const query = graphql`   query($ slug: String!) {     allWpPost(filter: { slug: { eq: $ slug } }) {       nodes {         title         content       }     }   } `

As explained in the tutorial, the above code snippets create a single post with React JSX and wraps post.title and post.content (lines 12-13) around the src/components/layout.js components. At the bottom section of the file, a GraphQL query is added and calls a specific post based on the post slug variable $ slug. This variable is passed to the blog-post.js template when the page is created in gatsby-node.js.

Next we should also update lines 12-13 of our gatsby-node.js file with the following code from the tutorial.

// gatsby-node.js const path = require(`path`)   exports.createPages = ({ graphql, actions }) => {    const { createPage } = actions    return graphql(`      {        allWpPost(sort: { fields: [date], order:DEC }) {          nodes {            title            excerpt            content            slug          }        }      }    `).then(result => {     result.data.allWpPost.nodes.forEach(node => {         createPage({           path: node.slug,           component: path.resolve(`./src/templates/blog-post.js`),           context: {             // This is the $ slug variable passed to blog-post.js             slug: node.slug,           },         })       })    })  }

Let‘s stop and restart our local server with gatsby develop and view the site. We won’t see our homepage with a list of blog post links. However, if we check with http://localhost:8000/abcdf we should see the following 404 page with a list of individual pages and posts links.

If we check http://localhost:8000/hello-gatsby-world, we should our “Hello Gatsby WordPress World” post in all its glory.

The next step is to link the post titles from the homepage to the actual posts.

Linking to posts from the homepage

Linking the work from the homepage to post pages is done by wrapping post titles in the index.js file with Gatsby‘s Link component. Let’s open the index.js file that we created earlier and add the Link component:

// src/components/pages/index.js import React from "react" import { Link, graphql } from "gatsby" import Layout from "../components/layout" import SEO from "../components/seo"  export default function Home({ data }) {   return (     <Layout>       <SEO title="home" />      {/* <h1>My WordPress Blog</h1>       <h4>Posts</h4> */}       {data.allWpPost.nodes.map(node => (         <div key={node.slug}>           <Link to={node.slug}>             <h2>{node.title}</h2>           </Link>           <div dangerouslySetInnerHTML={{ __html: node.excerpt }} />         </div>       ))}     </Layout>   ) }  export const pageQuery = graphql`   query {     allWpPost(sort: { fields: [date], order: DEC  }) {       nodes {         title         excerpt         slug       }     }   } `

We imported the Link component from Gatsby and then wrapped the post title with the Link component and reference the slug of the post. Let’s clean up the code by commenting out the page title, changing the title element to <h2>, and adding sorted posts order to DEC in our graphql query as well as the gatsby-node.js file.

As we did earlier, let’s stop and restart the development server with gatsby develop, and view our homepage at http://localhost:8000. The post title should link to single post page.

This is as far as we’re going to take this second method. The rest of what we cover will describe how to fetch menu items and query other data types — like custom post types — and configure incremental build and previews etc.

You can apply the same procedure to calling and creating pages, custom post types, custom fields, taxonomies, and all the fun and flexible content WordPress is known for. This can be as simple or as complex as you would like it to be, so explore and have fun with it!

Gatsby tutorial doc 

Option 3: Using Gatsby’s WordPress Twenty Twenty Starter

Gatsby’s starter template for the default WordPress Twenty Twenty theme is created and maintained by Henrik Wirth, who also has an extremely detailed and thorough step-by-step guide that you might recall from my previous article. This starter, unlike the others, is actually updated to version 4 of the Gatsby Source Plugin and works out of the box after the initial WordPress setup described in the documentation. It maintains the same Twenty Twenty styling in the Gatsby front-end site, but has few limitations — including, comments, monthly archive pages, and tags — that are unsupported.

First let’s clone the starter in our twenty-twenty-starter folder.

#! clone gatsby-starter-wordpress-twenty-twenty  gatsby new twenty-twenty-starter https://github.com/henrikwirth/gatsby-starter-wordpress-twenty-twenty 

Let’s cd into that folder and then run gatsby develop to spin up the site. It won’t work properly the first time because we have not changed our WPGRAPHQL_URL value yet in the env.example file. We need to rename the file from .env.example to simply .env, as suggested in the documentation.

After that, restart the development server with gatsby develop. It should build the site successfully.

The menu may or may not appear depending on how the WordPress menu is named. The starter’s menu slug for querying menu items is primary in Menu.js (line 8). Because I had set my WordPress site up using main-menu instead, I had to update the Menu.js file accordingly.

Screenshot showing Menu.js file with changed menu slug to “main-menu” in line 8.

Because the starter was tested with older versions of our tools , I decided bump up the plugins  to the latest versions — WPGraphQL 1.2.6, WPGatsby 1.0.6, and Gatsby Source WordPress  4.0.1 — and it worked fine without any errors.

The Twenty Twenty starter follows the file structure of the Twenty Nineteen Gatsby theme, as well as Gatsby Starter WordPress Advanced. Henrik Wirth describes how WordPress data is ported to Gatsby in his step-by-step guide, as does Muhammad Muhsin in a tutorial. Otherwise, creating pages, page templates, porting menu items is exactly the same.

Screenshot showing Gatsby Starter WordPress Twenty Twenty’s file structure.

This starter uses the same CSS that the default WordPress Twenty Twenty theme does, and the same assets folder, including fonts, images, SVG files, and other files that are included in the default theme.

Screenshot showing the Gatsby Starter WordPress Twenty Twenty assets folder contents open in VS Code.

If you are happy with WordPress Twenty Twenty styling, then that’s it. Enjoy your new decoupled Gatsby site!

But let’s say we want to work with custom styles. The CSS files are imported from the assets folder via the gatsby-browser.js file.

Screenshot showing the Gatsby StarterWordPress Twenty Twenty style.css file opened next to the WordPress Twenty Twenty theme’s style.css file. The two contain the exact same code.

Let’s modify the styles for the site’s header, footer, posts and pages. Gatsby provides different options to style its components and, in this project, I followed the CSS module for styling and modified CSS markup of the Twenty Twenty starter components accordingly.

We can start by creating a style folder at src/components/styles and, inside it, a base folder. Here’s the general file structure we’re aiming for:

#! partial structure of /style folder src  |--/components    |--/styles      |--main.css                |--/base        |--reset.css        |--variables.css      |--/scss        |--header.module.css        |--mainNav.module.css        |--footer.module.css        |--elements.module.css        // and so on...

We want to style the site’s header and footer, so let’s open up the Header.js and Footer.js components in the starter and replace the code with the following:

// src/components/Header.js import React from "react" import { graphql, Link, useStaticQuery } from "gatsby" import Menu from "./menu" import style from "../styles/scss/header.module.css" import logo from '../images/gatsby-icon.png'  const Header = ( ) => {   const { wp } = useStaticQuery(graphql`     {       wp {         generalSettings {           title           description         }       }     }   `)   return (     <header className={style.masthead}>       <div className={style.masthead_info}>        <Link to="/">         <img src={logo} alt="logo" width="100" height="100" display="inline-block" marginBottom= "0"  className={style.site_logo} />       </Link>       <div className={style.site_header} >         <div className={style.site_title}>           <Link             to="/"             dangerouslySetInnerHTML={{ __html: wp.generalSettings.title }} />         </div>         <div className={style.site_description} dangerouslySetInnerHTML={{ __html: wp.generalSettings.description }} /></div>        </div>       <Menu />     </header>   ) }  export default Header

Similarly, the Footer.js component was modified as follows:

// src/components/Footer.js import React from "react"  import style from "../styles/scss/footer.module.css"  export default () => (   <footer className={style.colophon}>     <p>© {new Date().getFullYear()} | This site is Powered by {'   ' } <a href="https://www.gatsbyjs.org">GatsbyJS</a> {'   and  '} <a href="https://www.wordpress.org">WordPress</a></p>   </footer> )

Now, let’s restart our development server. We should see the following, including a new customized header and footer. I used the same style from Learning Gatsby which is an online course by Morten Rand-Hendriksen (I am a fan!).

Screenshot showing modified header and footer styling.
Screenshot showing modified header and footer styling.

You can grab the all the code I used over at GitHub.

What all this means for WordPress enthusiasts

There are many posts that compare the advantages and disadvantages of a decoupled WordPress and Jamstack site like the Gatsby examples we’ve covered. In my research, I realized that none of them are as exhaustive as what Chris already wrote in ”WordPress and Jamstack” where he compares everything, from performance and features, to the developer experience and build processes, and beyond.

I found the following articles draw some helpful conclusions on a variety of topics, including:

What’s the cost?

The general assumption is that Jamstack hosting is cheap, and cheaper than traditional LAMP stack hosting. But there’s actually quite a bit to consider and your actual costs might vary.

  • “How to Run Your WordPress Site On Local, Gatsby and Netlify for FREE!” (Nate Fitch): Nate’s take is that a headless WordPress setup like this might be a good option if the project is a static blog or a site that doesn’t require any interactions. For example, It wouldn’t take too much work to get images hosted on Cloudinary, or another CDN, but it would for large, interactive sites.
  • “WordPress and Jamstack” (Chris Coyier): There’s a specific section in here where Chris breaks down the pricing for different types of hosting for Jamstack sites and why a blanket statement like “Jamstack is cheaper” doesn’t fly because the actual cost depends on the site and its usage.
  • “Choosing between Netlify, Vercel and Digital Ocean” by (Zell Liew): Zell discusses his experience choosing a hosting plan. His take: If you have a small project, go with Netlify; if you have a larger project, use Digital Ocean.

Why go static at all?

Considering all the things you get for “free” in WordPress — think comments, plugins, integrations, etc. — you might wonder if it’s even worth trading in a server-side setup for a client-side solution. In his “Static or Not?” post, Chris breaks down the reasons why you’d want to choose one over the other.

How do we get commenting functionality?

We get native commenting right out of the box with WordPress. Yet, support for comments on a static site is a bit of a juggernaut. In “JAMstack Comments” here on CSS-Tricks, the author explains how dynamic comments can be implemented in a static site, like Gatsby, using Netlify services. I briefly touched on this in my previous article.

What about SEO?

  • “Gatsby SEO For WpGraphQL and Yoast” (Gatsby Community Plugin): The widely used Yoast SEO plugin for WordPress can be integrated into a Gatsby front-end using this plugin.
  • “A primer on JavaScript SEO for WordPress” (Jono Alderson): This exhaustive guide includes a section on how to integrate Yoast SEO into a headless architecture and the implications of relying on JavaScript for SEO. The bottom line is that theme and plugin developers shouldn’t worry much about the changing landscape of JavaScript and SEO as long as they continue following best practices. At the same time, they should be aware of what’s changing and adapt accordingly.

How do things work together?

There are currently no Gatsby React templates that are geared toward non-developers but some agencies, like Gatsby WP Themes and the Themeforest marketplace, are beginning to fill the gap. For example, Gatsby WP Themes covers plugins for dynamic contents like MailChimp integration, using the Contact Form 7 plugin for forms, Yoast SEO, and more. Themeforest lists 30+ Gatsby templates, including the Gatsby – WordPress + eCommerce theme which gives you an idea of how far we can go with this sort of setup. Just remember: these are commercial sites, and much of what you’ll find has a cost attached to it.

My evolving personal take

If you recall, I ended my last article with a personal reflection on my journey to create a headless WordPress site that uses Gatsby as the front end. My initial take was less than a glowing review:

Based on my very limited experience, I think that currently available Gatsby WordPress themes are not ready for prime time use for users like me. Yeah, it is exciting to try something on the bleeding edge that’s clearly in the minds of many WordPress users and developers. At the same time, the constantly evolving work being done on the WordPress block editor, WPGraphQL and Gatsby Source WordPress plugins makes it difficult to predict where things are going and when it will settle into a state where it is safe to use in other contexts.

So, after all this my long journey to headless WordPress site, what is my take now? As an open-minded learner, my thoughts are still evolving. But I couldn’t agree more with what Chris says in his “Static or Not?” post:

It’s a perfectly acceptable and often smart choice to run a WordPress site. I think about it in terms of robustness and feature-readiness. Need e-commerce? It’s there. Need forms? There are great plugins. Need to augment how the CMS works? You have control over the types of content and what is in them. Need auth? That’s a core feature. Wish you had a great editing experience? Gutenberg is glorious.

I am a WordPress enthusiast and I love WordPress as a CMS. However, as a technological learning challenge, I have not given up yet to have a decoupled WordPress site as a personal project.

I must admit that learning to create a decoupled Gatsby site with WordPress has continued to be frustrating. I acknowledge that any modern technology stack is not “a cup of tea” for many WordPress users. Gatsby has steep learning curve as these stacks are targeted for experienced React and JavaScript developers.

Self-learning a new technology can be a frustrating experience. Learning Gatsby is especially frustrating if we (including yours truly) happen to lack experience with Node, React, JavaScript and, most importantly, GraphQL. My learning project sites would break because of some dependency and fixing it might take me several days of research. I sometimes wonder if the trouble is worth the outcome. Don’t get me wrong; my frustration is with my own lack of experience, not the frameworks themselves (because they are amazing).

Even experienced developers like David Cramer and Jared Palmer find using Gatsby and GraphQL frustrating and echo some of the same sentiments that we beginners face when using GraphQL. I couldn’t agree more with David who writes:

It’s a static website generator. It literally does not need GraphQL all over the place. While there are few instances in the real world where that is valuable, it shouldn’t require a GraphQL API to read objects that are already in memory.

GraphQL is an opinionated query language API and its specification changes frequently. Indeed, most of the discussion in the WPGraphQL Slack are related to queries.

While working on this project, I came cross the Frontity React Framework while reading an article on CSS-Tricks. It fetches all WordPress data with the REST API without writing a single query. That seems to be a better option, at least for my use case. Additionally, it appears to be a much simpler alternative. In my brief experience with it, I didn’t have to deal with any dependency or library issues at all. Frontity’s themes concept is so WordPress-y and provides excellent tutorials.

I am currently exploring whether the Frontity framework would be a better option for my decoupled project site and will share my experience in a future article.

Resources

Gatsby feels like it is targeted at experienced React and JavaScript developers, not for beginners like me! The gatsby-source-wordpress and gatsby-source-wpgraphql plugins do an excellent job of exposing WordPress data into Gatsby sites, but the rest is up to users to present the data on the front end using your framework of choice: React, Vue, Next, etc.

A lack of sound knowledge of React and JavaScript is the main hurdle for beginners. The Gatsby community fills a lot of these gaps, and there are a lot of resources available to keep learning and exploring.

Gatsby Conference 2021 talks

Two workshop talks from the recent 2021 Gatsby Conference were related to Gatsby WordPress sites. In one, Jason Bahl hosts a workshop that walks through how to create a Gatsby blog powered by WordPress data, including support the Yoast SEO plugin, and how to deploy the site to Gatsby Cloud.

There’s another workshop hosted by WP Engine’s Matt Landers where he demonstrates how to set things up using the Advanced Custom Fields plugin to create a team member page.

Both talks are good, especially if you learn better with hands-on experience. I also found this Matt Report podcast episode with Jason Bahl where Jason answers basic questions that are geared toward beginners.

Tutorial courses

Morten Rand-Hendriksen has an excellent course on LinkedIn Learning that uses the Gatsby Source WordPress plugin. If you are interested in more hands-on experience making a customized site that expands on the two Gatsby starters we covered, this course is great because in teaches how to create a complete working site, complete with a dropdown header navigation, footer menus, posts, pages, categories, tags, and page navigation.

Check that out, a homepage, post template, categories, tags, a header that includes navigation… there’s a lot going on here!

The exercise files for the course are available in the GitHub LinkedIn Learning repository.

Gatsby starters

At the time I’m writing this, there are ten Gatsby starters for WordPress. As we mentioned earlier, only Gatsby Starter WordPress Twenty Twenty is based on the latest version of the Gatsby Source WordPress plugin; the rest are version 3.


Thanks for reading. I am always interested to know how fellow WordPress users who lack heavy technical experience like me are using this plugin. If you have any feedback, please feel free to post them in the comments.


The post Using New Gatsby Source WordPress Plugin appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , ,
[Top]

Creating CSS APIs without JavaScript With the datasette-css-properties plugin

Simon Willison has a project called Datasette, an open source multi-tool for exploring and publishing data. I’m not sure I’m qualified to explain it, but it’s like a tool to make handling data easier and doing more — through the web — with data you have. Like making that data queryable and giving it an API.

I would think, typically, you’d get the results of an API call against your data in something useful, like JSON. But Simon made a plugin that outputs the results as CSS custom properties instead, and blogged it:

It’s very, very weird—it adds a .css output extension to Datasette which outputs the result of a SQL query using CSS custom property format. This means you can display the results of database queries using pure CSS and HTML, no JavaScript required!

Here’s what I said just recently in “Custom Properties as State”:

This makes me think that a CDN-hosted CSS file like this could have other useful stuff, like today’s date for usage in pseudo content, or other special time-sensitive stuff. Maybe the phase of the moon? Sports scores?! Soup of the day?!

And Simon is like, how about roadside attractions?

My brain automatically worries about the accessibility of that, but… aren’t pseudo-elements fairly and reliably read in screen readers these days? You still can’t select the text though, or find-on-page, which are both usability and accessibility issues, so don’t consider this like a real thing that you really do for production work with unknown users.

His blog post demonstrates a slightly more dynamic example where the time of day outputs a different color. That makes me think of @property and declaring types for custom properties. I think this gets a smidge more useful when you can use the values that come back as specific syntaxes.


The post Creating CSS APIs without JavaScript With the datasette-css-properties plugin appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , , , ,
[Top]

Designing a JavaScript Plugin System

WordPress has plugins. jQuery has plugins. Gatsby, Eleventy, and Vue do, too.

Plugins are a common feature of libraries and frameworks, and for a good reason: they allow developers to add functionality, in a safe, scalable way. This makes the core project more valuable, and it builds a community — all without creating an additional maintenance burden. What a great deal!

So how do you go about building a plugin system? Let’s answer that question by building one of our own, in JavaScript.

I’m using the word “plugin” but these things are sometimes called other names, like “extensions,” “add-ons,” or “modules.” Whatever you call them, the concept (and benefit) is the same.

Let’s build a plugin system

Let’s start with an example project called BetaCalc. The goal for BetaCalc is to be a minimalist JavaScript calculator that other developers can add “buttons” to. Here’s some basic code to get us started:

// The Calculator const betaCalc = {   currentValue: 0,      setValue(newValue) {     this.currentValue = newValue;     console.log(this.currentValue);   },      plus(addend) {     this.setValue(this.currentValue + addend);   },      minus(subtrahend) {     this.setValue(this.currentValue - subtrahend);   } }; 
 // Using the calculator betaCalc.setValue(3); // => 3 betaCalc.plus(3);     // => 6 betaCalc.minus(2);    // => 4

We’re defining our calculator as an object-literal to keep things simple. The calculator works by printing its result via console.log.

Functionality is really limited right now. We have a setValue method, which takes a number and displays it on the “screen.” We also have plus and minus methods, which will perform an operation on the currently displayed value.

It’s time to add more functionality. Let’s start by creating a plugin system.

The world’s smallest plugin system

We’ll start by creating a register method that other developers can use to register a plugin with BetaCalc. The job of this method is simple: take the external plugin, grab its exec function, and attach it to our calculator as a new method:

// The Calculator const betaCalc = {   // ...other calculator code up here 
   register(plugin) {     const { name, exec } = plugin;     this[name] = exec;   } };

And here’s an example plugin, which gives our calculator a “squared” button:

// Define the plugin const squaredPlugin = {   name: 'squared',   exec: function() {     this.setValue(this.currentValue * this.currentValue)   } }; 
 // Register the plugin betaCalc.register(squaredPlugin);

In many plugin systems, it’s common for plugins to have two parts:

  1. Code to be executed
  2. Metadata (like a name, description, version number, dependencies, etc.)

In our plugin, the exec function contains our code, and the name is our metadata. When the plugin is registered, the exec function is attached directly to our betaCalc object as a method, giving it access to BetaCalc’s this.

So now, BetaCalc has a new “squared” button, which can be called directly:

betaCalc.setValue(3); // => 3 betaCalc.plus(2);     // => 5 betaCalc.squared();   // => 25 betaCalc.squared();   // => 625

There’s a lot to like about this system. The plugin is a simple object-literal that can be passed into our function. This means that plugins can be downloaded via npm and imported as ES6 modules. Easy distribution is super important!

But our system has a few flaws.

By giving plugins access to BetaCalc’s this, they get read/write access to all of BetaCalc’s code. While this is useful for getting and setting the currentValue, it’s also dangerous. If a plugin was to redefine an internal function (like setValue), it could produce unexpected results for BetaCalc and other plugins. This violates the open-closed principle, which states that a software entity should be open for extension but closed for modification.

Also, the “squared” function works by producing side effects. That’s not uncommon in JavaScript, but it doesn’t feel great — especially when other plugins could be in there messing with the same internal state. A more functional approach would go a long way toward making our system safer and more predictable.

A better plugin architecture

Let’s take another pass at a better plugin architecture. This next example changes both the calculator and its plugin API:

// The Calculator const betaCalc = {   currentValue: 0,      setValue(value) {     this.currentValue = value;     console.log(this.currentValue);   },     core: {     'plus': (currentVal, addend) => currentVal + addend,     'minus': (currentVal, subtrahend) => currentVal - subtrahend   }, 
   plugins: {},     
   press(buttonName, newVal) {     const func = this.core[buttonName] || this.plugins[buttonName];     this.setValue(func(this.currentValue, newVal));   }, 
   register(plugin) {     const { name, exec } = plugin;     this.plugins[name] = exec;   } };    // Our Plugin const squaredPlugin = {    name: 'squared',   exec: function(currentValue) {     return currentValue * currentValue;   } }; 
 betaCalc.register(squaredPlugin); 
 // Using the calculator betaCalc.setValue(3);      // => 3 betaCalc.press('plus', 2); // => 5 betaCalc.press('squared'); // => 25 betaCalc.press('squared'); // => 625

We’ve got a few notable changes here.

First, we’ve separated the plugins from “core” calculator methods (like plus and minus), by putting them in their own plugins object. Storing our plugins in a plugin object makes our system safer. Now plugins accessing this can’t see the BetaCalc properties — they can only see properties of betaCalc.plugins.

Second, we’ve implemented a press method, which looks up the button’s function by name and then calls it. Now when we call a plugin’s exec function, we pass it the current calculator value (currentValue), and we expect it to return the new calculator value.

Essentially, this new press method converts all of our calculator buttons into pure functions. They take a value, perform an operation, and return the result. This has a lot of benefits:

  • It simplifies the API.
  • It makes testing easier (for both BetaCalc and the plugins themselves).
  • It reduces the dependencies of our system, making it more loosely coupled.

This new architecture is more limited than the first example, but in a good way. We’ve essentially put up guardrails for plugin authors, restricting them to only the kind of changes that we want them to make.

In fact, it might be too restrictive! Now our calculator plugins can only do operations on the currentValue. If a plugin author wanted to add advanced functionality like a “memory” button or a way to track history, they wouldn’t be able to.

Maybe that’s ok. The amount of power you give plugin authors is a delicate balance. Giving them too much power could impact the stability of your project. But giving them too little power makes it hard for them to solve their problems — in that case you might as well not have plugins.

What more could we do?

There’s a lot more we could do to improve our system.

We could add error handling to notify plugin authors if they forget to define a name or return a value. It’s good to think like a QA dev and imagine how our system could break so we can proactively handle those cases.

We could expand the scope of what a plugin can do. Currently, a BetaCalc plugin can add a button. But what if it could also register callbacks for certain lifecycle events — like when the calculator is about to display a value? Or what if there was a dedicated place for it to store a piece of state across multiple interactions? Would that open up some new use cases?

We could also expand plugin registration. What if a plugin could be registered with some initial settings? Could that make the plugins more flexible? What if a plugin author wanted to register a whole suite of buttons instead of a single one — like a “BetaCalc Statistics Pack”? What changes would be needed to support that?

Your plugin system

Both BetaCalc and its plugin system are deliberately simple. If your project is larger, then you’ll want to explore some other plugin architectures.

One good place to start is to look at existing projects for examples of successful plugin systems. For JavaScript, that could mean jQuery, Gatsby, D3, CKEditor, or others.

You may also want to be familiar with various JavaScript design patterns. (Addy Osmani has a book on the subject.)  Each pattern provides a different interface and degree of coupling, which gives you a lot of good plugin architecture options to choose from. Being aware of these options helps you better balance the needs of everyone who uses your project.

Besides the patterns themselves, there’s a lot of good software development principles you can draw on to make these kinds of decisions. I’ve mentioned a few along the way (like the open-closed principle and loose coupling), but some other relevant ones include the Law of Demeter and dependency injection.

I know it sounds like a lot, but you’ve gotta do your research. Nothing is more painful than making everyone rewrite their plugins because you needed to change the plugin architecture. It’s a quick way to lose trust and discourage people from contributing in the future.

Conclusion

Writing a good plugin architecture from scratch is difficult! You have to balance a lot of considerations to build a system that meets everyone’s needs. Is it simple enough? Powerful enough? Will it work long term?

It’s worth the effort though. Having a good plugin system helps everyone. Developers get the freedom to solve their problems. End users get a large number of opt-in features to choose from. And you get to grow an ecosystem and community around your project. It’s a win-win-win situation.


The post Designing a JavaScript Plugin System appeared first on CSS-Tricks.

You can support CSS-Tricks by being an MVP Supporter.

CSS-Tricks

, , ,
[Top]

WordPress Plugin Overload? Give Jetpack a Try!

The WordPress ecosystem has a plentiful supply of plugins that offer everything from AMP to Zapier integration and so, so, so many other things in between. It’s a significant contributor to what makes WordPress great because plugins can account for the needs of nearly any website.

How many plugins are installed on your WordPress site? Five? Fifteen? Fifty? We’ve been up to 31 plugins here at CSS-Tricks and we rely on them for everything from content delivery to performance. Why rebuild the wheel if you don’t have to right? It’s simply too easy and convenient to reach for something someone else has already created (and for free).

Whether you have a handful or a truckload of plugins, you know that each one adds a little bit of complexity to your site, especially when it comes to maintenance and updates. It’s not uncommon to see that little badge at the top of the WordPress admin bar displaying a number of available plugin updates that are ready to install. The problem is that it can happen a lot and staying on top of updates turns almost into a game of Whack-a-Mole that not only eats up time, but risks conflicts on your site that could break things. Plugins are great! But mashing up code from third-party authors is always a (often slight) possibility.

One way to cut down on the number of plugins: Jetpack. It’s a single plugin that provides the features and functionality of dozens. the number of plugins on CSS-Tricks would likely be much higher if we weren’t relying on it for blocking spam comments, security scans, search, social sharing, post subscriptions, and displaying related posts… just to name a few. Jetpack is literally capable of so much that’s hard to contain in a single post. We’ve outlined our favorites, though. And we can’t recommend it enough.

Try Jetpack on your WordPress site to see all the ways it can help you.

The post WordPress Plugin Overload? Give Jetpack a Try! appeared first on CSS-Tricks.

CSS-Tricks

, , , ,
[Top]