Tag Archives: function

Getting Started With The Web MIDI API

As the web continues to evolve and new browser technologies continue to emerge, the line between native and web development becomes more and more blurred. New APIs are unlocking the ability to code entirely new categories of software in the browser.

Until recently, the ability to interact with digital musical instruments has been limited to native, desktop applications. The Web MIDI API is here to change that.

In this article, we’ll cover the basics of MIDI and the Web MIDI API to see how simple it can be to create a web app that responds to musical input using JavaScript.

What Is MIDI?

MIDI has been around for a long time but has only recently made its debut in the browser. MIDI (Musical Instrument Digital Interface) is a technical standard that was first published in 1983 and created the means for digital instruments, synthesizers, computers, and various audio devices to communicate with each other. MIDI messages relay musical and time-based information back and forth between devices.

A typical MIDI setup might consist of a digital piano keyboard which can send messages relaying information such as pitch, velocity (how loudly or softly a note is played), vibrato, volume, panning, modulation, and more to a sound synthesizer which converts that into audible sound. The keyboard could also send its signals to desktop music scoring software or a digital audio workstation (DAW) which could then convert the signals into written notation, save them as a sound file, and more.

MIDI is a fairly versatile protocol, too. In addition to playing and recording music, it has become a standard protocol in stage and theater applications, as well, where it is often used to relay cue information or control lighting equipment.


A performer plays a digital piano onstage


MIDI lets digital instruments, synthesizers, and software talk to each other and is frequently used in live shows and theatrical productions. Photo by Puk Khantho on Unsplash.

MIDI In The Browser

The WebMIDI API brings all the utility of MIDI to the browser with some pretty simple JavaScript. We only need to learn about a few new methods and objects.

Introduction

First, there’s the navigator.requestMIDIAccess() method. It does exactly what it sounds like—it will request access to any MIDI devices (inputs or outputs) connected to your computer. You can confirm the browser supports the API by checking for the existence of this method.

if (navigator.requestMIDIAccess) 
    console.log('This browser supports WebMIDI!');
 else 
    console.log('WebMIDI is not supported in this browser.');

Second, there’s the MIDIAccess object which contains references to all available inputs (such as piano keyboards) and outputs (such as synthesizers). The requestMIDIAccess() method returns a promise, so we need to establish success and failure callbacks. And if the browser is successful in connecting to your MIDI devices, it will return a MIDIAccess object as an argument to the success callback.

navigator.requestMIDIAccess()
    .then(onMIDISuccess, onMIDIFailure);

function onMIDISuccess(midiAccess) 
    console.log(midiAccess);

    var inputs = midi.inputs;
    var outputs = midi.outputs;


function onMIDIFailure() 
    console.log('Could not access your MIDI devices.');

Third, MIDI messages are conveyed back and forth between inputs and outputs with a MIDIMessageEvent object. These messages contain information about the MIDI event such as pitch, velocity (how softly or loudly a note is played), timing, and more. We can start collecting these messages by adding simple callback functions (listeners) to our inputs and outputs.

Going Deeper

Let’s dig in. To send MIDI messages from our MIDI devices to the browser, we’ll start by adding an onmidimessage listener to each input. This callback will be triggered whenever a message is sent by the input device, such as the press of a key on the piano.

We can loop through our inputs and assign the listener like this:

function onMIDISuccess(midiAccess) 
    for (var input of midiAccess.inputs.values())
        input.onmidimessage = getMIDIMessage;
    
}

function getMIDIMessage(midiMessage) 
    console.log(midiMessage);

The MIDIMessageEvent object we get back contains a lot of information, but what we’re most interested in is the data array. This array typically contains three values (e.g. [144, 72, 64]). The first value tells us what type of command was sent, the second is the note value, and the third is velocity. The command type could be either “note on,” “note off,” controller (such as pitch bend or piano pedal), or some other kind of system exclusive (“sysex”) event unique to that device/manufacturer.

For the purposes of this article, we’ll just focus on properly identifying “note on” and “note off” messages. Here are the basics:

  • A command value of 144 signifies a “note on” event, and 128 typically signifies a “note off” event.
  • Note values are on a range from 0–127, lowest to highest. For example, the lowest note on an 88-key piano has a value of 21, and the highest note is 108. A “middle C” is 60.
  • Velocity values are also given on a range from 0–127 (softest to loudest). The softest possible “note on” velocity is 1.
  • A velocity of 0 is sometimes used in conjunction with a command value of 144 (which typically represents “note on”) to indicate a “note off” message, so it’s helpful to check if the given velocity is 0 as an alternate way of interpreting a “note off” message.

Given this knowledge, we can expand our getMIDIMessage handler example above by intelligently parsing our MIDI messages coming from our inputs and passing them along to additional handler functions.

function getMIDIMessage(message) 
    var command = message.data[0];
    var note = message.data[1];
    var velocity = (message.data.length > 2) ? message.data[2] : 0; // a velocity value might not be included with a noteOff command

    switch (command) 
        case 144: // noteOn
            if (velocity > 0) 
                noteOn(note, velocity);
             else 
                noteOff(note);
            
            break;
        case 128: // noteOff
            noteOff(note);
            break;
        // we could easily expand this switch statement to cover other types of commands such as controllers or sysex
    }
}

