A partial solution to this challenge is to create a design pattern library (or style guide) for the project and have the client approve it first. While this helps, one common problem (as my colleagues have observed) is that the client sometimes has an issue with an element in the design pattern library later in the project. The particular challenge this presents is that changing an element in the style guide late in the project invalidates all the design comps that use the element.
The current software that our design comps are built in (Sketch) apparently does not have the capability of automatically updating based on a change in a design pattern library.
So how does this relate to WordPress?
In exploring the Advanced Custom Fields Pro (ACF) plug-in, there is a powerful feature called flexible content that we will explore as a way to take elements from a design pattern library and use them in WordPress in drag-and-drop (sort-of) fashion to build design comps (or even front-end implementation in the case of a marketing site).
As a trivial example, imagine that our style guide had just three elements: Hero block, One Column block, and Two Column block.
Hero
This block is fully responsive (stretches) consisting of an image with a text overlay.
One Column
This block is a single column of rich text.
Two Column
This block is two columns of rich text.
An implementation of these three elements are at: http://jsfiddle.net/sckmkny/ncLnj8f4/.
The first step is to update the theme's (e.g., Barebones) stylesheet with the style guide's CSS.
style.css
.my_hero {
position: relative;
height: 300px;
background-size: cover;
background-repeat:no-repeat;
background-position: center;
}
.my_hero h1 {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin: 0px;
color: #ffffff;
text-align: center;
}
@media screen and (min-width: 768px) {
.my_hero {
height: 600px;
}
}
.my_columns {
margin-top: 20px;
}
Next we create a page template in the theme, e.g., called Flex Template (will update later):
page_flex.php
<?php /* Template Name: Flex Template */ ?>
<?php get_header(); ?>
<?php wp_nav_menu(array('theme_location' => 'header-menu')); ?>
<?php if (function_exists('yoast_breadcrumb')) {
yoast_breadcrumb();
}?>
<?php while (have_posts()) : the_post(); ?>
<?php endwhile; ?>
<?php get_footer(); ?>
The next step is to create a new ACF field group, e.g., called Flex Group:
- Set the field group's Location to apply when the page template is Flex Template.
- Add a field called Flex Field.
- Change the Button Label to be Add Element.
- Add a layout for each of the three elements in the style guide, e.g.,
- Hero
- Field: Image (Type: Image)
- Field Text (Type: Text)
- One Column
- Field: Content (Type: Wysiwyg Editor)
- Two Column
- Field Left Content (Type: Wysiwyg Editor)
- Field Right Content (Type: Wysiwyg Editor)
Next create a page with the template Flex Template and add the three elements (Hero, One Column, and Two Column) with sample content to the Flex Field.
Following our previous strategy of getting data out of PHP and into JavaScript code as soon as possible, we update the page_flex.php template as follows (using Mustache JavaScript template library):
page_flex.php
<?php /* Template Name: Flex Template */ ?>
<?php
function add_flex_scripts() {
wp_register_script('mustache',
get_template_directory_uri() .
'/bower_components/mustache/mustache.min.js',
array(), '20150824', true);
wp_enqueue_script('mustache');
}
add_action('wp_enqueue_scripts', 'add_flex_scripts');
get_header();
?>
<?php
wp_nav_menu(array('theme_location' => 'header-menu'));
if (function_exists('yoast_breadcrumb')) {
yoast_breadcrumb();
}
while (have_posts()) {
the_post();
$flex_field = get_field("flex_field");
}
?>
<div id="flex_elements"></div>
<?php get_footer(); ?>
<script>
(function() {
var i, element;
var elements = {
'hero': [
'<div ',
'style="background-image: ',
'url({{image}});" ',
'class="my_hero"',
'>',
'<h1>',
'{{text}}',
'</h1>',
'</div>'
].join(''),
"one_column": [
'<div class="container my_columns">',
'{{{content}}}',
'</div>'
].join(''),
"two_column": [
'<div class="container my_columns">',
'<div class="row">',
'<div class="col-sm-6">',
'{{{content_left}}}',
'</div>',
'<div class="col-sm-6">',
'{{{content_right}}}',
'</div>',
'</div>',
'</div>'
].join('')
};
var flexField = <?php echo json_encode($flex_field); ?>;
for (i = 0; i < flexField.length; i++) {
element = flexField[i];
jQuery('#flex_elements').append((Mustache.render(elements[element.acf_fc_layout], element)));
}
})();
</script>
Next, we need to work to get the Mustache template entries out of the template file and into a custom post type for easy editing. As before we create a new post type in an update functions.php file.
note: At some point, one would consider moving to a plug-in design to pull out all the code.
functions.php
<?php
add_action( 'init', 'create_element_type' );
add_action('wp_enqueue_scripts', 'add_theme_scripts');
add_action( 'init', 'register_my_menu' );
function create_element_type() {
register_post_type( 'elements',
array(
'labels' => array(
'name' => __( 'Elements' ),
'singular_name' => __( 'Element' )
),
'public' => false,
'has_archive' => false,
'show_ui' => true,
)
);
}
function add_theme_scripts() {
wp_register_style('bootstrap',
get_template_directory_uri() .
'/bower_components/bootstrap/dist/css/bootstrap.min.css',
array(), '20150629', 'all');
wp_register_style('style', get_stylesheet_uri(),
array(), '20150629', 'all');
wp_register_script('bootstrap',
get_template_directory_uri() .
'/bower_components/bootstrap/dist/js/bootstrap.min.js',
array('jquery'), '20150629', true);
wp_enqueue_style('bootstrap');
wp_enqueue_style('style');
wp_enqueue_script('bootstrap');
}
function register_my_menu() {
register_nav_menu('header-menu',__( 'Header Menu' ));
}
// REMOVED CLOSING TAG PER WP CODING STANDARDS
Now we create an ACF field group to structure the data in the custom element post type, e.g., named Element. Create a required Text Area field called Template.Then populate the Elements with the three elements:
hero
<div style="background-image: url({{image}});"
class="my_hero"'>
<h1>{{text}}</h1>
</div>
one column
<div class="container my_columns">
{{{content}}}
</div>
two_column
<div class="container my_columns">
<div class="row">
<div class="col-sm-6">
{{{content_left}}}
</div>
<div class="col-sm-6">
{{{content_right}}}
</div>
</div>
</div>
Now we need to use this post type in our page template as follows:
<?php /* Template Name: Flex Template */ ?>
<?php
function add_flex_scripts() {
wp_register_script('mustache',
get_template_directory_uri() .
'/bower_components/mustache/mustache.min.js',
array(), '20150824', true);
wp_enqueue_script('mustache');
}
add_action('wp_enqueue_scripts', 'add_flex_scripts');
get_header();
?>
<?php
wp_nav_menu(array('theme_location' => 'header-menu'));
if (function_exists('yoast_breadcrumb')) {
yoast_breadcrumb();
}
$args = array(
'post_type' => 'elements',
'nopaging' => 'true'
);
$loop = new WP_Query($args);
$elements = array();
while ($loop->have_posts()) {
$loop->the_post();
$fields = get_fields();
$fields['title'] = get_the_title();
$elements[] = $fields;
}
while (have_posts()) {
the_post();
$flex_field = get_field("flex_field");
}
?>
<div id="flex_elements"></div>
<?php get_footer(); ?>
<script>
(function() {
var i, element
var elements = {};
var elementsArray = <?php echo json_encode($elements); ?>;
for (i = 0; i < elementsArray.length; i++) {
element = elementsArray[i];
elements[element.title] = element.template;
}
var flexField = <?php echo json_encode($flex_field); ?>;
for (i = 0; i < flexField.length; i++) {
element = flexField[i];
if (elements[element.acf_fc_layout]) {
jQuery('#flex_elements').append((Mustache.render(elements[element.acf_fc_layout], element)));
}
}
})();
</script>
Whew.
No comments:
Post a Comment