Run A Quick, Local WP_Query Injection With A Closure Through Post Clauses Filters

We use the posts to posts (p2p) plugin a lot for building relationships between posts and post types. Occasionally you will have a query to get connected posts that will return multiple copies of the same post. So I worked out this method to handle that efficiently.

This method can be used for more than just query injections but that seems to be where I find myself doing it most. Sometimes you need a tweak to a get_posts or a new WP_Query but it’s so localized to the particular function it is in that it’s best to just take care of it there. No need to build out a class to handle it, just give this a shot.

Being Efficient

When coding, avoiding unnecessary sql queries and loops with conditionals is at the top of the list in keeping your site’s speed as optimized as possible. I had a query that was pulling in duplicate copies of posts thanks to the way p2p works. I could certainly just loop through the results and build a new array of distinct articles but that would be wasting processor power and making my query return far more than I needed.

I needed to do this right. So my thought was to filter into the query and adjust the sql before it ran. There’s a multitude of ways to do that but I also felt that this was so unique to this particular function that building out a class or a helper function to do it was unnecessary and would involve too much code for a simple task.

So the goal is to slap an sql clause filter on before the query and make sure that filter was removed before any other queries ran.

Choosing The Clause Filter

So the simplest filter would be to use ‘posts_distinct’ and return “DISTINCT.” This puts a DISTINCT string right after the SELECT statement. It works great for a typical query but when you have a complex JOIN query sometimes it just won’t work.

I toyed with the ‘posts_fields’ filter, but didn’t get far and never got the results I was after. I finally realized the sql I was invoking through p2p and WP_Query was needing a GROUP BY piece to group the results by post ID and remove duplicates.

function groupby( $groupby ) {
    global $wpdb;
    return "{$wpdb->posts}.ID";
}

Now I just needed to implement my filter somewhere.

Add Filter, Remove Filter

We need to make sure our filter only hits this single query we are running. What we can do is this:

  1. Build a closure: Assign a variable’s value a function to handle the groupby needs.
  2. Add a filter that executes our closure.
  3. Run our get_posts() or new WP_Query.
  4. Remove the filter.

It’s actually super simple and efficient. Here’s the code I used:

By adding the filter right before get_posts() and removing it right after we are making sure that filter only hits the query executed by get_posts().  Also, by storing the function as a closure in the $distinct_ids variable we are able to target it in our add_filter and remove_filter with ease.

WP_Query Filters

There’s a whole bunch of cool filters you can tap into to customize the sql query before it executes.

  • posts_fields – Filter the fields right after the SELECT of the query
  • posts_join – Filter the JOIN
  • posts_orderby – Filter the ORDER BY
  • posts_where – Filter the WHERE statements
  • posts_distinct – Use return “DISTINCT” to avoid duplicates (unless you have a situation like mine here).
  • posts_clauses – This one is awesome.  It passes in a single parameter which is an array of all the above and you can adjust them all in the same function.

This shit is really powerful and when you start reaching more advanced levels of WordPress development you’ll find yourself using them regularly.  Check out my co-workers blog post about building out a query for calculating distance between two geo coordinates.  This was what taught me a lot about this stuff and it’s really amazing.

Version 16.1 of WordPress PHP Info Released

I adopted this plugin a while back from a friend. It was closing in on 10,000 active installs and I thought might be fun to tinker with.  The code was pretty sloppy as it was from his younger days and he didn’t feel like maintaining it.

I took it over and didn’t do much with it.  I added a pretty crappy email the php info feature that didn’t really work well at all.  Still, people needed it and it was a first mover so it’s the go to phpinfo() plugin for people.

It hit 20,000 active installs just a few days ago.  Well I decided to spice it up a bit.  Over the past few evenings I rewrote it from scratch with much better code and WordPress standards.  I cleaned up the interface to be much nicer and fine tuned the email info feature to include multiple addresses and work securely.

Check it out here: https://wordpress.org/plugins/wordpress-php-info/

Building a Payment Gateway for Give WP the Donation Plugin for WordPress

My father runs a non-profit organization and I told him I’d help with some of his online needs.  I’m in the midst of a task for him where I need a very simple, but precise method of donations through Stripe.  While the Stripe Add-On for Give is excellent, it’s more than I need and missing some small features my project requires.  I’m not going to get into that specific project but show you what I’ve learned.

Unless I’m missing something obvious on their site and with some quick googling, there’s no documentation for building Give gateways. I had to reverse engineer a couple that are available to see what is necessary to make it work.  Here it is in its simplest form.

Bare Bones Gateway

When building an extension for a plugin I like to try and build the absolute barest possible version.  What you see at the bottom of this section is just that.  We use just two hooks:

  • add_filter( ‘give_payment_gateways’ )
  • add_action( ‘give_gateway_{gateway_slug}’ )

