Blog posts under the Employee Post category https://webdevstudios.com/category/employeepost/ WordPress Design and Development Agency Mon, 15 Apr 2024 16:03:23 +0000 en-US hourly 1 https://wordpress.org/?v=6.6.2 https://webdevstudios.com/wp-content/uploads/2022/07/cropped-wds-icon.white-on-dark-60x60.png Blog posts under the Employee Post category https://webdevstudios.com/category/employeepost/ 32 32 58379230 Helpful Books for Front-End Developers https://webdevstudios.com/2016/07/05/books-for-front-end-developers/ https://webdevstudios.com/2016/07/05/books-for-front-end-developers/#respond Tue, 05 Jul 2016 16:49:46 +0000 https://webdevstudios.com/?p=13271 “Please, no matter how we advance technologically, please don’t abandon the book. There is nothing in our material world more beautiful than the book.” –Patti Smith There are many great pathways to glean new information out there, whether it be on the web or in a class. Your mileage may vary depending on your learning Read More Helpful Books for Front-End Developers

The post Helpful Books for Front-End Developers appeared first on WebDevStudios.

]]>

“Please, no matter how we advance technologically, please don’t abandon the book. There is nothing in our material world more beautiful than the book.” –Patti Smith

There are many great pathways to glean new information out there, whether it be on the web or in a class. Your mileage may vary depending on your learning style or the topic at hand. With the tech industry, evolution often occurs at a faster rate than print media can keep up.

Still, sometimes a good ol’ print version of what you need comes along that earns its place on your bookshelf. Maybe it got there after you heard it mentioned for the tenth time. Maybe it is the book you always find yourself lending out to someone when they want to dip their feet in to a new niche (regardless of the evolution of name-your-favourite-framework-here.js). Maybe it is the book that someone leant to you at a crucial step of your learning. There are brilliant books for front-end developers out there–and they are definitely worth looking over.

A single book won’t be able to provide you with the breadth of information necessary, especially with today’s multi-dimensional coding ecosystems. Often, books cite wonderfully curated online resources so you are able to use their foundation as a jumping off point for knowledge expansion.

The WordPress-specific

WebDevStudios is abundant with people who know more than a few things about WordPress–with a stack of books to their credit, no less! One book from this list is Professional WordPress: Design and Development, which starts from a top-level view on WordPress then digs down into all the nitty-gritty. Sure, I’m biased, but this is a wonderful additional to any WordPress developer’s bookshelf.

The Process

For those who want to know more about the principles of intuitive navigation and information design, Don’t Make Me Think: A Common Sense Approach to Web Usability, by Steve Krug, is an excellent straight-forward resource for both beginners and the more-seasoned on how people connect with interfaces. This is a good resource for management, designers, and developers alike.Print book covers displayed in line

The Visual

Are you more visually inclined? Jon Duckett’s books on HTML/CSS and JavaScript/jQuery may be a good fit. They each include code examples and there is a general assumption of little-to-no previous programming experience that make these a good beginner’s starting point and reference.

The Varied

Smashing Magazine offers many great resources and one compilation is Smashing Book 5: Real-Life Responsive Web Design. While responsive design is a default these days, this gathers techniques and strategies on everything from workflow to SVGs to debugging. (There is a level of assumed knowledge and experience in many chapters.)

The Non-Code Code Books
  • Code: The Hidden Language of Computer Hardware and Software: Starting with Morse Code and working its way linearly through telegraphs, barcodes and I/O devices, this isn’t going to teach you how to better implement code but you will likely have a new respect for the history behind the work you’re doing (Published in 2000, so don’t expect discussion of technologies beyond)
  • Quiet: The Power of Introverts in a World That Can’t Stop Talking: Okay, this one has truly nothing to do specifically with code. This book explores the dominant values of business culture and how the leadership potential of introverts is often overlooked.

What are some other must-reads that you have on your bookshelf?

The post Helpful Books for Front-End Developers appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2016/07/05/books-for-front-end-developers/feed/ 0 13271
WP API: Adding Custom Endpoints https://webdevstudios.com/2016/05/24/wp-api-adding-custom-endpoints/ https://webdevstudios.com/2016/05/24/wp-api-adding-custom-endpoints/#comments Tue, 24 May 2016 16:21:37 +0000 https://webdevstudios.com/?p=13093 Here at WDS, we’re expanding our usage of the WP API. We have had a number of API posts in the past, and now we want to cover custom API endpoints more thoroughly. When working with custom content in WordPress, it is likely that you will come to a point where you want to retrieve that Read More WP API: Adding Custom Endpoints

The post WP API: Adding Custom Endpoints appeared first on WebDevStudios.

]]>
Here at WDS, we’re expanding our usage of the WP API. We have had a number of API posts in the past, and now we want to cover custom API endpoints more thoroughly.

When working with custom content in WordPress, it is likely that you will come to a point where you want to retrieve that custom data via the WordPress REST API. There are a number of methods that you can use to expose your data via the API. This tutorial aims to explain those methods and provide useful examples.


WP API, WordPress, WordPress tutorials, WordPress REST API, WordPress 101, WordPress how-to, learn WordPress

Post Meta

A common way to add custom data to WordPress is to utilize post meta (preferably using CMB2!). If you want to add this custom post meta to the default API output for a post, this is easy to do with register_rest_field(). For a good explanation of how to use register_rest_field(), as well as example usage, it will be helpful to refer to the REST API Documentation.

Adding Custom Post Types

One of the most common way to create custom data in WordPress is to create a Custom Post Type (CPT). When utilizing CPTs, it is very easy to ensure that your data is accessible via the API. When registering your CPT, you can add a few parameters to the register_post_type() function call:

$args = array(
    // other args...
    'show_in_rest'          => true,
    'rest_base'             => 'foo',
    'rest_controller_class' => 'WP_REST_Posts_Controller',
);

register_post_type( 'wds_foo', $args );

Each of these parameters is optional, and you will typically only ever need to use show_in_rest. The show_in_rest parameter allows the REST API to automatically detect your CPT and add it to the registered API Endpoints. Using only the show_in_rest parameter above will give you this for an endpoint: /wp-json/wp/v2/wds_foo.

Suppose you want the API endpoint to be different from the registered post type for some reason. By using the rest_base parameter, you can modify the endpoint to suit your needs. With this parameter, we now have an endpoint that looks like this: /wp-json/wp/v2/foo.

The final parameter, rest_controller_class, is definitely for more advanced usage. This allows you to change the name of the class that the REST API will use to process your CPT. By default, the API will use WP_REST_Posts_Controller for all CPTs. After a bit more explanation below, I’ll provide an example of why you might need this parameter.

Custom Endpoints

There will be times when you find that you need to register your own API endpoints to handle custom functionality. There are two ways of doing this: basic endpoints and the controller pattern. While the REST API Documentation is very good at covering this topic, I would like to add a bit more commentary and some examples.

But first, what exactly is an endpoint? An endpoint has two components: the route (URL), and the method. In this case, method refers to one of the HTTP Methods. Most people are familiar with the GET method, which is what you used to read this page, as well as the POST method, which is what you use to submit data to a website. In the REST API, the same route can do different things depending on what method is used. For example, the posts route /wp-json/wp/v2/posts can list all of the posts on the site using the GET method. But that same route can be used to create a new post when using the PUT or POST method.

When dealing with endpoints, you first specify the route. You can then specify one or more methods that can be used with that route. With that knowledge, let’s take a look at the two ways of setting up your own endpoints.

Basic Endpoints

Basic endpoints are most useful when you have small or uncomplicated pieces of functionality that you need to create. There are endless use cases that you could come up with, but here are a few ideas:

  • Creating a widget that dynamically updates via Ajax and the API
  • Utilizing a custom search engine to return found posts
  • Retrieving data from a custom database table

To create a basic endpoint, you will need to make use of the register_rest_route() function. This function should be called during the rest_api_init action. Here’s a simple example:

add_action( 'rest_api_init', 'myplugin_register_routes' );

/**
 * Register the /wp-json/myplugin/v1/foo route
 */
function myplugin_register_routes() {
    register_rest_route( 'myplugin/v1', 'foo', array(
        'methods'  => WP_REST_Server::READABLE,
        'callback' => 'myplugin_serve_route',
    ) );
}

/**
 * Generate results for the /wp-json/myplugin/v1/foo route.
 *
 * @param WP_REST_Request $request Full details about the request.
 *
 * @return WP_REST_Response|WP_Error The response for the request.
 */
function myplugin_serve_route( WP_REST_Request $request ) {
    // Do something with the $request

    // Return either a WP_REST_Response or WP_Error object
    return $response;
}

For more details, take a look at the documentation on WP-API.org.

Advanced Endpoints

For a more advanced custom API endpoints, you may find that you need multiple endpoints that work together to create your own functionality. The best way to tie all of these together is by utilizing the Controller Pattern for your endpoints. The Controller Pattern is essentially a template for an entire set of routes that are meant to work together. The various routes and supporting functions are all included in a single class that can handle the details. The WP_REST_Controller class that is provided as part of the REST API is meant to provide basic functionality. By extending this class, you can implement the exact features that you need without having to create your own logic for some of the more mundane details, such as the schema of parameters.

To see an example of an entire implementation of the WP_REST_Controller for a custom set of data, take a look at my API Link Manager code. Additionally, the official documentation is a great resource for examples and best practices.

One other use case of an advanced endpoint is to customize an existing controller to suit your needs. For example, suppose you want to add an API endpoint for your own Custom Post Type, but you don’t want those endpoints to be visible to anyone. One option is to extend the existing WP_REST_Posts_Controller class that is part of the API so that you can tweak it without needing to replace all of its functionality. Below is an example of overriding the register_routes() method in your own class. Specifically note the additional show_in_index keys (lines 42, 49, 61, 68, and 80) of the arrays:

<?php

/**
 * Extend the main WP_REST_Posts_Controller to a private endpoint controller.
 */
class JPry_REST_Private_Posts_Controller extends WP_REST_Posts_Controller {

    /**
     * The namespace.
     *
     * @var string
     */
    protected $namespace;

    /**
     * The post type for the current object.
     *
     * @var string
     */
    protected $post_type;

    /**
     * Rest base for the current object.
     *
     * @var string
     */
    protected $rest_base;

