Qpractice case study, Zao client spotlight, Zao WordPress web development, Zao WordPress eCommerce development, Zao WordPress plugin development, custom WordPress plugin,

Zao Client Spotlight: Our Collaboration with Qpractice

One of Zao’s goals includes taking on complex projects that require in-depth strategy. We don’t want to merely solve problems, but add value to the technology our clients are using. We take a boy scout approach to the work we do: Always leave the campground cleaner than we found it.

This means not only cleaning up what messes we may find when we arrive, but ensuring our clients have sustainable technology that benefits them in the future.

We recently had the pleasure of completing an initial phase with Qpractice, a website built to help interior designers prepare for the NCIDQ exam. So far it has been a complex, but extremely exciting collaboration with Lisa League, designer and founder of Qpractice. We’re here to share what we’ve done so far, and be sure to check out our interview with Lisa to hear her thoughts on working with Zao!

What Qpractice Does

The NCIDQ exam is an interior design licensing and certification test offered in the US and Canada. According to Lisa, it tends to be commercially oriented, with a focus on health, safety, and welfare. It tests designers on their understanding of necessary codes and regulations, making sure they can demonstrate their understanding of the non-structural part of the building (like plumbing, electrical, mechanical systems, etc.).

The exam tests knowledge interior designers should have accumulated both during their education and from their work experience. The NCIDQ exam can be a crucial element in an interior designer’s career trajectory; designers often seek out the exam to move up to a senior design position or land higher profile, higher paying projects.

Qpractice aims to help interior designers prepare for the NCIDQ exam by providing extensive opportunities for trial, error, and education. The Qpractice site provides practice tests that in many ways mirror the real NCIDQ exam, allowing designers to become familiar with the format and feel confident when facing the exam live.

Zao’s work on Qpractice

Like any ongoing project on a live, thriving site, as we worked through the initial phase, the scope was extended to cover new and emerging (and sometimes urgent) issues and inconveniences. Zao updated much of Qpractice’s existing system, as well as revamped the entire theme, added functionality, and created several plugins to better serve Qpractice’s needs. The NCIDQ exam also recently added a new quiz format, and Qpractice needed to have that created for test takers continued comfort and familiarity with the exam.

The discovery process

As we do with most of our clients, we did a significant code and performance audit before diving in. JT talked about how vital the discovery process is before, and it’s a staple in the way we approach projects. For Qpractice, we made recommendations for custom features that can be added, as well as data migrations from one plugin to another, and more.

During discovery, we don’t always recommend changes. Sometimes we recommend staying with the current solution if it’s best serving our client’s needs. We believe this is just as important as adding the new and shiny features.

Qpractice was set up using Sensei and WooCommerce Memberships, and we suggested that they continue to do so. From our initial discovery document:

  • Sensei – Given the high level of integration with custom functionality plugins and the purpose Sensei provides on your site, we’d recommend keeping it as your quiz management solution. Developing a custom quiz management solution would offer minimal long-term benefit and incur a high short-term cost.
  • WooCommerce Memberships – Based on our discussions with you, the most recent changes to WooCommerce that have resolved outstanding issues, and the cost of switching membership platforms, we recommend sticking with WooCommerce Memberships.

We aren’t kidding when we say Zao is working on behalf of our clients at every turn.

Once the discovery document was sent and we got the approval from Lisa, we went straight to work.

Order up: adjusting Genesis and making the menu

Lisa wanted to make some adjustments and add new elements to the Qpractice theme, but wanted to stay on Genesis.

One of the big pieces that took a lot of time and effort was the way the menu functions. We overhauled the entire menu system in terms of functionality and mobile responsiveness. It’s a specific implementation that works responsibly, as well as opens and closes according to different user actions. When logged in, Qpractice users have access to an additional menu with custom functionality as well.

The entire site is now device agnostic, which is particularly important for appealing to new users and making it possible for existing users to access information like the study guide, grades, and more, with ease.

Creating seamless integrations

On Qpractice, these three tools are integrated to offer the most to users, as well as make the business easy to run. Sensei powers the Qpractice learning and quiz systems, WooCommerce Memberships controls access to those systems, and WooCommerce powers the eCommerce component of the site.

Between these three tools, there were lots of bits and pieces that needed cleaning up. When one would update, it would often introduce a bug to one of the others, and it would impact the entire setup negatively. Zao’s first step in improving the Qpractice site was obvious: we triaged a bunch of bugs popping up in the integrations between Sensei, WooCommerce, and WooCommerce Memberships, as well as submitting several pull requests against their respective repos.

