Layers Extension Guide

This guide provides an overview of what the strengths and limitations of extensions are, how to go about building one for Layers, and how to add or remove functionality the right way. The result should be a clean, Layers-compatible plugin.

This guide is intended for developers who are looking for guidance in creating a commercial extension for Layers, or those working on projects with custom requirements.

Before moving forward with this tutorial, you should have at least an elementary understanding of writing a WordPress plugin. Jonathan from Tuts+ has written an amazing tutorial on “How to write a WordPress Plugin”. Give it a read.

What is an Extension?

An extension is a special type of WordPress plugin that extends the functionality of a given theme or plugin framework, such as Layers or WooCommerce.

Most functionality may be added to specific implementations of Layers through existing Layers extensions, or many of the wonderful plugins already available under your Plugins → Add New page, so be sure to check out what is available.

Why Extensions?

A child theme is limited to affecting the front-end styling and basic functionality of Layers. It should  not be used for introducing content structures such as post types, or features that should be available in spite of the activated child theme, such as Shortcodes and widgets. This is where an extension comes in.

There are a few reasons why you would want to build an extension:

  • If you modify Layers directly, you or your client will not be able to update it without losing the changes
  • Extensions greatly speed up development time and testing and can be easily turned on and off.
  • Your extension is essentially a self-contained set of changes which you are in a better position to track and manage.
  • Extensions can be sold for profit and used in tandem with other extensions or child themes, giving them greater reach and application

Child Theme or Extension?

The division between themes and plugins in WordPress has been a bit blurry for a long time, as both can introduce new functionality to a WordPress install. In general, you need a Child Theme when you want to re-style a theme without or beyond what the WordPress customizer controls or other plugins allow you to do, when you want to add a bit of code to a specific place (such as a search field in the header) or when you want to add custom page templates.

If you want to add functionality such as post types, widgets, meta fields and so on, you must assess whether you want that functionality to be available to other child themes if your theme is deactivated. In most cases, this answer should be yes, since the extension extends Layers, not your child theme – in which case you should separate out front-end from back-end and segregate any major new functionality into an Extension.

Extensions may also be created to provide changes to existing Layers functionality through hooking, such as adding support for all post types to the Posts widget, or enabling the off-canvas sidebar all the time (as you see with our WooCommerce extension)

In this series you will learn:

  • Benefits of using plugins over child themes for adding functionality to Layers
  • How to structure your extension
  • How to use plugin classes
  • How to add things like shortcodes, custom post types, widget areas and custom HTML snippets through action hooks
  • How to add Layers Builder widgets and customizer controls
  • How to test and submit your extension

The first task in creating a Layers Extension is to think about what the Plugin will do, and come up with a unique, but semantic name. Always check the existing Layers Extension list (Layers → Marketplace) and other repositories to verify that your name is unique; you might also do a Google search on your proposed name. If you are creating a Layers version of an existing plugin, it is best to use the original plugin title coupled with “Layers”. Example, VideoBox for Layers

Create the Folder

Creating a Plugin from scratch is fairly simple. It is the functions you intend to add and the widget construction that bring the complexity. Starting with a file framework like the one below, or downloading our example plugin should help simplify the process.

  1. Create a folder with a lower-case name, prefixed by layers-. Use hyphens to separate multiple words. In this example, we call our extension “layers-demo-extension”:
  2. Create a new PHP document and save it inside this folder as functions.php, index.php or alternatively name it the same as your plugin, ie “layers-demo-extension.php”
  3. Create an assets folder to hold any front-end stuff such as CSS, images, or scripts.
  4. Create an includes folder for your plugin class file and any supporting PHP files or libraries.
  5. Create a lang folder if your plugin will use its own text domain to manage translations
  6. If you plan to introduce widgets in your plugin, you may also have a widgets folder.
  7. Create a blank plain-text file for your readme and changelog. Using markup and the md extension allows these files to integrate with Git and can be opened by normal text editors on the local computer. We will cover what these files should contain at the end of the guide.

You would now have a very basic skeleton for your plugin with the following structure:

Main Plugin File

Your main plugin file (functions.php, index.php or your-plugin.php) is where the majority of your custom functions and hooks will reside and is also how your plugin is recognized and registered in WordPress.  A basic wireframe of this file looks like this:

Header

The file header , which is all the info contained by asterisks, provides identifying information for your plugin and should include what is shown above for any Layers Extensions.

The absolute minimum information WordPress needs to recognize your Plugin is the Plugin Name line. The rest of the information (if present) will be used to create the table of Plugins on the Plugin management screen. The order of the lines is not important. Below is a quick overview of the elements shown in our example above:

  • Plugin Name: The name of your plugin as you want it to appear in the Plugin management screen
  • Version: Your first release will typically be 1.0
  • Plugin URI: The url to where users can view info about the plugin
  • Description: What does your plugin do for Layers?
  • Author: Your name as you want it to appear in the Plugin listings
  • Author URI: Your website or url to the plugin website, appears in the Plugin listings.
  • Requires at Least: This info is optional, but helpful if your extension needs a specific version of WordPress to support functions or hooks it uses.
  • Tested Up To: Usually the version of WordPress you are running during development, or a future release if you choose to test your plugin against a release candidate
  • Layers Plugin: Should be true if your extension needs Layers to work.
  • Layers Required Version: Used to help notify users if they need to update Layers before using your Extension. Set to the minimum required version.
  • Text Domain: a unique text domain that allows any visible text elements to be translated in their own language file.
  • Domain Path is optional. Specify a path if the translations are located in a sub-folder. Example: if you have a “lang” folder setup to hold the default .po and .mo file for translation plugins to use, the Domain Path will be /lang/ and must have the first slash.