    /**
     * Register the routes for the objects of the controller.
     *
     * Nearly the same as WP_REST_Posts_Controller::register_routes(), but all of these
     * endpoints are hidden from the index.
     */
    public function register_routes() {
        register_rest_route( $this->namespace, '/' . $this->rest_base, array(
            array(
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => array( $this, 'get_items' ),
                'permission_callback' => array( $this, 'get_items_permissions_check' ),
                'args'                => $this->get_collection_params(),
                'show_in_index'       => false,
            ),
            array(
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => array( $this, 'create_item' ),
                'permission_callback' => array( $this, 'create_item_permissions_check' ),
                'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
                'show_in_index'       => false,
            ),
            'schema' => array( $this, 'get_public_item_schema' ),
        ) );
        register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
            array(
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => array( $this, 'get_item' ),
                'permission_callback' => array( $this, 'get_item_permissions_check' ),
                'args'                => array(
                    'context' => $this->get_context_param( array( 'default' => 'view' ) ),
                ),
                'show_in_index'       => false,
            ),
            array(
                'methods'             => WP_REST_Server::EDITABLE,
                'callback'            => array( $this, 'update_item' ),
                'permission_callback' => array( $this, 'update_item_permissions_check' ),
                'args'                => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
                'show_in_index'       => false,
            ),
            array(
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => array( $this, 'delete_item' ),
                'permission_callback' => array( $this, 'delete_item_permissions_check' ),
                'args'                => array(
                    'force' => array(
                        'default'     => false,
                        'description' => __( 'Whether to bypass trash and force deletion.' ),
                    ),
                ),
                'show_in_index'       => false,
            ),
            'schema' => array( $this, 'get_public_item_schema' ),
        ) );
    }
}

When you’re registering your CPT as I described above, you can now use the name of your custom controller class, and the API will automatically make use of that class to include your endpoints in the API.

These are just a few examples to get you thinking about how much you can do with the REST API, as well as how easy it is to customize the API according to your own needs.

Do you have any questions? Feel free to leave a comment below!

The post WP API: Adding Custom Endpoints appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2016/05/24/wp-api-adding-custom-endpoints/feed/ 11 13093
Is Clever Code OK? https://webdevstudios.com/2016/05/17/is-clever-code-ok/ https://webdevstudios.com/2016/05/17/is-clever-code-ok/#respond Tue, 17 May 2016 15:53:22 +0000 https://webdevstudios.com/?p=12982 “Clever code” is a term that you may have heard before, accompanied by sighs and groans from other developers. Often, people seem to think of clever code as annoying, and perhaps even harmful. In this article, I’m going to give a brief overview of what clever code is, why it’s often avoided, and how it can Read More Is Clever Code OK?

The post Is Clever Code OK? appeared first on WebDevStudios.

]]>
“Clever code” is a term that you may have heard before, accompanied by sighs and groans from other developers. Often, people seem to think of clever code as annoying, and perhaps even harmful. In this article, I’m going to give a brief overview of what clever code is, why it’s often avoided, and how it can be turned into a learning experience.

What is “clever code?”

For most, clever code is code that does not immediately “explain” itself. What that means is that the average developer might see it and have to spend more than a few seconds reading the context around it to understand what it does. Here’s an example in PHP:

$foo = 'bar';
// snip
$value = $foo ?: false;

Considering I’ve been writing PHP for nearly sixteen years, I was bewildered when I first saw this in a co-worker’s code a few weeks ago.

“Pretty nifty, huh?”

You bet! I want to use that in the future, and it is a prime example of clever code–the slang of a programming language.

Opposition to clever code

If you’ve used clever code in the workplace, or in other projects where collaboration is a part of what you do, then you’ve probably run across a decent number of people who don’t like it. Some examples of feedback:

  • “So, why did you do it like this?”
  • “What am I looking at?”
  • “Don’t do that again.”

All very reasonable responses. Clever code is often cited as bringing a disadvantage beyond reading comprehension; it’s also viewed as a source of bugs. Implementing code that is harder to read means it’s more likely that you or a developer working in the same file later are more likely to not read the proper flow of the program. Here’s an example of using PHP’s Bitwise And operator:

// Bitwise And.
$foo = false;
$foo &= false;
$foo &= true;
$foo &= false;

var_dump( $foo ); // int(0)

$foo = false;
$foo &= false;
$foo &= true;

var_dump( $foo ); // int(0)

In the first example, you might expect the outcome of false, or “int(0)”. But the second example is a bit confusing–didn’t that end with setting $foo to true? The Bitwise And operator instead looks at both the left-hand value of “$foo” and the right-hand value when making its assignment; thus, if $foo is false even once, the equation will always look like “$foo = ( 0 * 1 = 0 = false ).” This can be extremely useful, but also incredibly confusing.

Another example of Bitwise confusion comes from the Javascript Bitwise NOT operator:

var a = ["f", "o", "o", "b", "a", "r" ];

if ( a.indexOf( "g" ) > -1 ) {
    console.log( "Typical style" );
}

if ( !!~a.indexOf( "g" ) ) {
    console.log( "Clever style" );
}

Again, we can see that the “tilde” operator, coupled with a double negative “!!”, creates clean code that won’t make sense to the average programmer.

How to be smart and clever

This all leads to what I’d like programmers to start doing when considering clever code: create a learning environment for other developers. I’ve seen clever solutions criticized on StackOverflow, and a particular question about it on the Programmer’s StackExchange asking for advice on how to avoid writing clever code in the first place. 

This, to me, is a great example of how programmers see clever code: it’s a party trick; it’s dangerous; it is to be avoided by “serious” programmers.

On the other hand, I think we can start to turn clever code into a learning experience. Once you recognize clever code, you can start to document it when you use it so others on the project know what you’re doing:

function check_user( $can_go_on ) {
    /**
     * NB, Clever: Using PHP's bitwise And operator.
     * See: http://php.net/manual/en/language.operators.bitwise.php
     */
    if ( ! current_user_can( 'manage_network' ) ) {
        $can_go_on &= false;
    }

    return $can_go_on;
}

function check_screen( $can_go_on ) {
    $screen = get_current_screen();

    if ( ! $screen || 'post' !== $screen->base ) {
        $can_go_on &= false;
    }

    return $can_go_on;
}

add_filter( 'can_we_continue', 'check_user' );
add_filter( 'can_we_continue', 'check_screen' );

$can_go_on = apply_filters( "can_we_continue", true );

In the above example, the ‘check_user’ function is documented to give a clear and distinct “Hey! I’m doing something weird here,” as opposed to the second method ‘check_screen’ which quietly uses the Bitwise And without any discussion. Most any programmer would be forgiven for missing it or thinking it’s a typo, and a scrutinizing lead would almost certainly see it and think “Great–now I have to change this and test everything this filter touches.”

A real world example looks like this:

/**
 * CLEVER CODE ALERT. This shorthand ternary accepts the tested value as the value returned if
 * true, otherwise the else value. NB this does not work in reverse (i.e. $a = $b ? 'value' :; ).
 */
$blog_id = $blog_id ?: get_current_blog_id();

Here’s that nifty shorthand ternary again! This saves some characters and looks pretty neat, but there’s a pretty hefty comment above it to explain what’s going on. The comment alone negates the time saved in not writing out the whole ternary, but for me the point of code like this, and the associated documentation, is to teach and inform others.

As programmers working in an increasingly collaborative world, we should be making strides in documentation–not only to guide other developers through the big ins and outs, but also to illuminate the many tricks and secrets that the language holds.

Happy coding!

The post Is Clever Code OK? appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2016/05/17/is-clever-code-ok/feed/ 0 12982
Building Content Teams with WP User Groups and Custom User Roles https://webdevstudios.com/2016/03/22/building-content-teams-wp-user-groups/ https://webdevstudios.com/2016/03/22/building-content-teams-wp-user-groups/#comments Tue, 22 Mar 2016 16:02:29 +0000 https://webdevstudios.com/?p=12823 The WordPress user roles and capabilities system is built to be pretty flexible. There’s a hierarchy of responsibilities in place that can be used to inform a content workflow from lower on the totem pole to higher. But sometimes those user roles aren’t quite sufficient to perform the particular kinds of tasks (but not other Read More Building Content Teams with WP User Groups and Custom User Roles

The post Building Content Teams with WP User Groups and Custom User Roles appeared first on WebDevStudios.

]]>
The WordPress user roles and capabilities system is built to be pretty flexible. There’s a hierarchy of responsibilities in place that can be used to inform a content workflow from lower on the totem pole to higher. But sometimes those user roles aren’t quite sufficient to perform the particular kinds of tasks (but not other tasks) that you want your users to perform. Or perhaps you need to create subdivisions within your roles to create “content teams” of users–that’s not really supported by WordPress out of the box. I recently built a fairly complex content team system based on John James Jacoby‘s excellent WP User Groups plugin and I’m going to show you how it works–and how to extend it–in this post.

This is going to be extremely technical, and you probably won’t have need for this specific functionality, but hopefully it will give you an idea of some of the cool things you can do with the tools at hand.

User Roles at a Glance

robot-soccer-goal

Have you ever really thought about the roles and capabilities system in WordPress? Most of the time, it’s invisible–just a thing that you know is there but you don’t really ever deal with. If you work with WordPress on a daily basis, you probably know that a Subscriber doesn’t really have any privileges; they can just log into the site and update their profile. Administrators have full keys to the castle, those are the users that can do everything. Somewhere in the middle there’s Editors, who are really similar to Administrators, except they can’t edit settings or install plugins or themes. And then there’s Authors and Contributors and…well, they do something but outside of creating content, we’re not really sure what the difference between the two is…

I think that’s probably how most people see the user roles system. Those with a bit more insight into technical systems and access rights in general might assume, since this is a hierarchical system, that these roles are based on an access level system; that is, at the lowest level you can do these specific tasks, and as you go up the ladder, additional tasks are added that you have access to. In fact, WordPress used to use an access level system, but doesn’t anymore. The problem with access level systems is it’s very hard to make exceptions for specific tasks. For instance, what if you want to grant a user at level seven some capabilities that are only accessible at level nine but you don’t want to promote the user? You can’t in an access level-based system. The other problem with this system is that it doesn’t really account for custom roles–what if you wanted to create a totally different role with different rights and responsibilities? Where do they fit in the user level system? They don’t.

If WordPress doesn’t use an access level-based system, maybe they use some form of access control list (ACL) system. If you’ve ever managed an IRC channel or a BBS server (I realize I’m dating myself here…), this type of access will make sense to you. In an ACL system, you can give users access rights to specific tasks higgledy-piggledy pretty much at your whim. Their specific role doesn’t matter so much as the list of capabilities that they have. In WordPress, this would look like this: I want Bob the Editor to be able to update plugins for me, so I go into his account and I grant him the update_plugins capability. Great, now Bob can update my plugins for me. Bob’s not an administrator, but he has a specific administrative capability to help me do my job as the administrator.

This isn’t how WordPress works either, not usually, although you could engineer WordPress to work this way and there are plugins that can help with this. Rather, WordPress uses a Role Based Access Control system. Role Based Access Control (RBAC) extends the idea of the original system that handled access control in WordPress (that of user levels), but rather than checking if a user is a particular user level, WordPress roles have a number of capabilities assigned at each level. The number and complexity of the capabilities ascends from the lowest (read only for Subscribers) to the highest (dozens including manage_options for Administrators). In a way, it takes the best of both worlds: You can still have a hierarchical structure, but you also have the ability to grant specific capabilities to specific users.

When working with user roles and capabilities, however, it’s good to keep this foundation of how WordPress handles them natively in mind. As I said, I could just grant Bob, specifically, the capabilities that I want his user account to have. But on a large enough scale, that kind of system gets incredibly unwieldy–you never truly know what users have what capabilities and responsibilities without cross-referencing with their specific list of capabilities. If you have 100 people in the admin, and each is responsible for a different part of the site, and each has a completely unique set of capabilities, you can see how this can get a bit out of hand.