Browser Compatibility And Polyfill

As of the writing of this article, the Web MIDI API is only available natively in Chrome, Opera, and Android WebView.


Browser support for Web MIDI API from caniuse.com


The Web MIDI API is only available natively in Chrome, Opera, and Android WebView.

For all other browsers that don’t support it natively, Chris Wilson’s WebMIDIAPIShim library is a polyfill for the Web MIDI API, of which Chris is a co-author. Simply including the shim script on your page will enable everything we’ve covered so far.

<script src="WebMIDIAPI.min.js"></script>    
<script>
if (navigator.requestMIDIAccess)  //... returns true
</script>

This shim also requires Jazz-Soft.net’s Jazz-Plugin to work, unfortunately, which means it’s an OK option for developers who want the flexibility to work in multiple browsers, but an extra barrier to mainstream adoption. Hopefully, within time, other browsers will adopt the Web MIDI API natively.

Making Our Job Easier With WebMIDI.js

We’ve only really scratched the surface of what’s possible with the WebMIDI API. Adding support for additional functionality besides basic “note on” and “note off” messages starts to get much more complex.

If you’re looking for a great JavaScript library to radically simplify your code, check out WebMidi.js by Jean-Philippe Côté on Github. This library does a great job of abstracting all the parsing of MIDIAccess and MIDIMessageEvent objects and lets you listen for specific events and add or remove listeners in a much simpler way.

WebMidi.enable(function () 

    // Viewing available inputs and outputs
    console.log(WebMidi.inputs);
    console.log(WebMidi.outputs);

    // Retrieve an input by name, id or index
    var input = WebMidi.getInputByName("My Awesome Keyboard");
    // OR...
    // input = WebMidi.getInputById("1809568182");
    // input = WebMidi.inputs[0];

    // Listen for a 'note on' message on all channels
    input.addListener('noteon', 'all',
        function (e) 
            console.log("Received 'noteon' message (" + e.note.name + e.note.octave + ").");
        
    );

    // Listen to pitch bend message on channel 3
    input.addListener('pitchbend', 3,
        function (e) 
            console.log("Received 'pitchbend' message.", e);
        
    );

    // Listen to control change message on all channels
    input.addListener('controlchange', "all",
        function (e) 
            console.log("Received 'controlchange' message.", e);
        
    );

    // Remove all listeners for 'noteoff' on all channels
    input.removeListener('noteoff');

    // Remove all listeners on the input
    input.removeListener();

});

Real-World Scenario: Building A Breakout Room Controlled By A Piano Keyboard

A few months ago, my wife and I decided to build a “breakout room” experience in our house to entertain our friends and family. We wanted the game to include some kind of special effect to help elevate the experience. Unfortunately, neither of us have mad engineering skills, so building complex locks or special effects with magnets, lasers, or electrical wiring was outside the realm of our expertise. I do, however, know my way around the browser pretty well. And we have a digital piano.

Thus, an idea was born. We decided that the centerpiece of the game would be a series of passcode locks on a computer that players would have to “unlock” by playing certain note sequences on our piano, a la Willy Wonka.

This is a musical lock
This is a musical lock

Sound cool? Here’s how I did it.

Setup

We’ll begin by requesting WebMIDI access, identifying our keyboard, attaching the appropriate event listeners, and creating a few variables and functions to help us step through the various stages of the game.

// Variable which tell us what step of the game we're on. 
// We'll use this later when we parse noteOn/Off messages
var currentStep = 0;

// Request MIDI access
if (navigator.requestMIDIAccess) 
    console.log('This browser supports WebMIDI!');

    navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure);

 else 
    console.log('WebMIDI is not supported in this browser.');


// Function to run when requestMIDIAccess is successful
function onMIDISuccess(midiAccess) 
    var inputs = midiAccess.inputs;
    var outputs = midiAccess.outputs;

    // Attach MIDI event "listeners" to each input
    for (var input of midiAccess.inputs.values()) 
        input.onmidimessage = getMIDIMessage;
    
}

// Function to run when requestMIDIAccess fails
function onMIDIFailure() 
    console.log('Error: Could not access MIDI devices.');


// Function to parse the MIDI messages we receive
// For this app, we're only concerned with the actual note value,
// but we can parse for other information, as well
function getMIDIMessage(message) 
    var command = message.data[0];
    var note = message.data[1];
    var velocity = (message.data.length > 2) ? message.data[2] : 0; // a velocity value might not be included with a noteOff command

    switch (command) 
        case 144: // note on
            if (velocity > 0) 
                noteOn(note);
             else 
                noteOff(note);
            
            break;
        case 128: // note off
            noteOffCallback(note);
            break;
        // we could easily expand this switch statement to cover other types of commands such as controllers or sysex
    }
}

