How to embed Svelte apps inside PHP?
Justin Ahinon
Last updated on
Heads up!
Svelte version: 4.2.0
rollup-plugin-svelte version: 7.1.6
GitHub repository: https://github.com/JustinyAhin/twentytwenty
During my time as a Senior Frontend Engineer at WebDevStudios, we were walking on a lot of headless WordPress projects with custom PHP WordPress themes.
One of them was the new NBA Cares website. While building this site, we faced situations where we needed some highly interactive sections/components that would be hard to build with PHP or just vanilla JavaScript .
As a Svelte enthusiast, I advocated a lot for trying Svelte for those components .
This blog post is a summary of the approach we used, and more generally, a guide on how to embed Svelte apps inside monolithic PHP apps.
Why adding Svelte to my PHP codebase?
You might be wondering:
Why would I add Svelte to my PHP codebase? I can do everything with PHP.
What are the benefits of adding Svelte to my PHP codebase?
These are all legitimate questions. Let's try to answer them.
First, from my experience teams / people who go to using Svelte inside PHP codebases have one (or all) of these motivations:
They are in the process of migrating their codebase to a modern JavaScript framework
This is the most common use case I've noticed. The team is in the process of migrating their codebase to a modern JavaScript framework (React, Vue, Svelte, etc.). They want to start using the new framework for new features, but they don't want to rewrite the whole codebase at once . So, the solution is to do it progressively.
Svelte makes this incremental adoption very straightforward by allowing developers to write and bundle Svelte components, and import them as JavaScript modules in their PHP codebase.
Remember, at its core, Svelte is a compiler that turns your declarative Svelte components into highly performant native JavaScript code.
No need to set up complex systems to handle a frontend framework runtime on your application. Just import the JavaScript code generated by Svelte and you're good to go.
They need some interactivity or state management features that hard to implement with PHP / vanilla JavaScript
Modern JavaScript frameworks like Svelte provide powerful capabilities for building interactive UI components with minimal code . Features like declarative bindings, built-in state management, and reactive directives allow developers to create dynamic interfaces that would require significantly more effort with plain PHP/JS.
For example, implementing complex interactions like drag-and-drop, infinite scroll, or live filtering/searching using vanilla PHP/JS often involves a lot of imperative DOM manipulation and "state juggling" between HTML, JS, and PHP.
With Svelte, the same features can be built in a declarative in a fraction of the code.
State management with global stores/contexts, custom events, lifecycle hooks, etc. also becomes much simpler compared to passing data back and forth between PHP controller logic. This makes it easier to build encapsulated, reusable components with managed internal state.
So for teams that need richer interactivity and state management, adding Svelte components can provide a big productivity boost compared to staying within PHP/JS. The components handle the complex UI code internally, while exposing a simple interface to the rest of the PHP app.
Practical example: building an interactive and filterable blog posts search component inside a PHP WordPress theme
Now that you've seen why you might want to add Svelte to your PHP codebase, let's see how to do it in practice. For this example, we will build a blog posts search component that will be embedded inside a PHP WordPress theme.
The idea is to be able to:
Fetch blog posts from the WordPress REST API inside the Svelte component
Filter the blog posts by category
Filter the blog posts by search query
Here is a demo video of the final result:
You can also check the theme code on GitHub here:
For this example, I'm going to use a "classic" (or PHP) WordPress theme, Twenty Twenty.
In order to not mess up with the theme architecture, I've created a new custom page template named "Svelte Posts Search".
Initially, it's just a replicate of the default singular.php
of Twenty Twenty that I'll later on update with my custom Svelte component code.
Setup
Since it's the compiled JavaScript by Svelte that we are including in our WordPress, we need a tool that will transpile our Svelte code to JavaScrip t.
For that, I like using Rollup. It's a module bundler that allows you to write your code in the latest JavaScript syntax and bundle it for production. It's also very easy to use with Svelte.
I'm also going to use TypeScript as much as possible (in my Svelte components).
I like and highly recommend using Svelte with TypeScript. The experience is really worth it, and the benefits in terms of developer experience and code maintainability are high.
I wrote a blog post about why I like using TypeScript with Svelte and SvelteKit here.
Let's start by installing the needed dependencies:
code loading...
Now, we can go ahead and create our Rollup configuration file:
code loading...
Note that here we are using the .mjs
extension for the Rollup file. This is because our package.json
doesn't contain a "type": "module"
.
Here is what's happening in the config:
We define the entry point of our Svelte app.
We define the output format
And we add the necessary plugins
Another nice addition to the project would be a minimal tsconfig.json
file for proper TypeScript support.
code loading...
We are now ready to start writing Svelte code inside our WordPress theme.
Our first Svelte component
Svelte entry point
As you saw above, our Svelte code is going to be located in the svelte
folder at the root directory. Inside this folder, we have a main.ts
entry point.
code loading...
What's happening here is quite simple. We are importing an App.svelte
component (we'll create this in the next step), and exporting the component, with the target being an element with the id wp-svelte-search
.
Add the target for the Svelte application in the template
This is actually an HTML element that we need to create in the PHP template (the custom WordPress template we created earlier), and on which the Svelte application is going to be hooked.
Here is the full code for the PHP template. Notice that we are creating an empty div
element with the wp-svelte-search
ID.
code loading...
Enqueue the compiled JavaScript in our theme
Now, it's time to enqueue the compiled JavaScript in our theme. Firs, let's add the following scripts in our package.json
to watch and build the JavaScript.
code loading...
We can now update the theme function.php
to include the script.
Ideally, I would have done that in a WordPress child theme, but, for the sake of keeping this article simple, I will add it directly to the main theme functions.php.
code loading...
Here, we are updating the initial twentytwenty_register_scripts()
function to enqueue the script, and then, we are using the script_loader_tag
to load the script as a JavaScript module.
Create the Svelte component
The last step in the process is to create the App.svelte
component.
code loading...
Quite simple right? Just a h1
tag with a red font color and a console.log()
.
Fetching data from the WordPress REST API
The first step in creating our blog posts search component is to fetch the blog posts from the WordPress REST API. This is quite simple if you look at the documentation of the WordPress REST API.
code loading...
Since we are using the browser fetch API, we need to make sure our component is mounted before fetching the data. This is why we are using the onMount
lifecycle hook. Doing that help us in two ways:
We can wrap the
onMount
callback in anasync
function and use theawait
keyword to wait for the response.We avoid potentials errors that could happen if we try to fetch the data before the component is mounted. See https://www.okupter.com/blog/sveltekit-document-is-not-defined and https://www.okupter.com/blog/sveltekit-window-is-not-defined for more details on this.
Note that I'm casting the response to the WP_Post type that is defined in another file. This is because I'm using TypeScript. If you are using plain JavaScript, you can remove this line.
Once we have the data, we can use it in our component.
code loading...
With this code, we are looping over the filteredPosts
array and displaying the title and the excerpt of each post.
Searching and filtering the posts
The next step is to add the search and filter functionality to our component. This is also quite simple with Svelte. We need a search input field, and we need to filter the posts array based on what's being typed.
Now, since we will make many operations on the posts
array, it's a good idea to create another variable that will be reactive to posts
and on which we will perform the filtering operations; while preserving the initial posts array.
code loading...
A lot of things are happening here, but let's break it down:
The search input field is bound to the
searchPosts
function on thekeyup
event.Every time this event is fired, we get the value of the input field, and we filter the
posts
array based on this value.
This will automatically update the markup and display the filtered posts.
Now, this implementation is very simple and works well since the data we are filtering on is already local. In case we need to fetch the data from an external API, we might need to use a more advanced technique like debouncing.
Filtering by category
Now, let's tackle the category filtering. This is a bit more complex than the search filtering because we need to fetch the categories from the WordPress REST API, and then, we need to filter the posts based on the selected category.
Here are the utilities functions that I've used to handle different parts of this:
code loading...
getCategoryData()
is a function that fetches a category from the WordPress REST API based on its ID.getUniqueCategoriesFromPosts()
returns an array of unique categories from an array of posts.getCategoryCountInPosts()
returns the number of posts that belong to a specific category.
Notices that here, although I could have directly used the posts array for the last two functions, I'm still passing it as an argument.
This is because I want to make sure that the functions are pure and don't mutate the posts array if they are used somewhere else in the component.
Also, this will make things easier in the future if we need to use these functions in another component.
Let's take a look at the markup for the filter:
code loading...
Let's break down again what we are doing here:
We created a reactive
checkedCategoriesIds
array that will hold the IDs of the selected categories.We are using the
checkedCategoriesIds
array to filter theposts
array and display only the posts that belong to the selected categories. In case no category is selected, we display all the posts.In the markup, we loop over the unique categories and display them as checkboxes. We also display the number of posts that belong to each category.
All the checkboxes are bound to the
checkedCategoriesIds
array thanks to Sveltebind:group
binding.
And that's it! We now have a fully functional blog posts search component that we can embed inside our PHP WordPress theme.
Conclusion
In this post, we explored how to embed interactive Svelte components into a PHP codebase, using a WordPress theme as a practical example.
The key takeaways are:
Svelte's compiled output is just JavaScript, which makes it easy to integrate into any backend using simple script tags. No complex integration logic needed.
For development, you can use a bundler like Rollup to watch your Svelte code and output browser-ready JS bundles.
Svelte components can fetch data from PHP APIs and integrate tightly with the backend, while keeping complex UI code encapsulated.
Features like declarative bindings, reactivity, and stores make it simple to build interactive interfaces that would require much more imperative code with PHP/JS.
Svelte is a great way to progressively modernize a PHP app, by gradually replacing PHP view code with reusable components.
Overall, adding Svelte allows you to leverage the benefits of a modern web framework incrementally, without needing to rewrite your entire app.
So if you have a PHP app and are looking to enhance the frontend with more interactivity and cleaner code, give Svelte a try! Start small, and you'll soon find places where it can really improve your development experience.