License

At some point within or after your file header, you need to include the GPL2 License URI or a full license text blurb as shown here:

Make it Secure

You’ll want to block direct access to your plugin PHP files by adding the following line at the top of each of them on the first line of code (ie after the comment section is closed off)

 Save your file in the root of your new plugin folder.

Important: file must be in UTF-8 encoding!

For a detailed overview of plugin header information, refer to the WordPress Codex: Writing a Plugin section. Please note the Codex tutorial is worded specifically for writing WordPress plugins intended for the .org repository and may not pertain to your project.

Constants

Constants act as placeholders for commonly repeated information and do not need to be globally declared. These are optional, but can reduce edits and mistakes and are referenced extensively throughout this guide. Here we define 6:

LAYERS_DEMO_EXTENSION_SLUG
= Set to a simple text string that will be used as your text domain or wherever the theme slug needs to be referenced.
LAYERS_DEMO_EXTENSION_VER
= Your plugin’s version. Don’t forget to update this every time you release a new update of the plugin!
LAYERS_DEMO_EXTENSION_DIR
= Returns the absolute path to the plugin folder. See plugin_dir_path
LAYERS_DEMO_EXTENSION_URI
= Returns the fully qualified url to the plugin folder. See plugin_dir_url
LAYERS_DEMO_EXTENSION_FILE
= Returns the path to the plugin file
LAYERS_REQUIRED_VERSION
= Set to the minimum required Layers version your plugin needs. We will use this later when setting up version check notifications.

We use trailingslashit on these path functions to ensure that any trailing slashes are removed, and then only one is applied to the end of the path or URL. This helps avoid accidental double-slashes.

Install & Activate

You should now have a bare-bones project setup with a populated functions file which can be activated in WordPRess. Zip up the folder, then give it a test-run by uploading it to the PluginsAdd New screen and activating it.

listing

Installing the Plugin

  1. Ensure Layers is already installed!
  2. Navigate to Plugins and click  ADD NEW
  3. Click UPLOAD Plugin.
  4. Click Browse and choose your zip, then click INSTALL NOW.
  5. Once it is installed, click Activate.

 

If you’ve activated just a bare functions.php, you should get a success message, but your plugin isn’t doing anything useful yet. In the next part of this guide, we will cover each section of the functions file in detail.

View example of  full demo extension functions file

Before You Begin

This guide includes several code examples which use a placeholder callback, variable or ID such as layers_demo_extension. Do not copy/paste code directly from this guide into your project without changing these values to be unique to your project!

Including Files & Adding Functionality

In the next section we will cover instantiating your plugin class, which includes most hooks and public functions, as well as adding common functionality like widgets, post types, shortcodes and scripts. This guide will walk you through using Object Oriented Programming to organize your hooks and functions in a more efficient and reusable way via a plugin class.

Include the Class

If your plugin will be hooking into any WordPress or Layers filters or actions, a core class should be created to help keep your code organized, efficient and reusable.

To execute everything in your class, you need to include it in your main plugin file (ie functions.php), and instantiate it. You may also have other helper files or libraries which can be included this way, but don’t use require_once   for scripts or styles – those will be included via your class.

Create an empty PHP file in your includes folder now to set the file name with the following syntax: class-layersyour-extension-name.php

Add your file to the main plugin file using the internal path with require_once  :

Setup Class

Your Class opens with a simple header and a unique class name. Class names are typically case-sensitive and capitalized on the first letter. To keep things consistent, begin your class name with Layers , and end it with your Extension’s name. In this example, our extension is called Demo Extension. Make sure yours is something unique.
class Layers_Demo_Extension{}
Keep in mind Classes_Are_Always_Capitalized

get_instance()

The first thing we do inside our class is setup the instance and initiate it. The get_instance()   function creates a singleton class that’s cached to stop duplicate instances.

Constructor

Next, we setup a constructor to hold our hooks and custom functions.

PHP classes have a constructor function, __construct   we can use here.

All WordPress and Layers actions and filters (hooks) will be registered under this constructor, which is executed when a new instance of the class is instantiated from our functions file.

init() can be used in place of __construct() but is not as sensible or necessary. If init() is used, be sure it is referenced on line 3 of the get_instance function.

Below is an example of a group of hooks for the functions we will be creating to localize, setup some page templates, create some customizer controls, and enqueue our scripts and stylesheets:

Adding functions

The remainder of your class will consist of the functions utilizing the hooks and filters registered in your constructor. These might include:

  • Localizing your plugin via plugins_loaded
  • Adding Template Locations via layers_template_locations
  • Adding or modifying customizer controls via layers_customizer_controls
  • Adding Sidebar locations
  • Adding option panel links to the Layers Admin menu
  • Enqueing scripts or stylesheets via admin_enqueue_scripts or wp_enqueue_scripts
  • Registering widget files

These will be covered in detail later on in this guide. To give you an idea of how these look, let’s localize the plugin:

Localization

Your first custom function allows translation of any text strings you may have in your plugin. You must have a lang folder in your plugin structure to hold the .mo file. We will cover how to generate this file for your plugin during the testing phase of this walkthrough.

Reference: load_plugin_textdomain() and i18n

Instantiating

When you are ready to give your plugin a go with your new plugin class, switch to your main plugin file (ie functions.php or index.php) and create a new custom function i.e. layers_demo_extension_init() . This new instance of your class is registered using the new   keyword and should be placed right after the require_once()  call to the class file.