// Function to handle noteOn messages (ie. key is pressed)
// Think of this like an 'onkeydown' event
function noteOn(note) 
    //...


// Function to handle noteOff messages (ie. key is released)
// Think of this like an 'onkeyup' event
function noteOff(note) 
    //...


// This function will trigger certain animations and advance gameplay 
// when certain criterion are identified by the noteOn/noteOff listeners
// For instance, a lock is unlocked, the timer expires, etc.
function runSequence(sequence) 
    //...

Step 1: Press Any Key To Begin

To kick off the game, let’s have the players press any key to begin. This is an easy first step which will clue them into how the game works and also start a countdown timer.

function noteOn(note) 
    switch(currentStep) 
        // If the game hasn't started yet.
        // The first noteOn message we get will run the first sequence
        case 0: 
            // Run our start up sequence
            runSequence('gamestart');

            // Increment the currentStep so this is only triggered once
            currentStep++;
            
            break;
    
}

function runSequence(sequence) 
    switch(sequence) 
        case 'gamestart':            
            // Now we'll start a countdown timer...
            startTimer();
            
            // code to trigger animations, give a clue for the first lock
            break;
    
}

Step 2: Play The Correct Note Sequence

For the first lock, the players must play a particular sequence of notes in the right order. I’ve actually seen this done in a real breakout room, only it was with an acoustic upright piano rigged to a lock box. Let’s re-create the effect with MIDI.

For every “note on” message received, we’ll append the numeric note value to an array and then check to see if that array matches a predefined array of note values.

We’ll assume some clues in the breakout room have told the players which notes to play. For this example, it will be the beginning of the tune to “Amazing Grace” in the key of F major. That note sequence would look like this.


A visual representation of the first nine notes of “Amazing Grace” on a piano


This is the correct sequence of notes that we’ll be listening for as the solution to the first lock.

The MIDI note values in array form would be: [60, 65, 69, 65, 69, 67, 65, 62, 60].

var correctNoteSequence = [60, 65, 69, 65, 69, 67, 65, 62, 60]; // Amazing Grace in F
var activeNoteSequence = [];

function noteOn(note) 
    switch(currentStep) 
        // ... (case 0)

        // The first lock - playing a correct sequence
        case 1:
            activeNoteSequence.push(note);

            // when the array is the same length as the correct sequence, compare the two
            if (activeNoteSequence.length == correctNoteSequence.length) 
                var match = true;
                for (var index = 0; index < activeNoteSequence.length; index++) 
                    if (activeNoteSequence[index] != correctNoteSequence[index]) 
                        match = false;
                        break;
                    
                }

                if (match) 
                    // Run the next sequence and increment the current step
                    runSequence('lock1');
                    currentStep++;
                 else 
                    // Clear the array and start over
                    activeNoteSequence = [];
                
            }
            break;
    }
}

function runSequence(sequence) 
    switch(sequence) 
        // ...

        case 'lock1':
            // code to trigger animations and give clue for the next lock
            break;
    
}

Step 3: Play The Correct Chord

The next lock requires the players to play a combination of notes at the same time. This is where our “note off” listener comes in. For every “note on” message received, we’ll add that note value to an array; for every “note off” message received, we’ll remove that note value from the array. Therefore, this array will reflect which notes are currently being pressed at any time. Then, it’s a matter of checking that array every time a note value is added to see if it matches a master array with the correct values.

For this clue, we’ll make the correct answer a C7 chord in root position starting on middle C. That looks like this.


A visual representation of a C7 chord on a piano


These are the four notes that we’ll be listening for as the solution to the second lock.

The correct MIDI note values for this chord are: [60, 64, 67, 70].

var correctChord = [60, 64, 67, 70]; // C7 chord starting on middle C
var activeChord = [];

function noteOn(note) 
    switch(currentStep) 
        // ... (case 0, 1)

        case 2:
            // add the note to the active chord array
            activeChord.push(note);

            // If the array is the same length as the correct chord, compare
            if (activeChord.length == correctChord.length) 
                var match = true;
                for (var index = 0; index < activeChord.length; index++) 
                    if (correctChord.indexOf(activeChord[index]) < 0) 
                        match = false;
                        break;
                    
                }

                if (match) 
                    runSequence('lock2');
                    currentStep++;
                
            }
            break;
    }

function noteOff(note) 
    switch(currentStep) 
        case 2:
            // Remove the note value from the active chord array
            activeChord.splice(activeChord.indexOf(note), 1);
            break;
    
}

function runSequence(sequence) 
    switch(sequence) 
        // ...

        case 'lock2':
            // code to trigger animations, stop clock, end game
            stopTimer();

            break;
    
}

Now all that’s left to do is to add some additional UI elements and animations and we have ourselves a working game!

Here’s a video of the entire gameplay sequence from start to finish. This is running in Google Chrome. Also shown is a virtual MIDI keyboard to help visualize which notes are currently being played. For a normal breakout room scenario, this can run in full-screen mode and with no other inputs in the room (such as a mouse or computer keyboard) to prevent users from closing the window.

