Blog posts under the Snippets category https://webdevstudios.com/category/snippets/ WordPress Design and Development Agency Mon, 15 Apr 2024 16:05:11 +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 Snippets category https://webdevstudios.com/category/snippets/ 32 32 58379230 Five Reusable Code Snippets to Reduce Development Time https://webdevstudios.com/2019/01/08/reusable-code-snippets/ https://webdevstudios.com/2019/01/08/reusable-code-snippets/#respond Tue, 08 Jan 2019 17:00:29 +0000 https://webdevstudios.com/?p=19592 When was the last time you started a project from scratch? I mean literally from scratch—not using a framework, a parent/child theme, or any plugins. Maybe never? One could argue that as long as you’re using WordPress that you’re not necessarily creating anything from scratch since the CMS offers so much functionality out of the box already. What you Read More Five Reusable Code Snippets to Reduce Development Time

The post Five Reusable Code Snippets to Reduce Development Time appeared first on WebDevStudios.

]]>
When was the last time you started a project from scratch? I mean literally from scratch—not using a framework, a parent/child theme, or any plugins. Maybe never? One could argue that as long as you’re using WordPress that you’re not necessarily creating anything from scratch since the CMS offers so much functionality out of the box already.

What you do, though, is iterate on that functionality and build upon the tools provided to you or the tools you have built for yourself in the past. After all, if you’re doing work around the house and need to hammer some nails into the wall, you’re not going to head into your garage to carve the wood and forge the steel to make a new hammer every single time (unless you’re our very own builder and wood magician Will Schmierer). You’ll use the same hammer to do the same job until the hammer is no longer useful or you find a new tool with which to replace it.

Why then would you not develop a site in the same way? Granted, most projects are going to require distinct sets of functionality unique to the projects themselves but there are plenty of ways you can reuse code to save time so you can truly focus on providing the best possible work with the best possible turnaround. Some of these reusable code snippets might not be necessary for every project, and that’s okay. Maybe you only need to use them a few times a year, but whenever the need arises you find yourself searching online or through your old code to find something you know you’ve written at least once before.

In this post, I’m going to share some things that have made their way into wd_s because we, as developers, find ourselves using similar functionality over and over again. Maybe you’ll find one, some, or all of these snippets useful. Whatever the outcome, I hope that I can help to trigger some thoughts on when and where you can reuse functionality in your own processes to more efficiently complete your projects.

1. Social Network Links

Social networks, despite all the good and bad they put out into the world, are almost essential to have a digital life in this day and age. As such, there is rarely a website out there without links to the various social media accounts linked to the business or person attached to the site. In a WordPress install, there are several ways you could implement links to a set of social networks.

You could create a widget to manage the URLs, but what if you have many sidebars throughout your site and don’t want to deal with the tedium of manually replicating the same widget over and over again?

You could add URL fields to the Customizer and pull the data out into a template tag, but even then you’re limited by a finite number of fields in the Customizer. Perhaps, at launch, you only have Twitter and Facebook accounts, but six months down the road you spin up an Instagram account. Now, you’ve got to dive back into the code and go through the somewhat convoluted steps to add a new field to your Customizer settings.

You could even add the links to your social networks in a menu and then add a custom class to the menu items, like menu-icon-facebook, and then target that class (or set of classes, for all of your networks) in your CSS. Still, that requires an extra step and if you’re building a site for someone who may not be familiar with WordPress’ menu interface this could be confusing or frustrating.

So, what’s the solution? This is what I’ve found to be useful time and time again. First, it can be helpful to register a brand new menu location for your social networks:

View the code on Gist.

By registering a menu, you’re making it easy to reuse that menu anywhere you want throughout your site. You can add it as a widget via the built-in Custom Menu widget; you can create a custom template tag in your theme to display the menu attached to that particular menu location, and any number of countless things that can be done with a WordPress navigation menu. You’re already making life easier for yourself by relying on WordPress to do a bunch of work for you!

You don’t want to have to worry about doing any extra work when adding your menu items. You want to create the menu, add your links, and have your social icons displayed through some sort of magic. Well, I don’t have any actual magic for you but I do have a Sass snippet that will get the job done for you.

By targeting the menu and the href attribute values of the menu items, we can display the corresponding icon for each social network. Let’s take a look at that:

View the code on Gist.

First, you’re creating a $social-sites Sass list which holds the names of all of our social networks. Be mindful of this and don’t try to get cute with the names as they have to correspond directly to the URL you’re providing for your links.

Next, you’re targeting the links within your menu and looping through your $social-sites list to add an SVG as a background image. Your each loop is going to target your link’s href attribute and set the background image to match. This requires you to remember two things:

  1. As noted above, be sure to use the actual domain of the social network so your href targeting will work as expected.
  2. Remember to name your SVG files (or whatever other files you wish to use) to include the domain name. You can append or prepend a string (like icon-facebook.svg), but just be sure to make sure your background-image path matches your naming convention.

Now, wherever you use that menu throughout your site you should “automatically” see the icon displayed. You’ll want to do some other work to make sure the text also doesn’t display so that you’re seeing just the icon, or tweak the styles as you see fit if you do wish to display both the icon and the link text. You have the power!

2. Open Graph (OG) and Meta Tags

With social networks in mind, you’ll also want to make sure that any content shared from your site looks beautiful across every platform. There are plugins that will handle this for you, like Yoast SEO, but what if you don’t need a full SEO plugin or prefer to use a different solution for search engine optimization?

Fret not! OG and other essential meta tags can be a bit daunting at first, but with a recent update to wd_s we’ve tried to take some of the guesswork out of them. There are a lot of conditions that you could, and should, check for if you’re writing your own tags. You may want to serve up different sets of data for different post types or taxonomies, in which case you would need to modify the example snippet a bit to suit your needs.

Of course, if you’re using a plugin like Yoast, which will also provide you with all of the fancy-schmancy meta tags you need to produce beautiful Twitter and Facebook cards, then we’ll want to avoid messing with them. At WDS, we don’t tend to run into many clients who want to use an SEO plugin other than Yoast, so the snippet you’ll see below includes a check for that specific plugin:

View the code on Gist.

If Yoast is active, bail so that we don’t wind up with duplicate meta tags causing headaches and collisions. If you make this a part of your framework, you’ll want to be sure to either add in the checks for any plugins you may use to manipulate OG tags or simply remember to remove the function if you know that you’re going to be using a plugin to handle these tags. This also future-proofs your theme, if you’re doing work for a client. Should they launch their site without Yoast and then decide to add it six months down the line, you’ve got them covered. Your custom meta tag solution won’t interfere with their activation of the plugin, thanks to the conditional at the top of the function.

3. Archive Page Titles

You’re always going to have archive pages of some sort in WordPress, but for some reason, the titles of these pages are always a point of contention. Out of the box, WordPress creates a category archive page with a heading like “Category: Category Name.” Have you ever wanted to keep the prefix on that title? I certainly haven’t, and I don’t think we’ve had a single project in my (so far) seven years at WebDevStudios where a client wanted us to keep the prefix either.

If you’re working on a project for a client of your own, perhaps you never discussed this ahead of time. Since the archive pages are created dynamically, it may just be a passing note that the pages will retain the same look and feel as the rest of the site without much more discussion. However, more often than not, you’ll realize that everybody has an opinion on this after the fact even if they never stated their preference before.

Luckily, it’s pretty simple to remove the prefix from titles of these archive pages. So, instead of displaying “Category: Category Name” as the page title, you will instead display “Category Name.” Maybe you do want to add something before (or after) the base page title. Good news: you can! This snippet simply removes the prefix, but you can modify it to do any number of things to suit your needs from project to project. If nothing else, this is a handy snippet to keep on hand so you don’t have to Google “remove prefix from WordPress archive pages” every time you need to do this.

View the code on Gist.

4. Numeric Pagination

This isn’t a huge one, as WordPress provides an out-of-the-box way to display pagination throughout a site via paginate_links. So, what can we add to something already built into WordPress? We can make it easier to use and reuse in your templates. As you can see at the Codex link above, paginate_links offers a whole slew of options of which you can take advantage. You can customize the previous and next link text and how many page numbers are displayed in your pagination amongst others.

The issue with just using the core template tag is that anytime you use it, you need to set your own values, if you want to override the defaults provided by WordPress. We can get around this by creating our own template tag and invoking paginate_links with our own array of customizable options.

View the code on Gist.

In this snippet, we’re creating a template tag to power our paginated links. The function accepts an array, which means we can still customize the output of the links as if we were using paginate_links by itself, but we have the bonus of being able to include our own set of default values so you never have to worry about filling those in whenever you want to use this function. Then, if you do happen to have a spot on your site where you want to override your own custom defaults, you simply need to call the new template tag with the array of custom values passed in. As our function is, more or less, a wrapper for paginate_links, it accepts the same parameters for customization as seen in the Codex.

5. Post Headers and Footers

Nine times out of ten, the blog posts for your project are going to require some additional information displayed outside of title and content. We’re talking categories, tags, a posted-on date, and an author name. Once again, WordPress offers a number of ways to grab all of that information out of the box, but why toil around looking for the best way to display these extra details when you can just have it from the get-go? After all, am I going to need get_categorieswp_list_categories, get_the_category_list, wp_get_post_categories…? Stop the insanity!

Instead, let’s do this once and we can always tweak it on a per-project basis if need be, rather than starting with a blank canvas every single time. Let’s start at the top where we’ll want to display some important information: author and post date. With the following snippet, not only are we just getting the information we need, we’re also outputting it with some handy-dandy markup to make it even more usable.

View the code on Gist.

So now, you’ve digested the post title, author, and posted date. You’re ready to sit back and enjoy the contents of the post before you reach the end and look for some additional, related content and ready your nimble fingers to leave a friendly comment on the post (because you would never leave anything other than a friendly comment somewhere on the internet).

This snippet, just like the others in this post, can be modified to fit your needs. For us, we’re only going to try and display categories and tags on posts but you can adjust this for other post types or even rework the template tag on a deeper level to include custom taxonomies. First, we check to see if we’re in a post before checking for and displaying categories and tags. Then, if comments are open and the post isn’t protected, we’ll display the comments link. Finally, we’re displaying the edit post link so you can quickly jump back into edit mode if you need to do so.

View the code on Gist.

Quick Wrap-Up

