QuickWP.

A couple of weeks back, we released the prototype of QuickWP, an AI-powered WordPress site builder that uses OpenAI, an FSE theme, and WordPress Playground to generate a personalized theme for the user based on the topic and description of your website.

If you haven’t checked it out yet, you can see the preview of QuickWP on Twitter (aka X).

QuickWP - an AI-powered WordPress site builder

Building QuickWP has been a challenging and learning experience for us, and today, we are open-sourcing the code base for the project so you can also learn from it and maybe even build something awesome upon it.

In this article, I will discuss the ideas, challenges, and things we learned by working on QuickWP. I hope this helps you if you ever face similar challenges.

The idea

While we have thought of experimenting with AI and OpenAI APIs for a while, we never planned to create an AI website builder. Previously, we tried integrating AI with the Otter Blocks plugin to generate layouts from available patterns using AI prompt, but that implementation was quite primitive. The results were very generic and did not consider user context much in the provided result.

Given that patterns in Block Editor are easy to break even with minor changes, we could not simply ask GPT to create patterns on the fly or even ask it to replace content.

It all changed when we thought of this idea based on wireframes. It is simple: we create an FSE theme with wireframes and extensive color palettes. And then, with AI, we pick the patterns based on user prompts.

In FSE themes, using the theme.json file properties, we can easily modify the styling of the entire website from one place. And the same is applied to our patterns so that we have uniformity across the website without worrying about different patterns having different settings that need to be modified separately.

Here, we also use a CC0 image directory to populate the website with images to give a better starting point to the user.

While the idea sounds simple enough, it required some trials and errors for us to reach the point where it could generate results that were good enough for the user. The goal was to spend as little time as possible to create a prototype that users can use as a SaSS from the product website.

Overview of project stack

The project required more than one part, so we used a number of stacks, i.e., whatever made it easier for us to prototype as quickly as possible.

Here are the various parts of the project:

  • FSE Theme: The base of the project. It includes various patterns and a comprehensive theme.json file.
  • Base Plugin: This plugin has all the functionality and UI required to make the project work.
  • API Endpoint: An API endpoint communicating between the user website and OpenAI API.
QuickWP Diagram

Here is a simplified diagram to show the entire workflow.

FSE theme

The FSE theme works as the base of the entire project. To make prototyping easier, we started with a fork of the Twenty Twenty-Four theme. We pretty much removed all the patterns and customized the theme.json properties as per our needs.

FSE theme best practices are changing very quickly, and with each version of WordPress, we have a new way of doing things. Starting with the fork of the default theme allows us to build upon a solid foundation with minimal work.

In terms of code, most of the things are as you would expect in an FSE theme. The only difference you will notice is how we use strings and images in patterns.

Here, we add default text, template-specific namespace for the strings, and a default preview namespace to each string.

The default text is the text that will appear in the patterns when used normally, in case someone is adding a pattern inside the editor or using the theme without QuickWP AI.

The template-specific namespace is an identifier for that particular string. And the default preview namespace is a shared namespace that we use for all the strings in context. We will come back to this later.

AI prompt generation

As it was a quick prototype, we wanted to explore easier testing and implementation methods. We experimented with various AI models but ended up with the most popular option, which is OpenAI. During the development phase, we used GPT-4 as the results were much better with OpenAI’s latest model offering, but it was too costly, so we decided to shift to using GPT-3.5 Turbo for most tasks. I say most of the tasks as we are still using GPT-4 for color palette generation as the color variety was not great with GPT-3.5

For making requests, we tried different options that OpenAI offers but found the Assistant API best suited for our needs. To avoid some bad-faith actors, we also used OpenAI’s Moderation API to prevent processing the requests if they do not align with OpenAI’s content policies. As we can see after the release, people have tried to experiment with all sorts of prompts that could have landed our OpenAI account in trouble, so adding the moderation was worth the time. And yes, it is free to use!

Image generation

When we were imagining this project, one of the issues was how to generate images. We could, of course, use Dall-E or other models to do it, but they’re slow, low-quality, and quite expensive. It turned out that we were thinking in the wrong direction. Why generate images when there are millions and millions of CC0 images available on the internet?

After some consideration, we chose Pexels. The reason behind choosing Pexels was that it has more liberal request limits and a good catalog of images. And, of course, we link back to the original image on our app.

How do you maintain context site-wide?

The first problem we needed to solve to make this project work was to see how we could maintain context site-wide when generating content for the user. Different patterns have different numbers and types of strings, and we can’t just randomly add content there and hope it will be relevant for the website.

And this is where our great friend JSON came to the rescue. With some creative prompts (found in the source code) and a consistent JSON schema, we could maintain context throughout the website and have strings that complement each other, rather than random gibberish.

If you look at one of our templates, you will see how we list each pattern with a description to let the API know its purpose and what strings it contains.

For example, here’s the first pattern from that template:


{
    "order": 1,
    "slug": "quickwp/hero-centered",
    "name": "Hero Centered",
    "description": "Hero sections are used to introduce the product or service. They are the first and primary section of the website. This is a centered hero section with a large title, a subtitle and two buttons.",
    "category": "heroes_page_titles",
    "strings": [
        {
            "slug": "hero-centered/title",
            "description": "Main title of the hero section"
        },
        {
            "slug": "hero-centered/subtitle",
            "description": "Subtitle of the hero section"
        },
        {
            "slug": "hero-centered/button-primary",
            "description": "Primary button text of the hero section"
        },
        {
            "slug": "hero-centered/button-secondary",
            "description": "Secondary button text of the hero section"
        }
    ],
    "images": [
        {
            "slug": "hero-centered/image",
            "description": "Background image of the hero section"
        }
    ]
}

Each string, along with the namespace, also describes its connection to the rest of the pattern. This allows us to make sure that GPT does not repeat the same thing in multiple places and, for example, keeps the subtitle related to the title of the pattern.

When we get the request back on the site, we use the string slug to replace it in the pattern.

While our current implementation is primitive, you can use this approach to give even more context to the string, such as the length and tone of the string. This way, we only exchange the data and not the markup.

We need WordPress instances for each user

Another problem we needed to solve was to have an instance of WordPress for each user session. In our implementation, we are making changes live on the WordPress instance of the current user and then using existing WordPress functionality to export the FSE theme. Only if there was a solution to create WordPress instances without pretty much building a small web hosting solution…

Let me introduce you to WordPress Playground. Playground allows you to run WordPress in your browser with zero clicks. If you have not used the WP Playground, you will be surprised at how awesome it is!

What will you be building with WordPress?

Now that we have walked you through some of the challenges we faced, what will you be building with these tools? We hope the article inspired you to use some of the tools we discussed, like OpenAI API, FSE themes, and WordPress Playground, and build something awesome. If you do, let us know because we would love to try it!

Once again, all the source code is available on our GitHub, so feel free to use it in any way it can help you!

Yay! 🎉 You made it to the end of the article!

2 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Mark Mapstone
March 28, 2024 1:33 pm

Great. However the QuickWP plugin on the wordpress repository is 7 years old and creates a fatal error and downloading the Git quickwp-main.zip does the same. What am I doing wrong?

Or start the conversation in our Facebook group for WordPress professionals. Find answers, share tips, and get help from other WordPress experts. Join now (it’s free)!