Side note: This is where retainers become necessary. Plugin teams have their technical goals in mind when they’re building their product, but they do not have your specific ecosystem in mind when they release. That’s why paying to have a technical partner to bridge the gap between the technology and your specific needs is so valuable.

Simple, but lovely features

WooCommerce Product Bundles price shortcodes

Qpractice uses WooCommerce’s Product Bundles, but there wasn’t a good way to output the price for the each product in the bundles and show the user what each item cost and just how much they were saving. The shortcode is super easy to use (of course), and makes solving this problem extremely simple.

WooCommerce Product Bundles, WooCommerce WordPress websites, WooCommerce development, WordPress web development

Custom message bar

Zao added a way for Qpractice to flash a message bar at the top of the site. We wanted it to integrate nicely with the Qpractice menu and show up in certain scenarios set by the admin. Although there are plugins that offer this kind of functionality, most of them only create a message bar that shows universally across the site, and we wanted to give Qpractice more control over this component of the site. The message can be shown across the site entirely, or the site admin can toggle it to show exclusively to logged out users, which is particularly useful as a promotional tool.

All the WordPress plugins

As mentioned, the Qpractice site is using Sensei, WooCommerce Memberships, and WooCommerce.

Additionally, we migrated Qpractice from another affiliate plugin to AffiliateWP, built by Pippin’s Plugins. They create great products and support AffiliateWP incredibly well; we felt confident that AffiliateWP would put Qpractice’s site (and affiliate program) in good hands.

Once again, we make sure our clients are gaining the most value from their technology, which means setting them up with what we believe to be the best products, and there’s no doubt that AffiliateWP falls into that category.

Custom WordPress plugin development

Qpractice had some specific needs and problems to resolve that existing plugins couldn’t address, so we did one of the things we do best: we built them.

We encourage all of our clients to open source the plugins we create for them, and Lisa was especially enthusiastic about creating products that are open sourced and available to the public. Not all of them are open sourced just yet, but many of them are.

Bulk Boot for Sensei

The way that Sensei is built means that users are signed up indefinitely unless they remove themselves, but this presented a problem for Qpractice, which operates on a seasonal schedule. At the end of every season, they needed to be able to remove access to the courses and encourage users to sign up for the next season, should they want to do so.

We discussed the fact that booting learners from a course is actually a pretty intense operation performance-wise and that it needed to be an asynchronous operation. As a result, we decided the best course of action was to add an optional turtle to help the user’s anxiety levels.

Bulk Boot for Sensei, Qpractice, Bulk Boot WordPress plugin, WordPress plugin development, custom WordPress plugin development

We wrote Bulk Boot for Sensei to give Qpractice the ability to bulk remove all learners from a specific course at the end of the season. Now, tidying up user access in Sensei is super easy.

Sensei Advanced Quizzes

The Qpractice site already had a plugin that extends Sensei, adding additional functionality, and we built upon that to add more useful tools in the admin area.

One of the most frustrating things about Sensei is that it dumps all questions/question-types in one big listing in the admin without faceted filters for drilling down to certain types of questions. Qpractice has a variety of question types that act a certain way, and Lisa had no way to search by the group. We created a tool that adds columns and filters to allow advanced sorting so she has a much easier time of filtering.

WordPress plugins, WordPress WooCommerce Sensei, using WooCommerce Sensei, WordPress eCommerce development, WordPress educational development,

WooCommerce Custom Product Redirects

Zao created a custom plugin called WooCommerce Custom Product Redirects. This plugin is not only a great sales and customer support tool, but it allows the Qpractice site to direct their users to information they may find crucial for using the products they’re purchasing.

With WooCommerce Custom Product Redirects, if a user has a product in their cart and makes a purchase, they will be redirected to relevant content set by the site admin. If the site admin has a relevant tutorial to the product being purchased, they may decide to custom redirect to that tutorial for the customer’s benefit. If there are two products that have URLs, the site admin can define priority, ensuring that their customers get any and all pertinent information automatically delivered to them post-purchase.

WooCommerce VitalSource Redemption Codes

Qpractice offers an e-book that is delivered by a third party, but purchased through the Qpractice site. Qpractice needed a way to keep an inventory of codes and her stock in WooCommerce without spending a lot of time keeping track of it manually.

With WooCommerce VitalSource Redemption Codes, every time a user purchases a product stored on a third party site, it associates one of the codes (in Qpractice’s case, a free code for the e-book) with that user so they can find the code on their receipt, and so inventory is neatly kept in WooCommerce.