Line 1: Setup your custom function

Line 5: Set the global variable to your class name’s instance

Line 8: Hook your function to plugins_loaded()  }

Next up, how to include scripts and stylesheets →

Including PHP files

Files may be included within your plugin class contructor, or straight-away in your main plugin file. In either case, you use the PHP  require_once() method. From within a class, you must use your path constant.

From Main File

Use the internal path to your subfolder and file without the leading slash

The following example shows how you might include a helper file from inside __construct(){}   which adds custom meta fields to a post type. We use our dir path constant and then set the subfolder without a leading slash.

Inside the Class

In Variables

When setting variables, we append  our constant to  the internal file path with no leading slash.

Registering Widgets

If your extension will include custom widgets, you can use our custom register_widgets()   function and hook it onto widgets_init()   as shown in the plugin class tutorial to set the location of the files to be loaded. This uses require_once()   just like including other helper libraries. We use our dir path constant and then set the subfolder without a leading slash.

Files can be included a few other ways explained here:

How to Include and Require Files on Tuts+

Enqueueing Scripts and Styles

Enqueueing provides a safe way to introduce scripts and stylesheets on page load, and ensures code is only executed when required.

Here we make use of WordPress core functions wp_enqueue_script() and wp_enqueue_style() in our custom
enqueue_scripts()
function, which we hooked into admin_enqueue_scripts() while setting up our class. WordPress provides two hooks to choose from, admin_enqueue_scripts or wp_enqueue_scripts, depending on if your files should be loaded in the admin or in the front-end. Regardless of the hook you use, the function structure is the same:

Note that we are using constants here for the slug, uri and version, to make things more efficient.

 Admin-only Styles & Scripts

When enqueueing admin scripts or styles, it is best to setup a condition that ensures they only load on the page they are used on. This helps reduce potential script conflicts with other plugins.

In this example, the javascript file for our custom meta will load in the head section of the post editor screen only (edit.php).

Note that this can only be used for admin pages.

Next up, how to add custom post types and templates →

Custom Post Types

Custom post types can be registered inside your plugin class, or from within the main plugin file.

The following references register_post_type() and register_taxonomy() and the core WP init hook. Note the extensive use of our constants here where the slug would normally be repeated in single quotes. As a shortcut, we define a pair of variables to cut down on repetition of our post type name. this makes it easier to change, filter and translate.

This example will create a new post type of layers-demo-posts  called Demo Post

Line 3: You must add a condition check for your custom post type name, shown here as layers-demo-posts  , especially if it could potentially already exist. Unique post type names are best, even if using this check, to make absolutely sure the user doesn’t get an error on activation of your plugin.

You can still set your post type slug as something more generic. In this example,  the post type slug is just story  so the permalinks look better. Users can also translate this easily if they are running a multilingual site.

Lines 7-8: We use variables for our post singular and plural name just to make things easier to manage if we need to edit. This also makes it easier for others to translate and filter if needed.

Custom Taxonomies

This works just like adding a post type.

Refer to register_taxonomy()

Line 30:  Taxonomies work a little differently than post types in terms of the permalink structure. We use the rewrite argument here to set a more generic, custom slug that can be translated.

Line 33: We use register_taxonomy() to link our new taxonomy called layers-demo-category  to our custom post type created above, layers-demo-posts

Custom Page Templates

This works just like child themes with the exception of the template location. In a plugin, place all your custom template files into the templates sub-folder. (You do not need a partials folder, etc)

In our plugin class __construct()  , we setup this filter:

Now we need to add a new public function to set the correct location of all our template files, which is the templates sub-folder of our plugin.

From there, you only need to ensure all of your custom page templates are in the templates folder, and your custom post type templates follow the recommended template structure and hierarchy.

To set the  single or archive template for your custom post type,
single_template
or
archive_template
can be hooked.  You must use the full internal path, shown here with our dir constant. The subfolder and file should not have a leading slash.

Jump to how to add custom fields to the post editor if you would like to work on meta before getting into widgets or customizer controls.

These are added using action hooks and core WordPress functions. See How to Add Custom Widget Areas to Layers

WordPress Customizer Controls are the form elements that you see inside the WordPress Customizer which provide options such as color pickers, layouts, styling and widget area selectors . These Controls get assigned to accordion-like groups for organization (panels), making it easier for user to find the options they want.

Customizer controls may be added in both Extensions and Child Themes. The following assumes you have already setup your Child Theme or Layers Extension and are at the point where you are adding custom functions.

Defaults

You may add defaults for the pre-existing Layers controls via the layers_customizer_control_defaults hook as described in the Styling section of this guide. This is recommended in Child Themes where you need to reset the default color controls to ensure your CSS is honored. Click the hook link above to view detailed instructions.

Panels, Sections and Controls

To understand where your customizations will appear, and which element you need to add, the following illustrates the terms we use:

customizer

  1. Panel
  2. Section
  3. Control
  4. Option

The first tier, high level, groups are know as Panels, and those inside them are called Sections, and finally those open up to reveal the Controls containing all the options. WordPress allows theme and plugin developers to add sections and panels using the add_section()   function. Controls are then added to these sections by first registering a ‘theme_mod’ type setting using add_setting()  and then assigning the setting to a Control using add_control()   that will decide how the setting is presented to the user.

We make this process easier by providing a set of filters and keys for building custom controls in a more efficient way.

You can choose to add custom panels to house your new sections and controls, or you can add sections to existing panels or controls to existing sections. Adding to our config array will neatly initialize your controls at the same time the Layers controls are initialized.

Filter Structure

Plugin