When I’m working with custom user roles and custom capabilities, I always like to base them off the core roles system within WordPress. That is, I will use hierarchical capabilities, where necessary, and make sure to grant those capabilities to other, core WordPress user roles, so my custom user roles aren’t out on an island, the only users in the system able to perform a specific function.

Creating Groups of Users with WP User Groups

robot-soccer-fall

Let’s get down to the nitty-gritty of building a system to handle different “content teams.”

Here’s the elevator pitch: I need a solution to allow different teams of users to create content for different parts of the site. They cannot create content that is outside of their own team. They cannot edit content that is outside of their own team. They can view (on the front-end of the site) content submitted by anyone, but they are only responsible for those things that align with the teams they are members of. Within these teams, there are two levels of users, content creators and content editors. The creators can only submit the content. They can’t actually publish the content. The content editors can actually approve and publish the content. Above these two user types there are global content creators and editors who can create and edit any kind of content–these can just be core WordPress users. Additionally, when content editors approve or “publish” their team’s content, it only appears on their team’s section of the website by default; it doesn’t exist globally until it has been reviewed by a global content editor or administrator.

Sounds like fun, right? Let’s start with JJJ’s WP User Groups plugin.

WP User Groups is part of the Stuttter group of plugins that John has been working on for the past year or so, which are all very small plugins that perform very simple, singular tasks. In this case, the ability to group users together. The way it does this is by using custom taxonomies and taxonomy terms to associate to users.

    /**
     * Registers the taxonomies to be used by WP User Groups as User Taxonomies.
     *
     * In order to create teams that can work with certain types of content,
     * we need to be able to group users into teams. Uses WP User Groups.
     *
     * @link https://github.com/stuttter/wp-user-groups
     */
    function wds_register_user_taxonomy() {
        // Make sure that WP_User_Taxonomy class exists
        if ( ! class_exists( 'WP_User_Taxonomy' ) ) {
            return;
        }

        // Create the new user taxonomy.
        new WP_User_Taxonomy( 'content_team', 'users/content-team', array(
            'singular' => __( 'Team',  'wds' ),
            'plural'   => __( 'Teams', 'wds' ),
        ) );

    }
        add_action( 'init', 'wds_register_user_taxonomy' );

    /**
     * Register a new taxonomy for content teams to be used as a User Taxonomy.
     * We're using John Billion's Extended Taxonomies library to simplify the taxonomy
     * creation.
     *
     * @link https://github.com/johnbillion/extended-taxos
     */
    function wds_register_taxonomies() {
        /*
         * The Content Team taxonomy.
         *
         * This is a user taxonomy that is used to create "teams" of users based on 
         * the area(s) they specialize in. Members of a Content Team can only see 
         * documents within their own team.
         */
        register_extended_taxonomy( 'content_team', array(), array(), array(
            'singular' => __( 'Team', 'wds' ),
            'plural'   => __( 'Teams', 'wds' ),
            'slug'     => 'content-team',
        ) );
    }
        add_action( 'init', 'wds_register_taxonomies', 90 );

Creating a user taxonomy is really more like associating a taxonomy to act as a user taxonomy. The distinction is important–the taxonomy needs to exist first, and it needs to not be a taxonomy that you’re using for content (technically you can associate content to a user taxonomy, but you aren’t able to query content by a user taxonomy, only users, so they’re best left separate). In the snippet above, I’m creating a normal taxonomy and using the WP_User_Taxonomy class to make that taxonomy a user taxonomy.

By default, WP User Groups comes with two pre-existing User Taxonomies: Types and Groups. They’re there so the plugin actually can be shown to be doing something out of the box and also there as sort of proof-of-concepts to give you an idea of how User Taxonomies are created. It’s really easy to remove these default user taxonomies and, if you aren’t going to be using them, that’s probably a thing you should do. All you need to do to remove them is add a remove_action in your plugin.

/* Remove default User Taxonomies */
remove_action( 'init', 'wp_register_default_user_group_taxonomy' );
remove_action( 'init', 'wp_register_default_user_type_taxonomy' );

That sets up my initial groups that I’ll use to associate with content teams. Now let’s create some custom user roles for those users on those teams.

Creating Custom Hierarchical User Roles

robot-soccer-obama

For my content teams plugin, I needed two basic user levels: A user who could submit content for review, and a user who could review that content and approve it. These more or less correspond to the WordPress user roles of contributor and editor, so we can reference the list of capabilities granted to those users and base our capabilities for our custom user roles off that.

This gives us a list of capabilities that looks like this:

        // Content Creators are set up like Contributors.
        add_role( 'content_creator', __( 'Content Creator', 'wds' ), array(
            'read'                            => true,
            'delete_posts'                    => true,
            'edit_posts'                      => true,
            'upload_files'                    => true, // Let them upload files, they'll need it.
            'edit_pages'                      => true, // Able to edit WordPress pages.
        ) );

        // Content Approvers are set up like Editors with fewer caps.
        add_role( 'content_approver', __( 'Content Approver', 'wds' ), array(
            'delete_posts'                    => true,
            'delete_published_posts'          => true,
            'edit_others_posts'               => true,
            'edit_posts'                      => true,
            'edit_published_posts'            => true,
            'publish_posts'                   => true,
            'read'                            => true,
            'unfiltered_html'                 => true,
            'upload_files'                    => true,
        ) );

This should be run on plugin activation or run as some other kind of single-use function. add_role creates the role and sets up the basic capabilities of how that role will behave. We can (and will) adjust those capabilities later. You can add any capabilities from the list of capabilities within WordPress that you like here, or introduce new, custom capabilities here that aren’t used in WordPress. As you can see, there’s two areas where my Content Creator role veers away from what standard contributors can do, and that’s by allowing them to upload files and edit pages.

But I also want to add some custom capabilities, not only to my new user roles, but also my existing user roles. These capabilities will define who can edit content that is team-specific and who can edit content that is global. So I’ll create a couple new capabilities to handle those rights that I can then build methods and functions around later to check who has what caps.

    /**
     * Take a role and return the new capabilities that should be added to that role.
     * @param  string $role Any role used by the Content Teams plugin.
     * @return array        Array of new capabilities added to that role.
     */
    public function role_to_caps_map( $role = '' ) {
        // Bail if no role was passed.
        if ( '' == $role ) {
            return false;
        }

        // Check if the role passed is one we're using.
        if ( ! $this->using_role( $role ) ) {
            return false;
        }

        // Map the new capabilities to user roles.
        $caps_map = array(
            'administrator' => array(
                'edit_team_content',   // Able to view content from teams.
                'edit_global_content', // Able to view all content, regardless of team.
            ),
            'editor' => array(
                'edit_team_content',   
                'edit_global_content', 
            ),
            'contributor' => array(
                'edit_team_content',   
                'edit_global_content', 
            ),
            'site_approver' => array(
                'edit_team_content',   
                'team_publish_posts',  
            ),
            'site_creator' => array(
                'edit_team_content',   
            ),
        );

        // Return the new capabilities for the given role.
        return $caps_map[ $role ];
    }

This function doesn’t do much by itself other than return an array of capabilities for a given user role. However, I’m stopping here to show the two new capabilities I’m adding: edit_team_content and edit_global_content. edit_team_content is granted to everyone (at least everyone I care about, namely my custom roles, as well as WordPress contributors, editors and administrators) — anyone can edit content that belongs to a specific team. edit_global_content is only granted to the default WordPress user roles; we’re using those existing roles to be the default, master level administrative roles able to not only create content specific to a team but, in the case of a WordPress Editor or Administrator, also edit and publish that content. We haven’t gotten to associating content to specific teams yet, but that’s coming. Let’s combine this map with something that actually adds or removes these capabilities.

    /**
     * Adds or removes the new capabilities required for Content Teams.
     *
     * @param  string $action The desired action. Either 'add' or 'remove'.
     */
    public function adjust_caps( $action = '' ) {
        if ( ! in_array( $action, array( 'add', 'remove' ) ) ) {
            return;
        }

        $adjust_cap = $action . '_cap';

        // Loop through all the content team roles.
        foreach ( $this->content_team_roles() as $this_role ) {
            // Check if the role exists and save the role to a variable.
            if ( $role = get_role( $this_role ) ) {
                // Loop through each cap for that role.
                foreach ( $this->role_to_caps_map( $this_role ) as $cap ) {
                    // Add the cap to the role.
                    $role->$adjust_cap( $cap );
                } // Ends caps loop.
            } // Ends role check.
        } // Ends role loop.
    }

    /**
     * Triggered on activation, adds the new capabilities for Content Teams.
     */
    public function add_caps() {
        $this->adjust_caps( 'add' );
    }

    /**
     * Triggered on deactivation, removes the new capabilities for Content Teams.
     */
    public function remove_caps() {
        $this->adjust_caps( 'remove' );
    }

What’s going on here? Well, first we’re making sure that the only action passed to adjust_caps is either “add” or “remove”, then we’re mapping that action to a variable function. Variable functions are fun and can help keep your code DRY (Don’t Repeat Yourself). In this case, we’re using $adjust_cap as a variable function to stand in for either add_cap or remove_cap depending on which one was passed to our adjust_caps function. Then we run a loop through all of the roles we care about and add or remove the relevant capabilities for that role. (The nested foreach loop could probably be simplified, but you get the idea–for each role that we care about, make sure the role exists, then loop through and add all the capabilities that role should have.)

At the end, there’s some helper methods used for adding or removing capabilities. It’s important to remember that just because you wrote code that adds a capability to a user role your user role might not have that capability unless there’s another function or method that’s triggered the adding or removing of that capability. It sounds obvious but you’d be surprised how easy it is to forget and assume that the capability is already there–especially when you’re working with a local and a separate test, lab, or production environment. It’s not–at least, it’s not unless you’ve deactivated and reactivated your plugin (assuming you’ve got those capabilities added on activation). So these add/remove caps functions can be triggered on activation or whenever we might need them (like if we needed to reset the capabilities manually).

That pretty much does it for our custom user roles. There will be one more capability we’ll add later, but for now, let’s move on to associating content to teams.

Creating Content Teams

The idea behind content teams is that, let’s say you’ve got a tech blog with a lot of writers. And on this tech blog you’ve got pretty distinct categories, like say Apple, Microsoft, Google, Mobile, Social Media, Gadgets, etc. Maybe you’ve got some crossover with some of your writers (for instance if a writer contributed content to both the Mobile and Apple teams), but, for the most part, let’s assume these teams are pretty siloed. What I want to do is give my members of these teams custom views of the WordPress admin that will only show them or allow them to edit content that is within their team (or one of their teams if they are on multiple teams).

The way I did this was by using a taxonomy for the content itself, and that taxonomy was mirrored as a User Taxonomy. So whenever a new “category” taxonomy term was created, a new content team was created, too. For those users who are content creators or approvers (e.g. the ones on the teams), their team’s taxonomy term would automagically be associated with the content they are creating. Then we can filter the post list in the admin by what the logged in user should be able to see based on his or her team.