WebMIDI Breakout Game Demo (watch in Youtube)

If you don’t have a physical MIDI device laying around and you still want to try it out, there are a number of virtual MIDI keyboard apps out there that will let you use your computer keyboard as a musical input, such as VMPK. Also, if you’d like to further dissect everything that’s going on here, check out the complete prototype on CodePen.

See the Pen WebMIDI Breakout Room Demo by Peter Anglea (@peteranglea) on CodePen.

Conclusion

MIDI.org says that “Web MIDI has the potential to be one of the most disruptive music [technologies] in a long time, maybe as disruptive as MIDI was originally back in 1983.” That’s a tall order and some seriously high praise.

I hope this article and sample app has gotten you excited about the potential that this API has to spur the development of new and exciting kinds of browser-based music applications. In the coming years, hopefully, we’ll start to see more online music notation software, digital audio workstations, audio visualizers, instrument tutorials, and more.

If you want to read more about Web MIDI and its capabilities, I recommend the following:

And for further inspiration, here are some other examples of the Web MIDI API in action:

Smashing Editorial
(rb, ra, hj, il)

Read More:

Getting Started With The Web MIDI API

Three Approaches To Adding Configurable Fields To Your WordPress Plugin


Anyone who has created a WordPress plugin understands the need to create configurable fields to modify how the plugin works. There are countless uses for configurable options in a plugin, and nearly as many ways to implement said options. You see, WordPress allows plugin authors to create their own markup within their settings pages. As a side effect, settings pages can vary greatly between plugins.

In this article we are going to go over three common ways you can make your plugin configurable. We will start by creating a settings page and create our fields using the default WordPress Settings API. I will then walk you through how to set up your fields with a custom handler. Finally, I will show you how to integrate a great configurable fields plugin Advanced Custom Fields (ACF) into your own plugin.

The post Three Approaches To Adding Configurable Fields To Your WordPress Plugin appeared first on Smashing Magazine.

Originally from – 

Three Approaches To Adding Configurable Fields To Your WordPress Plugin

Extending WordPress With Custom Content Types

WordPress does some pretty amazing things out of the box. It handles content management as well as any other open-source solution out there — and better than many commercial solutions. One of the best attributes of WordPress is its ease of use. It’s easy because there’s not a significant amount of bloat with endless bells and whistles that steepen the learning curve.

On the flip side, some might find WordPress a little… well, light. It does a lot, but not quite enough. If you find yourself hacking WordPress to do the things you wish it would do, then the chances are high that this article is for you.

WordPress can be easily extended to fit the requirements of a custom data architecture. We’re going to explore the process of registering new data types in a fully compliant manner.

If you want to follow along at home, we’ve provided the full source code1 (TXT, 5.0 KB).

Custom Post Types

WordPress gives you a very simple and straightforward way to extend the standard two data types (Posts and Pages) into an endless array for your custom needs. A digital agency or freelancer would need a “Project” post type. A mall would need a “Location” post type.

Quick point. Spinning off custom post types is a great idea for content that is intrinsically different than either Posts or Pages. There could be a case where you would want press releases to live in their own type. But more often than not, the press releases would be a Post and categorized as a press release. Or you may want to create a post type for landing pages. It may very well belong as a custom type, but it likely could also exist as a Page.

For the sake of this article, we’re going to follow a real-world scenario of creating a Project post type to store samples of work. We’ll register the post type, add some meta data to it, include additional information in WordPress’ administration screens, and create custom taxonomies to supplement.

Registering The Post Type

To get started, we’ll need some code to register the post type. We’re going to go with an object-oriented approach because we’ll be spinning off this post type later with some added functionality that would be done much more efficiently with an object model. To start, let’s create the function that registers the post type.

function create_post_type() 
  $labels = array(
    'name'               => 'Projects',
    'singular_name'      => 'Project',
    'menu_name'          => 'Projects',
    'name_admin_bar'     => 'Project',
    'add_new'            => 'Add New',
    'add_new_item'       => 'Add New Project',
    'new_item'           => 'New Project',
    'edit_item'          => 'Edit Project',
    'view_item'          => 'View Project',
    'all_items'          => 'All Projects',
    'search_items'       => 'Search Projects',
    'parent_item_colon'  => 'Parent Project',
    'not_found'          => 'No Projects Found',
    'not_found_in_trash' => 'No Projects Found in Trash'
  );

  $args = array(
    'labels'              => $labels,
    'public'              => true,
    'exclude_from_search' => false,
    'publicly_queryable'  => true,
    'show_ui'             => true,
    'show_in_nav_menus'   => true,
    'show_in_menu'        => true,
    'show_in_admin_bar'   => true,
    'menu_position'       => 5,
    'menu_icon'           => 'dashicons-admin-appearance',
    'capability_type'     => 'post',
    'hierarchical'        => false,
    'supports'            => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments' ),
    'has_archive'         => true,
    'rewrite'             => array( 'slug' => 'projects' ),
    'query_var'           => true
  );

  register_post_type( 'sm_project', $args );