The filter registers our gateway.  This will then show our gateway as an option in the Give gateway settings.

The action is where we process the submitted form data.  It’s pretty straight forward, the function has a single parameter ($purchase_data) passed to it which contains all data submitted and generated by Give that’s needed to process a donation.

The $payment_data array is created and built to hold all the necessary items for processing a transaction and recording it.  Then we simply call the Give function give_insert_payment( $payment_data).

Settings

The next feature you will probably want to add is the admin settings for your plugin.  This will allow your users to set api keys and other various options you’d like to have.  You can see a good example of establishing settings here:

https://github.com/WordImpress/Give/blob/master/includes/gateways/offline-donations.php#L281

Pending Status

I tried using ‘publish’ instead of ‘pending’ in the payment data but this caused some php warnings to pop up.  Even though the donation went through, the results were ugly and obviously not to spec with the Give plugin’s functionality.  So after checking if the payment is valid simply run the give_update_payment_status function.  Or, if you need to verify the payment through your payment processor you can have  a separate function that handles this.

Fleshing It Out

This, as stated, is a completely bare bones gateway that does nothing but record a donation.  give_gateway_{plugin_slug} action is a blank canvas for handling processing.  You can do your own verifications, reach out to your processor, manage the response and more.  I would suggest looking at the Give plugin directory give/includes/gateways files offline-donations.php and paypal-standard.php and check out the different hooks and functions you can use to expand your gateway’s user experience and capabilities.

The Give plugin is very powerful and very extendable.

Import Leads From WordPress to Insightly with Caldera Forms & Insight.ly API v2.2

Recently I had a client ask to take submissions from a formsite.com form into their Insight.ly account as soon as submitted from their WordPress site.  This was no easy task as formsite uses javascript embedded code to generate an iframe and load the form.  I pulled it off by interfacing both the formsite api and the insightly api on a thank you page redirect from formsite but it was gross code and had a moderate failure rate at importing correctly.

Remove The Middle Man

Don’t let its modern, sexy homepage fool you, Formsite is pretty archaic in methods and form generation.  It’s a sad case a site and tool so large can be so crappy.  I needed to just build a form that shot the info over to insightly while also looking nice and sending an email to the site owner.

I’ve done some work for Caldera and I can honestly say they have the best, easiest to use and easiest to extend form building system for WordPress… bar none.  They also look gorgeous.  The drag and drop interface is beautiful and works flawlessly.  The options and extensions vary from simple needs to extremely complex ones.  What we are going to build here is somewhere in between.

Extending Caldera Forms

First build a form.  The Insightly API has some requirements but they are not documented well.  From trial and error I believe first name, last name and email are the main requirements… maybe phone.  So create a simple form in Caldera with these and whatever else you need then let’s move on.

Add the official Caldera plugin Caldera Forms Run Action to your WordPress installation.  This plugin allows you to to hook into the form data being processed before, during and after the processing.  Before we start writing code, let’s set that up on our form.

Go to the “Processing” tab on the form editing page, add a processor of type “Run Action” and fill in details like this.  You can use a different name for your filter/hook but just remember it when we start coding.

Run Action Processor Settings

We are saying we want to do some stuff with the form data after the user submits but BEFORE it gets processed.  This way if we have any trouble with the insightly api we can let the user know so they can fix their input.

Hooking Into Caldera

To do this, you need to put some code into WordPress.  You can do this in your theme’s functions.php file but I recommend you create a very small plugin.  To create this plugin you will add a folder to your wp-content/plugins directory called caldera-insightly.  Inside that folder you will create a php file named caldera-insightly.php.  That file will look like the below code.  Don’t forget to go to “Plugins” in your admin and activate it.

This code is BARE BONES.  I did not build this out like a big proper plugin but it’s simple in its functions and will work for the basics of interfacing the insightly API v2.2.  I explain the code below.

The add_filter line is where we put in the hook that we registered on the Run Action processor on our caldera form.  The second parameter ‘process_insightly_data’ tells it what function to perform on the data from the form.  Remember this is all happening before Caldera processes the data so if we return anything at all from this function the processing fails and the user gets an error message.

$form_data[‘first_name’] is referencing the “slug” of the form field.  You can see this when building your form in caldera.  Each field input has a slug that is sent as the form data.

Insightly requires the data to be formatted in JSON with very specific keys.  You can see a list of options here.  The FIRST_NAME, LAST_NAME and so on are very straight forward.  The complicated shit happens when you hit the LEAD_SOURCE or want to do CUSTOM_FIELDS.  I’ve had a time and a half working with custom fields and got it to work once, so I just avoid it now if I can.  The lead source requires you to already have lead sources setup in insightly.  You need to get the ID’s of those sources and use them to create your lead source array.

Lead source is not required so you can delete that whole section if you want.

