Stars: 586
Forks: 66
Pull Requests: 322
Issues: 87
Watchers: 23
Last Updated: 2023-09-05 17:16:59
Component based WordPress starter theme, powered by ACF Pro and Timber, optimized for a11y and fast page load results.
License: MIT License
Languages: PHP, JavaScript, CSS, SCSS, Twig
Flynt is a lightning-fast WordPress Starter Theme for component-based development with ACF Pro.
<your-project>/wp-content/themes
.flynt/vite.config.js
to match your domain:const wordpressHost = 'http://your-project.test'
# wp-content/themes/flynt
composer install
npm install
npm run build
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!
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.
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.
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
customTaxonomies
fieldGroups
After the files from ./lib
and ./inc
are loaded, all components from the ./Components
folder are loaded.
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 the index.twig
template.Besides the main document structure (in ./templates/_document.twig
), everything else is a component.
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 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>
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"
load:on="visible"
load:on="load"
(default)load:on:media="(min-width: 1024px)"
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.
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 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'
]
]
]
]);
});
Here we use the ACF Field Group Composer plugin, which provides the advantage that all fields automatically get a unique key.
Flynt includes several utility functions for creating Advanced Custom Fields options pages. Briefly, these are:
Flynt\Utils\Options::addTranslatable
Flynt\Utils\Options::addGlobal
Flynt\Utils\Options::getTranslatable
Flynt\Utils\Options::getGlobal
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.
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
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.
});
If you want to use https in development, please define the following variables inside a .env
file:
VITE_DEV_SERVER_HOST=https://your-project.test
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
This project is maintained by Bleech.
The main people in charge of this repo are:
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.
MIT © Bleech