Now that you’ve got a handful of useful snippets to speed up your next project, what other ways can you think of to smartly reuse code from project to project smartly, and what are you going to do with all of that newfound spare time? Let us know in the comments below!

The post Five Reusable Code Snippets to Reduce Development Time appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2019/01/08/reusable-code-snippets/feed/ 0 19592
Get Loopy with Sass https://webdevstudios.com/2017/02/07/get-loopy-sass/ https://webdevstudios.com/2017/02/07/get-loopy-sass/#respond Tue, 07 Feb 2017 17:00:53 +0000 http://webdevstudios.com/?p=16553 Whether you use Sass/SCSS, Less, or Stylus to compile your CSS, one thing’s for certain; it just makes life much easier. These preprocessors give us access to variables, necessary calculations, and powerful mixins that allow us to take our front-end workflow to the next level. As time passes the projects I tackle tend to present Read More Get Loopy with Sass

The post Get Loopy with Sass appeared first on WebDevStudios.

]]>
Whether you use Sass/SCSS, Less, or Stylus to compile your CSS, one thing’s for certain; it just makes life much easier. These preprocessors give us access to variables, necessary calculations, and powerful mixins that allow us to take our front-end workflow to the next level.

As time passes the projects I tackle tend to present questions that require unique answers — answers that don’t always need a PHP or programmatic approach; found in the lesser known (or utilized) parts of Sass: control directives. Similar to PHP or Javascript, Sass has if(), @if, @else, @else if, @for, @each, and @while that we can use to conditionally define or loop through styles using booleans or multiple variable checks. Why not save time and energy and make our compiler do the heavy lifting? You could even, in theory, automate the styles for an entire page or global elements. Let’s start off with the basics and end with a bang, then get into something more advanced.

if()

if() is a boolean expression that only returns one of two possible values: true or false, and it works like this.

if(true/false, true, false);

So a use case for this might be:

$boolean: false;

.text-color {
    $color: if($boolean, #000, #fff);
    color: $color;
} // .text-color

Which would output this:

.text-color {
    color: #fff;
} // .text-color

That’s pretty simple. I’ve found this useful when building two containers with same styles, with the exception that their colors are inverted. Using if() checks I can define either white or black depending on div-specific boolean variables.

@if and @else

@if is different than if(), though it is still a boolean, if() is a singular check, while @if evaluates a statement and runs code depending on the outcome. When used in conjunction with@else you can create a loop to allow for multiple checks for true as well as a default should all prior nested statements prove false.

Let’s build on the example above:

$text: #fff;
$boolean: false;

.text-color {

// Internal variables.
$color: if($boolean, #000, #fff);

// Determine background-color.
@if $text == #000 {
    background-color: #fff;
} @else {
    background-color: #000;
}

color: $color;
} // .text-color 

Notice here we’re using ==, but just like Javascript or PHP you have the whole list of operators to choose from including arithmetic (+ - * / %), equality (== !=), logical (and or not), and comparison (> >= < <=) to determine whether or not a statement is true or false.

Bonus: If you want to up your game check out string and color operations.

Which would output this CSS:

.text-color {
    background-color: #000;
    color: #fff;
} // .text-color

Though it does essentially the same thing, we allow for multiple conditionals and multiple possible outcomes with a few lines of code and one variable. A real time saver, and in my opinion, easier to read than a standard if() clause.

We can also do multiple @if checks with @else if, for example:

@if $text == #000 {
    background-color: #fff;
} @else if $text == #fc0 {
    background-color: #69ace5;
} @else if $text == #273143 {
    background-color: #ccc;
} @else {
    background-color: #000;
}

Tip: Remember that numbers, letters, and variables are case sensitive when doing checks.

@for

For those of you familiar with Javascript and jQuery, this might not be unfamiliar, but who knew?

@for can be used two ways looping from x “through” y or from x “to” y. “through” starts and iterates to and including the last item while “to” iterates and does not include that one last iteration.

Here’s a simple @for loop to help us generate helper classes for a grid framework:

@for $i from 1 through 4 {
    $width: 1 / $i;

    .col-#{$i} {
        width: $width;
    } // .col-#{$i}
} // end @for

This would output to:

.col-1 { width: 100%; }
.col-2 { width: 50%; }
.col-3 { width: 33.33%; }
.col-4 { width: 25%; }

Perhaps a more advanced usage might be to define the number of columns before you loop. You could also define mixins inside of the loop. Let’s take bourbon for instance.

$num-columns: 4;

@for $i from 1 through $num-columns {

    .col-#{$i} {
        @include span-columns( $num-columns / $i );
    } // .col-#{$i}
} // end @for

Would output to this:

.col-1 { 
    float: left;
    display: block;
    width: 100%;
}
.col-2 { 
    float: left;
    display: block;
    width: 48.8217%;
    margin-right: 2.35765%;
}
.col-3 { 
    float: left;
    display: block;
    margin-right: 2.35765%;
    width: 31.76157%;
}
.col-4 { 
    float: left;
    display: block;
    margin-right: 2.35765%;
    width: 23.23176%;
}

Note: If I was creating a grid, I might even add conditionals to make .col-1 output @include fill-parent; or even add &:nth-child(x);to remove the margin-right from the last item in a column row.

@each

each() works like you’d expect: @each $variable in <list or map>. You can loop through custom-defined class names to define a color or image (example below), which makes styling similar items a snap.

$type: action, western;

@each $movie in $type {
    .#{$movie}-container {
        background-image: url("assets/images/#{$movie}-bg.jpg");
    } // .#{$movie}-container
} // end @each

Output:

.action-container {
    background-image: url("assets/images/action-bg.jpg");
} // .action-container

.western-container {
    background-image: url("assets/images/western-bg.jpg");
} // .western-container

I would say, super helpful. You can go one step further and define multiple variables within a map.

$type: (action, #fc0), (western, #8a472c);

@each $movie, $color in $type {
    .#{$movie}-container {
        background-image: url("assets/images/#{$movie}-bg.jpg");
        color: $color;
    } // .#{$movie}-container
} // end @each

Which becomes:

.action-container {
    background-image: url("assets/images/action-bg.jpg");
    color: #fc0;
} // .action-container

.western-container {
    background-image: url("assets/images/western-bg.jpg");
    color: #8a472c;
} // .western-container

Using Sass maps is super helpful within loops. Check those out here.

@while

I rarely use @while loops. You can accomplish most everything you might need to achieve with @if or @each directives. That said, they are sometimes useful. Particularly within a @mixin since they run if a condition is met avoiding extra code.

$num: 4;

@while $num > 0 {
    .block-#{$num} {
        content: "#{$num}";
    } // .block-#{$num}
    
    // Reset loop and go again.
    $num: $num - 1;
} // end @while

This outputs:

.block-4 {
    content: "4";
} // .block-4

.block-3 {
    content: "3";
} // .block-3

.block-2 {
    content: "2";
} // .block-2

.block-1 {
    content: "1";
} // .block-1

Advanced Usage

Separately, any of these can be a major help, but you generate more markup to turn a @mixin into something like a function for Sass.

Here’s an example with documentation, which outputs a standard hamburger button.

//-----------------------------------------
// Make the Hamburger Icon
//-----------------------------------------
@mixin generate_hamburger($width, $height, $space, $color, $position, $radius, $speed) {    

  // Start variables.
  $gutter: $height + $space;
  
    // Determine position left right or center.
    @if $position == right {
        float: right;
    } @else if $position == left {
        float: left;
    } @else {
        margin-left: auto;
    margin-right: auto;
    }
    margin-bottom: $height + $space;
    margin-top: $height + $space;
    position: relative;
    text-indent: -9999em;
  
  // All bar sizes.
  &,
  &::before,
  &::after {
    background-color: $color;
    
    // Border radius?
    @if $radius != 0 {
      border-radius: $radius;
    }
    height: $height;
    transition: all $speed ease-in-out;
    width: $width;
  } // &, &::before, &::after
  
  // Top/bottom bars.
  &::before,
  &::after {
    content: "";
    left: 0;
    position: absolute;
  } // &::before, &::after
  
  // Top bar.
  &::before {
    top: -$gutter;
  } // &::before
  
  // Bottom bar.
  &::after {
    bottom: -$gutter;
  } // &::after
}