After building our array of data we json_encode it and send it on its merry way.  Don’t forget to grab your API key and replace it in this code.  To get that code once logged into insightly click your profile picture in the top right corner then hit User Settings.  Scroll down on that page and you will see API KEY at the bottom.

I detect for “LEAD_ID” in the return string as this means a new lead was created and assigned an ID.  If it’s not there then we return that an error has occurred.  This could be handled better but I was in a hurry as the client wasn’t paying for a lot of hours.

Yoast Primary Category Endpoint for the WP REST API

I had a special case today where I needed to pull in posts specifically from a Yoast SEO Plugin‘s primary category.  Yoast SEO allows you to set a single, primary category for a post in WordPress.  This is an awesome feature and very useful.

A site I’m building right now uses the API to pull in the latest articles of a category in a big drop down hero navigation system.  The thing is, just pulling from a category gets a lot of the same articles when clicking around the different category options.  We wanted to pull by primary category so each click gives a unique set of posts that are very relevant to the category option.

The Struggle

There may be a super simple way to do this already but I was seriously struggling googling for the answer.  I’ve done some extending of the WP REST API but I’m still a novice so I was hoping to avoid it.  But glad I didn’t because I learned a lot and I made a cool thing!

I couldn’t find a function in Yoast that pulled post IDs or anything based on a primary category.  I needed to figure out how they assigned this.  I dug through the database and found a post meta with the key ‘_yoast_wpseo_primary_category.’  This is it, this is what I’ll use to build my end point.

The Code

First we need to register our endpoint/route.  I prefer building things in classes so I created a class:

<?php
class Rest_Api_Posts_By_Primary_Category {}

I register the endpoint in the __construct() as so:

SITE_PREFIX is something I set in my theme’s functions.php file.  You need a namespace here so make it unique based on your plugin or theme or site in general.

The callback function is where the magic happens.  In get_posts_by_primary_cat( $data ) we do a simple WP_Query that makes use of the meta_query ability.  The thing is, I need the children of categories too.  Here’s an example similar to what I’m dealing with.

Let’s say we have three categories and these categories are what we see in our navigation menu: Math, Reading, History

Then those categories each have two children: ###-Lessons, ###-Research

So our final category structure looks like

Math
 – Math-Lessons
 – Math-Research
Reading
 – Reading-Lessons
 – Reading-Research
History
 – History-Lessons
 – History-Research

If someone clicks Reading I want to load all posts that have a primary category of Reading, Reading-Lessons or Reading-Research… so I need the children.

In the function below you can see I run get_categories on the selected category withe parent argument assigned.  This gets me all the children.  I just need their ids and I need them in string format so I run a quick foreach loop.   I make sure to add the original parent id back to the new array too.  Then I run the WP_Query.

At this point you could just return $posts->posts but I needed the featured image and only a few of the pieces like title, time and a link.  So I built out what I need and return that.

Conclusion

Now to use this we simply visit http://yoursite.com/wp-json/SITE_PREFIX/v1/yoastprimary/##-catid-## and replace ##-catid-## with the actual category number.  I could’ve just made this a static class now that I think about it but whatever, you must remember to initiate it to work.  So in your functions.php of the theme or somewhere in your plugin call $rest_api_primary_cat = new Rest_Api_Posts_By_Primary_Category();

This was easy to parse in my javascript and is running great.  Hope it helps someone! Here’s the full code:

Remove the +Add New Category / Custom Taxonomy Link in WordPress

This post is more about custom taxonomies than it is adjusting category capabilities, but it’s  probably resolved the same way.   So i mention how I’d go about it after I explain what I’ve been doing.

I have a theme that has a custom post type called Members.  These members need to be attached to posts at the authors choice.  For instance, an admin is adding a new blog post.  There are three posts in the custom post type Members: John, Jack & Jill.  This post should be attached a Jill taxonomy/category.

I could solve this with a custom taxonomy, but I want the term options to be only what posts are made in Members.  Problem is, I don’t want the admin to be able to add new terms here.  So that big +Add New Category/Member link has to go.

I could do it with CSS but then someone smart could get around that.  I need it done server side.

Removing the Functionality

As far as I can tell there’s no filter to hook into and remove that feature.  It’s not an argument when registering a taxonomy so you can’t just re-register category or set it when creating a custom tax.

What you can set is what users are allowed to edit/add terms.  The long route would be creating a custom user role and assigning only them.  But I thought to myself, what would WordPress do if I just used a user role that doesn’t exists?  So I did this:

I set edit_terms and manage_terms to ‘god’ and voila! The option is gone!

Add Variation To Cart in WooCommerce: Don’t Forget The Attributes!

The point of this post is to help others that are having a problem dynamically adding a variation of a product (or subscription product in my case) to cart.  I get to that at the bottom of this post if you want to skip the story.

The Problem