In my case, though, I needed to go one step farther. For each content team there should be a sort of landing page for that team. This is where, by default, all content that was written for that team should be published first. Content can, additionally, be displayed sitewide but not all content will necessarily be everywhere. It will, however, all be on the team’s landing page.

Custom post types have better WordPress hooks for editing and deleting than taxonomies, so using a post type here actually helps us out a bit. Rather than hooking into when a term is edited or deleted, we can hook into when a post type is saved or trashed. For the initial term creation though, we’ll use the create_{$taxonomy} hook to create a new term in our User Taxonomy that’s a copy of the term we just created in our content taxonomy.

    /**
     * Create a content team term when a content area term is created.
     *
     * @param  int $term_id The term ID.
     * @param  int $tt_id   The term taxonomy ID.
     */
    function wds_create_content_team( $term_id, $tt_id ) {
        $term = get_term_by( 'id', $term_id, 'content_area' );

        if ( ! $term ) {
            return;
        }

        wp_insert_term( $term->name, 'content_team', array(
            'description' => $term->description,
            'slug'        => $term->slug,
        ) );
    }

    add_action( 'create_content_area', 'wds_create_content_team', 10, 2 );

In the code above, whenever a new content_area term is created, we create a new content_team term. You should remember that content_team is the User Taxonomy we’re using for our teams. We’ll assume when our post type for that team is created, that it will create a new taxonomy content_area taxonomy term.

    /**
     * Runs on the save_post hook to handle adding terms for Content Areas.
     *
     * @param int    $post_id The ID of the Content Area post
     * @param object $post    The post object.
     */
    function wds_save_taxes( $post_id, $post ) {
        // If this isn't the Content Area CPT, then bail.
        if ( 'content_area_cpt' !== $post->post_type ) {
            return;
        }


        // Add term for the Content Area.
        if ( 'publish' == $post->post_status ) {
            $this->add_content_area_term( $post->ID, $post->post_title );
        }
    }
    add_action( 'save_post', 'wds_save_taxes', 10, 2 );


    /**
     * Inserts or updates a Content Area term.
     *
     * @param string $slug   The post slug.
     * @param string $title  The post title.
     */
    function wds_add_content_area_term( $slug, $title ) {
        $term = get_term_by( 'slug', $slug, 'content_area', OBJECT );

        if ( ! $term ) {
            wp_insert_term(
                esc_html( $title ),
                'content_area',
                array( 'slug'   => $slug )
            );
        } else {
            wp_update_term(
                $term->term_id,
                'content_area',
                array(
                    'name'   => esc_html( $title ),
                    'slug'   => esc_attr( $slug ),
                )
            );
        }
    }

Now, when a new “content area” post type is created, it also creates a new content_area taxonomy term which, in turn, triggers the creation of a content_team term. Now let’s deal with altering the views for our content creators and approvers.

pre_get_posts is a handy WordPress hook that alters the main WordPress query object before it’s rendered on the page. It’s generally the last place where the query can be altered before you see it (the absolute last place is through query_posts on the actual template, but this is discouraged because query_posts is altering the actual $wp_query global which can be dangerous). pre_get_posts has the added bonus of being a thing that can run in the WordPress admin or on the front-end of a site. This helps us out because this means we can filter the posts for our teams based on their user taxonomy before they are even displayed on the Edit Posts list.

    /**
     * Handles the magic filtering of Program Areas by Content Team.
     *
     * @param  class $query WP_Query that we're modifying.
     */
    function wds_filter_content_areas( $query ) {
        if ( ! is_admin() ) {
            return;
        }

        // Get the post type.
        $current_post_type = $query->get( 'post_type' );

        // Make sure we're on the right post type edit page.
        if ( in_array( $current_post_type, wds_content_area_post_types() ) ) {

            if ( wds_is_site_content_editor() ) {

                $teams = ( wp_get_terms_for_user( get_current_user_id(), 'content_team' ) ) ? wp_get_terms_for_user( get_current_user_id(), 'content_team' ) : array();
                $areas = array();

                foreach ( $teams as $team ) {
                    $areas[] = wds_get_term_id_by_team( $team, 'content_team' );
                    $content_area_cpt_ids[] = absint( $team->slug );
                }

                $content_area_cpt_ids = ! empty( $content_area_cpt_ids ) ? $content_area_cpt_ids : array( 0 );

                if ( 'clp_program_area_cpt' == $query->get( 'post_type' ) ) :

                    $query->set( 'post__in', $program_area_cpt_ids );

                else :

                    $query->set( 'tax_query', array(
                        array(
                            'taxonomy' => 'content_area',
                            'field'    => 'term_id',
                            'terms'    => $areas,
                            'operator' => 'IN',
                        ),
                    ) );

                endif;

            }
        }
    }
    add_action( 'pre_get_posts', 'wds_filter_content_areas', 10 );

    /**
     * Return a term ID for a content term based on that term's content team term.
     * @param  object $term The original term object.
     * @return int          The taxonomy term id.
     */
    function wds_get_term_id_by_team( $term ) {
        if ( is_array( $term ) && isset( $term['invalid_taxonomy'] ) || empty( $term ) ) {
            return;
        }

        $new_term = get_term_by( 'slug', $term->slug, 'content_area' );
        return $new_term->term_id;
    }

    /**
     * Break down the checks to user capabilities. If they can edit global content, show them things that they need to do their job.
     *
     * @return bool If a user is a member of a specific team, hide things.
     */
    function wds_is_site_content_editor() {

        // If the current user can edit global content, we don't need to filter.
        if ( current_user_can( 'edit_global_content' ) ) {
            return false;
        }

        // If the current user can only edit team content, we do need to filter.
        if ( current_user_can( 'edit_team_content' ) ) {
            return true;
        }

        return false;
    }

There’s a lot going on here, and there’s a number of helper functions that I’ve included so you can see more of what’s going on. I’m also showing line numbers in this snippet so I can refer to those specifically.  The pre_get_posts filter callback function starts on line 6 above.  When working with pre_get_posts we get a query object that we can manipulate and get information from, like on line 12 when we’re getting the post type. We then compare that against an array of post types (returned by wds_content_area_post_types()) to make sure we’re looking at one of the post types that’s going to be filtered for content creators and approvers. On line 17 we run a check and that function starts below on line 70–we’re making sure that the current user is a content creator–so, specifically, we’re checking against the edit_global_content capability, the higher level capability indicating that they are one of the default WordPress user roles.

If they don’t have that capability, we make sure that they have the edit_team_content capability, e.g. they are a content creator. If they lack that, too, we just return false and don’t filter anything. This will only allow users who are assigned to a specific team through the check. wp_get_terms_for_user is a function that’s added by WP User Roles. It returns an array of term objects for all of the User Taxonomy terms that a user is tagged with. We’re going to loop through these teams and save the term IDs to an array that we’ll pass to pre_get_posts later.

We’re also saving the slug to a variable array storing all the content team CPT post IDs. Huh? Saving a slug as an ID? Yes. We found in doing this process that using slugs to connect posts to taxonomies and taxonomies to taxonomies was not always reliable. Since none of the taxonomies we’re using are going to be on an archive page in our setup (what would be an archive page is actually the single post page for the content area CPT), we don’t care if the taxonomy slugs aren’t pretty. Saving the CPT post ID as the taxonomy term slugs ensures that we have a way to directly reference and relate not one but both of our taxonomies back to the CPT they relate to.

At this point, things get pretty simple. I’ve got an array of CPT IDs and if I’m looking at the content area CPTs right now, we’re going to filter down the list of posts that display to only those that relate to teams that I’m on. This ensures that members of that team could edit the landing page for that team (at least if they have edit_others_posts and/or edit_published_posts).

I’ve also got an array of term IDs that relate not to the content teams I’m on (although I got that, too) but to the content_area terms that those are connected to (the content taxonomy, not the user taxonomy). If I’m on any other type of edit screen, and we’re using the content_area taxonomy on that post type, my view will be filtered to only show me things belonging to the team(s) that I am on.

Now let’s see about saving our team’s term automagically to the post.

    /**
     * Adds Content Areas automagically to the post when it's saved.
     *
     * If a user creates any other post type, we want to find out what content
     * area they are in and add that content area to the post. This automatically
     * adds a the content area the user is associated with to the post.
     *
     * @param  int $post_id The post ID you're editing.
     */
    function wds_add_user_team_terms_to_post( $post_id ) {
        if ( wp_is_post_revision( $post_id ) )
            return;

        // Set Post taxonomy terms to sync with the users taxonomy terms.

        $user_terms = wp_get_terms_for_user( get_current_user_id(), 'clp_content_team' );

        // Get the normal taxonomy terms that are the same as the user taxonomy terms.
        foreach ( $user_terms as $term ) {
            $post_terms[] = $term->slug; // Add the slug to the array, when we add the normal taxon term below it will use the same slug.
        }

        // Actually associate the matched terms with the post.
        if ( isset( $post_terms ) ) {
            $__terms = wp_set_object_terms( $post_id, $post_terms, 'content_area' );
        }
    }
    add_action( 'save_post', array( $this, 'add_user_team_terms_to_post' ), 99 ); // User Content Team > Post Content Area.

This part is relatively straightforward. Once again we need to get the user taxonomy terms for the current user; this will give us an array of the teams the current user is on. Then we loop through those and start to populate a variable array of term slugs for each of those terms. The slugs will be the same for both taxonomies so the next step is to simply add those back in using wp_set_object_terms with a different taxonomy. One thing to keep in mind when using wp_set_object_terms–if an empty value is passed into it, and the final, $append parameter is not set to true (it defaults to false and is not used here), it will clear out any terms that were previously set on the post object. I spent two days of troubleshooting on this particular problem only to realize that the terms I was setting in one save_post hook were being overwritten with an empty value in a later save_post hook.

Let’s recap: I have users that I want to break down into teams. These teams are focussed around certain types of content. Each team has a landing page where all their posts for that subject or “content area” is published. If a user is on a team, everything they write should automatically be tagged with their team’s term. When they are in the WordPress admin, they will only see other content that’s tagged similarly with terms that correspond with their teams. There are global editors, too, and those users can view or edit any kind of content, regardless of what team it’s on.

There’s one final piece to this jigsaw puzzle and that’s publishing content to a specific page vs. publishing content globally. For this, we need to create custom post statuses.

Creating Custom Post Statuses

robot-soccer-falling

If you ask any developer how to create a custom post status, I guarantee you they will tell you “just use Edit Flow.” For a long, long time that was the only valid answer, it was a project maintained by some Automatticians and it did the thing that everybody needed it to do, at least with regard to custom statuses, and it did a pretty good job of it, too. However, it’s a project that’s been left along the wayside for a while and has not been maintained. As a result, when I went to actually use the custom post statuses module of Edit Flow, it just didn’t work. Not at all. It actually created a bunch of errors that I wasn’t eager to try to debug. Instead, I decided to try to actually create my own post statuses. Custom post statuses aren’t currently fully supported by WordPress, so some of this is a bit hacky and some of this may change later as support for custom post statuses is fleshed out more in Core.