Not much mysterious here. We’re calling the create_post_type function, which registers our post type. We’re giving the type some labels for back-end identification and giving it a list of specifications in what it can do. For a full list of reference for each of these variables, take a look at the WordPress Codex2, but we’ll hit on a few key items.

labels

For brevity, we’ve created a labels array and simply passed it to the arguments array. WordPress enables us to identify a slew of labels for singular, plural and other purposes.

public

This setting is a parent of sorts for a few of the other settings that appear later in the list. The default value for the public attribute is false. The value of public is passed to the following other attributes when they are not explicitly defined: exclude_from_search, publicly_queryable, show_in_nav_menus and show_ui.

exclude_from_search

The default setting here is the opposite of the public attribute. If your post type is public, then it will be included in the website’s search results. Note that this has no implication for SEO and only restricts or allows searches based on WordPress’ native search protocol. There’s a chance you would want the post type to be public but not appear in these search results. If that’s the case, set this attribute to true.

publicly_queryable

This attribute is exclusively for front-end queries and has no real back-end implications. The default value is the same as the public attribute. Note that when it’s set to false, you will not be able to view or preview the post type in the front end. For example, if you wanted to create a post type that populates a personnel page with a list of everyone’s name, title and bio but didn’t want them to have their own URL on the website, then you would set publicly_queryable to false.

show_ui

Most of the time, you’ll want to set show_ui to true. The default value pulls from the public attribute but can be overridden. When it’s set to false, then a UI element on WordPress’ administration screen won’t be available to you. A practical reason why you would want this set to false is if you had a post type that merely managed data. For example, you may want an Events post type that has a recurring attribute. When you save an event, new posts of a different type would be created to handle each event occurrence. You would want the UI to show only the primary Events post type and not the event occurrence’s meta data.

show_in_nav_menus

Pretty simple and straightforward. If you don’t want this post type to appear in WordPress’ default menu functionality, set this to false. It takes the value of public as default.

show_in_menu

You can modify the position of the post type in the back end. When set to true, the post type defaults as a top-level menu (on the same hierarchical level as Posts and Pages). If false, it won’t show at all. You can use a string value here to explicitly nest the post type into a top level’s submenu. The type of string you would provide is tools.php, which would place the post type as a nested element under “Tools.” It derives its default value from show_ui. Note that show_ui must be set to true in order for you to be able to control this attribute.

show_in_admin_bar

Pretty self-explanatory. If you want UI elements added to WordPress’ administration bar, set this to true.

menu_position

The default value of null will place the menu (at the top level and if not overridden using show_in_menu) below “Comments” in the back end. You can control this further by specifying an integer value corresponding to WordPress’ default menu placements. A value of 5 will place the post type under “Posts,” 10 under “Media,” 15 under “Links,” and 20 under “Pages.” For a full list of values, check out the WordPress Codex3.

menu_icon

You can pass a URL to this attribute, but you could also simply use the name of an icon from Dashicons for a quick solution. Supplying the attribute dashicons-admin-appearance would give you a paint brush4. A full list of Dashicons is available5 as a handy resource. The default is the thumbtack icon used for Posts.

capability_type

This attribute quickly gets into some advanced user-role segmenting concepts. Essentially, assigning post to this attribute generates a capability structure that exactly mimics how access to Posts works. Using this value, subscribers would not be able to access this post type, whereas Authors, Editors and Administrators would. Using page here would limit access to just Editors and Administrators. You can define a more granular structure using capability_type and capabilities attributes in the arguments list. Note that we did not use the capabilities attribute in this example because we’re not explicitly defining a custom capability structure to be used with this post type. This is an advanced concept and one for a completely different article.

hierarchical

This is basically the difference between a Post and a Page. When set to true, a parent post can be identified on a per-post basis (basically, Pages). When false, it behaves as a Post.

supports

A whole bunch of default functionality is attached to each new post type. This array tells WordPress which one of those to include by default. There may be an instance when you don’t want the editor on your post type. Removing that from the array will remove the editor box on the post’s editing screen. Eligible items for the array include the following:

  • title
  • editor
  • author
  • thumbnail
  • excerpt
  • trackbacks
  • custom-fields
  • comments
  • revisions
  • page-attributes
  • post-formats

has_archive

When this is set to true, WordPress creates a hierarchical structure for the post type. So, accessing /projects/ would give us the standard archive.php view of the data. You can template out a variant of archive.php for this particular archive by creating a new file in your theme system named archive-sm_project.php. You can control the default behavior at a more granular level by spinning it off from your primary archive.php.

rewrite

The rewrite option allows you to form a URL structure for the post type. In this instance, our URL would be http://www.example.com/projects/slug/, where the slug is the portion assigned by each post when it’s created (normally, based on the title of the post). A second variable can be assigned inside the rewrite array. If you add with_front => false (it defaults to true), it will not use the identified front half of the URL, which is set in “Settings” → “Permalinks.” For example, if your default WordPress permalink structure is /blog/%postname%/, then your custom post type would automatically be /blog/projects/%postname%/. That’s not a good outcome, so set with_front to false.