This plugin was written specific to VitalSource, a Qpractice partner. We will likely adjust it and make it open source soon–stay tuned!

Zao Sensei Media Attachments

We created an alternative to a WooCommerce plugin that allows the site admin to associate media items with a lesson and ensures the media shows up in the resources list for associated courses. Zao Sensei Media Attachments now serves the same function, but uses CMB2 to create a better user interface. CMB2 simplifies the admin fields and provides more filters for modification.

WordPress plugins, Zao WordPress plugins, WordPress plugin development, Qpractice, working with Qpractice, e-commerce website development, eCommerce website development, hire a developer, looking for an eCommerce developer, WordPress eCommerce,

CMB2 Snippet Library: Associate WordPress Menu Field

We also contributed one of the features back to the CMB2 code snippet library. With this feature, Qpractice can select or create a curated WordPress custom menu to associate with a quiz or lesson and that menu will be displayed by placing the “Associated Post Menu” in the corresponding sidebar widget area.


Working with Qpractice has been an absolute delight. Lisa is a creative powerhouse, suggesting all kinds of ideas that we had the opportunity to create into a tangible, functional reality. We’re on the next phase of the project, and we’re all too excited to see what comes next. We’ll keep you posted!

Check back later this week for an interview with Lisa sharing her perspective of the project. 

JavaScript, learn to use JavaScript, using JavaScript in WordPress, learn to code in WordPress, WordPress coding tips, WordPress coding tutorials, how to use wp.template, using wp.template, wp.template tutorial

How to Use wp.template, WordPress’ Underscore.js Template Method

Like many developer agencies, we have a few different audiences, including clients (current and prospective) and other developers. Our aim is to serve all of our audiences, who fall on a broad spectrum of technical knowledge. Even if you’re not a professional developer, we know that many of you still educate yourselves on the technology used on your site–and we want to help! If there’s anything we cover that you don’t understand (or anything you’d like to see us cover that’s WordPress related, even 101!), please let us know. There are no stupid questions.

That said, let’s dive into something fun: WordPress’ Underscore.js Template Method, wp.template.


If you’re not yet familiar, wp.template() is a cool little JavaScript utility method that is provided with the WordPress core ‘wp-util’ script. At its core, it uses the Underscorejs .template() method.

WordPress uses this utility to load templates for all of the backbone views, but backbone is not required to use it. First, I’ll demonstrate using wp.template() with a little jQuery in order to output some JavaScript data into an HTML template, then later as a bonus, we’ll rebuild wp.template() as our own module with some additional features.

Keep in mind: this is meant to be an example presented as simply as possible, and not something you would copy/paste into production code. Please continue to follow standard best practices, including things like putting JavaScript in its own file, avoiding anonymous functions, internationalizing your text strings, etc.

By default, the method requires a script tag with an id of tmpl-my-template-name. Because all of WordPress uses this templating method/system, you will want to make sure you properly prefix your ids, so as not to conflict with another template that may be loaded on the page. That script tag should also have a type of “text/template.”1

Let’s get started:

<?php 
function zao_item_status_tmpl() {
    ?>
    <script type="text/template" id="tmpl-zao-item-status">
        <span class="zao-status" data-id="{{ data.id }}">
        <# if ( data.status.name ) { #>
            <div class="zao-item-status">
                <span class="zao-status-color" style="display: inline-block;background-color:{{ data.status.color }};width:10px; height:10px;"></span>
                {{{ data.open }}}
                    {{ data.status.name }}
                {{{ data.close }}}
            </div>
        <# } else { #>
            &mdash;
        <# } #>
        </span>
    </script>
    <?php 
}

So now we have the proper script template tag ready to go in a PHP function, with unique id, tmpl-zao-item-status. As you can see, this isn’t 100% standard HTML. You can see we are using Mustache-inspired data variables, as well as Underscorejs logic blocks.

From the Codex:

WordPress defines its own interpolation tags using the _.template( options ) to avoid incompatibility in some PHP configurations with asp_tags enabled. The WordPress-specific interpolation syntax is inspired by Mustache templating syntax:

  • Interpolate (unescaped): {{{ }}}
  • Interpolate (escaped): {{ }}
  • Evaluate: <# #>

An important bit to understand is the <# and #>, which signals the opening/closing of raw JavaScript output, so you can do things like logic operators (like the if statement in the example above). You can also see we’re taking advantage of the unescaped interpolation when we output the data.open and data.close parameters, since those will contain HTML and we don’t want that escaped.

At this point, let’s hook into WordPress so we can see this in action.

