A bare-bones, dependency-free WordPress starter theme. Ships without custom CSS, JavaScript or opinionated markup so page builders such as Elementor stay in full control and the site stays lightning fast.
Most "minimal" WordPress themes still ship a stylesheet, header/footer markup,
default post titles and a 404 template. When the real rendering is done by a
page builder all of that becomes dead weight or, worse, fights the builder
(double H1, doubled headers, leftover sidebars). ScratchStart goes further than
Hello Elementor: by default the theme renders nothing beyond the document
skeleton and a single <main id="main"> wrapper holding the_content().
Header, footer, post title, post meta, comments, sidebar and the archive loop
are opt-in via filters.
- No own CSS, no own JavaScript — builders such as Elementor or Bricks own the frontend.
- No theme-rendered chrome by default —
<header>,<footer>, post title, post meta, sidebar, comments and the archive loop are opt-in via single-line filters. - Optional WordPress core cleanup (disable emojis / wp-embed JS / block-library CSS / RSD/wlw/generator/REST/shortlink head links), all opt-in or via a single
scratchstart_lightning_modemaster switch. - No
404.php: WordPress falls back toindex.phpso a builder's "Not Found" template can take over. - Clean, escaped, translation-ready template files.
wp_body_open()hook fired in the right place, skip-link and accessible<main id="main">available on demand.- Block-editor friendly:
responsive-embeds,post-thumbnails,html5,title-tag,automatic-feed-links. - Composer-installable as a
wordpress-themepackage. - Automated GitHub Release builds a ready-to-install ZIP.
- WordPress 6.4 or newer (tested up to 6.9)
- PHP 8.4 or newer
- Grab
scratchstart.zipfrom the latest GitHub Release. - In WordPress admin: Appearance → Themes → Add New → Upload Theme.
- Upload the ZIP and activate.
composer require dennismenken/scratchstart-themecomposer/installers places the theme under wp-content/themes/scratchstart/.
If the repository is not on Packagist yet, add it as a VCS repository:
{
"repositories": [
{ "type": "vcs", "url": "https://github.com/dennismenken/scratchstart-theme" }
]
}cd wp-content/themes
git clone https://github.com/dennismenken/scratchstart-theme.git scratchstartThe theme renders nothing besides the document skeleton and <main> by
default. Enable any chrome part you actually want from a child theme, a
mu-plugin or even a snippet plugin:
add_filter('scratchstart_render_skip_link', '__return_true');
add_filter('scratchstart_render_header', '__return_true');
add_filter('scratchstart_render_footer', '__return_true');
add_filter('scratchstart_render_post_title', '__return_true');
add_filter('scratchstart_render_post_meta', '__return_true');
add_filter('scratchstart_render_comments', '__return_true');
add_filter('scratchstart_render_sidebar', '__return_true');
add_filter('scratchstart_render_archive_loop', '__return_true');scratchstart_render_header and scratchstart_render_footer additionally
require an assigned menu (Header Menu / Footer Menu under
Appearance → Menus) before any markup is emitted. The sidebar opt-in
also requires at least one widget in the Main Sidebar area.
WordPress core itself injects a few things that page-builder workflows rarely need (emoji detection script, oEmbed JS, default block-library CSS, RSD/wlwmanifest/generator/REST/shortlink links). Each is opt-in:
add_filter('scratchstart_disable_emojis', '__return_true');
add_filter('scratchstart_disable_embed_script', '__return_true');
add_filter('scratchstart_disable_block_library_css', '__return_true');
add_filter('scratchstart_clean_head', '__return_true');Or flip all four at once:
add_filter('scratchstart_lightning_mode', '__return_true');scratchstart_disable_block_library_css removes both the classic block-library
CSS and the modern global-styles / classic-theme-styles handles. Re-enable
on a per-page basis if a single post relies on Gutenberg blocks.
scratchstart_disable_emojis also removes the emoji detection script in the
admin (matches the de-facto behaviour of "Disable Emojis"-style plugins) so
the editor doesn't ship the script either.
scratchstart_clean_head removes both the wp_head markup output and the
matching HTTP Link: headers (REST, shortlink) emitted on template_redirect.
Fork or clone, then search-and-replace the slug scratchstart and the text
domain across the codebase with your own theme name. The theme deliberately
avoids enqueueing anything — add a wp_enqueue_style call in
functions.php only if you actually ship styles.
Install dev dependencies:
composer installRun static analysis (PHPStan level 6, with WordPress stubs via
szepeviktor/phpstan-wordpress):
composer analyseRun a quick PHP syntax sweep over every template:
composer lintCI runs both on every push to main and on every pull request via
.github/workflows/ci.yml.
- Bump the
Version:header instyle.css. - Commit on
main. - Tag and push:
git tag v2.0.0 git push origin v2.0.0
- The
ReleaseGitHub Actions workflow verifies that the tag matchesstyle.css, lints every PHP file, buildsscratchstart.zipand attaches it to an auto-generated GitHub Release. Versions containing a hyphen (e.g.v2.1.0-rc1) are published as prereleases.
A manual workflow_dispatch run builds the ZIP as a workflow artifact without
creating a release — useful for smoke-testing changes.
WTFPL — Do What The F*ck You Want To Public License.
- Page-builder-first by default (breaking vs. 1.x): every chrome part –
<header>,<footer>, post title, post meta, comments, sidebar, archive loop, skip-link – is opt-in viascratchstart_render_*filters. Default theme output is just<!DOCTYPE>,<head>, body skeleton withwp_head/wp_body_open/wp_footer, and<main id="main">containingthe_content(). - Optional WordPress core cleanup filters:
scratchstart_disable_emojis,scratchstart_disable_embed_script,scratchstart_disable_block_library_css,scratchstart_clean_head(plusscratchstart_lightning_modemaster switch). All default off. - Bumped minimum PHP to 8.4. Added PHPStan (level 6) static analysis with
szepeviktor/phpstan-wordpressstubs and a CI workflow (.github/workflows/ci.yml) that runs on every push tomainand on every PR. - Removed
404.phpso WordPress falls back toindex.phpand lets a builder's "Not Found" template take over viatemplate_include. - Zero-CSS / zero-JS posture: theme no longer enqueues
style.css. - Hardened i18n: escaped output, consistent
scratchstarttext domain, fixedyour_themetypo,wp_ksesallowlist for translated HTML. - Modernised
functions.php: consolidatedafter_setup_themecallback,load_theme_textdomain,automatic-feed-links,responsive-embeds, widenedhtml5support. defined('ABSPATH') || exitguards on every template.- Sidebar template additionally collapses when no widgets are active even if opted in.
- Navigation menus require an assigned menu before emitting markup; no
wp_page_menuleak. composer.jsonfor installation as awordpress-themeComposer package.- GitHub Actions workflow publishes
scratchstart.zipon tag pushes. - Theme metadata refresh (
Requires at least,Tested up to,Requires PHP, correctAuthor URI).
- Initial release.