401 / wordpress-base-theme
401 Wordpress Theme
Package info
bitbucket.org/weidenhammer/wordpress-base-theme
Type:wordpress-theme
pkg:composer/401/wordpress-base-theme
Requires
- php: >=5.3.2
- composer/installers: ~1.0.12
This package is auto-updated.
Last update: 2026-06-16 02:20:37 UTC
README
NOTE NOTE NOTE: This includes an experimental update to vite. If things are broken and you can't get things to work again, pull the commit before this called "tweak" and go from there instead
Internal starter theme for agency-built WordPress sites. Copy this theme and the companion plugin into a new project, rename as needed, and build on top of the shared structure instead of starting from scratch.
The theme handles presentation: templates, styles, blocks, and site-specific layout. The plugin handles reusable functionality: admin tweaks, shared utilities, AJAX handlers, and post-type logic that should survive a theme swap.
Requirements
- WordPress 6.9+
- PHP 8.2+
- Advanced Custom Fields Pro (post types, taxonomies, options pages, and ACF blocks)
- [Weidenhammer - Custom] (
hammer-marketing-customplugin, required) - Node.js and npm (for compiling SCSS and JS during development)
Optional:
- [hammer-locations] for store locator / map builds
- WooCommerce (plugin detects it and loads ecommerce helpers)
- Yoast SEO (breadcrumbs helper in the plugin checks for it)
Both the theme and plugin use PHP namespacing (HammerTheme\ and HammerPlugin\).
Getting started on a new site
- Copy
theme2024intowp-content/themes/and rename the folder (updatestyle.cssTheme Name if you want a different label in the admin). - Copy
hammer-marketing-customintowp-content/plugins/and activate it. - Activate the theme.
- From the theme directory, run
npm installthennpm run build. - In ACF, sync field groups from the theme's
acf-json/folder. - Configure site colors, fonts, and padding under the Hammer settings options pages in wp-admin.
- Assign Primary and Secondary menus under Appearance > Menus.
If the companion plugin is not active, the theme shows an admin notice. Most template helpers and color variables depend on it.
Theme structure
theme2024/
├── acf-json/ Field group JSON synced from ACF
├── assets/
│ ├── fonts/ Icon font, woff2, config
│ ├── images/ Theme images (fallback blog image, etc.)
│ ├── js/
│ │ ├── modules/ Header bundle sources (micromodal, new window)
│ │ └── partials/ Footer bundle sources (__functions, _scripts)
│ ├── scss/
│ │ ├── core/ Reset, variables, mixins, utils
│ │ ├── editor/ Block editor-only styles
│ │ ├── partials/ Component and layout partials
│ │ └── vendor/ Hamburgers, Gravity Forms overrides
│ └── svg/ Inline SVG partials (logo, footer mark)
├── blocks/ ACF block definitions (block.json + PHP + SCSS)
│ └── _clone/ Scaffold reference; skipped at registration (leading _)
├── dist/ Compiled CSS and JS (commit built assets or rebuild on deploy)
├── inc/
│ ├── Assets.php Register and enqueue styles/scripts
│ ├── Functions_Custom.php Site-specific queries, archive helpers (HamCustom class)
│ ├── Menus.php Texas_Ranger walker + submenu ARIA attributes
│ ├── metadata.php Early <head> output: fonts, CSS custom properties
│ └── theme-hooks.php Theme supports, menus, block styles, body classes
├── templates/
│ ├── archive/ Archive and search templates
│ ├── components/ Reusable partials (intro hero, etc.)
│ ├── content/ Single post templates
│ ├── loop/ Markup for one item in a listing
│ └── pagination.php Standard pagination or AJAX load more
├── createblock.sh Scaffold a new ACF block
├── functions.php Bootstrap: constants, requires inc files
├── theme.json Gutenberg color palette, spacing, typography
├── header.php / footer.php
├── index.php Routes archives and taxonomies
├── single.php Routes single templates by post type
├── page.php Default page template
└── style.css Theme header only (styles live in dist/)
Bootstrap and namespacing
functions.php defines HAM_THEME_DIR and HAM_THEME_INC, loads theme-hooks.php (registers WordPress hooks), then pulls in Assets, Menus, and Functions_Custom.
theme-hooks.php sets up theme supports (thumbnails, HTML5, wide alignment, editor styles, custom header), registers nav menu locations, adds custom block styles for core List and Button, and warns if the plugin is missing.
Functions_Custom.php defines HammerTheme\Template\HamCustom. This is the main place for per-site query changes, archive titles, category filters, and the get_header_images() helper that renders the shared intro component. It only loads when the plugin is present.
Template routing
WordPress root templates stay thin and delegate to templates/:
| File | Behavior |
|---|---|
index.php | Blog home, search, taxonomies, and post type archives |
single.php | templates/content/content.php for posts; content-{post_type}.php for CPTs |
page.php | Outputs the_content() inside a wrapper (intro/breadcrumbs commented for easy enable) |
Archive routing in index.php:
is_home()→templates/archive/archive.phpis_search()→templates/archive/archive-search.phpis_tax()→templates/archive/taxonomy-{taxonomy}.phpis_category()→templates/archive/taxonomy-category.phpis_post_type_archive()→templates/archive/archive-{post_type}.php
Add new archive or single templates by creating the matching file under templates/archive/ or templates/content/. No need to touch the root PHP files unless routing logic changes.
Intro component and blocks
templates/components/intro.php is the shared hero partial (image, title, optional Yoast breadcrumbs). It is used by:
HamCustom::get_header_images()in archive and single templates- The Intro ACF block (
blocks/intro/intro.php), which maps ACF fields to the same partial
This pattern keeps block markup and PHP template markup in one place.
Menus
Menus.php provides Texas_Ranger, a custom Walker_Nav_Menu that:
- Adds a
menu_imageACF field on nav items for thumbnail mega-menu links - Outputs item descriptions
- Sets stable submenu
idattributes and pairs them witharia-controlson parent links
Front-end toggle behavior lives in assets/js/partials/__functions.js (hamburger, nav-open on <html>).
Colors, fonts, and CSS variables
inc/metadata.php runs before wp_head(). It prints custom font markup from ACF options and builds a :root block with color variables from the plugin's Functions::ham_get_colors(), plus --hammer_global__padding.
theme.json maps Gutenberg palette slugs to those same CSS variables (primary, secondary, etc.), so editor and front-end stay aligned.
ACF JSON
Field groups saved in the admin are written to acf-json/ for version control. After pulling theme updates, use ACF's Sync available to import changes. Block field groups (Intro, Hero, etc.) live here alongside global settings.
ACF blocks
Blocks live in blocks/{block-name}/ with three files:
block.json- block registration, style handle pointing at compiled CSS{block-name}.php- render template{block-name}.scss- block styles (compiled todist/blocks/)
The plugin's ACFs::ham_acf_init_block_types() glob-registers every folder under blocks/ except those starting with _ (so _clone is reference only).
Creating a new block
From the theme directory:
./createblock.sh my-block "My Block"
npm run build:blocks
The script creates block.json, PHP, and SCSS with sensible defaults. Edit the PHP template and fields in ACF, then re-run npm run build:blocks after SCSS changes.
Existing examples: hero, intro, responsive-spacer.
Block editor JavaScript
The current build pipeline covers global SCSS and legacy concatenated JS. Block-specific editor scripts are not part of the default npm scripts. If you add native block editor JS, install @wordpress/scripts and use wp-scripts build alongside the existing commands.
Front-end build
Hybrid setup: Dart Sass and PostCSS for CSS, esbuild for minifying concatenated legacy JS.
From the theme directory:
npm install # once per clone
npm run build # full compile
| Command | Output |
|---|---|
npm run build | Main CSS, editor CSS, all block CSS, header + footer JS bundles |
npm run build:css | dist/css/style.css and style-editor.css only |
npm run build:blocks | dist/blocks/**/*.css from blocks/**/*.scss |
npm run build:js | dist/js/header-scripts.min.js and dist/js/scripts.min.js |
npm run watch | Rebuild on changes under assets/scss, blocks, or assets/js |
Main CSS: assets/scss/style.scss → dist/css/style.css (compressed, source map, Autoprefixer, cssnano)
Editor CSS: assets/scss/style-editor.scss → style-editor.css (enqueued via add_editor_style)
Block CSS: each blocks/*/*.scss → matching path under dist/blocks/
JS bundles:
- Header:
assets/js/modules/_micromodal.js,_new_window.js - Footer:
assets/js/partials/__functions.js,_scripts.js
Assets.php enqueues Swiper 12 from CDN (gallery carousels in __functions.js), then theme CSS/JS. It localizes bloginfo on the header script with AJAX URL, nonce, query vars, and pagination state for load-more.
During active development, run npm run watch. Before deploy, run npm run build and commit dist/ if your workflow does not compile on the server.
SCSS organization
Add site-specific styles as new partials under assets/scss/partials/ and @use them from style.scss. Block styles should stay in each block's SCSS file so build:blocks stays fast.
For optional plugins (e.g. locations map), add something like assets/scss/partials/_locations.scss and import it in style.scss.
Per-site customization checklist
Typical changes when cloning for a client build:
- Branding - Replace
assets/svg/logo.svg, footer SVG, default blog image, andstyle.csstheme metadata. - Colors and fonts - Hammer settings in wp-admin (outputs via
metadata.php). Functions_Custom.php- Archive queries, filters, intro usage, custom query vars.page.php/ archive templates - Enable or disable intro, breadcrumbs, load-more vs paginated archives.- New CPT templates -
templates/content/content-{cpt}.php,templates/archive/archive-{cpt}.php, loop variants if needed. - New blocks -
createblock.sh, ACF field group, SCSS. - Plugin
PostTypes/- AJAX, filtering, or REST behavior tied to a CPT (copy_copy.phpas a starting point).
Keep shared, reusable logic in the plugin. Keep visual and layout choices in the theme.
Pagination and AJAX
templates/pagination.php accepts a loadmore argument.
false- standardpaginate_links()outputtrue- Load More button plus inline jQuery handler
Load more posts to load_more_ajax in the plugin (Ajax/Archive.php). The handler returns JSON with HTML fragments rendered via templates/loop/loop.php (or CPT-specific loop templates). Category archive filtering uses ham_filter_ajax with the same response shape.
Archive templates set $ajaxLoadMore = true|false locally. The blog archive (templates/archive/archive.php) ships with load-more enabled.
Companion plugins
hammer-marketing-custom (required)
Shared functionality layer. The theme expects HammerPlugin\HammerPlugin to be loaded.
hammer-marketing-custom/
├── Ajax/
│ └── Archive.php Load more and archive filter AJAX
├── assets/
│ ├── css/ Admin styles
│ ├── js/ Dashboard scripts
│ ├── images/ Dashboard icons
│ └── login.css.php Dynamic login screen styles
├── Components/
│ ├── ACFs.php Registers theme ACF blocks; User Settings field group
│ ├── Admin.php wp-admin tweaks and whitelabeling
│ ├── Analytics.php Analytics / GTM setup
│ ├── Dashboard.php Custom dashboard widgets and styling
│ ├── Ecommerce.php WooCommerce wrappers (loaded when WC is active)
│ ├── Enqueue.php Admin and login asset enqueue
│ ├── Functions.php Shared helpers (colors, excerpts, share, social, breadcrumbs)
│ └── dash/ Dashboard partials
├── PostTypes/
│ └── _copy.php Template for CPT-specific plugin logic
├── hammer-marketing-custom.php
└── setup.php Runs on plugin activation (default WP settings)
Theme vs plugin split: Clients can switch themes later without losing CPT behavior, AJAX endpoints, or admin customizations, as long as the plugin stays installed.
setup.php runs once on activation and adjusts baseline WordPress settings (permalink structure, default items to disable, etc.). Review it when onboarding a new site.
hammer-locations (optional)
Install only when the build needs a store locator.
- Registers the Locations CPT and ACF fields
- Provides page templates for the map list and AJAX popup
- Enqueues map assets in
assets/locations-scripts.js
Google Maps API key: define GOOGLE_MAPS_API in wp-config.php. The plugin passes it to ACF (acf/fields/google_map/api) and the front-end Maps script.
Styling: add assets/scss/partials/_locations.scss in the active theme and compile with the main theme CSS.
Post types and taxonomies
Custom post types and taxonomies are created in ACF, not in theme PHP. Template files follow the naming conventions above. CPT-specific AJAX, filtering, or admin behavior belongs in the plugin under PostTypes/, using _copy.php as a scaffold.
Known gaps / TODO
- Style form fields with newest Gravity Forms styling changes
- Improve menu accessibility (keyboard nav, focus management beyond current ARIA attributes)
- Broader accessibility pass (landmarks, skip links, contrast audit)