Add this snippet somewhere in your theme’s functions.php file, or a custom plugin:

<?php 
// Output this at the top of the post-edit screen just below the title input.
add_action( 'edit_form_after_title', function() {
    ?>
    <span class="zao-status"><span style="display: inline-block;background-color:red;width:10px; height:10px;"></span> Please wait...</span>
    <?php 
} );

If you go to a new-post or post-edit screen, you should see something like this:

That doesn’t do much for us. We’re going to need some JavaScript setup to grab our updated status and update the status markup. To simplify, we’ll simply fake an AJAX request by setting a short delay. You could also using something like the Zao Mock API to mock some API requests/responses.

The JavaScript:

<?php 
function zao_item_status_js() {
    ?>
    <script type="text/javascript">
        // Wait for the dom to be ready..
        jQuery( function( $ ) {

            // Get the template function corresponding to our template markup.
            var template = wp.template( 'zao-item-status' ); // uses script tag ID minus "tmpl-"

            // Let's wait a tick, so we can see it go from yellow to green.
            setTimeout( function() {

                // Let's fake some data (maybe this is data from an API request?)
                var tmplData = {
                    id: 1,
                    status: {
                        name: 'Success!',
                        color: 'green'
                    },
                    open: '<span class="status-name" style="color:green">',
                    close: '</span>'
                };

                // Send the data to our new template function, get the HTML markup back.
                var html = template( tmplData );

                // Now let's replace the contents of the existing markup with our updated template markup.
                $( '.zao-status' ).html( html );
            }, 1000 );
        });
    </script>
    <?php 
}

The code comments should be self-explanatory, but to recap:

  1. Call wp.template() with the ID of the script tag we created earlier minus the tmpl- prefix
  2. Fake an API request by setting a one second delay
  3. Generate an object of data and pass it to our new template function which returns the compiled HTML
  4. Take that HTML and replace the existing.

We now have the JavaScript output in a PHP function, which we can hook into the footer. We have almost all the pieces we need to make this work, so let’s update our edit_form_after_title anonymous function:

<?php 
// Output this at the top of the post-edit screen just below the title input.
add_action( 'edit_form_after_title', function() {

    // Hook in our template script tag to the footer.
    add_action( 'admin_footer', 'zao_item_status_tmpl' );

    // Hook in our custom JS for updating the status.
    add_action( 'admin_footer', 'zao_item_status_js' );

    // Now, enqueue the WP util script so we can use wp.template
    wp_enqueue_script( 'wp-util' );

    // Make the initial output have a yellow status square
    ?>
    <span class="zao-status"><span style="display: inline-block;background-color:#ffe24d;width:10px; height:10px;"></span> Please wait...</span>
    <?php
} );

With that, we should see the status go from yellow (“Please wait…”) to green (“Success!”).

wp.template success! gif

wp.template success!

Hopefully, this basic example will help you get started using wp.template() in your own work, but if you have any questions, please leave comments below.

The full output for this example snippet can be found here.

If you’re still with me: now that we’ve covered the basics of the WordPress’ utility, you might be interested in a similar utility based on wp.template() which I created, _templatize. This script simplifies the above steps a little by combining the template-getting and data-sending, and also provides a feature that allows creating a template by passing it an HTML string (vs being tied to a tmpl- script tag in the dom). As a bonus, you can see the above snippet updated to use _templatize here.


  1. The key is that it shouldn’t be type="text/javascript" (or no type specified). More info 
Zao, learning to code, WordPress developers, WordPress ecommerce, learn to build WordPress, learning to build in WordPress, learning WordPress, how to use WordPress

Five Things I Wish Someone Told Me When I Learned to Code

I haven’t been in the software development industry for loads of time, but thanks to some amazing people who championed my growth, I slingshotted in quicker than some other peers who did it all on their own. (Props to you individuals, by the way, that wrestled it all out by yourself–you are unstoppable!)

After thinking a bit about my experience I came up with five things I wish I had known when I started developing:

1. It’s 100% normal to feel like you’re drowning

I stumbled my way into coding; it initially started as a hobby.

At first, everything was bite-sized and easy. I was blissfully unaware of how little I knew. Once that bubble popped, my lack of knowledge was overwhelming. Everywhere I turned there was something I could not do.

I remember the first time I tried poking around in the Codex. I ran away thirty seconds later because it all seemed like Greek! I literally did not have the capacity or supporting framework to “get it.” I wish I had known in advance how often it would feel like drowning and that it was fine.

2. Just Keep Learning, Just Keep Learning