You first need to create a custom class to hold your controls inside a new file which we call controls.php.This class is setup just like the main plugin class.

Include this file from inside your main plugin class __construct() or init() function with a simple require_once():

Back to your controls class, setup a handful of helper filters for the panels, sections and controls inside your constructor or initializer. For demonstration we will use init() here so you can see the (small) difference between init() and __construct(). These filters can be used as shown here.

 

The corresponding functions are added along with other public functions in your main plugin class, after the init() function, explained in more detail below.

Child Theme

Your custom controls function in a child theme opens almost identically to an extension, but does not need to define public visibility.

The filter and custom function containing your controls can go into the child theme’s functions.php and requires a unique callback

Example:

The following explains each function in detail and how to format it based on whether you are adding new or adding to.

Custom Panels

Reference: layers_customizer_panels

Plugin

Child Theme

  • Line 1: Safety condition ensures a conflict does not occur if a function with the same name is already run. Choosing unique function names helps avoid this too.
  • Line 2: setup your function to modify the $panels index.
  • Line 3: Set the key or name for your panel, ie ‘mytheme-theme-options’. These should be lower-case and use only – or _ to separate words.
  • Line 4: Set the ‘title’ for your section that displays in the Customizer. Strings should always use l10n methods, ie
    __('string', 'textdomain')
  • Line 5: Set the ‘description’ (optional). This is a short bit of text you can use as instruction or clarification.
  • Line 6: Set the ‘priority’ which is a numeric value that determines where the panel sits sin the list. 130 is a safe choice as it ensures your panel loads below and after the core Layers panels.

Custom Sections

Reference: layers_customizer_sections

Plugin

The panel  value corresponds to the $panels  key, set in the above section as demoextension . If you are not creating a custom panel, then this would be a layers panel ID (see the linked reference above)

Child Theme

Each section should define a title  and the panel  it will be added to. This example shows how you would add a custom section called header-social-media   (Social Media Profiles) to our custom panel called demoextension   (Demo Extension)

Adding Sections to Existing Panels

This example shows how you would add our custom section called header-social-media    (Social Media Profiles) to the existing Header ( header ) panel in Layers. The primary difference here is the array_merge  which takes your section and merges it with the existing ones. You must merge on existing panels, whereas you don’t if using a custom panel.

The following panels are created by Layers:

Panel: Site Settings
site-settings
Panel: Header
header
Panel: Blog

Panel: Footer
footer
Panel: WooCommerce
woocommerce
You can also add custom sections to existing non-Layers panels like the default WordPress panels using the WordPress Core API instead of the Layers filters.

Custom Controls

Reference: layers_customizer_controls

Plugin

In our extension tutorial, we create a custom post type and add a few custom fields to it like a Credit Name, URL and Photo description. Our custom controls will add the option to show or hide this meta on single posts using our post type, in addition to basic meta like the date or sidebars.

The important bit here is the array merge, which takes these custom controls and adds them to the overall controls array for loading.

Each control group uses an array to define itself, ie demo-post-options . At a minimum you need a type   and label   within each individual option.

Child Theme

This example shows how you would add some text fields for entering Social Network URLs in the custom section header-social-media referenced in our custom section above:

$controls [‘section-name’] = In our example, our section is called header-social-media . Each option sets up its own array that must have a title and label.

type

Defines the type of control.

See layers_customizer_controls for a list of available types

label

The title. This should use l10n method
__()
to wrap the value

placeholder

Used in combination with a type of layers-text , layers-textarea , layers-rte  or layers-code  element, and sets some default text inside the field to use an example or instructions.

description

Long-form text describing what your control is used for (optional). Descriptions should be formatted with sprintf and use l10n

choices

Used in combination with a select type to define the drop-down options. The below example shows how we add a Widget Areas option using the layers-select type and populate the drop-down with 0-4 using choices.

Adding Controls to Existing Sections

In the above example we set the section name in the $controls array, then return $controls. When adding controls to an existing section, we need to use an array_merge before returning the $controls to set the section.

You can reference the available key names for the Layers Sections  in the $controls  array in core/customizer/config.php

In the following example, we setup a custom controls array $social_media_controls , then merge it with the $controls array in the header-layout section. See how the syntax varies slightly:

The following Panels and Sections already exist in Layers, which can be extended by adding your custom controls to the relevant section where header-layout is used in the above example:

  • Panel: Site Settings
    site-settings
    • Section: Logo & Title
      title_tagline
    • Section: Navigation
      nav
    • Section: Site Colors
      site-colors
    • Section: Sidebars
      content-sidebars
    • Section: Fonts
      fonts
  • Panel: Header
    header
    • Section: Layout
      header-layout
    • Section: Additional Scripts
      header-scripts
  • Panel: Footer
    footer
    • Section: Layout
      footer-layout
    • Section: Customization
      footer-customization
    • Section: Text
      footer-text
    • Section: Additional Scripts
      footer-scripts
  • Panel: WooCommerce
    woocommerce

WordPress offers the following defaults:

  • title_tagline – Site Title & Tagline
  • colors – Colors
  • header_image – Header Image
  • background_image – Background Image
  • nav – Navigation
  • static_front_page – Static Front Page

You can also add custom controls to existing non-Layers sections like the default WordPress sections  using the WordPress Core API instead of the Layers filters.

This should give you an idea of the general format of a control, and for more examples you can have a look in core/customizer/config.php where you’ll see all the controls that we initialize in Layers.

Removing or De-registering Existing Controls

We do not recommend doing this in commercial prodicts. See layers_remove_config_element() for details on how to use this filter when necessary.