query_var

This attribute controls where you can use a PHP query variable to retrieve the post type. The default is true and renders with the permalink structure (when set). You can use a string instead of a variable and control the key portion of the query variable with the string’s value.

Extending The Post Type With A Taxonomy (Or Two)

Out of the box, WordPress Posts have categories and tags attached to them that enable you to appropriately place content in these buckets. By default, new post types don’t have any taxonomies attached to them. You may not want to categorize or tag your post type, but if you do, you’d need to register some new ones. There are two variants of taxonomies, one that behaves like categories (the checklist to the right of the posts) and one like tags, which have no hierarchical structure. They behave in the back end pretty much in the same way (the only discernable difference being that categories can have children, whereas tags cannot), but how they’re presented on the administration screen varies quite wildly. We’ll register two taxonomies to give us one of each type.

function create_taxonomies() 

  // Add a taxonomy like categories
  $labels = array(
    'name'              => 'Types',
    'singular_name'     => 'Type',
    'search_items'      => 'Search Types',
    'all_items'         => 'All Types',
    'parent_item'       => 'Parent Type',
    'parent_item_colon' => 'Parent Type:',
    'edit_item'         => 'Edit Type',
    'update_item'       => 'Update Type',
    'add_new_item'      => 'Add New Type',
    'new_item_name'     => 'New Type Name',
    'menu_name'         => 'Types',
  );

  $args = array(
    'hierarchical'      => true,
    'labels'            => $labels,
    'show_ui'           => true,
    'show_admin_column' => true,
    'query_var'         => true,
    'rewrite'           => array( 'slug' => 'type' ),
  );

  register_taxonomy('sm_project_type',array('sm_project'),$args);

  // Add a taxonomy like tags
  $labels = array(
    'name'                       => 'Attributes',
    'singular_name'              => 'Attribute',
    'search_items'               => 'Attributes',
    'popular_items'              => 'Popular Attributes',
    'all_items'                  => 'All Attributes',
    'parent_item'                => null,
    'parent_item_colon'          => null,
    'edit_item'                  => 'Edit Attribute',
    'update_item'                => 'Update Attribute',
    'add_new_item'               => 'Add New Attribute',
    'new_item_name'              => 'New Attribute Name',
    'separate_items_with_commas' => 'Separate Attributes with commas',
    'add_or_remove_items'        => 'Add or remove Attributes',
    'choose_from_most_used'      => 'Choose from most used Attributes',
    'not_found'                  => 'No Attributes found',
    'menu_name'                  => 'Attributes',
  );

  $args = array(
    'hierarchical'          => false,
    'labels'                => $labels,
    'show_ui'               => true,
    'show_admin_column'     => true,
    'update_count_callback' => '_update_post_term_count',
    'query_var'             => true,
    'rewrite'               => array( 'slug' => 'attribute' ),
  );

  register_taxonomy('sm_project_attribute','sm_project',$args);

When registering a post type, a new menu will appear in the dashboard.6
After you register the new post type and taxonomies, you’ll be greeted with a handy menu in the back end. (View large version7)

All right, now we have two new taxonomies attached to the new post type. The register_taxonomy function takes three arguments. The first is the taxonomy’s name, the second is an array or string of post types, and the third is the arguments defined above.

A quick note on our prefixing. Our post type and taxonomies are all prefixed with sm_. This is by design. We don’t want future plugins to interrupt our infrastructure, so we simply prefix. The name of the prefix is completely up to you.

So, we’ve got a new post type and two new taxonomies attached to it. This essentially replicates the default Posts behavior of WordPress. This is all good stuff, but let’s dig a little deeper to make it more integrated.

Enhancing The Experience With Meta Data

Creating additional fields available to the author in WordPress’ administration screen can be a bit tricky — but abundantly useful. Where WordPress underperforms its competitors is precisely in this area. There’s no user interface where you can define additional pieces of information on a per-post basis. Make no mistake, WordPress fully supports this behavior, but it’s more of a developer tool than an out-of-the-box tool, which makes sense. One might need an endless number of combinations of additional fields. Even if WordPress provided a slick back-end interface to allow a non-technical user to define these fields, there’s no real seamless way to display that information in the front end without a developer putting their hands on it and making it so.

This is where Advanced Custom Fields8 comes in. ACF is a wonderful plugin that gives developers this interface and a full array of templating functions to pull the data in the front end. This article doesn’t detail how to do that, but ACF gives ample documentation9 to get you started and working in the ACF environment.

A preview of the ACF UI for creating custom metadata.10
ACF makes creating meta data and conditionally attaching to custom post types a snap. (View large version11)

Using ACF, you can define new fields and conditionally attach them to content throughout the website. For example, we could create a timeframe meta field that collects how long a particular project has taken. We could add additional fields for awards won or create fields to represent a list of references for any given project.

Using ACF really opens up the hood for what’s possible in WordPress.

Adding Columns To The Administration Screen