For our purposes, we want to add a single custom post status, Team Published, which will be used to display content on the team-specific pages. This makes it easy to prevent content in this specific post status is not globally searchable and won’t come up in archive pages or on other parts of the site (e.g. parts of the site that are using normal WordPress queries to display published posts) which is what I want. In this case, all I need to do is change the query that handles the posts that display on my custom post type single page for content area CPTs to display all posts that are either published or team published in that particular content area–that’s already going to be a custom template, so we don’t need to go backward and try to filter out all the published stuff, we just choose which pages to explicitly include posts saved in our custom post status.

Adding a custom post status is very similar to adding a custom taxonomy or post type:

    /**
     * Add custom post statuses.
     * Currently there's just one custom post status -- Team Published.
     *
     * @link  https://codex.wordpress.org/Function_Reference/register_post_status
     * @since 0.2.0
     */
    function wds_add_post_statuses() {
        register_post_status( 'team-publish', array(
            'label'                     => __( 'Team Published', 'wds' ),
            'public'                    => true,
            'exclude_from_search'       => true,
            'show_in_admin_all_list'    => true,
            'show_in_admin_status_list' => true,
            'label_count'               => _n_noop( __( 'Team Published <span class="count">(%s)</span>', 'wds' ), __( 'Team Published <span class="count">(%s)</span>', 'clp' ) ),
        ) );
    }
    add_action( 'init', 'wds_add_post_statuses' );

We call register_post_status, we give our status a name, define whether it’s public and searchable and where we can find it and customize the labels that appear above the edit list in the admin if there are posts saved in our custom post status.

As I said, custom post statuses aren’t fully supported and, as such, this isn’t the end of our job. One thing we still need to do is actually display our custom post status. It can be created and saved but you can’t actually use it until you do something and since it’s not supported by WordPress, that means hacking the DOM after the edit post page has rendered using jQuery.

    /**
     * Alter the post status dropdown and publish button.
     *
     * @link   http://jamescollings.co.uk/blog/wordpress-create-custom-post-status/
     * @since  0.2.0
     * @return null
     */
    function wds_append_post_status_list() {
        global $post;

        if ( ! $post ) {
            return; // We need a post.
        }

        // Set up some variables.
        $published = __( 'Published' );
        $option    = __( 'Team Published', 'wds' );
        $complete  = ( 'team-publish' == $post->post_status ) ? ' selected="selected"' : '';
        $label     = ( 'team-publish' == $post->post_status ) ? '<span id=\"post-status-display\">&nbsp;' . esc_attr( $option ) . '</span>' : '';

        // Use javascript to append the Team Published option to the list of post statuses.
        echo '
        <script>
        jQuery(document).ready(function($){
            $("select#post_status").append("<option value=\"team-publish\" ' . esc_attr( $complete ) . '>' . esc_attr( $option ) . '</option>");
               $(".misc-pub-section label").append("' . $label . '");
        });
        </script>
        ';

        // If the current user can Team Publish posts, change the Publish button to say "Team Publish" instead.
        if ( current_user_can( 'team_publish_posts' ) ) {
            echo '
            <script>
            jQuery(document).ready(function($){
                var publishInput = $("input#publish");
                if ( "Publish" == publishInput.val() ) {
                    publishInput.val("' . esc_attr__( 'Team Publish', 'wds' ) . '");
                }
                $("select#post_status").change(function(){
                    $("a.save-post-status").click(function(){
                        publishInput.val("' . esc_attr__( 'Team Publish', 'wds' ) . '");
                    })
                });
            });
            </script>
            ';
        }

        // If the current user can actually publish, add a Published status to the dropdown of post statuses, too.
        if ( current_user_can( 'publish_team_posts' ) ) {

            // Only add Published to the dropdown if the post isn't already published. Prevents a duplicate Published from displaying in the list.
            if ( $post->post_status !== 'publish' ) {
                echo '
                <script>
                jQuery(document).ready(function($){
                    $("select#post_status").append("<option value=\"publish\">' . esc_attr( $published ) . '</option>");
                });
                </script>
                ';
            }
        }
    }
    add_filter( 'admin_footer', 'wds_append_post_status_list', 999 );

There’s a couple things this JavaScript is doing. First, we’re appending Team Publish to the statuses dropdown list. That’s the easy part. Next, we have a couple new capabilities we’re checking, which means they need to be added up where we map our custom capabilities to user roles. One is team_publish_posts — this capability is granted to users who can publish posts as “Team Published.” This applies to only content approver users–users who are on a team and get to “approve” the posts of other users on their team. The most those approvers can do is “team publish” a post. If they have that capability, their “Publish” button becomes a “Team Publish” button.

The second new capability is publish_team_posts. This sounds like I’m just rearranging words, I know, but the idea here is that if we have a post saved in “Team Published” status, it is a “team post,” and I want to publish it, e.g. literally turn it into a post saved in “published” status. This would be granted to WordPress editors and Administrators only. If I’m one of those users, I will also have a Publish option in my post statuses dropdown as well as a Team Published option.

That’s great, but guess what that blue button does even if we change the label on it to Team Publish? If you said that it actually publishes the post, you’d be right. So we need to jump in there and hijack that process to save the post in team published status instead. That requires a little bit more code.

    /**
     * Prevent the post from saving as Published if submitted by a user who shouldn't be able to publish.
     *
     * @since  0.2.0
     * @param  array $data    The submitted data.
     * @param  array $postarr Array of post data.
     * @link                  http://wordpress.stackexchange.com/a/113545
     * @return array          Updated post data.
     */
    function wds_prevent_post_change( $data, $postarr ) {

        if ( ! isset( $postarr['ID'] ) || ! $postarr['ID'] ) {
            return $data;
        }

        // If a user isn't able to team publish posts (only Content Approvers), do the normal stuff.
        if ( ! current_user_can( 'team_publish_posts' ) ) {
            return $data;
        }

        $old = get_post( $postarr['ID'] ); // The post before update.

        if (
            $old->post_status == 'auto-draft' ||
            $old->post_status !== 'trash' && // Without this post restoring from trash fail.
            'publish' === $data['post_status']
        ) {
            // Force the post to be set as team-publish.
            $data['post_status'] = 'team-publish';
        }

        return $data;
    }
    add_filter( 'wp_insert_post_data', 'wds_prevent_post_change', 20, 2 );

Here, we’re hooking into the wp_insert_post_data action and we’re checking for the team_publish_posts capability. Again, this only applies to one group of people, content approvers, so if you aren’t one of those, you just carry on with your normal work. If you are one of those users, and the post status being submitted is publish, hijack that status and change it to team-publish — our custom post status.

Now we’ve got a fully customized workflow for content creation teams that plays nice with default WordPress user roles, follows WordPress Core’s example in creating a hierarchical user role structure while still being able to pull of some fairly extensive and complex stuff dealing with users of particular roles and belonging to particular teams seeing (or not seeing) different types of content. This was all made possible by John James Jacoby’s WP User Groups plugin, which allows us to use a taxonomy to group users into teams.

If you’ve got some creative ways of managing users or teams, or if you’ve used any of JJJ’s Stuttter plugins, let us know about what you’re working on in the comments!

UPDATE: It came to our attention that there is a method in one of the code examples above that is not defined (hat-tip Aagha). For completeness, a method that should be suitable is provided here.

<?php
/**
 * Return an array of applicable post types.
 *
 * @param array $args The args to lookup post types with.
 * @return array
 */
function wds_content_area_post_types( $args = array() ) {
    $post_type_args = wp_parse_args( $args, array(
        'public' => true,
    ) );

    /**
     * Filter the post types from WordPress before we return them.
     *
     * @param array $post_types Array of WP post types return from get_post_types().
     * @return array
     */
    return apply_filters( 'wds_content_area_post_types_filter', get_post_types( $post_type_args ) );
}

The post Building Content Teams with WP User Groups and Custom User Roles appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2016/03/22/building-content-teams-wp-user-groups/feed/ 8 12823
Welcome Our Newest Dev, Kellen Mace! https://webdevstudios.com/2016/02/26/welcome-our-newest-dev-kellen-mace/ https://webdevstudios.com/2016/02/26/welcome-our-newest-dev-kellen-mace/#respond Fri, 26 Feb 2016 19:59:55 +0000 https://webdevstudios.com/?p=12731 We have yet another new member that recently joined our team–please join us in welcoming Kellen Mace, our newest developer! A little bit about Kellen: Kellen is a lifelong learner with a fondness for interesting projects that push his creative and technical limits. He loves building and launching software that clients find both powerful and Read More Welcome Our Newest Dev, Kellen Mace!

The post Welcome Our Newest Dev, Kellen Mace! appeared first on WebDevStudios.

]]>
We have yet another new member that recently joined our team–please join us in welcoming Kellen Mace, our newest developer!

A little bit about Kellen:

Kellen is a lifelong learner with a fondness for interesting projects that push his creative and technical limits. He loves building and launching software that clients find both powerful and easy to manage.

Kellen started his career in the healthcare industry, but discovered a passion for tech, especially the creativity and problem solving inherent in web development. Eager to learn as much as he could on the subject, he completed coursework through a number of online educational services including Harvard University’s edx.org, Coursera, Lynda.com, Codecademy, and Code School. He ran a business for the next several years building WordPress-powered websites and custom themes and plugins, providing solutions to clients, and learning a great deal in the process.

Kellen has also released a theme and several plugins that are available on WordPress.org, and is a WordCamp conference speaker.

In his spare time, Kellen can be found going on adventures with his wife Meghan and their ridiculously cute two year old Desmond, reading, exercising, enjoying the outdoors, and rocking out on guitars, drums, keyboards, and digital audio workstations.

You can follow him over @kellenmace and find more of his social links here. Say hello! Oh, and guess what? We’re still looking for more back-end developers…come join us and build rad stuff!

The post Welcome Our Newest Dev, Kellen Mace! appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2016/02/26/welcome-our-newest-dev-kellen-mace/feed/ 0 12731
How to be a Better Developer https://webdevstudios.com/2016/01/28/how-to-be-a-better-developer/ https://webdevstudios.com/2016/01/28/how-to-be-a-better-developer/#comments Thu, 28 Jan 2016 16:23:38 +0000 http://webdevstudios.com/?p=12153 Becoming a good developer is super easy, right? You just read all the right books, learn the right languages, read the right blogs, and ? you’re a developer! It’s nothing a four year degree from a technical college couldn’t give you, right? Or maybe not. Colleges and universities are woefully behind on emerging technologies (where are you Read More How to be a Better Developer

The post How to be a Better Developer appeared first on WebDevStudios.

]]>
Becoming a good developer is super easy, right? You just read all the right books, learn the right languages, read the right blogs, and ? you’re a developer! It’s nothing a four year degree from a technical college couldn’t give you, right?

Or maybe not. Colleges and universities are woefully behind on emerging technologies (where are you supposed to learn this stuff???), blog posts and books have inaccurate or outdated information, and, anyway, you’re not really a developer…you just mess around in code sometimes. There’s no realistic way you could ever claim to be a “good” developer–there’s just too much you don’t know.