Setting Selectors for Color Controls

If you have setup a custom control with a type of layers-color  , you will need to link it to the element it needs to modify, then output the CSS correctly using layers_inline_styles . This ensures the customizer option overrides everything else, absolutely. It also allows you to tap into the invert control that helps text elements adjust automatically depending on if the user chooses a light or dark background color. This can help you set shortcuts and cut down on the number of color controls.

You can see how we do this for the default color controls in core/helpers/template.php inside the layers_apply_customizer_styles() function.

The first value wp_enqueue_scripts allows you to hook your function into the pre-existing lineup of scripts and let’s WordPress manage when the script fires and where in the source it is output. The second value defines your function name and the third is the priority. 100 is a safe number and is more important to plugin authors.

  • Line 1-2 : The above example creates a new function
    layers_child_customizer_styles
  • Line 3: Set up a variable
    $widget_title_color
    that will represent the user’s choice. We use
    layers_get_theme_mod()
    to grab our custom control
    widget-title-color
    defined on line 4 (assuming we created one with this key name using the above Custom Control methods)
  • Line 5:TRUE corresponds to$allow_empty  and should always be true for colors, so don’t worry about that!
  • Line 7:  A condition to ensure the option is set. If it is blank, no inline CSS will be output.
  • Line 8: Finally, we setup our inline css using layers_inline_styles()

This code goes in your theme’s functions.php or inside your plugin’s class where all other custom hooks go, NOT inside your custom controls, sections or panels functions!

Using Option Settings on the Front-End

To utilize a setting in the front end on Layers, we use a helper function called layers_get_theme_mod()  which works just like the WordPress core get_option().

Plugin

Each $option  for layers_get_theme_mod($option)  is the custom option name you setup in your custom controls array. This example shows how we would use a condition to determine whether a sidebar is added to the demo post view depending on the option choice.

 

Child Theme

In the following example we will add some social icons, corresponding to the networks set in these options, to the header of Layers using the layers_after_logo hook. This goes into your functons.php or plugin class where all other hooks are set.

When we refer to creating a widget, we are referring to the widgets that are used in the Layers Builder pages, which include specialized Layers controls such as the design bar.

The primary difference between the Layer Builder Widget creation process and a standard widget is that builder widgets require extending the Layers_Widget class, and use several helper functions from the Layers framework for building controls.

For more information on standard widget creation, which works from both themes and plugins, be sure to read the following tutorial on Tuts+. Introduction to Creating Your First WordPress Widget.

In this tutorial we will walk you through the structure of a Layers widget, referencing the Layers Post widget to create a custom version that looks at a custom post type. This is normally used in combination with a Plugin. If you are creating a widget in a Child Theme, you may use this tutorial to understand the structure in the core widgets so you are able to easily adapt the Content Widget to your needs.

We recommend choosing one of the core widgets to start with, then use this guide to supplement the code comments to learn more about what each code block is for.

Reference: View Layers Widget Structures here

Basic Widget Structure

The widget code structure itself is almost identical to a standard WordPress widget. However, you will notice we call several Layers-specific functions and begin with extending the Layers_Widget PHP class , which enables us to use helper functions that we’ve added to Layers to speed up widget creation.

Here is the basic layout of a Layers widget file:

Widget File Header

The first thing to do is give your widget class a unique name, where we define
Your Widget Name
Example:
Layers Stories Widget
We recommend keeping to the “Layers” + “Widget Name” convention to help users locate the widgets easier in the Customizer.

Widget Class

Your widget must have a unique PHP class name, which consists of capitalized words separated by underscores.

Example:
My_Layers_Stories_Widget

It is really important to put a unique prefix on the class here to avoid conflicts with another theme or extension that happens to load the same class name. Change the class of the example code to reflect your project, ie My_Layers_Stories_Widget.

We wrap this in a condition as a further safety measure so it doesn’t collide with another instance of the class (which is why it is important it have a unique name!)

1 – Widget Construction

The first thing inside our widget class is our widget function, which constructs the widget by setting up some basic rules and defaults.

Create a function for your class or edit the demo code. This should match the class name.

Set Variables

You will now add all the local scope variables  inside this function. Each of these variables is prefixed by $this-> which sets up each instance of these variables so the widget can be used multiple times.

Using the Posts widget from the Layers core as a guideline, this is how our variables would look for a custom widget used to display a Custom Post Type called layers-demo-posts

Each variable is explained below:

Widget Title

$this->widget_title;
Accepts a text argument that must be wrapped in __()
__('Title', 'layerswp');
This variable sets the title of the widget inside the customizer. We recommend retaining the layerswp textdomain here to make translation easier for those using translation plugins.

Widget ID

$this->widget_id;
This value should be a unique name which is used only for the widget you area creating i.e .
'myplugin-features'

Post Type

$this->post_type;
We declare the post type being used in the Posts widget so that there’s no confusion later on (for example when using
WP_Query()
). If you are constructing a widget for a custom post type, this would be the post type, such as
'layers-doc'
as we use on this site.

If you are not querying post objects, such as in creating a content or slider-type widget, you would leave this blank i.e.
$this->post_type = '';

Category & Taxonomy

$this->taxonomy;
The same way we declare the post type to be used, it’s easier to declare your taxonomy up here than remember it over and over.

The default taxonomy for posts in WordPress is 'category'

. If you will be querying posts and categories in your widget and want to use a custom post type, replace this value with your custom taxonomy name, i.e. 'topic'

is our custom taxonomy for the layers-doc post type.

