Fall in love with WordPress (again)
Flynt is a lightning-fast WordPress Starter Theme for component-based development with ACF Pro.
Dependencies
- WordPress >= 6.1
- Node = 18
- Composer >= 2.4
- Advanced Custom Fields Pro >= 6.0
Install
- Clone this repo to
<your-project>/wp-content/themes
. - Change the domain variable in
flynt/vite.config.js
to match your domain:const wordpressHost = 'http://your-project.test'
- Navigate to the theme folder and run the following command in your terminal:
# wp-content/themes/flynt
composer install
npm install
npm run build
- Open the WordPress backend and activate the Flynt theme.
Usage
To start developing run the following command:
# wp-content/themes/flynt
npm start
All files in assets
and Components
will now be watched for changes and served. Happy coding!
Base Style
Flynt comes with a ready to use Base Style built according to our best practices for building simple, maintainable components. Go to domain/BaseStyle
to see it in action.
Assets
The ./assets
folder contains all global JavaScript, SCSS, images, and font files for the theme. Files inside this folder are watched for changes and compile to ./dist
.
The main.scss
file is compiled to ./dist/assets/main.css
which is enqueued in the front-end.
The admin.scss
file is compiled to ./dist/assets/admin.css
which is enqueued in the administrator back-end of WordPress, so styles added to this file will take effect only in the back-end.
Lib & Inc
The ./lib
folder includes helper functions and basic setup logic. You will most likely not need to modify any files inside ./lib
. All files in the ./lib
folder are autoloaded via PSR-4.
The ./inc
folder is a more organised version of WordPress' functions.php
and contains all custom theme logic. All files in the ./inc
folder are automatically required.
For organisation, ./inc
has three subfolders. We recommend using these three folders to keep the theme well-structured:
customPostTypes
Use this folder to register custom WordPress post types.customTaxonomies
Use this folder to register custom WordPress taxonomies.fieldGroups
Use this folder to register Advanced Custom Fields field groups. (See Field Groups for more information.)
After the files from ./lib
and ./inc
are loaded, all components from the ./Components
folder are loaded.
Page Templates
Flynt uses Timber to structure its page templates and Twig for rendering them. Timber's documentation is extensive and up to date, so be sure to get familiar with it.
As part of the Twig Extension the theme uses a Twig function in to render components into templates:
renderComponent(componentName, data)
renders a single component. For example, in theindex.twig
template.
Besides the main document structure (in ./templates/_document.twig
), everything else is a component.
Components
A component is a self-contained building-block. Each component contains its own layout, its ACF fields, PHP logic, scripts, and styles.
ExampleComponent/
โโโ _style.scss
โโโ functions.php
โโโ index.twig
โโโ README.md
โโโ screenshot.png
โโโ script.js
The functions.php
file for every component in the ./Components
folder is executed during the WordPress action after_setup_theme
. This is run from the ./functions.php
file of the theme.
To render components into a template, see Page Templates.
Web Components
Web components provide a standard component model for encapsulation and interoperability HTML elements. Most components are based on an autonomous custom element called flynt-component
.
To define the name of a specific component use the name
attribute, which should match the componentโs folder name, to be ensure that its JavaScript is loaded as specified (see JavaScript modules for more details).
For example:
<flynt-component name="BlockWysiwyg" โฆ></flynt-component>
JavaScript modules
Using a module based approach, allows to breaks JavaScript into separate files and keep them encapsuled inside Components itself.
Different loading strategies can be defined for each component independently when using the custom element flynt-component
:
load:on="idle"
Initialises after full page load, when the browser enters idle state.
Usage example: Elements that donโt need to be interactive immediately.load:on="visible"
Initialises after the element get visible in the viewport.
Usage example: Elements that go โbelow the foldโ or if you want to load it when the user sees it.load:on="load"
(default)
Initialises immediately when the page loads.
Usage example: Elements that need to be interactive as soon as possible.load:on:media="(min-width: 1024px)"
Initialises when the specified media query matches.
Usage example: Elements which may only be visible on certain screen sizes.
Example:
<flynt-component name="BlockWysiwyg" load:on="visible"></flynt-component>
If it makes logical sense, loading strategies can be combined:
<flynt-component name="NavigationMain" load:on="idle" load:on:media="(min-width: 1024px)">
With nested components the loading strategy is waiting for parents. If you have a component with load:on="idle"
nested inside a component with load:on="visible"
, the child component will only be loaded on visible of the parent component.
Advanced Custom Fields
Defining Advanced Custom Fields (ACF) can be done in functions.php
for each component. As a best practice, we recommend defining your fields inside a function named getACFLayout()
which you can then call in a field group.
For example:
namespace Flynt\Components\BlockWysiwyg;
function getACFLayout()
{
return [
'name' => 'blockWysiwyg',
'label' => __('Block: Wysiwyg', 'flynt'),
'sub_fields' => [
[
'label' => __('Content', 'flynt'),
'name' => 'contentHtml',
'type' => 'wysiwyg',
'delay' => 0,
'media_upload' => 0,
'required' => 1,
],
]
];
}
Field Groups
Field groups are needed to show registered fields in the WordPress back-end. All field groups are created in the ./inc/fieldGroups
folder. Two field groups exist by default: pageComponents.php
and postComponents.php
.
We call the function getACFLayout()
defined in the functions.php
file of each component to load fields into a field group.
For example:
use ACFComposer\ACFComposer;
use Flynt\Components;
add_action('Flynt/afterRegisterComponents', function () {
ACFComposer::registerFieldGroup([
'name' => 'pageComponents',
'title' => 'Page Components',
'style' => 'seamless',
'fields' => [
[
'name' => 'pageComponents',
'label' => __('Page Components', 'flynt'),
'type' => 'flexible_content',
'button_label' => __('Add Component', 'flynt'),
'layouts' => [
Components\BlockWysiwyg\getACFLayout(),
]
]
],
'location' => [
[
[
'param' => 'post_type',
'operator' => '==',
'value' => 'page'
],
[
'param' => 'page_type',
'operator' => '!=',
'value' => 'posts_page'
]
]
]
]);
});
Here we use the ACF Field Group Composer plugin, which provides the advantage that all fields automatically get a unique key.
ACF Option Pages
Flynt includes several utility functions for creating Advanced Custom Fields options pages. Briefly, these are:
Flynt\Utils\Options::addTranslatable
Adds fields into a new group inside the Translatable Options options page. When used with the WPML plugin, these fields will be returned in the current language.Flynt\Utils\Options::addGlobal
Adds fields into a new group inside the Global Options options page. When used with WPML, these fields will always be returned from the primary language. In this way these fields are global and cannot be translated.Flynt\Utils\Options::getTranslatable
Retrieve a translatable option.Flynt\Utils\Options::getGlobal
Retrieve a global option.
Timber Dynamic Resize
Timber provides a resize
filter to resize images on first page load. Resizing many images at the same time can result in a server timeout. That's why Flynt provides a resizeDynamic
filter, that resizes images asynchronously upon first request of the image itself. Resized images are stored in uploads/resized
. To regenerate all image sizes and file versions, delete the folder.
To enable Dynamic Resize, go to Global Options -> Timber Dynamic Resize.
Twig Extensions
readingTime
(Type: Filter)
Returns the reading time of a string in minutes.
{{ 'This is a string'|readingTime }}
Example from Components/GridPostsArchive/index.twig
renderComponent($componentName, $data)
(Type: Function)
Renders a component. See Page Templates.
{% for component in post.meta('pageComponents') %}
{{ renderComponent(component) }}
{% endfor %}
Example from templates/page.twig
placeholderImage($width, $height, $color = null)
(Type: Function)
Useful in combination with lazysizes for lazy loading. Returns a "data:image/svg+xml;base64" placeholder image.
{{ placeholderImage(768, (768 / image.aspect)|round, 'rgba(125, 125, 125, 0.1)') }}
Example from Components/BlockImage/index.twig
resizeDynamic($src, $w, $h = 0, $crop = 'default', $force = false)
(Type: Filter)
Resizes an image dynamically. See Timber Dynamic Resize.
{{ post.thumbnail.src|resizeDynamic(1920, (1920 / 3 * 2)|round, 'center') }}
Example from Components/BlockImage/index.twig
Troubleshooting
Images
In some setups images may not show up, returning a 404 by the server.
The most common reason for this is that you are using nginx and your server is not set up in the the recommended standard. You can see that this is the case, if an image url return a 404 from nginx, not from WordPress itself.
In this case, please add something like
location ~ "^(.*)/wp-content/uploads/(.*)$" {
try_files $uri $uri/ /index.php$is_args$args;
}
to your site config.
Other issues might come from Flynt not being able to determine the relative url of your uploads folder. If you have a non-standard WordPress folder structure, or if you use a plugin that manipulates home_url
(for example, WPML) this can cause problems when using resizeDynamic
.
In this care try to set the relative upload path manually and refresh the permalink settings in the back-end:
add_filter('Flynt/TimberDynamicResize/relativeUploadDir', function () {
return 'app/uploads'; // Example for Bedrock installs.
});
SSL certificate for dev server
If you want to use https in development, please define the following variables inside a .env
file:
VITE_DEV_SERVER_KEY=<path-to-ssl-certificate-key>/your-project.test_key.pem
VITE_DEV_SERVER_CERT=<path-to-ssl-certificate-cert>/your-project.test_cert.pem
Maintainers
This project is maintained by Bleech.
The main people in charge of this repo are:
Contributing
To contribute, please use GitHub issues. Pull requests are accepted. Please also take a moment to read the Contributing Guidelines and Code of Conduct.
If editing the README, please conform to the standard-readme specification.
License
MIT ยฉ Bleech