Go after all the low hanging fruit that you can. It might seem like a waste of time to spread yourself so wide, but if you are truly a newbie and have no context for the developing world, the wider you go, the wider your foundation will be. Although you won’t be fully aware of it at the time, you’ll fill in the gaps of your understanding so you can level up.

When I felt like I was drowning, I continued to chip away at the pieces I could master and walked away from the pieces that made no sense to me. It paid off in the long run.

You can only handle so much drowning before you give up. By moving on, I kept my overload threshold in the green and experienced small wins that boosted my confidence.

Every so often, I would return to the Codex and give it a go again. When it still wasn’t useful for me, I moved on. I remember the day I was working on something, jumped around several Codex pages…and realized it made sense to me. Suddenly, the Codex was in my toolbox. By expanding my understanding in other areas, I built a framework that allowed me to tackle the previously impassable problems.

I wish I had given myself the permission earlier on to move on when it suited me. While there is a satisfaction to mastering something, I have found the field to be so wide, deep, and complex that it is rare to master something the first go around. Spending all your resources to come out utterly defeated is more costly than saying, “I don’t get it, so I’m going to move on to something else and return to it another time.”

It changed my experience from perpetually drowning to recognizing that I need to play in the wading pool a bit longer.

Note: This should go without saying, but don’t put yourself in a situation where you have committed to do something that is beyond your abilities for a client…because then, you don’t have the permission to walk away from it.

3. Hone in on your trusted sources

The internet is amazing and Google a robust resource, but not all of the resources out there are reliable.

As helpful as Stack Overflow is, quality control is not always a guarantee. Many of the solutions provided are hacks, instead of the industry standard approach to the problem. When you’re starting out, it’s hard to know who you should and shouldn’t listen to. It’s imperative to find good sources that you can soak up. This might require reaching out to experts in the business and find out who they trust.

My introduction to coding started with a free online coding tutorial resource. It was great for the most basic things. However, the further I got down the rabbit hole, I discovered that some of what they were teaching was completely wrong. Fortunately, friends who are professional developers pointed me to some credible resources.

It is hard to unlearn something foundational if you learned it wrong the first time. You only have so much time and you can spend eternity reading about all the different approaches.  Find approaches you can build on so it’s not considered time wasted later.

Team Treehouse proved to be an invaluable resource for me. They are trustworthy and they are actually good at teaching–a huge bonus because not all developers are good at breaking down what is natural for them into bite sized pieces for newbies.

4. After you learn it, build it

I cannot tell you how often I’d go through a tutorial and think to myself, “This makes complete sense. I get it!”

I followed with the tutorial and find myself at the end with the desired product. Ta-da! I learned it, right?

More times then I can count, I noticed that stepping away for the weekend would be enough for me to completely forget it. I found that after completing a tutorial, it was really helpful to go through and build the entire project again without the tutorial.

That was the real test of what I had actually learned, versus what I was regurgitating. It is great to follow along with a tutorial, but that’s only the first level. You need to practice it several times before you get it. The more you build it, the more muscle memory you create.

I wish I rebuilt the same things over and over instead of moving on to the next skill before mastering what I initially focused on.

One final point on building: going through other people’s tutorials is a great way to gain knowledge. However, reproducing something that already exists does not activate your creative thinking.

I discovered if I tried to implement a skill in a different context than the tutorial, I understood the steps to build one specific solution, but didn’t always grasp the concept in its entirety and how it could be applied to different situations. After you master a project on your own without the tutorial, try it again but with a different outcome as the goal. This will keep the skill pliable for you.

5. Get excited about pet projects

One of my biggest struggles when learning to code was that I had no idea what to build on my own. I desperately wanted to practice and try things out, but I had zero idea where to start.

As I mentioned earlier, you can only drown for so long before you give up. The antidote to this is passion. If you are really passionate about what you are building, you will have more endurance to push forward when the going gets tough.

Additionally, the great things about pet projects is that they are often side projects. You probably have other pressing matters that need attending, and so your project will get put on the back burner. This is fantastic!

When you return to it you will see your work through the eyes of a new developer. You will learn first hand the importance of commenting because you’ll probably have forgotten about why you did some of what you did and what all the moving pieces do.

As you improve your skills, you’ll find that when you return to your old work, you’ll be embarrassed by some of your approaches. The upside: you’ll have an opportunity to practice refactoring. These skills are super important and less painful to learn on your own project then in a group project where you’re impacting your peers and clients.


I wish I had known all of this sooner.  What about you? What things do you wish your baby developer self knew?