Viewing a list of your posts on the administration screen will give you the checkbox, the title and the date published. When registering taxonomies to the post type, you’ll get an additional column for each additional taxonomy. For the majority of cases, this is sufficient. But there may be an additional case or two where you need to provide a little more information. For example, referencing pieces of meta data in the administration grid might be useful. Maybe you want a quick reference for the timeframe or the awards field we defined above. We’ll need two functions attached to some WordPress hooks.

WordPress will give you a standard UI that will closely mirror the Post UI.12
WordPress gives you a standard administration screen out of the box that closely mirrors the built-in Post post type. (View large version13)

Let’s look at the code:

function columns($columns) 
  unset($columns['date']);
  unset($columns['taxonomy-sm_project_attribute']);
  unset($columns['comments']);
  unset($columns['author']);
  return array_merge(
    $columns,
    array(
      'sm_awards' => 'Awards',
      'sm_timeframe' => 'Timeframe'
    ));

The first line unsets the date column. You can unset any of the default columns that you wish. The second line unsets the custom taxonomy we registered (the tag-like one, not category). This could be useful for keeping the admin screen neat and tidy. As you may have noticed, we also unset the comments and author — information we didn’t think was necessary on the screen.

Then, we’re simply defining the new columns and merging them with the array that was passed in the function. We created two new columns, one for awards and one for timeline. The array keys are completely arbitrary. They could be anything, but we’ll need to reference them again when it comes time to pull data into those columns… which is what we’re going to do next.

function column_data($column,$post_id) 
  switch($column) 
  case 'sm_awards' :
    echo get_post_meta($post_id,'awards',1);
    break;
  case 'sm_timeframe' :
    echo get_post_meta($post_id,'timeframe',1);
    break;

All right, we’ve fetched the meta data and conditionally outputted it based on what column we’re on. This is where we’re referencing the array key from above. So, as long as they’re both the same, we could use any arbitrary string we want. Note that we’re pulling the meta fields over using WordPress’ native get_post_meta function.

Removing a few built-in columns and adding some of our own enhances the UI.14
Removing some built-in columns and adding a few of our own enhances the UI and streamlines the information displayed. (View large version15)

Sorting

Ah, sorting. As you probably know, WordPress sorts Pages by menu order and then alphabetically by title and Posts by date published. Let’s get fancy and sort our new post type by the number of awards won. The use case here is easy to see. You want your most award-winning work at the top of the list at all times. If we use standard WordPress queries, the order we’re about to establish will be honored – universally across the website. We will need a function to join the wp_posts and wp_postmeta tables and another to revise how the data is sorted.

function join($wp_join) 
  global $wpdb;
  if(get_query_var('post_type') == 'sm_project') 
    $wp_join .= " LEFT JOIN (
      SELECT post_id, meta_value as awards
      FROM $wpdb->postmeta
      WHERE meta_key =  'awards' ) AS meta
      ON $wpdb->posts.ID = meta.post_id ";
  
  return ($wp_join);
}

This function does the joining for us. We won’t get into why that select statement works (that’s for another article altogether). Pay attention to the if statement here. We’re determining the post type and then conditionally running the join if it meets the sm_project condition. Absent this if statement, you would be doing this join regardless of type, which is not likely something you want.

There could also be a case where you just want to sort the administration screens and not the front end. Fortunately, we can use WordPress’ built-in conditional statements to do that job. Just wrap your statement with another conditional and check against is_admin.

function set_default_sort($orderby,&$query) 
  global $wpdb;
  if(get_query_var('post_type') == 'sm_project') 
    return "meta.awards DESC";
  
  return $orderby;
}

Once again, we’re verifying our post type and then returning an amended order statement. Now we’re telling WordPress to order by the value from the wp_postmeta table descending. So, we’ll get a list of our awards from the most won per project to the least won per project.

Putting It All Together

None of these functions will do anything until they’re called and attached to WordPress hooks. We’ll do this and keep it neat by creating an object around the post type and using the constructor to attach each function to the appropriate hook. For brevity, we’re not going to repeat the code already referenced above.

class sm_project 

  function __construct() 
    add_action('init',array($this,'create_post_type'));
    add_action('init',array($this,'create_taxonomies'));
    add_action('manage_sm_project_posts_columns',array($this,'columns'),10,2);
    add_action('manage_sm_project_posts_custom_column',array($this,'column_data'),11,2);
    add_filter('posts_join',array($this,'join'),10,1);
    add_filter('posts_orderby',array($this,'set_default_sort'),20,2);
  

  function create_post_type() 
    …
  

  function create_taxonomies() 
    …
  

  function columns($columns) 
    …
  

  function column_data($column,$post_id) 
    …
  

  function join($wp_join) 
    …
  

  function set_default_sort($orderby,&$query) 
    …
  
}

new sm_project();

Voila! Everything has come together quite nicely. In our constructor, we referenced the appropriate actions and filters. We’re performing these functions in a particular order — and this must be followed. The post type has to be created first, the taxonomies attached second, then any sort of custom sorting. Keep that in mind as you’re creating your data type.