If you are not querying post objects, such as in creating a content or slider-type widget, you would leave this blank i.e.
$this->taxonomy = '';

Display Options

$this->checkboxes;
Our Posts widget presents several options for the user in the form of check-boxes under the Design Bar’s Display button, such as Show Dates or Show Tags. These options can be used in a variety of ways or be housed under a custom design bar button, or left out of your widget entirely. In our Posts widget, they are used to control the visibility of various elements of the post.

In order to sanitize our check-boxes in the save function, we declare them here. Each item in the array is the id of the check-box to be used in our form later on.

If creating a widget that queries posts, you may include all or only the values in the array that relate to your project.

For custom post types, you can setup unique options here that correspond to custom fields, or use the pre-existing ones to access core meta such as the title, date, etc when setting up your custom Design Bar options. We want to allow users to show or hide the Photo Credit or Topic setup in our custom post type meta and taxonomy, so we add

show_credit and show_topics to replace show_tags and how_categories you find in the default Posts Widget. These option keys will be used later when setting up our Design Bar Display options.

If your widget does not query posts, such as a widget based on the Content Widget, you can leave this blank, i.e.
$this->checkboxes = array();

Widget and Control Ops

$widget_ops  and $control_ops  are globals which allow you to set things like your widget’s CSS class, description, fixed height or width, etc.

'classname' = Prefixing the value with 'obox-layers-'  will add the Layers badge to the widget. You can copy the entire value in the example above to generate this class based on your widget ID 'description'  = takes a text string and should be wrapped in __()  to support localization.

'width'  = Takes a number in single quotes corresponding to pixels. This is optional, but 660 ensures the widget design is consistent with other Layers widgets.

'height'  = Takes a number in single quotes corresponding to pixels. Define this only if your widget requires a fixed height, otherwise leave NULL

'id_base'  = This sets a base for the widget ID, which is generated automatically. If you use our default value, it will output layers-widget-post , for example.

Note: We use the constant LAYERS_WIDGET_WIDTH_SMALL  in the Post Widget, however you won’t be able to call these constants from a plugin (but can make your own). This constant translates to 660 pixels, which is the standard Layers widget width setting. The height is set to NULL as we want our widget to span the entire screen height.

Putting all of the above together, we can safely instantiate our widget. This example complies with the WordPress 4.3 constructor requirements. You do not need to change anything about this line.

Widget Defaults

In the final part of our constructor, we set up our option defaults array. Since our widget functions just like a Post Widget, we can start with the defaults as they are defined in that widget file. We have already determined we will not have a Show Tags or Show Category option, so we can replace those option keys with our custom ones, show_credit  andshow_topic, which will correspond to custom checkboxes in the Display option of our widget’s Design Bar. Essentially your defaults setup each option key in the widget with a default value, following the 'option_key' => 'value', syntax.  The kind of value these option keys accept is defined by you later on and can be updated here if you change your mind.

2 – Widget Form

The next section of your class sets up the instance of your form which houses all of the option fields.

A Layers widget form consists of two main areas. The first area (1)  is our Design Bar, which offers the layout and styling control in the widget that makes it so great.

The second area is what we call the ‘canvas’ area or which holds the settings specific to this instance of the widget content and their respective content options form elements (2 & 3)

This is a free-form area which can be used in any way you please, as it accepts plain HTML and PHP, allowing full creative freedom inside the widget (a good example of this are our own content and slider widgets).

With that in mind, let’s move onto the code…

Widget Form Design Bar

design-bar

Widget Design Bar

The first action we take in our form is to grab the widget defaults (set in our construct) and extract the values from
$instance
You don’t need to do this but we find it easier to work with variables than with a large array. Your defaults start where “Form Elements go here” is shown in the example code above, by setting up some variables. These can be carried over as-is.

Next up we setup our Design Bar components. For more information on the different standard Design Bar components see Anatomy of the Design Bar

Inside our $design_bar_components  array, we will define the following components. You can leave one out if you don’t need it, or create your own custom component key here. Below is a overview of what our chosen component keys relate to.

layout  – Full Width / Boxed.

fonts – Font size / alignment, in this case it will apply to the widget Title & Excerpt.

custom – This indicates the placement of our custom components which we’ll unpack in the next section

columns  – How many columns we will display.

liststyle – This gives us the option of Masonry, Grid or List (standard blog list in this case).

imageratio - This will apply to our posts’ featured images.

background – This controls the background of the entire widget.

advanced- This will add our custom CSS control as well as margin & padding settings.

Note that we pass the components through a filter withapply_filters  so that other developers can hook into the setup, such as a Child Theme developer that wants to build a theme around your plugin but not allow the Advanced option. Filters are not required for the widget to work, but are encouraged.

Inside our$design_bar_custom_components   array, we can define all of our special option keys.

These custom elements allow us to specify our own controls which aren’t predefined by the Design Bar. In this case, it includes display check-boxes and text inputs. It’s important to note that this element is an array inside an array, which allows us to have more than one custom pop-out menu.

We start with the Display options  $design_bar_custom_components  defined in the Post Widget, but removeshow_tags and show_category and replace them withshow_credit and show_topics to work with our custom post type taxonomy and meta (remember we set these up in our checkboxes instance in the main function).

Let’s investigate the array on Line 4:

Beginning with the array key, we use 'display'  as these elements will control how content is displayed in the widget.

Each design bar option array contains the following:

icon-css- This is a CSS class used to display the pop out icon. Refer to the following for a detailed overview of the Layers Icon Set

label- Accepts a text argument that must be wrapped in

__() for localaization support.  Example:

__('Display', 'layerswp');