I have a pretty high up there client in the box subscription world.  I’ve been brought in to do some WooCommerce functionality with WooSubscriptions and everything else involved.

The checkout process is pretty customized.  We have a page that displays all the attributes available for the subscription variable product.  There’s a bunch of fancy selection boxes and lists and gift inputs and so on.  It’s front end heavy but communicates with a custom endpoint through the REST API that I wrote to add the item to cart.  Problem is, the sub form doesn’t give me a variation id, only the variable subscription product id and all the selected attribute values.

Finding the Variation

The first step is to find which variation they’ve selected.  Someone long before me went through the rigorous process of creating some 50-60 variations of this variable subscription product to match all the different options a user could select.

So I use a WP_Query search the for any post id that has all the meta_key/meta_value matches and select it.  It was a bit of a pain to figure out the best process here but this works.

Adding the Variation to Cart

Took me a few to find the right parameters for adding a variation to cart.  Now that I had the post id of that variation it looked pretty simple from what I found online:

$added = WC()->cart->add_to_cart( $query->post->post_parent, 1, $data['variation_id'] );

This did the trick.  Since I used a WP_Query to get the post I could select the parent (which is the main subscription variable product) needed for first parameter.  Then the quantity, then the variation id.  Which was $query->post->ID but I assigned it to some data my API was returning.

The user checked out and the variation was in the order.  A day after pushing this code the site owner asked where the order details went.  Turns out it original showed the selected attributes in the admin order panel.  I spent a couple hours figuring this out, which I feel dumb now, but going in blind what can you expect.

You have a fourth parameter you can for $variation_data.  This gives it the attribute love it wants and adds it to the order.  Why woo doesn’t just do this automatically if a variation is added? Beats me.  But here’s how you do it using a nice woo provided function for variations.

$added = WC()->cart->add_to_cart( $query->post->post_parent, 1, $data['variation_id'], wc_get_product_variation_attributes( $data['variation_id'] ) );

New Job, New Kid

Woke up this morning and saw a tweet @ me while heading out to work.

I accepted a position at FlowPress a couple weeks ago.  I start on November 7th and I’m crazy excited.  My dream the past couple of years has been to work for a WordPress agency remote.  My reasons:

  1. I love coding WordPress.  But in every job I’ve had I’ve been in charge or tasked in some way with digital marketing, banners and graphics, fixing co-worker computers and in the smaller companies helping move desks and furniture around.  I’m sick of this, I want to do what I’m good at and what I’m dedicated to.
  2. Why do all these jobs require me to come to an office? And why do I have to dress in a certain way? I sit in meetings that have nothing to do with me then I sit in my office and almost no one talks to me.  The times people do they could easily just call, email, text or smoke signal.  There is NO reason for me to drive some where every day.  Over the past three years I’ve been driving anywhere from 30 to 45 minutes each way to go sit in an office for no reason.

I work best when there’s no frivolous B.S. I have to deal with like a commute or dumb meetings about new rules surrounding the use of the office kitchen or what items should be in gift bags at a fund raising event… yes, these are actual meetings I’ve had at previous jobs as the WEBMASTER.

FlowPress

I’ll be a developer/engineer at FlowPress working strictly with WordPress systems.  This is my passion.  I cannot wait to start and look forward to being part of that team and growing with the company.

I’ve been chatting it up on Slack and made it to a couple of stand up meetings already.  I feel like I’m meshing well and will be a good fit.  We may actually be flying up to Toronto to hang with the team in person mid December!

August Knight

My start date was kind of floating.  My wife was due November 14th to bring our son into the world.  August Knight Flannagan decided to come three and a half weeks early and was born on October 21st at 8:51am.

While it was scary having a premature baby, he is completely healthy and so is momma.  I’m overjoyed to have him in our home and it’s cool he and I have birthdays only three days apart.

My wife had to go back into the hospital for 24 hours the day after we got home due to high blood pressure.  So I got to take care of him alone, overnight.  I was a nervous wreck but stayed strong and capable and we had an uneventful day/night together.

Perfect Timing

Honestly, his timing was perfect.  Now I’m able to start sooner with FlowPress.  We got our regiment down at home and I’ll be able to focus 100% when I start on Monday.

I was worried.  No one likes to start a new job with a bunch of unknowns being worked through at home.  If he came right as I was beginning my work with FlowPress I’d have been pulled away every day or two for a doctor appointment or to spend 24 hours alone with him while my wife was in the hospital or while figuring out sleeping patterns and so on.  The burden of dealing with that while starting this new venture is now gone!

So What’s Up

I’ll be dedicating myself to the new gig but keeping myself out there in the WordPress world as a contributor as well.  You will still find me blogging here and at The WP Crowd and I’m gonna try to up my Twitter game a bit.  I mean, I’ve been on there a year now, I should really start using it regularly.