Summing Up

Once you get the hang of it and you create a few of these, it’ll start to come naturally. I’ve got a bunch of these clips saved up in my toolbelt. I rarely create these from scratch anymore. Although this article is long and in-depth, it really is about a 10-minute process from concept to conclusion once you fully understand what’s going on.

References

(dp, al)

Footnotes

  1. 1 http://provide.smashingmagazine.com/full-source-code.txt
  2. 2 http://codex.wordpress.org/Function_Reference/register_post_type
  3. 3 http://codex.wordpress.org/Function_Reference/register_post_type
  4. 4 https://developer.wordpress.org/resource/dashicons/#admin-appearance
  5. 5 https://developer.wordpress.org/resource/dashicons/
  6. 6 http://www.smashingmagazine.com/wp-content/uploads/2015/04/wordpress-custom-post-type-menu-large-preview-opt.png
  7. 7 http://www.smashingmagazine.com/wp-content/uploads/2015/04/wordpress-custom-post-type-menu-large-preview-opt.png
  8. 8 http://www.advancedcustomfields.com/
  9. 9 http://www.advancedcustomfields.com/resources/
  10. 10 http://www.smashingmagazine.com/wp-content/uploads/2015/04/acf-ui-large-preview-opt.png
  11. 11 http://www.smashingmagazine.com/wp-content/uploads/2015/04/acf-ui-large-preview-opt.png
  12. 12 http://www.smashingmagazine.com/wp-content/uploads/2015/04/Custom-Post-Type-Administration-Screen-Before-large-preview-opt.png
  13. 13 http://www.smashingmagazine.com/wp-content/uploads/2015/04/Custom-Post-Type-Administration-Screen-Before-large-preview-opt.png
  14. 14 http://www.smashingmagazine.com/wp-content/uploads/2015/04/Custom-Post-Type-Administration-Screen-After-large-preview-opt.png
  15. 15 http://www.smashingmagazine.com/wp-content/uploads/2015/04/Custom-Post-Type-Administration-Screen-After-large-preview-opt.png
  16. 16 http://codex.wordpress.org/Function_Reference/register_post_type
  17. 17 http://codex.wordpress.org/Function_Reference/register_taxonomy
  18. 18 https://codex.wordpress.org/Metadata_API
  19. 19 http://codex.wordpress.org/Function_Reference/get_post_meta
  20. 20 http://www.advancedcustomfields.com/resources/get_fields/
  21. 21 http://codex.wordpress.org/Template_Hierarchy
  22. 22 http://codex.wordpress.org/Plugin_API/Action_Reference
  23. 23 http://codex.wordpress.org/Plugin_API/Filter_Reference

The post Extending WordPress With Custom Content Types appeared first on Smashing Magazine.

From:  

Extending WordPress With Custom Content Types

Thumbnail

WordPress Functions To Make Blogging Easier

The WordPress functions.php theme file provides an efficient way to modify WordPress theme by theme. This file contains mostly theme-related functions but can also be used to enhance or modify default WordPress behavior. This file is saved in the themes folder, and an unlimited number of modifications may be added.

In this article, we’ll share a few helpful functions that use WordPress default code to modify or enhance a blog’s behavior.

Link to article:

WordPress Functions To Make Blogging Easier

How To Create Perfect Emails For Your WordPress Website

Whatever type of website you operate, its success will probably hinge on your interaction with your audience. If executed well, one of the most effective tools can be a simple email.
WordPress users are in luck, since WordPress already has easy-to-use and extendable functions to give you a lot of power and flexibility in handling your website’s emails.
Further Reading on SmashingMag: Building An Advanced Notification System For WordPress Schedule Events Using WordPress Cron Improve Your Email Workflow With Modular Design Design and Build Email Newsletters’“) In order to create our own system, we will be doing four things.

Originally from – 

How To Create Perfect Emails For Your WordPress Website

WordPress Essentials: How To Create A WordPress Plugin

WordPress plugins are PHP scripts that alter your website. The changes could be anything from the simplest tweak in the header to a more drastic makeover (such as changing how log-ins work, triggering emails to be sent, and much more). This article has been checked and updated on July 5th, 2017.
Whereas themes modify the look of your website, plugins change how it functions. With plugins, you can create custom post types, add new tables to your database to track popular articles, automatically link your contents folder to a “CDN” server such as Amazon S3… you get the picture.

Jump to original:  

WordPress Essentials: How To Create A WordPress Plugin

Form Follows Function?

You’ve likely heard the phrase “form follows function,” but have you really thought about what it means or what it implies about Web design? On the surface, “form follows function” seems to make a lot of sense. The way something looks should be determined by its purpose. Is this really true? Does the phrase hold up upon deeper inspection? [Links checked February/23/2017]
In the context of designing a website, “form follows function” is often taken to mean that the designer should first gather the website’s requirements from the client and then determine the aesthetics of the website based on those functional requirements.

Jump to original:  

Form Follows Function?