WordPress Tooling

October 16, 2020

a.k.a. how Ian got started with WP development without banging his head against the wall

The Tools ๐Ÿ› 

  • Timber
  • create-guten-block
  • Advanced Custom Fields PRO
  • node-wpapi
  • WP CLI

Timber ๐ŸŒฒ

A faster, easier and more powerful way to build themes. Because WordPress is awesome, but the loop isnโ€™t.

  • Twig template engine
  • Object-oriented Post class
  • ACF integration
  • Extra goodies

What's included?

Twig ๐ŸŒฑ

The flexible, fast, and secure template engine for PHP

  • Variables
  • Filters
  • Functions
  • Control structures
  • Comments
  • Escaping

What's included?

  • Include templates
  • Template inheritance
  • Expressions
  • Operators
  • Macros
  • Extensions

Twig ๐ŸŒฑ

PHP template

<?php
if( have_rows('left_column') ):
  while ( have_rows('left_column') ) : the_row(); ?>
<div class="acg-layout-column acg-layout-column--left">
  <?php
    while ( have_rows('flexible_column') ) : the_row();
      if( get_row_layout() == 'content' ):
        $heading = get_sub_field('heading');
        $content = get_sub_field('content');
  ?>
  <h2><?php echo $heading; ?></h2>
  <div><?php echo $content; ?></div>
  <?php
      endif;
    endwhile;
    ?>
</div>
{% if layout.left_column %}
  {% for column in layout.left_column.flexible_column %}
    {% if column.acf_fc_layout == 'content' %}
      <div class="acg-layout-column acg-layout-column--left">
        <h2>{{ column.heading }}</h2>
        <div>{{ column.content }}</div>
      </div>
    {% endif %}
  {% endfor %}
{% endif %}

Twig template

Object-Oriented Post

object(Timber\Post)[1811]
  public 'id' => int 6
  public 'ID' => int 6
  public 'post_author' => string '1' (length=1)
  public 'post_content' => string '' (length=0)
  public 'post_date' => string '2012-08-06 20:01:08' (length=19)
  public 'post_excerpt' => string '' (length=0)
  public 'post_parent' => int 0
  public 'post_status' => string 'publish' (length=7)
  public 'post_title' => string 'Homepage' (length=8)
  public 'post_type' => string 'page' (length=4)
  public 'slug' => string 'homepage' (length=8)
  public 'callout_item_0_callout_title' => string 'United Against Racism' (length=21)
  public 'callout_item_0_callout_text' => string 'Silence in the face of racism and discrimination, both individual and systemic, is indefensible.' (length=96)
  public 'callout_item_0_callout_link' => boolean false
  public 'callout_item_0_callout_image_svg' => string 'icon-book' (length=9)
  public 'callout_item_1_callout_title' => string 'Free Problem Solving Workshops for Organizations Pursuing Social Justice' (length=72)
  public 'callout_item_1_callout_text' => string 'We want to help your organization overcome critical challenges through Design Thinking' (length=86)
  public 'callout_item_1_callout_link' => boolean false
  public 'callout_item_1_callout_image_svg' => string 'icon-sync' (length=9)

Object-Oriented Post

  • post.id
  • post.title
  • post.date
  • post.link
  • post.content
  • post.categories
  • post.tags
  • post.thumbnail
  • post.preview
  • post.pagination
<article class="tco-post--type-{{ post.post_type }}" id="post-{{ post.ID }}">
  {% include "partials/header-blog.twig" %}
  <div class="tco-post-body">
    <div class="tco-container-wrapper">
      <div class="tco-container tco-container--narrow">
        {{ post.content }}
        {% include "partials/post-info.twig" %}
      </div>
    </div>
  </div>
</article>

ACF Integration

  • Access ACF fields from Post object directly OR
  • From post.meta("acf_field_name")