//-----------------------------------------
// Usage
//-----------------------------------------
.menu-toggle {
    @include generate_hamburger(30px, 5px, 5px, #000, null, 5px, 0.3s);
} // <div class="menu-toggle"></div>

You could take this even further to add a focus state with some animation doing like this. We’ll add a is-active class and some js to help us along.

//-----------------------------------------
// Make the Hamburger Icon
//-----------------------------------------
@mixin generate_hamburger($width, $height, $space, $color, $position, $radius, $speed) {    

  // Start variables.
  $gutter: $height + $space;
  
    // Determine position left right or center.
    @if $position == right {
        float: right;
    } @else if $position == left {
        float: left;
    } @else {
        margin-left: auto;
    margin-right: auto;
    }
    margin-bottom: $height + $space;
    margin-top: $height + $space;
    position: relative;
    text-indent: -9999em;
  
  // All bar sizes.
  &,
  &::before,
  &::after {
    background-color: $color;
    
    // Border radius?
    @if $radius != 0 {
      border-radius: $radius;
    }
    height: $height;
    transition: all $speed ease-in-out;
    width: $width;
  } // &, &::before, &::after
  
  // Top/bottom bars.
  &::before,
  &::after {
    content: "";
    left: 0;
    position: absolute;
  } // &::before, &::after
  
  // Top bar.
  &::before {
    top: -$gutter;
  } // &::before
  
  // Bottom bar.
  &::after {
    bottom: -$gutter;
  } // &::after
  
  // Active state.
  &.is-active{
    @include activate_hamburger(#675aac);
  } // &.is-active
}

// If active.
@mixin activate_hamburger($color) {

  // Top/bottom bars.
  &::before,
  &::after {
    background-color: $color;
  } // &::before, &::after

  // Top bar.
  &::before {
    top: -1px;
    transform: rotate(45deg);
  } // &::before

  // Bottom bar.
  &::after {
    bottom: 1px;
    transform: rotate(-45deg);
  } // &::after
}

//-----------------------------------------
// Usage
//-----------------------------------------
.menu-toggle {
    @include generate_hamburger(30px, 5px, 5px, #000, null, 5px, 0.3s);
} // <div class="menu-toggle"></div>

See the Pen Hamburger Mixins by jomurgel (@jomurgel) on CodePen.

Conclusion

Sometimes it’s the little things. With the goal to optimize load times, increase proficiency, and generate dynamic content easily, it’s a no-brainer that utilizing control directives in Sass is the way to go. At the very least, it can cut your dev time in half on certain tasks. I wholeheartedly recommend taking a deep dive into Sass and the power of if(), @if, @else, @else if, @for, @each, and @while.

We’d love to know how people use loops in new and exciting ways. Let us know in the comments below.

The post Get Loopy with Sass appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2017/02/07/get-loopy-sass/feed/ 0 16553
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
Using Sass Mixins to Power Your Projects https://webdevstudios.com/2016/03/01/using-sass-mixins-power-projects/ https://webdevstudios.com/2016/03/01/using-sass-mixins-power-projects/#respond Tue, 01 Mar 2016 17:34:25 +0000 http://webdevstudios.com/?p=12554 If you’ve followed along the WDS blog/Github/Twitter etc, you’ll know pretty well by now we’re a team that uses Sass as a part of our daily workflow for front-end styling. Sass is a powerful CSS preprocessor tool and it’s awesome. If you’re late to the game or new to front-end development there are lots of great Read More Using Sass Mixins to Power Your Projects

The post Using Sass Mixins to Power Your Projects appeared first on WebDevStudios.

]]>
If you’ve followed along the WDS blog/Github/Twitter etc, you’ll know pretty well by now we’re a team that uses Sass as a part of our daily workflow for front-end styling. Sass is a powerful CSS preprocessor tool and it’s awesome. If you’re late to the game or new to front-end development there are lots of great resources for getting started with Sass. 

Please note: This post will assume that you have at least a basic understanding of Sass and have used it at least a handful of times.

Today, we’ll be skipping over some of the basics like variables, nesting, and partials and get to some of the more intermediate working of Sass, specifically mixins, and we’ll touch on placeholders briefly as well. Mixins are a fantastic way to create and package blocks of reusable code so that you don’t have to continuously write out items that can become repetitive and sometime tedious (not to say they’re not important).

Before we completely dive into some cool mixins I’ve come across and libraries to checkout, I will quickly touch on placeholders vs. mixins. There’s been quite a bit of discussion around the web on the topic, but it’s a bit all over the place, so I wanted to cover some of what I found while doing some research for this post.

I think this first post by Hugo Giraudel speaks to front-end development work in general: “It depends.”

Hugo goes on to say:

The best advice would be: if you need variables, use a mixin. Otherwise, extend a placeholder. (placeholder vs mixin).

I think that’s solid advice and typically how I approach the topic as well. What’s also worth noting here is that Shay Howe did some pretty extensive research on the topic, the results of which I found as surprising as he did in his article, “Sass Mixins vs Extends the Data.”

It seems as though big picture, mixins create a bit more bloat in the compiled output and that they resulted in faster load time overall, which was interesting and seemed noteworthy as that’s an important detail not to be overlooked.

Despite that discovery, I still think both have their place and can be useful in certain projects. More or less, that puts us back to where we started–it depends on the project and situation, as always! With all front-end development, as long as it works, makes sense, and has been carefully thought through, there’s no reason not to use both in a given project from my perspective.

Here at WDS, we have several useful mixins included in our wd_s theme that are worth checking out. They’re particularly useful for our most common use cases. In this post, I will highlight some additional useful (less common) mixins that I’ve come across and used before. We haven’t necessarily included them in wd_s (at least not yet), because we intentionally keep things relatively lean there.

If you’re new to mixins, it would be wise to make sure you have a basic understanding. The following list is by no means comprehensive, but I tried to find a few that we’ve either used here at WDS or didn’t appear on every other list of “Top 10 Mixins that Should Be in Your Toolbox Post.” That’s not to say they won’t appear in other places–they are just not quite as common as breakpoint mixins or px to rem conversions.

Cross Browser Opacity Mixin

We all know cross browser compatibility is certainly improving with modern browsers, but even today, the struggle is real, and there are lots of projects that still require backwards compatibility for various reasons. This one should work all the way back to and including IE6.

@mixin opacity($opacity) {
    $opacity-ie: $opacity * 100;

    filter: alpha(opacity=$opacity-ie); //IE8
    opacity: $opacity;
}

//Usage
.faded-text {
    @include opacity(0.8);
}

Centering Mixin(including a new Fancier Version for Vertical/Horizontal/Both options)

Centering elements vertically, horizontally, or in some cases both axis, can always be a bit of a struggle for a variety of reasons. This mixin requires the parent element to have a position of relative to work and the mixin should be applied to the child element you’re trying to center vertically/horizontally or both. Here is the mixin–and be sure to check it out in its full glory on CSS-tricks.com.

@mixin center($horizontal: true, $vertical: true) {
    position: absolute;

    @if ($horizontal and $vertical) {
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
    } @else if ($horizontal) {
        left: 50%;
        transform: translate(-50%, 0);
    } @else if ($vertical) {
        top: 50%;
        transform: translate(0, -50%);
    }
}

Font Stack Mixin

This is particularly useful for combining fonts and font weights. I find this one super useful for when you have to manage multiple fonts and weights throughout a project. It’s also super useful also if you are working in a multilingual project and certain languages require different fonts within the same project. Hat tip to Stacy Kvernmo, the original creator of this.

Title Border

This may not be an everyday use case mixin, but it was used on a recent project and came in pretty handy considering the number of times we had to implement a partial title border that didn’t need to be flexible depending on which section of the site or particular page a user might be visiting. This particular version has a number of arguments you can pass through which was a nice touch and well done. Hat tip to fellow teammate Allison Tarr on this one.

// Title Border
// Apply a short border beneath a title
// Usage @mixin title-border(color);

@mixin title-border($color, $height, $width, $position) {

    @if $position == center {
        $position: 0 auto;
    } @else {
        $position: 0;
    }

    &:after {
        border-bottom: $height solid $color;
        content: '';
        display: block;
        margin: $position;
        padding-bottom: rem(15);
        width: $width;
    }
}

//Use Case:

.h1 {
    @include title-border($color, rem(5), rem(85), left);
}

Sticky Footer:

While poking around on CodePen, I came across this sticky footer mixin by Zoe Rooney. I quite like this and could see some practical use cases for this being used as we begin (hopefully) the trend away from hamburger menu for navigation. As mobile phone use continues to grow each month for everyday web browsing, this seems like a very practical application.

Tooltips:

Although I will say I’m not a super huge fan of tooltips, there are some fairly good use cases for them from time to time throughout a project so long as they’re not abused. This tooltip mixin uses only HTML and CSS(SCSS), and is a nice combination of a few mixins to make this a well done reality.

These are just a few mixins and use cases for them. In addition to these, and the ones in our wd_s starter theme, there are a number of libraries worth looking into as well for mixins and may already be incorporated into your workflow, like Bourbon.io (part of wd_s).

Some noteworthy libraries to also check out. Full disclosure: I’ve not thoroughly gone through all of these but they look worthy of investigating further: 

Sass mixins are undoubtedly powerful and useful for building all types of sites. Do you have any mixins that you particularly like or use often that you’ve found helpful for your own projects? If so, feel free to share them in the comments! We’d love to hear from you!

The post Using Sass Mixins to Power Your Projects appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2016/03/01/using-sass-mixins-power-projects/feed/ 0 12554
DIY: Twitter Share Counts (Part 1) https://webdevstudios.com/2016/01/14/diy-twitter-share-counts-part-1/ https://webdevstudios.com/2016/01/14/diy-twitter-share-counts-part-1/#comments Thu, 14 Jan 2016 12:00:03 +0000 http://webdevstudios.com/?p=12250 From time to time, you may get clients that want share counts to be displayed on their site. There are indeed SAAS (software as a service) services out there that do this for you, but what if a third party isn’t possible? Since Twitter dropped their JSON endpoint for share counts, a lot of people are looking Read More DIY: Twitter Share Counts (Part 1)

The post DIY: Twitter Share Counts (Part 1) appeared first on WebDevStudios.

]]>
From time to time, you may get clients that want share counts to be displayed on their site. There are indeed SAAS (software as a service) services out there that do this for you, but what if a third party isn’t possible? Since Twitter dropped their JSON endpoint for share counts, a lot of people are looking to these services, and most are commercial, offer a lot of bloat, and just do MORE than what you want. Instead, learn how to use the Twitter REST API to your advantage when counting your tweets.

Getting Started

To get going, you’re going to need two things at minimum. First and foremost, I’m not going to go into detail about how OAuth works, so for that we’ll use Abraham’s Oauth Library. If you don’t use composer, click the Manual Installation tab, and download it from his GitHub. Secondly, you’ll need a Twitter app. For this DIY, we’re going to be bending the REST API to do our bidding, and for that, you need an app. If you want to wing it and think you’ll be okay without instructions, here’s a handy link to get you there. If you’re not entirely sure how to register an app with Twitter, follow this blog post on iag.me which shows you how to register a Twitter app.

Once you make your app, go to ‘Keys and Access Tokens’ and note the following (you’ll need them in the code coming up):

  • Consumer Key
  • Consumer Secret
  • Access Token
  • Access Token Secret

On to the Code!!!

For the purposes of this tutorial, we’re going to use a simple singleton class. We know that for a definite we need a template tag to display the count. One other thing to keep in mind is Twitter’s rate limit; each API call has its own limits, so for this we’re going to use the GET search/tweets endpoint, which has a rate limit of 180 calls per fifteen minutes. Due to this rate limit, you want to make sure to cache the resulting count; for this I’m using transients, however, if you have a persistent cache like WP Engine, you may want to use wp_cache_get/set functions instead. So here’s our scaffolding:

<?php
class Twitter_Counts {

    /**
     * @var Twitter_Counts null
     */
    public static $instance = null;

    private function __construct() {
        // Fancy stuff.
    }

    public static function get_instance() {
        if ( is_null( self::$instance ) ) {
            self::$instance = new self;
        }
        return self::$instance;
    }

    public function tweet_count( $post_id ) {

    }
}

function Twitter_Counts() {
    return Twitter_Counts::get_instance();
}

