Starter Theme Generator
A working classic PHP theme as files: the template hierarchy, functions.php with the supports that matter, and an optional Tailwind build.
Enable JavaScript to change the fields; the files below are for the defaults.
Goes in the style.css header, which is how WordPress finds the theme at all.
Leave empty to use the theme name. This is also the default text domain.
Must match the folder name for WordPress.org translations to load. Empty uses the folder name.
Every function in functions.php starts with this. Empty derives it from the folder name.
title-tag is required by the theme directory and by most SEO plugins. html5 and editor-styles are expanded into the calls they actually need.
Create this folder: wp-content/themes/acme-starter
Block themes are the default, and there is a generator here for those. This makes the other kind: the PHP
theme with a template hierarchy, which is still what you want when the design is not expressible as block
templates, when templates need their own queries, or when a client’s plugins expect the_content()
inside a loop in a file you control.
What it writes is deliberately small. An underscores-style starter ships a couple of thousand lines, including a navigation script, a customizer stub and a set of template tags, most of which get deleted on day one. This writes the files the hierarchy actually requires, the theme supports that matter, and nothing you have to read before you can remove it.
How to use
- Name the theme. The folder name and text domain follow it unless you set them.
- Choose the theme supports.
title-tagis required by the theme directory and by most SEO plugins. - Decide about menus, a widget area and Tailwind.
- Copy the files into
wp-content/themes/your-theme/and activate.
Example
The default set produces thirteen files:
wp-content/themes/acme-starter/
style.css the header WordPress reads to find the theme
functions.php setup, assets, menus
header.php doctype to the opening main, with wp_head and wp_body_open
footer.php the close, with wp_footer
index.php the fallback, and the only file WordPress insists on
single.php a post, with comments and post navigation
page.php a page
archive.php categories, tags, authors, dates, taxonomies
search.php results, with the search form when there are none
404.php a search form and a way back
comments.php so core does not fall back to theme-compat
template-parts/content.php one entry, called by all of the above
Turning on the widget area adds sidebar.php and the register_sidebar() call; turning on Tailwind adds
package.json, tailwind.config.js and src/input.css, and points the stylesheet enqueue at
build/style.css.
Pitfalls
wp_head(), wp_body_open() and wp_footer() are not optional. Plugins hook all three. A theme
missing one breaks analytics, the admin bar and a good part of the plugin directory, and the failure is
silent.
The text domain must match the folder name for translations from WordPress.org to load. It is the single commonest reason a translated theme shows English.
Version your stylesheet by its modification time. The generated functions.php uses filemtime(). A
hard-coded version string is the reason a client says they cannot see the change: their browser still has
the old file.
Every function needs a prefix. PHP has one global namespace for functions, so setup() in a theme is
a fatal error waiting for the plugin that also defines it.
comments.php matters even if you do not want comments. Without it, core falls back to
wp-includes/theme-compat/comments.php and emits a deprecation notice that sits in a log for years.
the_content(), not echo $post->post_content. The filters are what make shortcodes, blocks and
embeds work; skipping them breaks half the plugins on a site in a way that looks like the plugins’ fault.
A classic theme does not get core block styles automatically. wp-block-styles is in the supports
list for that reason: without it, blocks in post content render unstyled on the front end.
Tailwind’s preflight strips the margins post content relies on. The generated input.css puts them
back inside .entry-content rather than turning preflight off, which would cost you the rest of the
reset.
Check the Tailwind content globs when you add a directory. A class that only appears in a file the globs miss is a class that works locally and vanishes in production.
Compatibility
Every file is also downloadable as a single .zip, built in your browser. The archive stores the files rather than deflating them, which is what WordPress’s own installer reads, and the whole set goes in a folder named after the theme, so Appearance → Themes → Add New → Upload installs it directly. The writer was checked by installing what it produces through WP-CLI on WordPress 7.1.2, activating it, and loading the home page.
Targets WordPress 6.5 and PHP 7.4 and up, both declared in the style.css header so the Themes screen can refuse an older install.
The generated theme was checked against WordPress rather than against itself: the files were written into
wp-content/themes, the theme was activated on a WordPress 7.1.2 install, and the home page, a search and
a 404 were requested. All three rendered, with entries, pagination and the footer credit, and nothing in
the log.
Both languages generate the files here: the browser builds them as you type, and PHP builds the same ones for the first paint, which is why the page works with JavaScript off. The build compares the two outputs across seven cases, including hostile input, so a change to one that is not made to the other fails the build rather than showing up as a page that changes after it loads.
Every PHP file of every test case goes through php -l. Generated code that does not parse is worse than
no generator, and the hostile case puts quotes, backslashes, */ and ?> through the theme name, author,
prefix and text domain.
The theme does not include a screenshot.png, a readme.txt or a languages folder. The first is a picture, the second has its own generator here, and the third is empty until you have strings to translate.
Frequently asked questions
Should I start a new site with this or with a block theme?
Is this underscores?
Can I add a block editor to it?
wp-block-styles,
align-wide and editor-styles is what makes the editor and the front end agree.How do I add a custom template?
single-book.php for a post type, taxonomy-genre.php for a
taxonomy, page-about.php for a specific page. The generated content.php is the part you reuse.