woah-php

Great developers aren’t grown in a lab. You can’t download all the awesome information you want to know into your brain like you can in The Matrix. When I started out, I was really intimidated by all the amazing developers out there, the guys who speak at WordCamp US or even–gasp–present at actual PHP or JS conferences. I thought, there’s no possible way that could ever be me; I just don’t have the chops. It’s easy to be intimidated (and maybe a little awed) by the WordPress rockstars who have their names on all the cool plugins you use. And it’s easy to look at really big and complex plugins like WooCommerce or Easy Digital Downloads and feel like there’s no way you could build something on that scale.

The key to beginning a journey to being a better developer is first by understanding that all those developers that you admire and respect started the exact same place that you did. Everyone starts from nothing. And, as hinted at above, most university programs are woefully behind the times when it comes to emerging technologies in web development–which is to say that most devs are, at least in part, self-taught. But that means that you can do it, too, if it is something that you choose to pursue.

Love what you do

Here’s the thing: you might not actually love developing. I mean, maybe you like it, in that you do it and it brings in some income and it could be a whole lot worse, but that’s a lot different from loving it. And if you don’t love coding, no amount of persistence and work and studying is going to make you a great developer. You could maybe be a good developer or a kind of okay developer, but if you don’t love what you’re doing, you’ll never be great at it.

Back when I was freelancing, I oscillated from euphoric joy when I completed a beautiful website design that I thought would look fantastic, to sheer, mind-numbing dread at actually presenting that design to a client. It’s not that I disliked the exchange with clients, or that I hated my clients. I just felt so attached to this work that I spent so much time and creativity on, that the idea of it being ripped to shreds — or outright denied — made me want to crawl into a hole. As a freelancer, I did most of the work of both creating a design for a site in Photoshop and writing the code to make that design a reality. But it wasn’t until I took on a project that was purely back-end development for a site that a friend and fellow freelancer had designed that I had an epiphany: I really don’t like doing design.

For me, design is hard. At best, my color choices are boring–my color palettes tend to be extremely monochromatic with no variety–and design is constantly changing. It’s hard to keep up. I really liked when using grunge and textures were styles that people were into. I could find some cool parchment or fabric texture, get some grungy type for the logo and build a site around it. And that’s what I did. But that trend lasted maybe three months and then it was all embossed buttons and glows and gradients and then we dropped all of that in favor of CSS drop shadows and images that looked like polaroids but then that was out of style and everything was flat, flat, flat…Designing something that like and designing something the client likes are often two completely different things and I discovered that I was much happier building back-end solutions for things and letting someone else handle designing a user experience that both delighted the client and resulted in increased sales.

If you aren’t having fun with what you do, you are doing the wrong thing. Or, at least, you’re not setting yourself up for success. You can’t get better at anything if you really aren’t that interested in the thing. In this case, you can’t be a better developer if you don’t like looking at code, writing code, coming up with solutions to problems, taking pride in the quality of your work. If you aren’t proud of what you’re writing, understand why and what you need to improve on to get better.

Never stop learning

whip-it-you-still-suck

I am always looking to understand why a thing works the way it does, and this drives me to sometimes unconventional solutions to problems. Many years ago, I did server support for a well-known, national grocery chain. One time, the store’s Unix server, which acted as the DHCP server in the store and was responsible for issuing specific IP addresses to all the other machines in the store (including the store computers and the Windows server, which I was supporting at the time), was not working properly. It was not giving the Windows server the correct IP address which was causing problems with the internal store network. I was on the Windows server support team, so this was pretty important to my job, but the Unix team really only knew to run a certain number of pre-written bash scripts. They didn’t really know anything about Unix administration, and the leads either weren’t helpful or were unavailable. So, I did the only thing I thought to do–I asked a bunch of geeks on an IRC channel I frequented who ran Unix and Linux servers for advice. It was through working with them that I was ultimately able to resolve the problem.

In the end, I was called a “cowboy” for going outside protocol. That’s largely what made me realize that this was not something that I really wanted to be doing with my life.

My “problem” was that it wasn’t okay for me to just click a button, or run a script, or escalate to my superiors when those things aren’t working (none of which, I will point out, were even possible in this case). I understood enough about the way the system worked that I could actually identify where the problem was and figure out a solution that would solve it. That comes from a never-ending curiosity and desire to understand what’s underneath things and how they work. It was that curiosity and thirst for knowledge that drew me to tech support in the first place.

As developers, we’re often asked to do things that are out of our scope of knowledge. We’re asked to build things that we’ve never built before. Sometimes, we’re asked to build things that don’t even exist, for which there’s no guidebook to how it should be done, nothing existing to copy or go off of. The best developers I know understand that maybe they don’t know everything, but they are confident that they can find out. Once you’ve built that really cool feature, you can add that solution to your toolbelt for next time you come across something similar. Or take the successes in how you approached that project with you when you take on your  next project.

Learning isn’t finite. You should be learning in everything you do.

Know your strengths

rodrigo-lopez-sacramento-republic-fc-60-yard-goal

You aren’t going to be an expert in everything. It’s just not possible. The saying “jack of all trades, master of none” exists for a reason. Understand the things that you excel at. If it’s hard for you to be an objective judge of your own talents, think about those things you enjoy doing most–those are probably the things that you are best at. If you’re still having a hard time, ask someone you trust or have someone review your code and give you some constructive feedback. Knowing what you’re good at is important because it leads to interactions where you can confidently say “Yes, I can do this, and here’s how it’s going to be built.”

Know your weaknesses

Thomas Müller, German soccer player, Silver Boot winner at the 2014 World Cup and not a great dancer
Thomas Müller, German soccer player, Silver Boot winner at the 2014 World Cup and not a great dancer

You also need to know what you aren’t so good at. Understanding where your weakest points are will help inform decisions about how to build a thing–where you might need help or what you might need to spend some extra time researching so you have an understanding of how something works. I’m weak in JavaScript. I know if a project is going to be JavaScript-heavy that I’m probably going to lean on other developers who are more proficient than I am for help or advice when I run into problems. I’m probably going to be hitting the documentation heavier, so I’ll need to anticipate spending more time on those tasks. And knowing what I am capable of, what I do feel comfortable with, helps when I’m tackling a problem that pushes me out of my comfort zone.

In order to get better, you need to be willing to learn and you need to build experience. Both of these things come from pushing at the edges of what your comfortable with, what is easy and familiar, and tackling some of those problems that you look at and just shake your head and ¯_(ツ)_/¯.

Surround yourself with other smart people

messi

Lionel Messi is an Argentine soccer player who is so good he makes the best players he comes against look like they’ve never played the sport before. Even more than that, he makes everyone else on his team look better.

I am incredibly lucky. I get to go to work (in my pajamas, if I like) with some incredibly smart, talented and experienced developers at WebDevStudios. This means that it’s easy for me to learn from some of the best WordPress developers in the business. For one thing, I can just ask them a question, and we talk about a lot of tricks and tips (as well as challenges and how to solve them) on a weekly developer call. But you might not be so lucky (although perhaps you could be!). For that, I highly suggest getting involved in an open source project. If you’re ambitious, maybe you can try your hand at submitting patches to WordPress core, or maybe join the WordPress Theme Review Team, which would give you an opportunity to look at a lot of people’s code and determine whether it follows the recommended guidelines. Or maybe you can try joining a smaller project that is no less committed to producing excellent code, something like Yoast SEO or BuddyPress. Thanks to GitHub, it’s easy to jump into existing projects like this and submit patches and pull requests.

It also helps actually being around (in the physical sense) other developers. Not because you absorb their intellect through osmosis or anything, but rather because it helps to get an idea of how other people work. It gives you the opportunity to ask questions face-to-face. A lot of people use co-working spaces for this purpose–so a bunch of people can collectively work remotely but in a group environment where you’re around other developers. I’m also a big advocate for local WordPress meetups–there’s probably one in your area and they are great places to meet other local developers and learn about what they are working on and the ways that they work.

One of my favorite Ben Folds songs says “There’s always someone cooler than you.” No matter how much you know, there’s always more to learn, no matter how expert you get in a particular subject, there’s someone else who knows more. Learn from the folks who have knowledge to share and share your own knowledge when and where you can. It’s been scientifically proven in sociology studies that people actually learn from the act of teaching, because showing someone else how to do a thing solidifies that process more for yourself. Don’t be afraid to share your own knowledge and experience. Everyone is an expert in something.

Ask for help

tetherball

It cannot be understated how important it is to ask other people for advice or help. I don’t necessarily mean “Hey man, can you do this thing for me?” That, to me, isn’t as helpful as explaining how and why a thing works. Teach a man to fish and all that. Before working at WDS, I once went through the hiring process and up to the code review portion for a company who we all know but who shall nevertheless remain unnamed. It was many years ago and I’ll be honest, my dev chops weren’t nearly where they are today. I was given a task to make a particular plugin “better”. That was it. Just make it better. So I worked on it for a week, I made several incremental improvements, but not nearly as much as I could have, because in many cases, looking at the code, I didn’t understand how it worked, so I just sort of ignored that bit and assumed that it just did work.

Can you guess what I did wrong?

After it was over and I was reflecting on the experience, it was my wife who pointed out the fact that one thing I didn’t do was ask for help. What is the WordPress community if not a community? I was so focussed on the task at hand, at passing this test, that I didn’t take advantage of the single thing that — in my mind — sets WordPress apart from other platforms and Content Management Systems. I tried to make it about me. But the me isn’t important. It’s never important. What’s important is the task at hand. Whether you’re building a plugin or theme or developing a website or making an app, the name on the outside (especially in open source) matters less than whether it does the thing as advertised. It’s okay to ask for help. It’s sometimes scary and seems like you’re admitting defeat in doing so, but you’d be surprised how helpful having another pair of eyes on a problem can be and how much you can learn from working with others, especially if you’re used to working by yourself.

Dealing with imposter syndrome

whip-it-nice

Before I go, I want to take a minute to talk about “imposter syndrome,” which is when you feel like you don’t belong among other more “established” or “experienced” developers or that you aren’t actually very good and someone will eventually find out. We’ve all been there. All of us feel the same thing. Some of us more than others, but it’s always there. For some, this feeling of inferiority acts to constantly drive us to be better at what we do. For others, it keeps us from taking chances or reaching for better opportunities because of our own self-perception. It can affect us in really subtle ways, like the way we talk about our accomplishments on a resume or in a job application. It can come out in interviews when we’re asked questions like “How good do you feel you are with x?” or “What do you feel your strengths are?”

Even the best developers suffer from imposter syndrome. When WebDevStudios first started really going through a growth spurt about two to three years ago, I thought “Hey, that’s cool…I wonder if–nah, they’d never hire me.” You can’t imagine (or maybe you can) how freakishly intimidating it can seem to work with people like Brad and Brian and Lisa who have written books about WordPress. Or with the guy who started Sucuri and challenged Matt Mullenweg to a throwdown. And, believe me, every single one of our developers are mind-bogglingly amazing. When I finally did muster up the courage to apply to WebDev a year and a half ago, at my first interview with Brad and Brian, I was terrified. I kept thinking “What if they find out I’m not actually a very good developer?”