function display_tweet_counts( $post_id = 0 ) {

    if ( empty( $post_id ) ) {
        $post_id = get_the_ID();
    }

    $cache_key = md5( 'twitter_counts_' . $post_id );
    $count = get_transient( $cache_key );

    if ( false == $count ) {

        $tc = Twitter_Counts();

        // ... do stuff

    }

    return $count;
}

Now that the scaffolding is setup, we need to start talking to Twitter with the OAuth library you downloaded. So setting it up is insanely easy (which is why I love this library):

require_once 'twitteroauth/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;

class Twitter_Counts {

    /**
     * @var Twitter_Counts null
     */
    public static $instance = null;

    private $consumer_key    = '';
    private $consumer_secret = '';
    private $access_token    = '';
    private $access_secret   = '';

    private function __construct() {
        // Fancy stuff.
    }

    public static function get_instance() {
        if ( is_null( self::$instance ) ) {
            self::$instance = new self;
        }
        return self::$instance;
    }

    public function tweet_count( $post_id ) {

        $oauth = new TwitterOAuth( $this->consumer_key, $this->consumer_secret, $this->access_token, $this->access_secret );

    }
}

If you are using Composer, you can ignore the first two lines. For me, I downloaded the library into a twitteroauth folder. Below that, you’ll see that there are new private variables. Since these are basically like passwords, it’s best if they’re inaccessible to anyone but the main class (although of course your requirements may be different and you’ll have to accommodate for that accordingly). Here is where those app values you copied from Twitter will come in handy; you’ll need to fill in these variables.

Line 29 is where the values are used. This literally does the OAuth handshake for you, and now all we have to do is make the request we want and process the results.

Getting the Data

Using the OAuth library makes it simple to do get requests. If you want to know all the parameters for the endpoint we’re using, you’ll need to consult the official search/tweets endpoint documentation. For now, we only need to worry about q, count, and include_entities.

Since we’re using the search endpoint, we need to search something unique to the page we’re looking at, or wanting counts for, that would be included in the tweet. Can’t get much more unique than the URL, right? We also want to return as many results as possible, this will help us in possibly going around the rate limit (unless you have a page with a million likes). For this, we set count to 100. Finally, we want to make sure to include Entities, since from what I can tell, those include the original URL prior to it being converted to the t.co shortener.

The code should look something like this:

    public function tweet_count( $post_id ) {

        $defaults = array(
            'q'                => get_permalink( $post_id ),
            'count'            => 100,
            'include_entities' => true,
        );

        $oauth = new TwitterOAuth( $this->consumer_key, $this->consumer_secret, $this->access_token, $this->access_secret );

        $statuses = $oauth->get( 'search/tweets', $defaults );

    }

So what about counts?

Looking at the results on the official documentation you’ll see that you get back a JSON object. A quite large one in fact, but don’t let that scare you, in the end, it’s all data, and we tell it what to do! So what do we do? Well, since the JSON data is keyed, you’ll see the main key we’re concerned with, statuses. Lastly we should also check if the property is available after the transformation by using an isset check.

Having as many checks as necessary prevents your debug log filling up. Alternatively, if you want to log these errors, you can do so in a much nicer manner. For that, you should read my other post on Debugging WordPress Tips and Snippets.

Now that we got those checks out of the way, it’s a simple as running count() over the statuses. The code goes like so:

    public function tweet_count( $post_id ) {

        $defaults = array(
            'q'                => get_permalink( $post_id ),
            'count'            => 100,
            'include_entities' => true,
        );

        $oauth = new TwitterOAuth( $this->consumer_key, $this->consumer_secret, $this->access_token, $this->access_secret );

        $statuses = $oauth->get( 'search/tweets', $defaults );

        if ( ! $statuses ) {
            return false;
        }
        
        if ( ! isset( $statuses->statuses ) ) {
            error_log( __LINE__ );
            return false;
        }

        return count( $statuses->statuses );
    }

The Finish Line

Now we have to wrap up–this is the simple part! Here we need to update our display_tweet_counts() template tag to actually use our tweet counting method. Since our count method can return a boolean value (true/false) we want to check for that and set the count to zero if there was a problem. Otherwise, we want to use the actual value.

So here’s the full code:

require_once 'twitteroauth/autoload.php';
use Abraham\TwitterOAuth\TwitterOAuth;

class Twitter_Counts {

    /**
     * @var Twitter_Counts null
     */
    public static $instance = null;

        // You'll need to fill these in with your own data.
    private $consumer_key    = '';
    private $consumer_secret = '';
    private $access_token    = '';
    private $access_secret   = '';

    private function __construct() {
        // Fancy stuff.
    }

    public static function get_instance() {
        if ( is_null( self::$instance ) ) {
            self::$instance = new self;
        }
        return self::$instance;
    }

    public function tweet_count( $post_id ) {

        $defaults = array(
            'q'                => get_permalink( $post_id ),
            'count'            => 100,
            'include_entities' => true,
        );

        $oauth = new TwitterOAuth( $this->consumer_key, $this->consumer_secret, $this->access_token, $this->access_secret );

        $statuses = $oauth->get( 'search/tweets', $defaults );

        if ( ! $statuses ) {
            return false;
        }

        if ( ! isset( $statuses->statuses ) ) {
            return false;
        }

        return count( $statuses->statuses );
    }
}

function Twitter_Counts() {
    return Twitter_Counts::get_instance();
}

function display_tweet_counts( $post_id = 0 ) {

    if ( empty( $post_id ) ) {
        $post_id = get_the_ID();
    }

    $cache_key = md5( 'twitter_counts_' . $post_id );
    $count = get_transient( $cache_key );

    if ( false == $count ) {
        $tc = Twitter_Counts();
        $result = $tc->tweet_count( $post_id );
        $count = false == $result ? 0 : $result;
        set_transient( $cache_key, $count, 1 * HOUR_IN_SECONDS );
    }

    return $count;
}

What about pages with 100+ shares?

That comes in part two, so stay tuned! In part two, we’re going to get into recursion, and how to walk over the results page-by-page. Keep an eye out for the second installment, and let me know if you have any questions!

The post DIY: Twitter Share Counts (Part 1) appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2016/01/14/diy-twitter-share-counts-part-1/feed/ 6 12250
The Future of JavaScript: ECMAScript 6 and You https://webdevstudios.com/2015/06/30/the-future-of-javascript/ https://webdevstudios.com/2015/06/30/the-future-of-javascript/#comments Tue, 30 Jun 2015 17:50:16 +0000 http://webdevstudios.com/?p=11376 Today, JavaScript fills every aspect of our online lives: it checks your e-mail in the background, it guides your online shopping cart, and it even autosaves your blog post as you write. From the client to the server, JavaScript is everywhere. Sometimes it’s hard to remember that this wasn’t always the case. When I started writing basic Read More The Future of JavaScript: ECMAScript 6 and You

The post The Future of JavaScript: ECMAScript 6 and You appeared first on WebDevStudios.

]]>
Today, JavaScript fills every aspect of our online lives: it checks your e-mail in the background, it guides your online shopping cart, and it even autosaves your blog post as you write. From the client to the server, JavaScript is everywhere. Sometimes it’s hard to remember that this wasn’t always the case.

When I started writing basic web pages in the late 90’s, “DHTML” was the acronym describing the use of JavaScript, HTML, and CSS; the “D” stood for “Dynamic.” DHTML sites were heavy and sluggish, yet they showcased the power of JavaScript (or JScript, depending on who you asked). They also served as a reminder of why many developers shied away from JavaScript at the time: it was resource-intensive, and implementations varied from browser to browser. At the time, I only knew a handful of people who did any kind of web development–we were, after all, more concerned with the issues of how much AP courses “sucked” and whether or not we could get tickets to see Blink 182. For us, the consensus was that JavaScript was for show, and any website could do what it needed to do without it.

JavaScript has now made a name for itself as the go-to for interactive sites. Gone are the days of full-page Flash applications, Shockwave Player, and Java as a general “necessity” for the web. JavaScript has even found it’s way onto the server with projects such as Node.js. Automation of screenshots, converting web pages to PDF, or headless testing can all be achieved from the command link using PhantomJS, a headless implementation of the WebKit engine. On the wider web, JavaScript gives us the little spinner that eventually leads to a table of search results populating without a page reload, or dragging-and-dropping an image to upload it to Imgur. Even some of the apps on the smartphones in pockets around the world use JavaScript. It’s no longer just for hobbyists or experimentation – knowing JavaScript is a part of the job.

Which brings us to ECMAScript 6, or ES6. JavaScript is an implementation of ECMAScript, which also covers languages such as ActionScript, JScript, QtScript, and many others. ES6, codenamed “Harmony,” has been in the works since 2008 and periodic drafts have been published since 2011. This month, June 2015, ECMAScript 6 was formally announced and released and includes a lot of new and interesting tidbits for developers of the modern web.

Below I hope to cover some of the new features, but by no means all of them, as that would be far beyond the scope of this post. For more information, you can check out the full specification PDF to get a look at all of the stuff coming to a browser near you.

Author’s note: the following will include some code examples – some modern browsers may still not recognize certain keywords or agree with their use. For instance, Chrome requires “use strict” to make use of the “let” keyword.

Constants

A simple idea in many languages, Constants have been absent in JavaScript until now. In programming, a constant is similar to a variable, in that you assign a value to an identifier, but differs in that it can never be changed throughout execution of the program. An example in PHP:

define('APPLICATION_VERSION', '1.2.0.4332');
echo APPLICATION_VERSION; // 1.2.0.4332
define('APPLICATION_VERSION', '1.3'); 
// Notice: Constant APPLICATION_VERSION already defined
echo APPLICATION_VERSION; // 1.2.0.4332

The constant APPLICATION_VERSION is defined and can never be altered, and PHP will let you know that if you try (and your error reporting is on). Attempts to redefine the constant will fail, and the original value will hold true. In Javascript, this was previously achieved by the clunky mechanism of defining a new Object property–this was only available in ES5, and only in the global scope. With ES6, things get a lot easier:

const APPLICATION_VERSION = '1.2.0.4332';
console.log(APPLICATION_VERSION); // '1.2.0.4332'
APPLICATION_VERSION = '1.3.0'; // "1.3.0"
console.log(APPLICATION_VERSION); // '1.2.0.4332'
// Notice that the Chrome console evaluated the assignment
// on line 3, however the value didn't change

