dennismenken / scratchstart-theme
A bare-bones, dependency-free WordPress starter theme. Ships without own CSS or JavaScript so page builders such as Elementor stay in full control and the site stays lightning fast.
Package info
github.com/dennismenken/scratchstart-theme
Type:wordpress-theme
pkg:composer/dennismenken/scratchstart-theme
Requires
- php: >=8.4
- composer/installers: ^2.3
Requires (Dev)
- phpstan/phpstan: ^2.1
- szepeviktor/phpstan-wordpress: ^2.0
README
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.
Why
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.
Features
- 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.
Requirements
- WordPress 6.4 or newer (tested up to 6.9)
- PHP 8.4 or newer
Installation
Option A — ZIP from GitHub Releases
- Grab
scratchstart.zipfrom the latest GitHub Release. - In WordPress admin: Appearance → Themes → Add New → Upload Theme.
- Upload the ZIP and activate.
Option B — Composer (Bedrock, composer-managed WP, etc.)
composer require dennismenken/scratchstart-theme
composer/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" }
]
}
Option C — Clone for development
cd wp-content/themes
git clone https://github.com/dennismenken/scratchstart-theme.git scratchstart
Customization
Opt-in chrome
The 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.
Optional WordPress core cleanup
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.
Forking
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.
Development
Install dev dependencies:
composer install
Run static analysis (PHPStan level 6, with WordPress stubs via
szepeviktor/phpstan-wordpress):
composer analyse
Run a quick PHP syntax sweep over every template:
composer lint
CI runs both on every push to main and on every pull request via
.github/workflows/ci.yml.
Release process (maintainers)
- 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.
License
WTFPL — Do What The F*ck You Want To Public License.
Credits
Changelog
2.0.0
- 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).
1.0.0
- Initial release.