WooCommerce: Add Fee To Order During Checkout If Cash On Delivery Or Any Other Reason/Gateway

Recently I was tasked with adding a field to the cash on delivery gateway in WooCommerce.  They wanted a field they could put in a dollar amount that would be tacked on as a fee to orders using that gateway.  Seemed simple enough with some googling but took a bit longer to tweak and get functioning correctly.

Add Field to Cash On Delivery Gateway

Adding fields in WooCommerce to its forms is pretty straight forward.  You hook into the WC Settings API and adjust them using this hook:

add_filter( 'woocommerce_settings_api_form_fields_<id>', function( $form_fields ) { return $form_fields; } );

Replace <id> with the id of the form.  In this case it’s “cod” for the Cash on Delivery form. In your hooked function you can manipulate the form fields array as needed.  For my case I just needed to add a field at the end for a fee so I do this:

Add Fee To The Order

Now that we have a fee set we need to hook into the checkout process.  For this I use the action “woocommerce_checkout_create_order” to manipulate the order right before it’s saved.  In WooCommerce 3.0 and over you no longer use the add_fee() function but instead create a line item fee object and add that to the order.  Here’s how I did what I needed:

SUPER IMPORTANT

Notice the add_item( $item ) call to place it in the order.  If that’s all you do then you will see the fee on the order but the order total won’t include it.  You need to make sure you run the order’s calculate_totals() function after adding the item.

Creating a Custom or Extended Gravity Forms Field with Multiple Inputs

I’m building a site for a Japanese company.  They need a Gravity Forms address field with a different order.  I spent a BOATLOAD of time trying to get this working and I finally did.  Here’s some details.

Extending Address Field

I started by extending the address field.  Simple enough.  Made some tweaks to the get_field_input() function to reorganize.  Made sure all other functions that used the .1, .2, etc. id’s for the inputs inside the field were updated in my field class.

After some trial and error with those I got the form field to be in the admin so I could add it to a form.  Awesome! Went to the front and there’s my new beautiful field.  But no matter how hard I tried it would not save any of the data.

I searched and searched through all the hooks I could find related to this.  I almost gave up but then I found a comment that said something about default inputs were loaded in js.php file.

JS.PHP

In the root directory of Gravity Forms is a file named js.php.  This file runs a switch case on different field types and populates some data.  If you look towards the bottom around line 838 at the writing of this post you will see:

<?php do_action( 'gform_editor_js_set_default_values' ); ?>

Right there you need to hook in your own default settings with field.inputs defined.  That’s about it! I just copied the info they had for the address field, tweaked it to match my class’s data and voila.

WordPress phpinfo() Version 16.3 – Click To Copy Plain Text

I’ve just released the latest version of my plugin to the WordPress repo.  You can now simply click a button to have a plain text version of the information copied to your clip board.  Paste into an email or support forum with ease and no crazy html or code getting included.

WordPress phpinfo()

Simple Custom Settings Fields for Give WP Donations Plugin

My previous post about Give was an intro to building a payment gateway for the plugin.  If you’ve built extensions for Give or are starting to then you’ve probably run into the settings fields API for adding a variety of inputs.  The options are limited and there are often times a need for custom fields.

How Give’s Settings Fields Work

In the class file class-admin-settings.php located in give/includes/admin/ the function output_fields handles displaying different types of fields registered.  If you are here you probably know the standard format for adding a settings field in your code:

settings[] = [
   'name'    => __( 'Select an Option', 'my-text-domain' ),
   'desc'    => '',
   'id'      => 'select_box_1',
   'type'    => 'select',
   'options' => [ 'op1' => 'Option 1', 'op2' => 'Option 2' ],
]

That adds a select field with a couple options.

As you add settings to an array they will be displayed in the same order in a Give formatted html table.  It appears they were using CMB2 but have since deprecated it.  I’m not 100% sure but there are remnants of it in the plugin.

Creating A Custom Field

Within the output_fields function I mentioned above there is a switch statement on the field type.  This goes through all the type options default in Give and outputs the field content based on type.  After all the case type options the default is a sweet do_action( ‘give_admin_field_’ . $value[‘type’], $value, $option_value );  This is how you do what you want to do with a custom field.

One thing I really needed when building an extension was a way to have inter-woven sub headers for form options.  I could not find a way to just output a title.  The type field title that’s default to Give outputs the top of a table with it as it’s meant to be, that’s right, at the top lol.

Let’s start with an example of creating a simple sub title output.

Remember, the form settings fields are all in a table so you need to use a table row to output your field.  Now we can add this subtitle between fields by using:

$settings[] = [
   'id'   => 'my_settings_subheader_one',
   'name' => 'Custom Sub Header Section',
   'type' => 'my_custom_subtitle',
];

Voila! We have a custom field in Give settings.  The type is set to what comes after give_admin_field_ in the add_action of our sample.

Custom Give Settings Fields Subheader and HR
Here I have two custom fields, a subheader field and a horizontal rule field

Saving Custom Field Data

Saving is pretty straight forward as well.  The example below is kind of pointless as Give already has a text box type but it shows how you’d go about saving your data in a custom field.

The key is figuring out how to structure your action’s name.  Give uses the settings page followed by _save_ followed by the tab you are on.  Here’s their documentation on it followed by an example.

/**
 * Trigger Action.
 *
 * Note: action dynamically fire on basis of setting page slug and current tab.
 * For example: if you register a setting page with give-settings menu slug and general current tab name
 *              then action will be give-settings_save_general
 *
 * @since 1.8
 */
do_action( self::$setting_filter_prefix . '_save_' . $current_tab );

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/