If we try to actually redefine the constant we get an error:

JavaScript constant redefinition

 

While a simple addition, the introduction of constants to JavaScript shows that the language is maturing in a way that will be welcome by many programmers.

How about something a little more interesting?

Default Parameter Values

If you have programmed in JavaScript, you’ve dealt with all of the ways in which default parameters can be mimicked in the language:

// The "if" way
function say_hi(iterations, greeting, name) {
    if( iterations === undefined ) {
        iterations = 5;
    }

    if( greeting === undefined ) {
        greeting = 'Hello';
    }

    if( name === undefined ) {
        name = 'World';
    }

    for ( var i = 0; i < iterations; i++ ) {
        console.log( greeting + ', ' + name );
    }
}

// The "||" way
function say_hi(iterations, greeting, name) {
    iterations = iterations || 5;
    greeting = greeting || 'Hello';
    name = name || 'World';

    for ( var i = 0; i < iterations; i++ ) {
        console.log( greeting + ', ' + name );
    }
}

// The jQuery "extend" way
function say_hi(args) {
    var params = {};
    var defaults = {
        iterations: 5,
        greeting: 'Hello',
        name: 'World'
    };
    
    jQuery.extend(params, defaults, args);

    for ( var i = 0; i < params.iterations; i++ ) {
        console.log( params.greeting + ', ' + params.name );
    }
}

Above we have several methods to handle “default parameters,” none of which are really ideal. The first method is clunky, the second method is cleaner but not necessarily self-explanatory (especially to novice programmers), and the third method uses jQuery’s “extend” method–this is a great way to define a default set of options in an arguments object, but this also obfuscates the intent of the function – you wouldn’t know it took those arguments just by looking at the method signature, and seeing it in use without one of the object properties defined would leave you oblivious to the fact that you could pass that property without reading the documentation or diving into the source.

ES6 introduces default variables in a way that should be familiar to most programmers. The new method is clean and readable:

function say_hi( iterations = 5, greeting = 'Hello', name = 'World' ) {
    for ( var i = 0; i < iterations; i++ ) {
        console.log( greeting + ', ' + name );
    }
}

At the time of writing, this only works in Firefox (versions 15 and on support basic defaults, while versions 26 and 41 introduce more complex usage). Chrome has an open support ticket to implement this feature in the V8 JavaScript engine, and any browser working towards ES6 should be following suit.

String Interpolation

Something I’ve done for a long time, templating with strings, usually requires custom functionality, regular expressions, and somewhat clunky code. The separation of template and data can hide how things tie together. Here’s an example done with an Ext.JS-like templating function:

function tpl( data, template ) {
    var r = new RegExp();

    for ( var key in data ) {
        if ( ! data.hasOwnProperty( key ) ) {
            continue;
        }

        r.compile( '{' + key + '}', 'g' );
        template = template.replace( r, data[ key  ] );
    }

    return template;
}

var myTplData = {
    name: 'John Smith',
    address: '4124 Rasperry Lane',
    city: 'Heartford',
    state: 'CT'
};

var myTpl = [
    '<div>',
        '<strong>Name: </strong> {name} <br/>',
        '<strong>Street Address: </strong> {address} <br/>',
        '<strong>City, State: </strong> {city}, {state} <br/>',
    '</div>'
].join("\n");

console.log( tpl( myTplData, myTpl ) );

/**
<div>
<strong>Name: </strong> John Smith <br/>
<strong>Street Address: </strong> 4124 Rasperry Lane <br/>
<strong>City, State: </strong> Heartford, CT <br/>
</div>
 */

The above code isn’t exactly great, and rather simple. When you look at Ext.JS’s XTempalte, you see just how much complexity gets added to what sounds like a straightforward concept. Other libraries provide their own methods of binding data to templates, but ES6 can at least begin to replace some of this functionality with an easier approach:

var myTplData = {
    name: 'John Smith',
    address: '4124 Rasperry Lane',
    city: 'Heartford',
    state: 'CT'
};

var myTpl = `
    <div>
        <strong>Name: </strong> ${myTplData.name} <br/>,
        <strong>Street Address: </strong> ${myTplData.address} <br/>,
        <strong>City, State: </strong> ${myTplData.city}, ${myTplData.state} <br/>
    </div>`;

console.log( myTpl );

/**
<div>
    <strong>Name: </strong> John Smith <br/>,
    <strong>Street Address: </strong> 4124 Rasperry Lane <br/>,
    <strong>City, State: </strong> Heartford, CT <br/>
</div>
 */

This completely removes the need for Regular Expressions, and carries a syntax somewhat familiar to those who use PHP and other languages. Integration of variables and strings has been long overdue for JavaScript, so it’s good to see ES6 finally make a change.

And More…

These are just a few of the myriad features coming in ECMAScript 6. While some of these exist in current browser implementations (notably Chrome and Firefox), we likely won’t see the full specification implemented for a few months, and adoption across the board will likely take much longer. That doesn’t mean there aren’t more things to look into and get excited about, such as MapsClassesIterators and Generators, and more.

The post The Future of JavaScript: ECMAScript 6 and You appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2015/06/30/the-future-of-javascript/feed/ 1 11376
Create Simple Inline Media Queries with include-media https://webdevstudios.com/2015/05/18/create-simple-inline-media-queries-include-media/ https://webdevstudios.com/2015/05/18/create-simple-inline-media-queries-include-media/#respond Mon, 18 May 2015 17:04:13 +0000 http://webdevstudios.com/?p=11231 Lately, I’ve been thinking that our current method of using inline media queries throughout our Sass partials has not been flexible enough for the projects we’ve been building. While it was simple and allowed for easy implementation, I think it is time to try yet another Sass library–specifically include-media. Eduardo Bouças, developer of include-media, states Read More Create Simple Inline Media Queries with include-media

The post Create Simple Inline Media Queries with include-media appeared first on WebDevStudios.

]]>
Lately, I’ve been thinking that our current method of using inline media queries throughout our Sass partials has not been flexible enough for the projects we’ve been building. While it was simple and allowed for easy implementation, I think it is time to try yet another Sass library–specifically include-media.

Eduardo Bouças, developer of include-media, states on the website:

“include-media is a Sass library for writing CSS media queries in an easy and maintainable way, using a natural and simplistic syntax.”

Simple, Natural Syntax

While there are many libraries out there to choose from, I really enjoy the syntax used by include-media. When writing code, it is always helpful to be able to translate what you are writing to your native language (in your head, of course).

Operators, FTW

I love using the operators as it is so simple to see what is taking place. Many media query libraries do not take into account the max value of the smaller breakpoint and the minimum value of the larger one, which means both media queries will be active at that same time potentially causing conflict. Having the ability to use the >= (greater than or equal to) or <= (less than or equal to) is very exciting.

BYOB

Bring your own Breakpoint names and values! By default, include-media will help you get started with the following:

$breakpoints: (
    phone: 320px,
    tablet: 768px,
    desktop: 1024px
);

I recommend that you redeclare these breakpoints based on when your content actually needs a breakpoint. You can also use your own naming conventions as well if device name is not your thing. To redefine your breakpoints, use the same Sass Map syntax. include-media can accept px, em or rem units:

$breakpoints: (
    phone: 24em,
    tablet: 50em,
    desktop: 72em
);

Now let’s put these babies to use:

.primary {
     // look at me, I’m mobile first and full width
    width: 100%;    

    // then when I reach a point where my main content area may be too wide
    // we can now call in our breakpoint
    @include media(">phone", "<=tablet") {
        width: 35%;
    }
}

How simple is that? I love speakable code.

Custom Values

Do you need an on-the-go breakpoint for those one-off situations? I am in favor of making variables for as many values as possible, but if that is your style this is for you:

@include media(">desktop", "<=2600px") {
    content: 'Why is your browser so wide?';
}

Supports Media Types and Static Expressions

You can target media types screen, print, handheld the same way you’d target a size:

.primary {
    content: 'screens are awesome';

    @include media("print") {
        content: 'people print websites?';
    }
} 

Or target retina screens:

.primary {
    // I’m a regular sized logo
    background-image: url(images/logo.png);

    // I’m a SUPER logo for pretty retina screens
    @include media("retina2x") { 
        background-image: url(images/logo@2x.png);    
    }
}

Couple of Caveats

  • include-media may not work as expected if you are using other libraries that have a mixin named ‘media’, like Bourbon Neat.
  • I really would love the ability to target height as well and that may be a feature that is currently being developed.

Give it a Try

To get started, you can either download the single scss file and @import it to your project manually or you can install via Bower:

bower install include-media

and import dist/_include-media.scss into your project.

Further Reading

The post Create Simple Inline Media Queries with include-media appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2015/05/18/create-simple-inline-media-queries-include-media/feed/ 0 11231
Use CMB2 to Create a New Post Submission Form https://webdevstudios.com/2015/03/30/use-cmb2-to-create-a-new-post-submission-form/ https://webdevstudios.com/2015/03/30/use-cmb2-to-create-a-new-post-submission-form/#comments Mon, 30 Mar 2015 17:32:09 +0000 http://webdevstudios.com/?p=10907 Here at WebDevStudios, we try to use CMB2 for pretty much anything form or field related. We do this for several reasons: It saves us time. It’s a framework that handles a lot of the nitty-gritty for us (creating markup, handling sanitizing, escaping and saving data, etc). It provides a lot of power. We can Read More Use CMB2 to Create a New Post Submission Form

The post Use CMB2 to Create a New Post Submission Form appeared first on WebDevStudios.

]]>
Here at WebDevStudios, we try to use CMB2 for pretty much anything form or field related.