I’m told this is a pretty common fear, the fear of being “found out” as an imposter. You tell me. For me, I just pushed on anyway, because if you never ask, you’ll never get the thing you want. I had to trust that if they did find out I wasn’t very good…well, I’d just have to figure out how to get better. Luckily, the folks here are also pretty amazing humans and it’s easy to forget that those superheroes in your head, the rockstar developers or professional athletes or published authors are all just that–humans. And we all start somewhere (seriously, have you seen the first incarnation of the WebDevStudios?).

I know it’s hard to overcome, but, trust me, the feeling that you aren’t good enough or can’t ever be a great developer is bunk. The best way to be a better developer is to understand that you’ll never know everything, but you can keep learning and improving and, if you continue to love building cool things, you will always get better.

And, you know, if that describes you…we’re hiring.

The post How to be a Better Developer appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2016/01/28/how-to-be-a-better-developer/feed/ 3 12153
Another Awesome WDS Year Down and Many More to Go https://webdevstudios.com/2015/12/29/another-awesome-wds-year-many-go/ https://webdevstudios.com/2015/12/29/another-awesome-wds-year-many-go/#comments Tue, 29 Dec 2015 19:10:02 +0000 http://webdevstudios.com/?p=12344 As the end of 2015 approaches, we have joined the masses in taking stock of the passing year and started setting our sights on the next. The last few years have been a big jump for us and we’ve grown a lot. These transitions haven’t always been easy (that’s why they’re called growing pains), but Read More Another Awesome WDS Year Down and Many More to Go

The post Another Awesome WDS Year Down and Many More to Go appeared first on WebDevStudios.

]]>
As the end of 2015 approaches, we have joined the masses in taking stock of the passing year and started setting our sights on the next. The last few years have been a big jump for us and we’ve grown a lot. These transitions haven’t always been easy (that’s why they’re called growing pains), but we’ve come out stronger and better than ever. We saw a lot of changes in 2015, particularly structurally, as well as hit a few milestones that we are STILL jazzed about. 

Let’s take a brief tour through recent WDS history to get you completely caught up to today:

Team Growth

WebDevStudios, WDS, WordPress developers, WordPress development, Professional WordPress, WordPress for Dummies, AppPresser, Maintainn

Prior to 2014, WDS worked in one group that took on projects based on developer availability, which was a controlled chaos, but chaos nevertheless. During that time, we transitioned from being a company that focused on small builds (blogs and businesses) to a full-scale design and development agency that took on enterprise clients; the kind of clients we looked to work with (and started to sign) expected high levels of customization and design work that was not only attractive, but effective, so we adjusted accordingly. This period also led us to narrowing our spotlight: we stopped splitting our labor between creating premium products and client services to focus exclusively on the latter.

As our workload increased, it became clear we needed more leadership and structure, as well as more people. As a result, at WDSCamp 2014, WDS created teams with a more hierarchical structure–including dedicated project managers and developer/designer leads.

In 2014, we also added a third team to our mix when WebDevStudios acquired Maintainn, a WordPress maintenance and support company founded by Shayne Sanderson. We were pleased and proud to bring Maintainn into the fold; combining their super-skilled folks with ours has allowed us to offer more comprehensive services to our clients. In 2015, we’ve been able to utilize this acquisition to offer clients a seamless transition from site build to ongoing maintenance and give them the opportunity to truly see their investment (their site!) in action. Being able to offer this has been huge for us; we get to provide clients the opportunity to keep their site in the hands of people they know and trust. 

In 2015, these teams became more focused, allowing us to take on bigger clients and more complex projects. After facing a few unexpected challenges in 2014, we pushed forward to update our operating procedures and standards–an endeavor in streamlining our workflow and boosting our efficiency that has extended well into this last year. Creating standardized processes for how we handle clients, projects, and internal communication has transformed the way that we work, and is something we’re continuing to do as we grow.

webdevstudios, WDS, WordPress developers, WordPress development, Professional WordPress, WordPress for Dummies, AppPresser, Maintainn

In the last two years, as the teams were truly hitting their stride, we also had the opportunity to expand other parts of WDS, including our marketing. Dre Armeda came on as the VP of Operations and led the charge on amping up our marketing efforts. In turn, this led to hiring me at the beginning of 2015. Since then, we’ve had a steady concentration on developing a more extensive strategy and refining our process moving forward.

One of the big things we set out to do was organically grow WDS’ presence on the web, and of course, content marketing is a major part of that. When we started collaborating around what we wanted that to look like, we realized that our major assets (our ragtag team of jaw-droppingly smart misfits with varied life and professional experiences) overlapped with our fundamental values (education and community), and that we could utilize this to our advantage.

Both learning and teaching, as well as contributing to the WordPress community, has always been high priority for WDS, and we wanted our content to reflect that. As a result, in the last year we’ve more than doubled the number of posts put out during the course of the year. While some of those still include the basics, like which events our team members will be attending, the vast majority of our blog is dedicated to sharing what we’ve learned, what we love, and what we’re trying out, and the response has been overwhelmingly positive. 

webdevstudios, WDS, WordPress developers, WordPress development, Professional WordPress, WordPress for Dummies, AppPresser, Maintainn

Over the last year and a half, we’ve seen our teams flourish into glorious, productive beasts, ready to take on pretty much anything, anywhere. As these teams have matured and improved the way we work, we’ve seen our folks do what they do best: get business done, learn well, and create fantastic work–even when the workload is intense!

Superheroes Stepping Forward

Part of that team growth is not only reflected in terms of numbers, but also advancement. Over the last year, these folks got promoted:

webdevstudios, WDS, WordPress developers, WordPress development, Professional WordPress, WordPress for Dummies, AppPresser, Maintainn

We created a few positions that hadn’t previously existed in their current iterations (Client Communications Specialist, Chief Marketing Officer, the Director of Engineering, and Maintainn’s Project Manager). All of these, of course, include tasks that were being completed before, but these positions were created to help ease the workload on those who were doing two, three, or four jobs at the same time and provide a concerted effort in areas that were being underserved.

We also said goodbye to some folks we adore; we were sad to say goodbye to Patrick Garman, Stacy Kvernmo, and Shayne Sanderson, who moved on to new endeavors.

We’ve Learned Some Stuff

We’re a relatively small company, but we still work with big clients. As a result, much of our education has been a baptism by fire! Over the last few years, we’ve learned a few crucial things:

Get everything in writing.

The necessity for the Director of Engineering position became clear when we realized that our communication with clients wasn’t absolutely everything it could be. In the past, we made the mistake of not having every minute detail planned out and assumed it would be fine–only to find out that this sometimes wasn’t the case.  By refining our process for project discovery and signing clients, we elevated the level of service we provide. We now have the ability to forecast more accurately, to be more efficient, and to make sure that everyone is on the same page–about absolutely everything.

Don’t be afraid to ask for accountability–both from your team and from your clients.

This is where the importance of leadership comes in. If you read our blog, you’ve probably already read a few things by our project managers on the importance of taking responsibility when leading a team; our three amazing PMs (and the developer leads they work with) have fearlessly served as advocates for both their team members and the clients they work with. Their motivation, organization, and fortitude has helped us all work better.

Know how–and when–to grow.

One of the conversations that is constantly taking place is: How and when can we extend? We work with big clients, but we’re still a small team. By being conservative but proactive in the way we hire, we avoid straining our resources.

Value the folks around you.

While we’re always accepting applications and have pushed for new hires throughout the year, you may have noticed that we love to promote from within. We’ve been lucky; we have a team of people who love to learn, love to teach, and have an overwhelming sense of humility when it comes to what they know and where they came from, as well as a strong sense of commitment (read: mild workaholism) and determination. As a result, we’ve ended up with a lot of die-hard WDS-ers who have grown within the company. Reward the folks you work with–not only because it’s the right thing to do, but because it makes your team better.

WDSCamp 2015 was also an extraordinary demonstration of how our team is valued. The bonding was real and it was derived from the company culture created by our executives. That culture prioritizes value even in day-to-day interactions; the politeness, appreciation, and admiration, both expressed directly and when someone isn’t around, would be too Pollyanna-ish to be believed if it weren’t so obviously sincere. This is a fundamental component of how and why our team can do what it does so well.

Cause for Celebration

This last year has been good to us! We’ve been fortunate to accomplish quite a lot: 

webdevstudios, WDS, WordPress developers, WordPress development, Professional WordPress, WordPress for Dummies, AppPresser, Maintainn

WebDevStudios in the New Year

Moving forward, we’re super excited to see what happens for WordPress in 2016 (and beyond). We’re looking forward to seeing how utilizing WP-Rest API enables us to provide more unique experiences for our clients and getting more focused on JavaScript as a team. We’ve spent extensive time working on stabilizing the WDS workflow and process, and we’re excited to see where that takes us next. We will be driving more focus toward certain products like Maintainn, AppPresser, and more. Lastly (but not least-ly), you’ll see us at more events, both domestically and internationally; we’ll still be a presence in the WordPress community that we adore and you’ll see us at other tech events as well.

WebDevStudios, WDS, WordPress developers, WordPress development, Professional WordPress, WordPress for Dummies, AppPresser, Maintainn
Shoutout to Simon for creating these gorgeous images

It’s a new year. 2016, we’re coming for you!

The post Another Awesome WDS Year Down and Many More to Go appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2015/12/29/another-awesome-wds-year-many-go/feed/ 9 12344
How Technology Can Help Your Health https://webdevstudios.com/2015/12/17/technology-can-help-health/ https://webdevstudios.com/2015/12/17/technology-can-help-health/#comments Thu, 17 Dec 2015 17:11:00 +0000 http://webdevstudios.com/?p=12170 Our mental and physical health is directly linked (no surprise there). For every article that shouts from the rooftops about all the ways technology makes our lives better as a global community, it is closely followed by another that is muttering under its breath: “Careful there; don’t over do it!” You can totally overindulge in technology Read More How Technology Can Help Your Health

The post How Technology Can Help Your Health appeared first on WebDevStudios.

]]>
Our mental and physical health is directly linked (no surprise there). For every article that shouts from the rooftops about all the ways technology makes our lives better as a global community, it is closely followed by another that is muttering under its breath: “Careful there; don’t over do it!”

You can totally overindulge in technology and have it affect you negatively. Don’t listen to Mr. Grumbles in the corner; that dude’s a total wet blanket. Let’s focus on the flip side–on the ways that technology can help contribute to our well-being(s). It helps us build communities and connect with others; it makes certain actions more efficient and, if used mindfully, can help us add to our existing set of cognitive skills.

Technology allows us to extend the niche of self-help and self-care and to make information and education much more readily available. The dynamics of an app often allow for interaction so it can be more engaging and supportive to assist someone with a change without being too intrusive.

Where’s a good starting point to dive into technology and my health?

