Welcome to the official repository of the TetraStarter theme, designed specifically for WordPress projects.
This theme leverages the power of Advanced Custom Fields (ACF) to craft custom Gutenberg Blocks, integrates Twig via Timber for efficient template management, and utilizes Tailwind CSS for its modern and responsive styling capabilities. Additionally, it incorporates Vite to efficiently compile assets. Furthermore, the theme supports Storybook, a tool for developing UI components in isolation, which enhances the design system and facilitates a more interactive component library.
Important
This is an opinionated starter theme for WordPress created by somoscuatro team. While PRs are welcome, this is designed to fit the needs of our team.
Key Features:
- Custom Gutenberg Blocks: Build unique and complex content layouts with ease using ACF.
- Twig Templating: Write maintainable and cleaner code with the power of Twig and Timber.
- Responsive Design: Achieve a consistent look across all devices with Tailwind CSS.
- TypeScript Integration: Enhance code reliability and maintainability with strong typing through TypeScript support.
- Assets Compilation: Simplify your assets management with Vite.
- Storybook Integration: Develop and test UI components in isolation and checking them using Storybook interactive environment.
To ensure a seamless installation and optimal functionality of this theme, please ensure that your system meets the following requirements:
- PHP: Version 8.4 or higher
- Composer: Version 2.9 or higher
- Node.js: Version 24 or higher
- bun: Version 1.3 or higher
- GitHub CLI: Version 2.83 or higher (optional, necessary for deployment scripts to work)
For those looking to quickly and effortlessly set up a local WordPress environment, we recommend exploring our tetra-docker-wordpress repository. It provides a Docker-based solution to get your WordPress instance up and running in no time.
Follow these instructions to get the TetraStarter WordPress Theme up and running on your WordPress site:
-
Clone the Repository:
Begin by cloning the repository into your WordPress themes directory. Open your terminal, navigate to the
wp-content/themesfolder of your WordPress installation, and run the following command:git clone git@github.com:somoscuatro/tetra-starter-wordpress-theme.gitAfter cloning, switch to the theme's directory:
cd tetra-starter-wordpress-theme -
Install Dependencies:
Install the required Node.js and PHP dependencies by running:
bun install && composer installThis will set up all necessary packages for the theme to function correctly.
-
Build Assets:
Compile the static assets such as CSS and JavaScript files with:
bun run buildThis command processes your assets using Vite and prepares them for production use.
-
Activate the Theme:
To activate the theme on your WordPress site, you can use the WP CLI with the following command:
wp theme activate tetra-starter-wordpress-themeAlternatively, you can activate the theme manually by going to the WordPress admin dashboard, navigating to Appearance > Themes, and clicking the Activate button for the TetraStarter WordPress Theme.
Enjoy your new theme! To learn how to further customize and extend it, keep on reading.
Our objective is to harness modern Object-Oriented Programming (OOP) practices in PHP, adhering to recommended coding standards. This approach ensures a well-organized and readable codebase without compromising on performance.
We structure our code by grouping related functionalities within classes. This modular design promotes clean and maintainable code. To streamline the inclusion of these classes, we implement class autoloading (see section Class Autoloading).
Additionally, we utilize methods attributes to manage WordPress hooks efficiently. This method allows us to keep our actions and filters handlers organized and easily traceable within the class context. See section WordPress Hooks Usage.
The TetraStarter WordPress Theme is organized into several directories, each serving a specific purpose in the theme's architecture:
assets: This directory houses all the static resources used by the theme.fonts: Contains custom fonts files. See How to Customize Fonts section.images: Stores static images that are integral to the theme's construction. Place assets such as favicons or any other images that you prefer to manage directly within the theme, rather than through the WordPress Media Uploader, here.scripts: Holds the JavaScript files that add interactive functionality to your theme.styles: Contains all the Tailwind CSS and custom style files that define the visual appearance of your theme.
languages: This directory contains the translation files. See Translations section.src: Serving as the primary namespace for the theme, this directory contains all the core logic, neatly organized into distinct classes.attributes: This subdirectory houses the mechanism for registering WordPress hooks using PHP method attributes. Within, thehooked-classes.phpfile enumerates classes that have methods designed to handle WordPress hooks.blocks: Custom Gutenberg blocks are stored here, each in its own dedicated folder for better organization. See How to Create Gutenberg Blocks section.cli: This is where we implement custom WP-CLI commands, extending the command-line interface capabilities for WordPress.custom-post-types: Definitions and configurations for WordPress Custom Post Types are located in this subdirectory. See How to Add Custom Post Types section.custom-taxonomies: Similarly, this subdirectory is dedicated to the definition of WordPress Custom Taxonomies. See How to Add Custom Taxonomies section.helpers: A collection of generic utility methods implemented as PHP Traits can be found here. An example includes a method for retrieving the last modified time of a file.
templates: This directory is home to the Twig templates used by the theme.parts: Here, you'll find reusable template partials.
The autoloader.php file is responsible for implementing a class autoloader
that adheres to the WordPress naming conventions for classes and
files.
Additionally, this autoloader invokes the Composer autoloader, guaranteeing that any third-party dependencies are also loaded automatically.
The theme uses PHP DI for Dependency Injection.
We utilize methods attributes to manage WordPress hooks efficiently. This approach allows us to keep our actions and filters handlers organized and easily traceable within the class context.
Our inspiration came from an insightful article by Markus Kober: How to register WordPress hooks with PHP attributes: A step-by-step guide.
To use method attributes in your class methods, follow these steps:
-
Define Your Class Method:
Write the method that you intend to use as a hook handler. For instance:
// src/class-my-beautiful-class.php namespace Somoscuatro\Tetra_Starter_Theme; class My_Beautiful_Class { public function my_beautiful_method(): void { // Your code here } }
-
Register the Method as a Hook Handler:
Apply the method attribute to register it as a handler for a WordPress action or filter. Here's how you would register a method for the
after_setup_themeaction:// src/class-my-beautiful-class.php namespace Somoscuatro\Tetra_Starter_Theme; use Somoscuatro\Tetra_Starter_Theme\Attributes\Action; class My_Beautiful_Class { #[Action('after_setup_theme')] public function my_beautiful_method(): void { // Your code here } }
Similarly, for a filter like
body_class, you would write:// src/class-my-beautiful-class.php namespace Somoscuatro\Tetra_Starter_Theme; use Somoscuatro\Tetra_Starter_Theme\Attributes\Filter; class My_Beautiful_Class { #[Filter('body_class')] public function my_beautiful_method(array $classes): array { // Your code here return $classes; } }
-
Specify Priority and Accepted Arguments (Optional):
You can also define the priority of the hook and the number of accepted arguments like this:
#[Filter('style_loader_tag', priority: 20, accepted_args: 2)]
If not explicitly stated, the default priority is set to 10, and the number of accepted arguments is 1.
Please note that class methods linked to hooks must be public to ensure WordPress can call them correctly.
-
Register Hooked Classes in hooked-classes.php:
To activate the hooked methods, you must register the class containing them in the
hooked-classes.phpfile. This step is essential to automatically attach your methods to the specified WordPress hooks. Add your class to the list as shown below:// hooked-classes.php use Somoscuatro\Tetra_Starter_Theme\My_Beautiful_Class; return [ // Other classes My_Beautiful_Class::class, ];
The starter theme includes two example custom fonts, Jost and Syne, to demonstrate how you can incorporate your own font choices.
To integrate your custom fonts into the theme, follow these steps:
-
Add Your Fonts:
Download your chosen fonts and place them in the
assets/fontsdirectory. For the best balance of efficiency and compatibility, we recommend using the WOFF2 format. -
Preload Your Fonts:
Improve your site's performance by preloading your fonts. In the
templates/partials/head.twigfile, insert a preload link for each font. For example:<link rel="preload" href="{{ get_static_asset('dist/fonts/my-beautiful-font.woff2') }}" as="font" type="font/woff2" crossorigin="anonymous" />
For a deeper understanding of preloading strategies, consider reading this informative blog post by Google.
-
Define Font-Face:
Declare your font in
assets/styles/fonts.cssusing the@font-facerule to specify the font family, style, weight, and file source. Here's an example:@supports (font-variation-settings: normal) { @font-face { font-family: 'My Beautiful Font'; font-style: normal; font-weight: 300 700; font-display: swap; src: url(../fonts/my-beautiful-font.woff2) format('woff2'); } }
-
Configure Tailwind:
Let Tailwind CSS know about your new font by updating the
assets/styles/theme/_fonts.cssfile. Here's how you can do it:@theme { --font-my-beautiful-font: 'My Beautiful Font', 'Helvetica Neue', 'Arial', 'sans-serif'; }
-
Apply Your Font:
Now you can use your custom font throughout the theme by applying the Tailwind class
font-my-beautiful-fontwherever you want your font to appear.
The starter theme includes a predefined color palette tailored to provide a cohesive visual design. To personalize this palette to match your brand or design preferences, follow these steps:
-
Modify Tailwind Colors Palette:
Update your custom color palette by adding your desired HEX codes to the
assets/styles/theme/_colors.cssfile. This file dictates the color scheme used throughout the theme via Tailwind CSS. -
Update ACF Color Picker Options (optional):
If you wish to have your new colors available as options within the Advanced Custom Fields (ACF) Color Picker, you'll need to mark the colors as safe.
To do this, add the prefix
--safe-colorto the CSS variable names of the colors you want to include in the ACF Color Picker. You can also use--safe-light-colorand--safe-dark-colorfor light and dark color variants, to ensure a correct color contrast between text and background.For example:
--safe-color-folly-700: var(--color-folly-700); --safe-color-anti-flash-white-100: var(--color-anti-flash-white-100); --safe-color-anti-flash-white-200: var(--color-anti-flash-white-200); --safe-dark-color-folly-700: var(--color-folly-700); --safe-light-color-anti-flash-white-100: var(--color-anti-flash-white-100);
Tailwind CSS and Vite are not able to understand classes that are dynamically added by PHP. To ensure the colors are compiled, add them to the Tailwind CSS safelist using
@sourceas documented by the Tailwind CSS docs.
To create a new Gutenberg Block using our ACF based implementation, follow the steps outlined below:
-
Initialize a New Block Directory:
Begin by creating a new folder within the
src/blocksdirectory. Name it to reflect your block's purpose, such asmy-beautiful-block. -
Create the ACF
block.jsonFile:The
block.jsonfile serves as the cornerstone for defining a Gutenberg block's metadata. It provides essential details about the block, such as its name, icon, category, and other characteristics. To gain a comprehensive understanding of theblock.jsonstructure and its role in block creation, consult the WordPress Developer Resources page on block.json.A critical attribute within
block.jsonis therenderCallback. This attribute should be set to reference the PHP class responsible for rendering the block (see step 3 below).Check the block.json of the sample block included in the theme for guidance.
Please be aware that when naming your block, it is essential to use the prefix
acf/to ensure that Advanced Custom Fields correctly recognizes and interprets your block. For example, if your block is namedmy-beautiful-block, the full name in theblock.jsonshould beacf/my-beautiful-block. -
Create the Block's Main Class:
For our given example, you would create a PHP file named
class-my-beautiful-block.php. This file should define a class namedMy_Beautiful_Block. This class acts as the foundation for your block's functionality. It must include theget_acf_fieldsmethod, which is responsible for specifying the ACF fields that will appear in the WordPress admin interface for your block.Check the class-sample.php of the sample block included in the theme for guidance.
You can use the ACF interface to design your custom fields group, and when ready, export it as PHP code directly from the ACF > Tools section in your WordPress dashboard. After exporting, integrate the PHP code into the
get_acf_fieldsmethod of your custom block or theme functions.Remember to deactivate or delete the original field group in the ACF interface. This will prevent the possibility of duplicate fields appearing and ensures that your fields are managed solely through code.
For detailed guidance on registering your fields through PHP, read this ACF documentation page.
-
Create the Block's Template:
Create your block's layout by creating a file named
template.twig. As for any other template in the theme, you can utilize Twig and Tailwind CSS in block templates.Within this template, you can access the ACF fields directly without the need to include the block prefix. For instance, if you have a field defined with the key
field_block_my_beautiful_block_heading, it will be accessible in the Twig template simply asheading(i.e.<p>{{ heading }}</p>).
To have a complete example of what explained above, have a look to the sample block included with the theme.
Your block may need to include frontend assets.
To register these assets, implement a register_assets method within your block
class. This method will handle the registration of any scripts or styles your
block needs.
For instance, if you want to include Alpine.js, your method would look like this:
public function register_assets(): void {
wp_register_script(
'alpine',
'https://unpkg.com/alpinejs@3.5.0/dist/cdn.min.js',
array(),
'3.5.0',
array(
'footer' => false,
'strategy' => 'defer',
)
);
}You should enqueue your block asets them within it's template.twig file. Use the
Twig function enqueue_script to do so. For example, to enqueue Alpine.js for
your block you would write: {{ enqueue_script('alpine') }}.
By enqueuing the script in the template file, you guarantee that it's only loaded when the block is actually being used, optimizing your site's performance.
In certain scenarios, you might find it necessary to augment or modify the global context of your block with additional data or to alter the information provided by Advanced Custom Fields (ACF).
To achieve this, you should define a method within your block class and
register it with filter
{theme_prefix}_block_context, where {theme_prefix} is the machine name of
your theme. This method will be responsible for receiving and processing the
block's context along with any other settings from ACF. Here's a basic outline
of how you can implement this method:
#[Filter('my_beautiful_theme_block_context', accepted_args:2)]
public static function set_custom_context( array $context, array $block ): array {
// Ensure we modify context just for this specific block.
if ( 'acf/my-beautiful-block' !== $block['name'] ) {
return $context;
}
// Manipulate the block context as you wish here.
// Return the updated context.
return $context;
}The theme includes a custom WP CLI command, export-acf-blocks-fields, which
allows you to export the field definitions for ACF Blocks into a JSON file. This
command is particularly useful for backing up your fields.
To learn more about the command's options and how to use it effectively, simply
run wp export-acf-blocks-fields --help in your terminal.
Once you have the generated JSON file for your block field group, you can easily import it into the ACF interface to make additional modifications. Navigate to ACF > Tools > Import within your WordPress dashboard. From there, you can upload the JSON file, which will seamlessly integrate your field group back into the ACF system. This allows you to adjust and refine your fields directly through the ACF interface with ease.
To introduce new Custom Post Types (CPTs) to your WordPress theme, you should
create a dedicated class within the src/custom-post-types/post-types
directory. Ensure that the class name reflects the CPT's purpose and is
consistent with its naming convention.
Within your CPT class, it's essential to define the singular and plural labels
for the CPT. Additionally, you may want to customize various attributes of your
CPT, such as its admin dashboard icon, the features it supports (e.g., title,
editor, thumbnails), and its visibility in the WordPress REST API, among others.
These customizations can be configured in the constructor of your CPT class. The
possible arguments are those accepted by WordPress method register_post_type.
See WordPress documentation for method
register_post_type.
The theme includes the implementation of a
CPT
named Sample you can use as reference.
To introduce new Custom Taxonomies to your WordPress theme, you should create a
dedicated class within the src/custom-taxonomies/taxonomies directory. Ensure
that the class name reflects the taxonomy purpose and is consistent with its
naming convention.
Within your taxonomy class, it's essential to define the singular and plural
labels for the taxonomy. Additionally, you may want to customize various
attributes of your taxonomy, such as its admin dashboard icon, the features it
supports (e.g., title, editor, thumbnails), and its visibility in the WordPress
REST API, among others. These customizations can be configured in the
constructor of your taxonomy class. The possible arguments are those accepted by
WordPress method register_taxonomy. See WordPress documentation for method
register_post_type.
The theme includes the implementation of a
taxonomy
named Sample you can use as reference.
Translations file are stored in the languages folder.
To create the necessary .po/.mo files for your theme's supported languages, we recommend using a tool like POEdit.
This theme includes translations for Catalan, Italian and Spanish.
This theme applies several improvements to ensure top performance, implemented
in src/class-performance.php:
-
Possibility of preloading assets. To use it, simply add a
-preloadsuffix to your assets handle name. For example:wp_enqueue_style( 'tetra-starter-wordpress-theme-fonts-preload', $this->get_base_url() . '/dist/styles/fonts.css', false );
-
Selective enqueueing of custom blocks assets, as explained in section Include Block's Assets.
Our code standards adhere to the guidelines established by the WordPress community. To ensure these standards are consistently applied, we utilize a suite of code quality tools:
Additionally, we use PHPStan for static analysis, which significantly improves our code quality by detecting bugs and potential issues before runtime.
This theme features a bun run deploy command that automates version bumping,
code pushing to GitHub, and release creation with the specified project version.
Ensure you have the GitHub CLI installed to utilize
this functionality.
If your WordPress site is on WP Engine, you may consider using our GitHub Action for automated deployments: action-deploy-to-wpengine
Any kind of contribution is very welcome!
Please, be sure to read our Code of Conduct.
If you notice something wrong please open an issue or create a Pull Request or just send an email to tech@somoscuatro.es. If you want to warn us about an important security vulnerability, please read our Security Policy.
All code is released under MIT license version. For more information, please refer to LICENSE.md file.