We do this for several reasons:

  1. It saves us time. It’s a framework that handles a lot of the nitty-gritty for us (creating markup, handling sanitizing, escaping and saving data, etc).
  2. It provides a lot of power. We can build awesome things quicker because CMB2 exists.
  3. We’re eating our own dogfood so that we can continue to hone the tool and make it as helpful as possible (see #1 & #2).

it's free software!

One of the cool and powerful ways we have used CMB2 is for creating front-end submission forms for our users. Traditionally we (and I’m sure many of you) have used Gravity Forms as your go-to front-end form solution. No doubt Gravity Forms is an incredible tool, but we decided for some use-cases, it isn’t the right tool.

For example, if I want to provide a front-end blog post (or other post-type) submission form, I want to avoid Gravity Forms. With a submission form like that, you generally want full control of how it looks, when/where it should display and where the data goes when submitted. You probably don’t want that form created in wp-admin where the site’s owner or users can edit it. Enter CMB2.

I’m going to walk you through how to create a front-end submission form with CMB2.

First step, we need to register our form. This is standard form and field registration:

/**
 * Register the form and fields for our front-end submission form
 */
function wds_frontend_form_register() {
    $cmb = new_cmb2_box( array(
        'id'           => 'front-end-post-form',
        'object_types' => array( 'post' ),
        'hookup'       => false,
        'save_fields'  => false,
    ) );

    $cmb->add_field( array(
        'name'    => __( 'New Post Title', 'wds-post-submit' ),
        'id'      => 'submitted_post_title',
        'type'    => 'text',
        'default' => __( 'New Post', 'wds-post-submit' ),
    ) );

    $cmb->add_field( array(
        'name'    => __( 'New Post Content', 'wds-post-submit' ),
        'id'      => 'submitted_post_content',
        'type'    => 'wysiwyg',
        'options' => array(
            'textarea_rows' => 12,
            'media_buttons' => false,
        ),
    ) );

    $cmb->add_field( array(
        'name'       => __( 'Featured Image for New Post', 'wds-post-submit' ),
        'id'         => 'submitted_post_thumbnail',
        'type'       => 'text',
        'attributes' => array(
            'type' => 'file', // Let's use a standard file upload field
        ),
    ) );

    $cmb->add_field( array(
        'name' => __( 'Your Name', 'wds-post-submit' ),
        'desc' => __( 'Please enter your name for author credit on the new post.', 'wds-post-submit' ),
        'id'   => 'submitted_author_name',
        'type' => 'text',
    ) );

    $cmb->add_field( array(
        'name' => __( 'Your Email', 'wds-post-submit' ),
        'desc' => __( 'Please enter your email so we can contact you if we use your post.', 'wds-post-submit' ),
        'id'   => 'submitted_author_email',
        'type' => 'text_email',
    ) );

}
add_action( 'cmb2_init', 'wds_frontend_form_register' );

As you can see, we’ve used the new CMB2 form and field registration API to register our front-end form and fields. We also used a new parameter from version 2.0.3: 'save_fields' => false. This prevents CMB2 from saving the fields, so we can do what we want with the submission.

We added fields for the post title, post content, and optional fields for the featured image, contributor name, and contributor email. The first item in the 'object_types' array will be used for the new post submission 'post_type'.

Now that we have our form registered, let’s go ahead and register a shortcode handler for our front-end submission form. This adds flexibility as the site owner can place this shortcode anywhere they want. We’ll also allow a few shortcode attributes that we’ll cover later.

/**
 * Handle the cmb-frontend-form shortcode
 *
 * @param  array  $atts Array of shortcode attributes
 * @return string       Form html
 */
function wds_do_frontend_form_submission_shortcode( $atts = array() ) {

    // Current user
    $user_id = get_current_user_id();

    // Use ID of metabox in wds_frontend_form_register
    $metabox_id = 'front-end-post-form';

    // since post ID will not exist yet, just need to pass it something
    $object_id  = 'fake-oject-id';

    // Get CMB2 metabox object
    $cmb = cmb2_get_metabox( $metabox_id, $object_id );

    // Get $cmb object_types
    $post_types = $cmb->prop( 'object_types' );

    // Parse attributes. These shortcode attributes can be optionally overridden.
    $atts = shortcode_atts( array(
        'post_author' => $user_id ? $user_id : 1, // Current user, or admin
        'post_status' => 'pending',
        'post_type'   => reset( $post_types ), // Only use first object_type in array
    ), $atts, 'cmb-frontend-form' );

    // Initiate our output variable
    $output = '';

    // Our CMB2 form stuff goes here

    return $output;
}
add_shortcode( 'cmb-frontend-form', 'wds_do_frontend_form_submission_shortcode' );

So we’ve registered our shortcode, cmb-frontend-form and supplied a callback, wds_do_frontend_form_submission_shortcode. Because our shortcode can accept a few attributes, we’re passing in the $atts array. This will be the array of attributes already parsed out for us by WordPress (if the shortcode has any attributes).

Next, you follow the inline comments to see what is happening.

We are:

  1. Getting the currently logged-in user’s ID (This will be the default post-author user ID for the new post).
  2. Creating our $metabox_id variable. It is the same value as the 'id' parameter we used when registering our metabox/form.
  3. Creating our $object_id variable. This looks hokey, but it allows us to prevent CMB2 from auto-magically finding an object id (which could end up being the post ID of the page the form lives on.. not what we want!). This will ensure that the form remains empty.
  4. Retrieving our $cmb metabox instance by passing the metabox/form id we registered in our first snippet, 'front-end-post-form'.
  5. Retrieving the 'object_types' property from the $cmb object. This object type will be the default 'post_type' for the new post submission (unless overridden by the shortcode attributes).
  6. Parsing the shortcode attributes. We’ll explain in a bit.
  7. Creating an empty $output variable that we’ll be appending (concatenating) too.

To parse the shortcode attributes, we use the shortcode_atts function. This function, according to the Codex, “…Combines user shortcode attributes with known attributes and fills in defaults when needed. The result will contain every key from the known attributes, merged with values from shortcode attributes.”

This allows us to specify some default attributes for our shortcode. In our case, our default 'post_author' for the submitted post will be the currently logged-in user or 1, the default submitted post’s status will be 'pending' and the default submitted post’s 'post_type' will be 'post'. If I wanted, I can change all those attributes by modifying the shortcode in my content like so: [cmb-frontend-form post_author=2 post_status="draft" post_type="page"].

Next, let’s add our CMB2 form to the shortcode output. We’re going to ‘zoom in’ a bit with our snippet. At the end, we’ll put it all together.

/**
 * Handle the cmb-frontend-form shortcode
 *
 * @param  array  $atts Array of shortcode attributes
 * @return string       Form html
 */
function wds_do_frontend_form_submission_shortcode( $atts = array() ) {

    // ... Previous function code omitted for brevity

    // Initiate our output variable
    $output = '';

    // Get our form
    $output .= cmb2_get_metabox_form( $cmb, $object_id, array( 'save_button' => __( 'Submit Post', 'wds-post-submit' ) ) );

    return $output;
}
add_shortcode( 'cmb-frontend-form', 'wds_do_frontend_form_submission_shortcode' );

With that new line, we’re actually retrieving the CMB2 form markup. The parameters we pass to the cmb2_get_metabox_formfunction include the $cmb object we just retrieved, the fake post id we created, and an array of arguments we want to override in the cmb2_get_metabox_form function. In our case, we only want to override the text of the 'save_button' to more accurately reflect what the button will be doing.

So now we have a form on the page, which is pretty exciting. At this point, you may want to take some time to add some custom styles to your theme’s stylesheet to make the form look how you want. But there is a key flaw: the form will not do anything when we submit. Our 'save_fields' => false ensures that. So let’s go ahead and create our submission handler.

/**
 * Handles form submission on save
 *
 * @param  CMB2  $cmb       The CMB2 object
 * @param  array $post_data Array of post-data for new post
 * @return mixed            New post ID if successful
 */
function wds_handle_frontend_new_post_form_submission( $cmb, $post_data = array() ) {

    // If no form submission, bail
    if ( empty( $_POST ) ) {
        return false;
    }

    // check required $_POST variables and security nonce
    if (
        ! isset( $_POST['submit-cmb'], $_POST['object_id'], $_POST[ $cmb->nonce() ] )
        || ! wp_verify_nonce( $_POST[ $cmb->nonce() ], $cmb->nonce() )
    ) {
        return new WP_Error( 'security_fail', __( 'Security check failed.' ) );
    }

    if ( empty( $_POST['submitted_post_title'] ) ) {
        return new WP_Error( 'post_data_missing', __( 'New post requires a title.' ) );
    }

    // Do WordPress insert_post stuff

    return $new_submission_id;
}

Our post-submission handler function, wds_handle_frontend_new_post_form_submission‘ takes two arguments, a CMB2 object, and an optional array of post data for the inserted post.

The first step is to check if the form has even been submitted. If not, we bail out early. If so, then we verify that all the security pieces are in place as well as the required post data. We’re requiring the user to at least submit a title for their post. If all goes well, we’re now ready to create our new post.

Now, let’s leverage a new method, get_sanitized_values, to sanitize the array of fields data submitted, We’ll pass it the $_POSTvariable. Once the values have been properly sanitized, let’s set our new post’s title and content from those fields and insert it!

/**
 * Handles form submission on save
 *
 * @param  CMB2  $cmb       The CMB2 object
 * @param  array $post_data Array of post-data for new post
 * @return mixed            New post ID if successful
 */
function wds_handle_frontend_new_post_form_submission( $cmb, $post_data = array() ) {

    // ... Previous function code omitted for brevity

    // Fetch sanitized values
    $sanitized_values = $cmb->get_sanitized_values( $_POST );

    // Set our post data arguments
    $post_data['post_title']   = $sanitized_values['submitted_post_title'];
    unset( $sanitized_values['submitted_post_title'] );
    $post_data['post_content'] = $sanitized_values['submitted_post_content'];
    unset( $sanitized_values['submitted_post_content'] );

    // Create the new post
    $new_submission_id = wp_insert_post( $post_data, true );

    // If we hit a snag, update the user
    if ( is_wp_error( $new_submission_id ) ) {
        return $new_submission_id;
    }

    return $new_submission_id;
}

Ok, Let’s handle the featured image and custom post meta for the new post:

/**
 * Handles form submission on save
 *
 * @param  CMB2  $cmb       The CMB2 object
 * @param  array $post_data Array of post-data for new post
 * @return mixed            New post ID if successful
 */
function wds_handle_frontend_new_post_form_submission( $cmb, $post_data = array() ) {

    // ... Previous function code omitted for brevity

    // If we hit a snag, update the user
    if ( is_wp_error( $new_submission_id ) ) {
        return $new_submission_id;
    }

    /**
     * Other than post_type and post_status, we want
     * our uploaded attachment post to have the same post-data
     */
    unset( $post_data['post_type'] );
    unset( $post_data['post_status'] );

    // Try to upload the featured image
    $img_id = wds_frontend_form_photo_upload( $new_submission_id, $post_data );

    // If our photo upload was successful, set the featured image
    if ( $img_id && ! is_wp_error( $img_id ) ) {
        set_post_thumbnail( $new_submission_id, $img_id );
    }

    // Loop through remaining (sanitized) data, and save to post-meta
    foreach ( $sanitized_values as $key => $value ) {
        update_post_meta( $new_submission_id, $key, $value );
    }

    return $new_submission_id;
}

You can see we’re using a helper function, wds_frontend_form_photo_upload, (which is just a wrapper for media_handle_upload). It’s not directly related to CMB2, so I won’t go over it here, but I’ll include it in the final code snippet.

After we upload our image to the new post, if all went well, we’ll make that image the post’s featured image (set_post_thumbnail).

And finally, we’ll loop through the rest of the sanitized field values and save them as post meta.

Now that we have our custom save handler, we need to incorporate it back into our shortcode handler function, wds_do_frontend_form_submission_shortcode.

/**
 * Handle the cmb-frontend-form shortcode
 *
 * @param  array  $atts Array of shortcode attributes
 * @return string       Form html
 */
function wds_do_frontend_form_submission_shortcode( $atts = array() ) {

    // ... Previous function code omitted for brevity

    // Initiate our output variable
    $output = '';

    // Handle form saving (if form has been submitted)
    $new_id = wds_handle_frontend_new_post_form_submission( $cmb, $atts );

    if ( $new_id ) {

        if ( is_wp_error( $new_id ) ) {

            // If there was an error with the submission, add it to our ouput.
            $output .= '<h3>' . sprintf( __( 'There was an error in the submission: %s', 'wds-post-submit' ), '<strong>'. $new_id->get_error_message() .'</strong>' ) . '</h3>';

        } else {

            // Get submitter's name
            $name = isset( $_POST['submitted_author_name'] ) && $_POST['submitted_author_name']
                ? ' '. $_POST['submitted_author_name']
                : '';

            // Add notice of submission
            $output .= '<h3>' . sprintf( __( 'Thank you %s, your new post has been submitted and is pending review by a site administrator.', 'wds-post-submit' ), esc_html( $name ) ) . '</h3>';
        }

    }

    // Get our form
    $output .= cmb2_get_metabox_form( $cmb, $object_id, array( 'save_button' => __( 'Submit Post', 'wds-post-submit' ) ) );

    return $output;
}
add_shortcode( 'cmb-frontend-form', 'wds_do_frontend_form_submission_shortcode' );

You can see, right after we intiate our $output variable, and just before we use cmb2_get_metabox_form to retrieve our form markup, we’re using our new wds_handle_frontend_new_post_form_submission function to save any submitted post entries. If it saves the post, it will return the new post ID, but if it hit a snag, will return a WP_Error object.

So if we got a response back from our save handler, we’re going to output a message to the user. If the submission process hit a snag, the user will be alerted with the proper error message (and otherwise be given a ‘success’ message). These messages get appended to the $output variable before the form markup so that they will show up at the top of the form.

One issue with this method is that if user hits refresh after submitting post, a new post will continue to be submitted. You should probably either check for an existing post with the submitted data BEFORE doing wp_insert_post, or implement a redirect when the form is submitted, but I’ll have to cover that another time. (Update 5/23/15: The snippet has been updated to now redirect on successful submission, woot!)

And there you have it! A flexible front-end submission form that you can use to generate new posts (or other post-types). You can use this for all kinds of ideas. Maybe you want a movie review site–just change the registered fields for your form to reflect the kind of data you would want for that review. Title, content, rating, submitter’s name/email, etc. You can see there is a lot of flexibility!

You can find the entire snippet at the CMB2 Snippet Library. If you haven’t yet checked out the CMB2 Snippet Library, you definitely should! There are a lot of tips and tricks (like this one!) throughout.

The post Use CMB2 to Create a New Post Submission Form appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2015/03/30/use-cmb2-to-create-a-new-post-submission-form/feed/ 84 10907
Create a Filterable Portfolio with WordPress and Jetpack https://webdevstudios.com/2015/01/27/create-a-filterable-portfolio-with-wordpress-and-jetpack/ https://webdevstudios.com/2015/01/27/create-a-filterable-portfolio-with-wordpress-and-jetpack/#comments Tue, 27 Jan 2015 21:36:04 +0000 http://webdevstudios.com/?p=10509 Have you ever wanted to add a filterable portfolio to your personal site to showcase your content? In this post, we’re going to include simple scripts for you to add to your existing theme to help make it easy to add a filterable portfolio to your project. Tools you’ll need: WordPress, installed and ready to Read More Create a Filterable Portfolio with WordPress and Jetpack

The post Create a Filterable Portfolio with WordPress and Jetpack appeared first on WebDevStudios.

]]>
Have you ever wanted to add a filterable portfolio to your personal site to showcase your content? In this post, we’re going to include simple scripts for you to add to your existing theme to help make it easy to add a filterable portfolio to your project.

