Building a Bulletproof Button: Reusable Twig Components in FlyntWP
When I first stumbled into the world of WordPress development, I spent too long wrestling with page builders. They promised speed but delivered bloat, and the resulting HTML was a chaotic mess of nested divs and inline styles. FlyntWP changed everything for me. It’s not about drag-and-drop; it’s about programmatic elegance, and at its heart are beautiful, modular Twig components. Today, I want to walk you through a small but mighty example: creating a truly reusable button component that ensures consistency across your entire site, keeps your DOM clean, and sets you up for stellar Core Web Vitals.
The problem with buttons, deceptively simple as they seem, is often their inconsistency. One developer hardcodes a blue button, another copies and pastes a green one, and suddenly your site’s call-to-actions feel disjointed. In FlyntWP, we tackle this by defining a single source of truth for our buttons. Imagine a `Components/Button` folder. Inside, you'd find an `index.php` for ACF Pro field definitions, `_button.twig` for the actual markup, `functions.php` for any logic, and `style.scss` for its specific styling.
Let's look at `index.php` first. Here's where we define the button's editable attributes using ACF Pro:
'label' => __('Button', 'flynt'), 'name' => 'button', 'type' => 'link', 'required' => 1, 'wrapper' => [ 'width' => 50, ],
'label' => __('Style', 'flynt'), 'name' => 'buttonStyle', 'type' => 'select', 'choices' => [ 'default' => __('Default', 'flynt'), 'primary' => __('Primary', 'flynt'), 'secondary' => __('Secondary', 'flynt'), ], 'default_value' => 'default', 'wrapper' => [ 'width' => 50, ],
This simple setup gives us a link field for the URL and text, and a select field for predefined styles. No more hex codes in the admin! Now, the magic happens in `_button.twig`. This file is where we render the button's HTML, keeping it as lean as possible:
{% if button %} <a class="button button--{{ buttonStyle }}" href="{{ button.url }}" target="{{ button.target ? '_blank' : '_self' }}" rel="{{ button.target ? 'noopener' : '' }}"> {{ button.title }} </a> {% endif %}
Notice the `button--{{ buttonStyle }}` class. This dynamic class, paired with our `style.scss`, allows us to easily switch between styles (e.g., `button--primary`, `button--secondary`) using BEM methodology without resorting to inline styles or overly complex CSS. The `target` and `rel` attributes are conditionally added for external links, ensuring best practices for accessibility and security. This is a far cry from the spaghetti code generated by many page builders; we have a single `<a>` tag, precisely what we need.
The `functions.php` file in this button component is a good place for any default values or data preparation before the Twig template. For instance, you might ensure `buttonStyle` always has a fallback:
add_filter('Flynt/addComponentData?name=Button', function ($data) { $data['buttonStyle'] = $data['buttonStyle'] ?: 'default'; return $data; });
Finally, your `style.scss` would define the visual appearance for each style:
.button { display: inline-flex; padding: 0.75rem 1.5rem; border-radius: 0.25rem; text-decoration: none; font-weight: 600; transition: background-color 0.2s ease-in-out;
&--default { background-color: #e0e0e0; color: #333;
&:hover { background-color: #ccc; } }
&--primary { background-color: #007bff; color: #fff;
&:hover { background-color: #0056b3; } } }
Now, the beauty of this. When you're building a `Hero` component, a `CallToAction` component, or any other component that needs a button, you simply include it:
{% include 'Components/Button/_button.twig' with { button: heroButton, buttonStyle: heroButtonStyle } %}
This pattern ensures that every button on your site looks and behaves consistently, is easily managed through ACF, and produces pixel-perfect, minimal HTML. It’s this meticulous approach to component design that allows FlyntWP sites to achieve blazing fast load times and flawless Core Web Vitals. We're not just building websites; we're crafting digital experiences with precision and performance at their core, one reusable component at a time. It's a programmatic joy that page builders simply can't match.