elements- An array containing the custom elements which will be shown inside the pop out.

Within the elements  array on Line 7 is where we can define our form fields by referencing the input types listed in the input() helper function. In the demo widget and code example below, we remove the show_tags  and show_categories elements and replace them with show_credit  and show_topics  to work with our custom post type taxonomy and custom meta.

The Display option in the Post widget already defines several elements  we can copy in after this and then modify if needed. Reference them here.

Gives us the following:

widget-display-options

Remember earlier where we said that we’ll extend the Layers_Widget  PHP class so that we can use helpers? Well this is the first time we’ll be using one of those helpers,

$this->designbar();, which instantiates the Design Bar.

The following options are set in this instance and do not need to be changed or customized for your widget.

side-  sets the ‘side’ CSS class to ensure the bar is positioned on the side of the widget. Don’t change this!

id  andname  – These are the Design Bar form name and ID fields. For the purpose of this widget type, we use 'design'. If you reference the Slider or Content Widget, you will see different values here such as design-liststyle. Don’t change them!

$instance- We pass through the widget $instance so that we can grab values from it.

$design_bar_components- Our standard Design Bar components as defined above.

$design_bar_custom_components- Our custom Design Bar components as defined above.

Content Options Form

As we mentioned before, your ‘canvas’ area is free-form (the area where the content of the widget is configured), but you may still use the Layers_Form_Elements Class to register your form elements.

The entire body of the widget to the left of the Design Bar is created with the .layers-container-large wrapper.

In a widget which intends to display a post type and give the user some options for customizing the category and number of posts, etc, you only need two primary sections, the widget header and the form elements themselves.

Widget Header

This is the blue bar across the top of the widget which houses the widget’s admin title and the Remove/Close buttons.

Create it using the built-in
header()
helper function. We instance it with the following syntax which sets the instance variable, and calls the form_elements class with the header helper:

This accepts the following parameters inside the helper array:
title
Accepts a text argument that must be wrapped in  __(). e.g.
__('Title', 'layerswp');
This variable sets the title of the widget inside the customzier, and appears in the blue bar at the top of the widget config panel. The second argument is your textdomain.

Using ‘layerswp’ is OK.

icon_class Will automatically be prepended by layers-icon- . A list of icon classes can be found in the Framework Reference.

Underneath our widget header and before the closing </div>  of the layers-container-large  wrapper,  we will add the Widget Title/Description Heading fields (2) and the content options (3).

Always include the Title/Description form in your widgets!

canvas-area

These are wrapped in a pair of framework wrappers and classes which will allow your form elements to style correctly. You do not need to worry about adding a

<form> or <fieldset>

element here!

Each form element inside this should be wrapped in
<p class="layers-form-item">
as noted in the input() reference. Below is a summary of the elements in our Post Widget which we will adapt for our widget:

Widget Title and Description

The first two we add are the widget Title and Excerpt which create the widget title and description shown above the posts on the front-end.

To define the field, the form_elements()->input helper is used, which accepts the following parameters:

We want a simple text field and textarea, so we give them a value of ‘text’ and ‘textarea’. Accepted values correspond to standard HTML form-element types such as text , etc.

name and id

We have already defined some shortcuts back in our widget construction that we can use here, $this->get_field_name( ‘title’ )helps keeps things consistent.

Accepts a text argument that must be wrapped in a gettext call and creates the text shown inside the text field by default before a user clicks into the field, best used to provide a tip on what the field is used for. Example:

value

We want the title to reflect what the user types in, so we set the value to the $title variable, already defined in the Layers_Widget PHP class.

class

Sets the CSS class to use for styling the field in the widget. For text fields, this is layers-text . For rich-text fields or textareas, this is layers-textarea. The layers-large class is added to define the icon size.

 

Category To Display

The next option we want is a drop-down to allow filtering content by Topic, which is our custom post type’s version of a category. To do this, we must loop through get_terms()  to populate a our options array, which looks at our custom taxonomy layers-demo-category which we already defined during widget construction above.

We can set a custom default label on Line 5, and a default to represent All categories on Line 6 in the $category_options[0] variable.

We then instance another input on Line 8. In the input instance, we set a new field ‘type’ of ‘select’ and set out ‘name’ and ‘id’ to grab the category value selected from the list generated by our terms query.

 

Number of Items to Show 

Instance another input, but this time give it a ‘type’ of ‘number’. This allows for setting some additional parameters, such as a minimum  (‘min’ ) and maximum (‘max’ ) value, or a step value, if needed.

Sort By and Sort Order

You should always allow for sorting of queried content. You can do this with another input instance that sets a ‘select’ type. In our sort option, we use a helper from the Form Class called
get_sort_options
as the ‘options’ value. This helper returns an array of sort options like “Newest First” that gives us two options in one, the order and orderby parameters.

 

Here is a sneak peek at the final widget form:

demo-widget-form

Note you wont see the widget in your customizer until you initialize and register it later.

3 – Update Controls

The
update
function beginning on line 275 of the Post widget, for reference, is the third thing we setup in the widget class. It takes our checkbox settings and ensures they update the selected status as the user sets each option. You do not need to change/customize this function.

That’s it for the back-end!

4 – Widget Front End

The widget front end is where we edit how the widget is rendered when the page is viewed in the browser. We utilize many more of theLayers_Widget PHP class helpers in this
widget
function, making this example great for getting used to the way we put our widgets together. All of your markup will go inside the widget function in section 4 of the widget layout.

To celebrate making it this far in the tutorial, get up and make another cup of coffee!