Tools you’ll need:

Notes on Isotope:

The great thing about Isotope is that it is GPL licensed for Open Source projects. However, if your site is a commercial project, I would highly recommend purchasing a commercial license. This will help the developer to continue to support Isotope.

Step 1:

The first thing we need to do is setup Jetpack and enable the ‘Portfolio Custom Content Type’. To do this, while in your WordPress dashboard, go to Jetpack > Settings and activate the ‘Custom Content Type’ module.

jetpack-settings

Next, we need to make sure your theme supports the Portfolio Custom Content Type. To do this, we need to add the following code to your theme, during after_setup_theme:

add_theme_support( 'jetpack-portfolio' );

Once that is added, you’ll see that a new menu item has been added to your WordPress dashboard:

portfolio-menu-item

Step 2:

We’ll need to properly enqueue all needed files for your theme. You can add this to wherever your theme is already enqueuing files.

wp_register_script( 'wds-isotope', get_template_directory_uri() . '/js/isotope.pkgd.min.js', array( 'jquery' ), $version, true );
wp_register_script( 'wds-portfolio', get_template_directory_uri() . '/js/wds-portfolio.js', array( 'jquery' ), $version, true );

if ( is_page_template( 'homepage-template.php' ) ) {
    wp_enqueue_script( 'wds-isotope' );
    wp_enqueue_script( 'wds-portfolio' );
}

Notice that we are using a conditional to only enqueue our scripts on any page using our ‘homepage-template.php’ page template. This is so that we are not enqueuing our JS files site wide. Now that they have been enqueued, download Isotope and add it to your theme’s JavaScript folder. Make sure this folder is named ‘js’. If not, you’ll need to update the above script and change the location of where it is being enqueued. Once you have added the Isotope file to your JS folder, create a new file and name it ‘wds-portfolio.js’. Add the following jQuery code and save the file into your ‘js’ folder.

/**
 * Portfolio functions
 */
( function( $ ) {
     $( window ).load( function() {

        // Portfolio filtering
        var $container = $( '.portfolio' );

        $container.isotope( {
            filter: '*',
            layoutMode: 'fitRows',
            resizable: true, 
          } );

        // filter items when filter link is clicked
        $( '.portfolio-filter li' ).click( function(){
            var selector = $( this ).attr( 'data-filter' );
                $container.isotope( { 
                    filter: selector,
                } );
          return false;
        } );
    } );
} )( jQuery );

Step 3:

Now that we have enqueued your files, let’s create a page template that is specific for your portfolio, and one to show everything on the homepage.

Create a new file and name it ‘homepage-template.php’. Copy and paste the following code:

<?php
/*
 * Template Name: Homepage Template
 *
 * @package wds_portfolio
*/

get_header();
?>

<div id="page" class="hfeed site">
<div id="main" class="site-main">
    
        <?php if ( ! get_theme_mod( 'wds_portfolio_hide_portfolio_page_content' ) ) : ?>
            <?php while ( have_posts() ) : the_post(); ?>

                <?php the_title( '<header class="page-header"><h1 class="page-title">', '</h1></header>' ); ?>

                <div class="page-content">
                    <?php
                        the_content();
                        wp_link_pages( array(
                            'before'      => '<div class="page-links"><span class="page-links-title">' . __( 'Pages:', 'wds_portfolio' ) . '</span>',
                            'after'       => '</div>',
                            'link_before' => '<span>',
                            'link_after'  => '</span>',
                        ) );
                    ?>
                </div><!-- .page-content -->

            <?php endwhile; // end of the loop. ?>
        <?php endif; ?>

        <div class="portfolio-filter">
            <ul>
                <li id="filter--all" class="filter active" data-filter="*"><?php _e( 'View All', 'wds_portfolio' ) ?></li>
                <?php 
                    // list terms in a given taxonomy
                    $taxonomy = 'jetpack-portfolio-type';
                    $tax_terms = get_terms( $taxonomy );

                    foreach ( $tax_terms as $tax_term ) {
                    echo '<li class="filter" data-filter=".'. $tax_term->slug.'">' . $tax_term->slug .'</li>';
                    }
                ?>
            </ul>
        </div>

        <div class="portfolio">
            <?php
                if ( get_query_var( 'paged' ) ) :
                    $paged = get_query_var( 'paged' );
                elseif ( get_query_var( 'page' ) ) :
                    $paged = get_query_var( 'page' );
                else :
                    $paged = -1;
                endif;

                $posts_per_page = get_option( 'jetpack_portfolio_posts_per_page', '-1' );

                $args = array(
                    'post_type'      => 'jetpack-portfolio',
                    'paged'          => $paged,
                    'posts_per_page' => $posts_per_page,
                );

                $project_query = new WP_Query ( $args );

                if ( post_type_exists( 'jetpack-portfolio' ) && $project_query -> have_posts() ) :

                    while ( $project_query -> have_posts() ) : $project_query -> the_post();

                        get_template_part( 'content', 'portfolio' );

                    endwhile;

                    wds_portfolio_paging_nav( $project_query->max_num_pages );

                    wp_reset_postdata();

                else :
            ?>

                <section class="no-results not-found">
                    <header class="page-header">
                        <h1 class="page-title"><?php _e( 'No Project Found', 'wds_portfolio' ); ?></h1>
                    </header><!-- .page-header -->

                    <div class="page-content">
                        <?php if ( current_user_can( 'publish_posts' ) ) : ?>

                            <p><?php printf( __( 'Ready to publish your first project? <a href="%1$s">Get started here</a>.', 'wds_portfolio' ), esc_url( admin_url( 'post-new.php?post_type=jetpack-portfolio' ) ) ); ?></p>

                        <?php else : ?>

                            <p><?php _e( 'It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps searching can help.', 'wds_portfolio' ); ?></p>

                        <?php endif; ?>
                    </div><!-- .page-content -->
                </section><!-- .no-results -->
            <?php endif; ?>
            </div><!-- .portfolio -->

