Website Documentation Releases Support
- Harness the power of Laravel and its available packages thanks to Acorn.
- Clean, efficient theme templating utilizing Laravel Blade.
- Lightning fast frontend development workflow powered by Bud.
- You must use
.eslintrcrules in the app development.
Make sure all dependencies have been installed before moving on:
- Acorn v2
- WordPress >= 5.9
- WP CLI
- PHP >= 7.4.0 (with
php-mbstringenabled) - Composer
- Node.js >= 16
- Yarn
Make sure your local DB_HOST is set to: 127.0.0.1
Install Sage in your WordPress themes directory and fire the following commands in directory:
composer installyarn && yarn build
themes/your-theme-name/ # → Root of your Sage based theme
├── app/ # → Theme PHP
│ ├── Core/ # → Theme core files
│ ├── Providers/ # → Service providers
│ ├── View/ # → View models
│ ├── filters.php # → Theme filters
│ └── setup.php # → Theme setup
├── composer.json # → Autoloading for `app/` files
├── public/ # → Built theme assets (never edit)
├── functions.php # → Theme bootloader
├── index.php # → Theme template wrapper
├── node_modules/ # → Node.js packages (never edit)
├── package.json # → Node.js dependencies and scripts
├── resources/ # → Theme assets and templates
│ ├── fonts/ # → Theme fonts
│ ├── images/ # → Theme images
│ ├── scripts/ # → Theme javascript
│ ├── styles/ # → Theme stylesheets
│ └── views/ # → Theme templates
│ ├── components/ # → Component templates
│ ├── forms/ # → Form templates
│ ├── layouts/ # → Base templates
│ ├── partials/ # → Partial templates
└── sections/ # → Section templates
├── screenshot.png # → Theme screenshot for WP admin
├── style.css # → Theme meta information
├── vendor/ # → Composer packages (never edit)
└── bud.config.js # → Bud configurationyarn dev— Compile assets when file changes are made, start dev sessionyarn build— Compile assets for production
Firestarter uses PHP types as much as possible...
Theme uses facade design pattern for managing internal dependencies, so instead of placing everything in the setup.php or filters.php files as Sage recommends, we should wrap custom features in specific boundaries placed in the app directory. Let's assume that we need to create Posts boundary that handles custom features for Post type.
├── app/
│ ├── Posts/
│ ├── ├── Post.php
│ ├── ├── Posts.phpApp/Posts is boundary context for Posts with Posts.php as fasade for internal actions. This facade should be initialized in the App\App like the here.
namespace App;
use App\Core\Singleton;
use App\Posts\Posts;
class App extends Singleton
{
private Posts $posts;
protected function __construct()
{
$this->posts = fireclass(Posts::class); # <- Context Initialization
}
public function posts(): Posts
{
return $this->posts;
}
}This facade might be used everywhere you need using firestarter function. Example: firestarter()->posts()->doSth().
Coditive theme uses a custom way for firing the WordPress hooks in the controllers. You can use @action, @filter and @shortcode in the comment block for initializing hooks in specific class.
class Example {
/**
* @action template_redirect
*/
public function sendMail(): void
{
wp_mail('test@example.com', 'Test Message', 'Test Content');
}
/**
* @filter the_title
*/
public function setTitle(string $title): string
{
return $title;
}
/**
* @shortcode title
*/
public function shortcode(): string
{
return get_the_title();
}
}But to make it work, there is a need to initialize instance using fireclass function: fireclass(Example::class). Of course you can also put all the hoods in default way (constructor).
All the app modules should be initialized as App class attributes placed in app.js file.
Routes module can be used for firing custom functions only on specific pages.
Create route controller in @scripts/routes directory.
class Home {
init() {
}
finalize() {
}
};Initialize route controller in @scripts/modules/Router constructor.
this.routes = {
home: new Home(),
};Router will take all <body> classes and convert them to camelCase that become routes keys that will be used for firing specific events. So for example if you want to fire specific functions pages that have template-home class, create a new controller and assign it to templateHome in the router. The system will automatically fire init or finalize functions.
@scripts/utils directory can be used for creating simple functions that may be used across the application. Please try to categorize them by meaing (for example, place array utils in @scripts/utils/array.js file).
Blocks can be used for building website content sections. The main advantage over Sage components is that assets are loaded on demand. So when specific block is not used on the page, its assets are not loaded at all. Sage components loads all the assets in the main script.js and style.js files, so assets are loaded even when not needed.
├── app/
│ ├── View/
│ ├── ├── Blocks/
│ ├── ├── ├── Testimonial.php
├── resources/
│ ├── blocks/
│ ├── ├── testomonial/
│ ├── ├── ├── scripts.js
│ ├── ├── ├── styles.scss
│ ├── ├── ├── template.blade.phpNew block can be created using the following command. That's all. All the block controllers will be initialized automatically.
wp firestarter block create --name=Testimonial{!! firestarter()->block('testimonial')->render(); !!}It is good to treat block controler as main source of data structure. So when the block needs to use $title in the template, this should be reflected in block data structure. Thank's to this, enyone can see what variables are available in the template and what are their default types and values.
In the example below, we need to utilize $title data in the template. So we set title in the structure with default value set as string, and then set the final value from some function.
class estimonial extends Block
{
public function __construct()
{
$this->setId('testimonial');
$this->setName('Testimonial');
$this->setStructure([
'title' => '',
]);
}
public function parse(array $data): array
{
$data = array_replace_recursive($data, $this->getStructure());
$data = apply_filters('firestarter_block_testimonial_data', $data);
$data['title'] = get_the_title_from_somewhere();
return $data;
}
}Firestarter implements settings page...
Firestarter contains two directories for assets:
resources/images- directory for images that can be accessed in CSS files (for exampleurl('../../images/filename.jpg')) and via the@assetdirective (for example@assets('images/filename.jpg'))resources/images/svg- directory for images that can be accessed via@svgdirective to get the full content of file, for example@svg('images.svg.filename.svg')
Theme by default uses Local JSON feature and stores fields sonfiguration in /resources/fields directory. You can disable this feature with the following wp-config.php entry.
define('FIRESTARTER_INTEGRATIONS_ACF_LOCAL_JSON', false);Firestarter adds support for ACF Blocks. So you can use previously described blocks architecture with ACF without any additional work.
Firestarter implements support for ACF Options.
firestarter()->settings()->get('site_logo')Intended for apache servers.
If you use the ACF Pro plugin you can enable the WebP functionality in the dashboard, just go to the "Firestarter -> Media Settings".
To make it works you need to update your .htaccess files with the following rules:
# CACHING | WebP Support | https://do.co/3aIKIb8
<IfModule mod_rewrite.c>
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_URI} (?i)(.*)(\.jpe?g|\.png)$
RewriteCond %{DOCUMENT_ROOT}%1%2.webp -f
RewriteRule (?i)(.*)(\.jpe?g|\.png)$ %1%2\.webp [L,T=image/webp]
RewriteCond %{HTTP_ACCEPT} image/webp
RewriteCond %{REQUEST_URI} (?i)(.*)(\.jpe?g|\.png)$
RewriteCond %{DOCUMENT_ROOT}%1.webp -f
RewriteRule (?i)(.*)(\.jpe?g|\.png)$ %1\.webp [L,T=image/webp]
</IfModule>
If you don't use the ACF Pro plugin and you would like to enable this functionality then you can go to the app -> Media -> WEBP.php file and set $this->convertImages to true.
You can check if it works correctly by checking, for example, the network tab in the Chrome developer tools (see image type column or response headers content-type).