<div class="tco-container-wrapper {{ background_class }}">
  <div class="tco-container {{ width_class }}">
    {% for component in content %}
    
      <div class="tco-component">
      {# START : COMPONENT INCLUDE #}
      {% set file_name = 'partials/' ~ component.acf_fc_layout ~ '.twig' %}
      {% include file_name %}
      {# END : COMPONENT INCLUDE #}
      </div>

    {% endfor %}
  </div>
</div>

Extra Goodies

  • Timber\Pagination
  • Timber\PostPreview
  • Timber\URLHelper
  • Timber\ImageHelper
<p>{{ post.preview.length(50).read_more('Continue Reading') }}</p>

<img src="{{ post.thumbnail.src|tojpg|resize(300, 300) }}" />

The Tools ๐Ÿ› 

  • Timber
  • ย 
  • create-guten-block
  • Advanced Custom Fields PRO
  • node-wpapi
  • WP CLI

create-guten-block ๐Ÿž

A zero-configuration developer toolkit for building WordPress Gutenberg block plugins

  • React, JSX, and ES6+ syntax support.
  • webpack dev/production build process behind the scene.
  • Auto-prefixed CSS, so you donโ€™t need -webkit or other prefixes.
  • A build script to bundle JS, CSS, and images for production with source-maps.
  • Hassle-free updates for the above tools with a single dependency cgb-scripts.

What's included?

React

registerBlockType( 'block/container', {
  title: __( 'Container' ),
  icon: 'align-center',
  edit: ( {attributes, setAttributes} ) => {
    return (
      <Fragment>
        <InspectorControls>
          <SelectControl label="Container Size"
            value={ attributes.size }
            options={ [
              { label: 'Medium', value: 'medium' },
              { label: 'Wide', value: 'wide' },
              { label: 'Narrow', value: 'narrow' }
            ] }
            onChange={ ( size ) => {
              setAttributes( { size } );
            } } />
         </InspectorControls>
        <div className={ classNames( baseWrapperClass, sizeClass ) }>
          <InnerBlocks />
        </div>
      </Fragment>
    );
  },
  save: ( { attributes } ) => {
     return (
      <div className={ classNames( baseWrapperClass, sizeClass ) }>
        <InnerBlocks.Content />
      </div>
     );
   }
});

+ WordPress

= ๐Ÿ˜ซ

The Tools ๐Ÿ› 

  • Timber
  • create-guten-block
  • Advanced Custom Fields PRO
  • node-wpapi
  • WP CLI

ACF PRO

ACF PRO includes extra fields & features to better develop websites including PHP Blocks, Repeatable Fields, Page Building tools, Media Galleries and Custom Options Pages.

  • Clone and Repeater fields
  • Flexible Content Field
  • Options Pages
  • ACF Blocks

What's included?

ACF Blocks

  acf_register_block( array(
      'name'            => 'Breadcrumbs',
      'title'           => __( 'Breadcrumbs', 'blocks' ),
      'description'     => __( 'Display breadcrumb links', 'blocks' ),
      'render_callback' => 'block_breadcrumbs_render_callback',
      'category'        => 'common',
      'icon'            => 'ellipsis',
      'keywords'        => array( 'breadcrumbs', 'navigation', 'links' ),
  ) );
{% set breadcrumbs = fields.breadcrumbs_block ? fields.breadcrumbs_block : post_ancestors %}
{% set show_site = fields.breadcrumb_block_show_site ?? true %}

<nav aria-label="Breadcrumbs" class="breadcrumbs">
  <ul class="breadcrumbs__list">
    {% if show_site %}
    <li><a class="breadcrumbs__list__link" href="{{ site.url }}">{{ site.name }}</a></li>
    {% endif %}
    {% for crumb in breadcrumbs %}
    {% set crumb_post = Post(crumb) %}
    <li><a class="breadcrumbs__list__link" href="{{ crumb_post.link }}">{{ crumb_post.title }}</a></li>
    {% endfor %}
    <li><span aria-current="page">{{ post.title }}</span></li>
  </ul>
</nav> 

+ Timber

= ๐Ÿฅณ

The Tools ๐Ÿ› 

  • Timber
  • create-guten-block
  • Advanced Custom Fields PRO
  • node-wpapi
  • WP CLI

node-wpapi ๐Ÿ”ฎ

An isomorphic JavaScript client for the WordPress REST API that makes it easy for your JavaScript application to request specific resources from a WordPress website.

  • API Discovery
  • Custom Routes
  • Querying and Filtering
  • Collection Pagination

What's included?

Resource Requests

const results = await this.wp
  .locations()
  .excludeTags(this.regionTag.id)
  .filter({ meta_query: query })
  .param('region', selectedRegion)
  .search(values.name)
  .perPage(9);
  • wp.posts()
  • wp.pages()
  • wp.categories()
  • wp.tags()
  • wp.taxonomies()
  • wp.media()
  • wp.users()
  • wp.settings()

The Tools ๐Ÿ› 

  • Timber
  • create-guten-block
  • Advanced Custom Fields PRO
  • node-wpapi
  • WP CLI

WP CLI ๐Ÿ’ป

A command-line interface for many actions you might perform in the WordPress admin... also includes commands for many things you canโ€™t do in the WordPress admin

  • Configuration changes
  • Manage plugins, themes, posts
  • Update users and user roles
  • And much more...

What's included?

Search and Replace

UPDATE wp_options SET option_value = replace(option_value, 'oldurl.com', 'newurl.com') WHERE option_name = 'home' OR option_name = 'siteurl';

UPDATE wp_posts SET guid = replace(guid, 'oldurl.com','newurl.com');

UPDATE wp_posts SET post_content = replace(post_content, 'oldurl.com', 'newurl.com');

UPDATE wp_postmeta SET meta_value = replace(meta_value,'oldurl.com','newurl.com');
wp search-replace 'oldurl.com' 'newurl.com' 
	--precise --recurse-objects --all-tables

๐Ÿ˜ฑ

๐Ÿ˜…

The Tools ๐Ÿ› 

  • Timber
  • create-guten-block
  • Advanced Custom Fields PRO
  • node-wpapi
  • WP CLI

Questionsโ”

Thanks! ๐Ÿ‘‹๐Ÿป

WordPress Tooling

By webguyian

WordPress Tooling

  • 240