<?php get_footer(); ?>

Next, we’ll need to create a ‘content-portfolio.php’ template file so we know what portfolio item to grab. Create a new file and name it ‘content-portfolio.php’. Here is our code for the content file:

Edit: See Stefan’s comment for necessary change for line 19.

<?php
/**
 * The template for displaying Projects on index view
 *
 * @package wds-portfolio
 */

// get Jetpack Portfolio taxonomy terms for portfolio filtering
$terms = get_the_terms( $post->ID, 'jetpack-portfolio-type' );
                        
if ( $terms && ! is_wp_error( $terms ) ) : 

    $filtering_links = array();

    foreach ( $terms as $term ) {
        $filtering_links[] = $term->slug;
    }
                        
    $filtering = join( ", ", $filtering_links );
?>

<article id="post-<?php the_ID(); ?>" <?php post_class( $filtering ); ?>>
    <a href="<?php the_permalink(); ?>" rel="bookmark" class="image-link" tabindex="-1">
        <?php  if ( '' != get_the_post_thumbnail() ) : ?>
                <?php the_post_thumbnail( 'wds-portfolio-img' ); ?>
        <?php endif; ?>
    </a>
</article><!-- #post-## -->

<?php
endif;

What this code does is include the page content of whatever the page you create that uses this page template. We are also grabbing all content that is published with the Portfolio Custom Content Type.

The following sections are necessary for filtering our portfolio items.

<div class="portfolio-filter">
    <ul>
        <li id="filter--all" class="filter active" data-filter="*"><?php _e( 'View All', 'wds_portfolio' ) ?></li>
        <?php 
            // list terms in a given taxonomy
            $taxonomy = 'jetpack-portfolio-type';
            $tax_terms = get_terms( $taxonomy );

            foreach ( $tax_terms as $tax_term ) {
            echo '<li class="filter" data-filter=".'. $tax_term->slug.'">' . $tax_term->slug .'</li>';
            }
        ?>
    </ul>
</div>

The above code block grabs all taxonomy terms from the Portfolio Custom Content Type in a list. This will allow us to filter our portfolio items.

The next block of code will display our portfolio posts:

<div class="portfolio">
<?php
    if ( get_query_var( 'paged' ) ) :
        $paged = get_query_var( 'paged' );
    elseif ( get_query_var( 'page' ) ) :
        $paged = get_query_var( 'page' );
    else :
        $paged = 1;
    endif;

    $posts_per_page = get_option( 'jetpack_portfolio_posts_per_page', '-1' );

    $args = array(
        'post_type'      => 'jetpack-portfolio',
        'paged'          => $paged,
        'posts_per_page' => $posts_per_page,
    );

    $project_query = new WP_Query ( $args );

    if ( post_type_exists( 'jetpack-portfolio' ) && $project_query -> have_posts() ) :

        while ( $project_query -> have_posts() ) : $project_query -> the_post();

            get_template_part( 'content', 'portfolio' );

        endwhile;

        wds_portfolio_paging_nav( $project_query->max_num_pages );

        wp_reset_postdata();

    else :
?>

    <section class="no-results not-found">
        <header class="page-header">
            <h1 class="page-title"><?php _e( 'No Project Found', 'wds_portfolio' ); ?></h1>
        </header><!-- .page-header -->

        <div class="page-content">
            <?php if ( current_user_can( 'publish_posts' ) ) : ?>

                <p><?php printf( __( 'Ready to publish your first project? <a href="%1$s">Get started here</a>.', 'wds_portfolio' ), esc_url( admin_url( 'post-new.php?post_type=jetpack-portfolio' ) ) ); ?></p>

            <?php else : ?>

                <p><?php _e( 'It seems we can&rsquo;t find what you&rsquo;re looking for. Perhaps searching can help.', 'wds_portfolio' ); ?></p>

            <?php endif; ?>
        </div><!-- .page-content -->
    </section><!-- .no-results -->
<?php endif; ?>
</div><!-- .portfolio -->

The key to the above block are the class names. The ‘portfolio’ class is being called in our wds-portfolio.js file. This tells our jQuery that all posts under this class are to be filtered.

The above code block also includes a specific query that grabs all posts from our ‘Portfolio Custom Content Type’.

Step 4:

Now it’s time to add some styling. The following styling will cover the filter list items and your portfolio items. Feel free to adjust it to match the look of your website.

.portfolio-filter {
  font-size: 14px;
  font-size: 1.4rem;
  overflow: hidden;
  text-transform: uppercase;
}

.portfolio-filter ul {
  margin: 0 0 2em;
  padding: 0;
  text-align: center;
  width: 100%;
}

.portfolio-filter ul li {
  background: #f0f0f0;
  color: #999;
  cursor: pointer;
  display: inline-block;
  list-style-type: none;
  margin: 0 1em 1em 0;
  padding: .2em .5em;
  text-align: center;
}

.portfolio-filter ul li:first-child {
  margin-right: .8em;
}

.portfolio-filter ul li:focus, .portfolio-filter ul li:hover {
  color: #000;
}

.portfolio .type-jetpack-portfolio {
  float: left;
  margin: 0 -1px -1px 0;
  width: 100%;
}

@media screen and (min-width: 480px) {
  .portfolio .type-jetpack-portfolio {
    max-width: 100%;
    min-height: inherit;
  }
}

@media screen and (min-width: 768px) {
  .portfolio .type-jetpack-portfolio {
    max-width: 239px;
    max-height: 180px;
  }
}

.portfolio .type-jetpack-portfolio img {
  display: block;
}

.portfolio .type-jetpack-portfolio:hover {
  background: #000;
  opacity: .6;
  transition: all .4s ease-in-out;
  -webkit-transition: all .4s ease-in-out;
  -moz-transition: all .4s ease-in-out;
  -o-transition: all .4s ease-in-out;
}

Step 5:

Now that all code and files are added to our theme, let’s go back into our WordPress dashboard to start publishing items in our Portfolio Custom Content Type. When publishing a new portfolio, be sure to add ‘Project Types’ to your posts. This will categorize your posts and your page will show the project types as fitlerable items–which will help in filtering your portfolio.

featured-imate

Added Bonus!

If you are running into any issues, we have included a free theme that you can download. You can compare your code with the files with this theme. This will help you debug any possible issues.

wds-portfolio

Live Demo Download Now

Like our free theme?

It’s on GitHub! Pull requests are welcome to help improve our theme.

Further Theme Development Resources

WordPress Theme Development Standards
All WebDevStudios’ posts on Theme Development and Designing

The post Create a Filterable Portfolio with WordPress and Jetpack appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2015/01/27/create-a-filterable-portfolio-with-wordpress-and-jetpack/feed/ 27 10509
Attaching Posts with CMB2 for WordPress https://webdevstudios.com/2014/12/23/attaching-posts-with-cmb2-for-wordpress/ https://webdevstudios.com/2014/12/23/attaching-posts-with-cmb2-for-wordpress/#comments Tue, 23 Dec 2014 19:49:58 +0000 http://webdevstudios.com/?p=8752 CMB2 creates metaboxes and forms with custom fields that will blow your mind. Attached Posts in an extension of this extremely useful plugin. Every once in a while you may find yourself needing to attach various pieces of content to various other pieces of content within your site. Maybe you want to display a list of Read More Attaching Posts with CMB2 for WordPress

The post Attaching Posts with CMB2 for WordPress appeared first on WebDevStudios.

]]>
CMB2 creates metaboxes and forms with custom fields that will blow your mind. Attached Posts in an extension of this extremely useful plugin.

Every once in a while you may find yourself needing to attach various pieces of content to various other pieces of content within your site. Maybe you want to display a list of related content on a single post but you’re extremely particular about which posts should display as related. Maybe you have a special page template which needs to display various posts as sections or chapters on a single page.

Whatever the case may be, we always seem to find ourselves needing to attach one type of content to another type of content. With CMB2 Attached Posts, we give you that ability.

Sure, there are plugins that will do this for you. Here at WebDevStudios we’ve used Posts 2 Posts quite a bit which is a wonderful plugin allowing you to pair content from one post type to another. Why use CMB2, then? Well, why not?? We want to make CMB2 be and do all that it can, and when the need for relationships between post types came up it seemed like the perfect time to integrate this functionality directly into CMB2.

First things first, you’ll need to check out the CMB2 Attached Posts repo. You’ll drop those files right into your /mu-plugins/ directory, which will register the new CMB2 field type and enqueue the necessary JavaScript and CSS files in the dashboard.

So now that you’ve got that taken care of, let’s go!

First, we need to add the field like we would with any other CMB2 field:

As an added bonus, our own Justin Sternberg just made an update to this functionality on line 15 above. You can now specify the number of posts you want to pull in when using this field type!

Once you’ve got all of your options and parameters set, you’ll wind up with something like this:

Attached Posts

Simple, right? This is going to look for posts and display this field ONLY on pages as indicated by the ‘object_types’ value above.

Once you have that in place, you’re ready to start draggin’ and droppin’!

Attached Posts Add Posts

When you update the post you’re editing, you’ll now have these post IDs saved in an array for you to use on the front-end. By rearranging posts, you’re able to rearrange them in the array itself; so, if you need to display this content in a specific order then drag and drop is going to be your best buddy.

Now that you have a nifty little array, you can do something like this do bring these babies to life:

The array stores the ID of each post, so the world is really your stinky little oyster as far as what you want to do with these posts. It’s all up to you!

You can grab CMB2 here: https://github.com/WebDevStudios/CMB2
You can grab CMB2 Attached Posts here: https://github.com/WebDevStudios/cmb2-attached-posts/

The post Attaching Posts with CMB2 for WordPress appeared first on WebDevStudios.

]]>
https://webdevstudios.com/2014/12/23/attaching-posts-with-cmb2-for-wordpress/feed/ 17 8752