As each code section is explained, we will point out where you can define custom values or change something. We are building from lines 93-351 of the Post Widget, broken down into manageable chunks below:

Setup

Let’s start with the initial extraction of the elements defined in the widget options.In this example, we’ve translated $instance  to $widget to be more semantic. The outline of this section is simple, beginning with an extract, setting a default variable, deciding whether to use it or not, then parsing the widget config. You don’t need to change anything here.

On Line 8 above, we look for an empty $instance in which case we use the widget defaults. That really helps users when first adding the widget to their page.

Check All The Things

Next up we go straight into a helper function. This time, we’re using an instance of check_and_return();  , which takes an argument and checks it against isset() , ensuring the option is not blank,  and allows us to check variables up to 4 levels deep.

Now we check our Layout and decide whether or not to enqueue Masonry (i.e. does the user have the Masonry grid style selected?)

Defining the Grid

The next function we perform is setting the column widths, which refer to the Layers Grid Framework classes.

Line 2-4 sets a fallback for the one-column class
span-12
Lines 5-7 demonstrate a shortcut for generating the class depending on the number of columns selected in the Design Bar option

Lines 8-10 set a default of 3 columns and its associated class. You can set a different number/class if you wish. Remember to update your widget defaults array in your main function if you do!

Colors and Font Settings

Time for more helpers! This time,  the helpers are going to allow us to automatically generate inline CSS according to our background and font setting choices. The function we will use is
layers_inline_styles();
Line 2: A condition to check the relevant Design Bar option

Line 3: Here we use
layers_inline_styles()
to take the value of our design controls and apply it to a specified selector. This function builds the required CSS for each Layers widget in the page as it is being influenced by the user’s choices. Once compiled it is output in the site footer as a performance measure.

This function needs the following arguments, shown below one per line:

Line 4 : Parent selector – The containing element we are targeting. By default this is an automatically generated widget ID via
$widget_id
. We recommend keeping it this way so users can properly create anchor links.

Line 5: CSS property – The property to set.  For more information on the different types of CSS available, see layers_inline_styles

Line 6: An array including our selectors and property values – In this case we are using background and color properties, and our selectors, such as those in the colors example,  are standard CSS selectors which will target the corresponding element inside our parent element.

In general, this should be carried over as-is to correspond to the controls in the Design Bar options if you have included the background and font color options in your Design Bar setup. If you have created additional color options, you would setup one layers_inline_styles() function for each option key to set its parent selector and CSS property.

Get Advanced Styles

The following function will generate our advanced styling for us. This includes our Advanced CSS Class and CSS, margin, padding and any other extended options added in the future or by other extensions.
// Apply the advanced widget styling $this->apply_widget_advanced_styling( $widget_id, $widget );

Featured Images

In the next block of code we pass our image settings through
 layers_translate_image_ratios();
. This function takes our Image Ratios option and returns the Layers-specific image ratio suffix. This grab the appropriate image crop and CSS classes and apply them to the featured image assigned to the post. You should insert this code as-is with no modification.

Query and Display Post Content

In order to display our custom posts in the widget, we need to build a custom query.

 

Lines 5-12: This is a standard way to setup pagination via
$paged
as you would use in a custom page template. Reference

Lines 14-16: These two variables set the post type and posts per page to grab the option value of
$this->post_type
 and your widget content form’s

posts_per_page
 

argument. You don’t need to change these unless you changed the option key names.

Lines 18-24: The $decode_order variable is where we take our single order  input, defined back in the Sort By section of our back-end form, and translate it into two options: Order and Order By. Neat!

Lines 28-38: The $tax_query argument is always a two-leveled array to allow  you to query more than one taxonomy at a time (and actually opens the option up to add tags or multiple taxonomies to this widget, if desired). Refer to wp_query for the basics of this array and other arguments accepted here. We left our category option as

'category', and defined the taxonomy to query in our instance of the taxonomy variable back in the beginning of the plugin class.

Line 41: Merges the arguments and sets up the new query. We will be modifying our post loop with the $post_query variable in just a bit.

Get Meta Data

We want our users to have control over the post meta that is displayed, so we populate an array with our Display option keys and the associated meta field key. These will be used later in a helper function called
layers_post_meta();
Note that we use isset()  here again as a safety measure so the data is only queried if the option is enabled.

Line 3:
date
pulls in the core Date Created time stamp on the post.

Line 4:
author
pulls in the author of the post

Line 5:
categories
will grab the categories (setup as topics for our post type) the post is assigned and output them in a comma-separated string.

In How to Add Custom Fields to Posts and Pages, we created two custom fields on our custom post type. One for a Photo Credit name and one for a Photo Credit URL that we can display under the Featured Image in our widget and in the post templates. These will be grabbed later inside the loop.

Now that we have setup a whole host of parameters, let’s start putting the HTML together.

Widget HTML

Note that the original structure, helpers, hooks and classes should be retained in your custom builder widgets to ensure proper linkage with the framework and widget options. You may inject custom classes or HTML but should not change the existing, with special care given to the default classes and the HTML element types used.

Layers Builder widgets are each wrapped in a few <div>  tags using specific classes and class constructors, which should be retained. In brief it opens like this (Reference):

Class Constructors

We  use the
check_and_return
helper again, this time going two levels deep to verify our own custom CSS class for this widget, if set in the Advanced option. We also make use of the
get_widget_spacing_class()
helper which will apply our margin and padding. This is required if you want this Design Bar option to work! (Reference)

 

From here  it is almost exactly like writing a template, where each of your input values is output or checked using
$widget['value']
syntax.

Title & D