F.lux – Too much screen time might be affecting your sleep patterns! Night time exposure to blue light keeps people up later than normal and f.lux adjusts colors in a way that reduces the power of those stimulating effects at night.

Fitbit – While not free, the Fitbit has varying capabilities depending on what you’re seeking out. Interested in tracking your sleep to optimize your sleeping habits? Your steps to see how your activity rate shifts? Your heart rate? The first step is adjusting a current pattern is becoming more knowledgable about your current habits.

“I think it’s very important to have a feedback loop, where you’re constantly thinking about what you’ve done and how you could be doing it better.” ~Elon Musk

Let’s not forget other more specialized tracking methods!

For those who have menstrual cycles, tracking and information-offering apps could be a helpful addition to learning more about how hormones are affecting your body every month (i.e. Clue &/or Hormone Horoscope).

What about something like MigraineBuddy? Designed by neurologists and data scientists, it can help quickly guide you through identifying and recording triggers and symptoms during an episode as well as providing a summary report of past incidents.

Anxiety-reducing apps like Personal Zen focus on training our attention to the positive are appealing to a larger audience because of how they translate effective strategies into a game format. Happify uses a similar strategy to disrupt patterns of negative thinking by framing existing habits in a more positive manner. Apps like these are also wonderful because they overcome a few treatment barriers by being brief and inexpensive.

Additional calming apps like Pause, Breathe2Relax, or Headspace assist in guiding you to channel the principles of a mindfulness and meditative practice. This allows you to regain focus by triggering the ‘rest and digest’ response to combat any potential ‘fight or flight’ you might be experiencing.

SAM and Mindshift are also good in regards to combining self-evaluation and tracking to come up with small steps for future change.

None of these are a substitute should you need more nuanced, immediate, or direct feedback from a trained professional in regards to your situation. They are, however, a great supplement if you want to explore entry-level options that use the ideas of mindfulness, cognitive behavioural therapy, or gamification to help you improve your day to day life.

Are there any uses of technology not mentioned above that help contribute to your heath in a positive way? Feel free to share below; I love learning more about what’s out there!

The post How Technology Can Help Your Health appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2015/12/17/technology-can-help-health/feed/ 1 12170
Helpful Packages for Atom Editor https://webdevstudios.com/2015/12/03/helpful-packages-for-atom-editor/ https://webdevstudios.com/2015/12/03/helpful-packages-for-atom-editor/#comments Thu, 03 Dec 2015 18:30:06 +0000 http://webdevstudios.com/?p=11918 It has been a few months since I’ve transitioned from using Panic’s Coda 2 to using Github’s Atom editor as my main application for working with code. I tried switching to Sublime Text a few times, and never successfully gave it a chance, but instead decided to dive right in with Atom. It seems that Read More Helpful Packages for Atom Editor

The post Helpful Packages for Atom Editor appeared first on WebDevStudios.

]]>
It has been a few months since I’ve transitioned from using Panic’s Coda 2 to using Github’s Atom editor as my main application for working with code. I tried switching to Sublime Text a few times, and never successfully gave it a chance, but instead decided to dive right in with Atom.

It seems that there can be allegiances to editors that can really rile people up. I’ve always been hesitant to make the jump mostly because of the productivity death effect switching can have. Obviously, the learning curve and installation seem to be the biggest obstacles. Why should I switch when I’m comfortable, and can ship code just as quick as the next person? So it was not until I had family vacation and knew I would have some downtime to try out Atom, and gave it a try.

Extending Atom with packages

Atom comes with dozens of pre-installed packages, as well as a few themes which can be switched on-and-off and tweaked to your heart’s desire. There is also a library of community contributed packages and themes. Here are a few packages I’ve found useful in my daily coding practices:

minimap

The minimap package shows a preview of source code along the side of the current file you’re working on.
minimap package for Atom editor
Minimaps has a growing library of other packages in which it integrates nicely. Pigments is one of them. Here is a full list.

Pigments

For anyone that does a lot of CSS, Less, or Sass, this is a must-have. The Pigments package sources your code for any colors, then displays and builds a palette.

Pigments package for Atom editor
It also comes with a lot of handy features, like Pigments: Show Palette, which can show the current project’s palette from the command palette (Cmd+Shft+P / Ctrl+Shft+P). Also, there is a contextual menu that allows you to convert Hex to RGB(A), and vice versa.
pigments package - show palette command in Atom Editor

File-Icons

The file-icons package adds file type icons to the Tree View, Fuzzy Finder and Tabs. Just a simple nuance to help visually distinguish one file type from another, and who does not like icons?file icons Atom package

Highlight-line

This is a simple tool to just highlight the current line, which can be customized as well.
highlight line package for Atom editor

Markdown Preview Plus (MPP)

Markdown Preview Plus provides a realtime preview of any markdown file you’re working on.
Markdown Preview Plus package for Atom screenshot

Color Picker

Right click and select Color Picker, or hit CMD-SHIFT-C/CTRL-ALT-C to open it. Currently reads HEX, HEXa, RGB, RGBa, HSL, HSLa, HSV, HSVa, VEC3 and VEC4 colors – and is able to convert between the formats.

It also inspects Sass and LESS color variables. Just open the Color Picker with the cursor at a variable and it’ll look up the definition for you. From there, you can click the definition and go directly to where it’s defined.
Color picker package for Atom screenshot

Gist-it

Atom has a nice way to save and deal with Snippets natively, but I sometimes prefer to share and save Gists. Gist-it allows you to easily post files (or current selection) from Atom to GitHub Gists.
gist-it Atom package screenshot

Conclusion

So far I’m digging Atom editor. I’ve been using the Atom Material UI theme with some simple customizations. I’ve barely scratched the surface of what lies underneath, and look forward to where the project’s Roadmap leads.

Check out the helpful documentation and get started if you like. Ultimately, I believe a tool is a tool, and it is how you use it that is most important.

The post Helpful Packages for Atom Editor appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2015/12/03/helpful-packages-for-atom-editor/feed/ 4 11918
You’re a Salesperson–Not Just a Designer https://webdevstudios.com/2015/11/17/youre-a-salesperson-not-just-a-designer/ https://webdevstudios.com/2015/11/17/youre-a-salesperson-not-just-a-designer/#respond Tue, 17 Nov 2015 19:03:05 +0000 http://webdevstudios.com/?p=10988 Designers face many challenges that are often discussed and pontificated on, from Grunt to typography. What’s worth emphasizing is what happens before and after the design is created. Design isn’t just about one thing, and in order to be a designer of any consequence one must be able to sell. One of the most frustrating Read More You’re a Salesperson–Not Just a Designer

The post You’re a Salesperson–Not Just a Designer appeared first on WebDevStudios.

]]>
Designers face many challenges that are often discussed and pontificated on, from Grunt to typography. What’s worth emphasizing is what happens before and after the design is created. Design isn’t just about one thing, and in order to be a designer of any consequence one must be able to sell.

One of the most frustrating experiences that I ever had in the business of design wasn’t with a client or agency I was consulting. One of the most painful experiences was with a designer. Designers can be hard to work with. I know–what a shock!

There is always a common thread to what designers do when they design successfully and most of it has to do with selling. By selling, I mean selling your ideas both to internal groups as well to colleagues and clients. The bulk of this post is directed towards selling to clients, but some of these tips can be applied across the board.

Care About Clients

Crazy, right? You need to actually care about the client! That means being thoughtful and listening, and it means eliciting answers to questions that your client didn’t even think to ask. Clients, at times, don’t know what they don’t know. It is your job to get answers and weave those answers into a viable solution.

Many times I have heard designers I worked discuss how something would hurt the user and not be beneficial to UX. Yes, that is important and at times critical. But it’s crucial to not discount client concerns without first considering where they are coming from. Definitely don’t use subjective usability references to win the battle and lose the war. Do your homework on the client. Spend time getting to know their needs. Know the client. Your solution may not be at all what the client was expecting, but because you care and have their trust, the solution you see will be easier to sell.

Here are some things to keep in mind in client interactions:

  • Clients need your help–not your design snark. Keep that snark for hilarious conversations amongst friends!
  • Identify with the client and listen–flex that empathy muscle.
  • Clients don’t hire designers all the time, so they’re not experts. Don’t expect them to be.
  • They don’t have the same knowledge you do, so approach it from an educational stance and share what you know and where you’re coming from.
  • Don’t mystify what you do as a designer. By obscuring what you’re doing, you’re making it harder for them to understand your recommendations, and you risk losing their trust.
  • The more you open your ears, the more you understand.
  • Don’t make assumptions, but trust your gut.
  • Set expectations by asking the right questions.
  • Your job is to solve problems and then sell the solution to anyone that will listen.

Designed To Sell

When designing I am concerned about three things and only three things:

1. The Client

The client comes first. Think about their position in their competitive set: Are they profitable YoY? Are they desperate for something to boost sales or boost company moral? Do they have operational issues or special situation? Are they hard to work with? You should know the clients’ wants versus needs. Research! When you’re on a call you should know what they represent–never guess.

2. The User

Interfaces should be entertaining and easy to use. Think about their users by asking questions: Who are they? Are there more of them this year than the last? What’s the demographic? In other words, you’re asking all the usual questions to understand the true user situation. Take the initiative to run your own usability tests if you have to! Get a baseline of what the users are feeling and see if that jives with executive strategy. After that, you may discover holes in their business strategy, so close those up in the design with the client.

3. The Technology

Make sure to use the right technology at the right time. That means you understand the tech and its associated financial costs. Don’t promise the moon and deliver a pizza pie. At the same time, it’s ok to stretch your developers to a point just before they send the one finger salute. Be realistic and creative. Understand exactly how the technology you’re designing for works. You’ll save time and money doing so.

Always Be Closing

Glengarry-Glen-Ross-DI
Alec Baldwin as David Mamet, Glengarry Glen Ross (1992)

The thing is, if you can’t adequately sell your solution to your colleagues when they have hard questions, how will you sell to clients? Presenting a design is not selling a design–one is passive and the other very active. This is about actively selling and not acting as if you’re owed deference, because you’re The Designer. It is important to be confident and not be afraid of disagreements, because there will be disagreements, and if you’re prepared, you can steer the conversation in a respectful, productive direction. Clients and vendors don’t always agree! The best designers sell their version of the story–they talk about where they are coming from, what the goals are, and what narrative this particular design creates, and how it all elevates the brand they are working with. Be professional, amiable, and lead design meetings. Leaders sell; followers purchase.

Helping clients starts with yourself. Helping clients is all about you; it’s about how you are going to solve a problem and then you sell the solution.

At the end of the day, you have to help the client know what they don’t know. You do so by first putting yourself in their position and simply listening. Research your client and their work, and think of the project itself as part of the sales cycle. Understand your relationship with this client can turn into not only more work for them, but referrals with others. The best part of your design is you. It’s not some grid or grunt task. It is not just design per se; it’s the story you’re telling with it. Whether you’re employed full-time or a rockstar consultant, selling is the order of the day. Go sell.

The post You’re a Salesperson–Not Just a Designer appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2015/11/17/youre-a-salesperson-not-just-a-designer/feed/ 0 10988