Bulk copy-paste post meta ( custom fields )

When dealing with highly customised WordPress websites you often end up with a lot of custom fields. Especially if using a manager like  Advanced Custom Fields, it could be tedious to manually copy all the fields.

Why not push the whole database?

That’s a very good solution if you have the staging and live websites in sync. In my experience though, especially when developing websites ( code ), you end up building pages locally or on staging and duplicating them is difficult.

Having a repeater field in ACF or a Flexible content field could mean lots of different text boxes to manage.

What’s the solution?

I wrote a small plugin which does a simple job:

  • Adds a textarea field with all your custom fields in JSON format.
  • Below that textarea you have a checkbox which when checked will use the value in the JSON to update the custom fields.

A simple usage example is:

  1. Install the plugin on both websites ( or just on one if you want to copy paste among pages/posts in the same website )
  2. Copy-paste the values and update.

That’s it!

Please note: the plugin is not really tested so use at your own risk, I will try to improve it as time allows it.

If you want to contribute, the GitHub repository is here.

You can download the current version here.

Photo by Paulius Dragunas on Unsplash

WordPress media uploader custom filename

In the past months, I’ve been working on a plugin which creates a custom screen in the WordPress admin. It’s a custom functionality entirely but I’ve tried using as much WordPress functions to keep the right feel in the interface.

One of the forms in this page has an image uploader which uses wp.media. I was faced with this challenge: change the filename of the images uploaded on that page.

I looked around the code and inspected the upload requests and this is the solution I came up with.

1. Mark in the media uploader

The first step was to make sure this won’t affect other media uploaders in the website. For that I used the hook current_screen in which I checked on what page we are.

Because this hook is called early on in the admin I added a filter inside of it for plupload_default_params. Using this filter I added a custom parameter which will be sent each time an image is uploaded on that page.

2. Change the filename

The next part was changing the filename. In my case I just wanted to make sure the filename is completely random ( for which I have a separate function ).

I found the most straight-forward way of doing this is using the sanitize_file_name filter. This also ensures that the filename is unique as it is called inside the wp_unique_filename function.

So inside the filter I added a check for the custom parameter added in step one and replaced the name.

The code

In order to make things easier to understand I stripped down the functions mentioned in the article and created a custom class.

Pretty easy in the end but hopefully will save someone time looking into a way of doing this. I am aware this might not be the best solution but it does a good job for what I wanted.

Photo by Samuel Zeller on Unsplash


Adding a custom element to the Enfold Avia Builder

In the very popular Enfold theme, the author created an easy to use layout builder called Avia Advanced Layout Builder. Because it’s so popular, I am constantly encounter it in the projects I work on for clients.

Most times I work on adding a new feature I prefer extending the builder. From a plugin or a child theme, this allows users to keep the theme up to date.

The Enfold custom element

In order to keep things simple we’re going to create a custom text element. And of course, I’m using the existing “Text block” element as reference & starting point.

Adding the new element is an easy 3-step process:

  1. Copy the existing class file to your child theme ( or plugin ), in this case /wp-content/themes/enfold/config-templatebuilder/avia-shortcodes/textblock.php. Don’t forget to include it.
  2. Change the name of the class if you don’t want to override the existing element.

    class avia_sc_text extends aviaShortcodeTemplate {


    class custom_text_element extends aviaShortcodeTemplate {
  3. Customize by changing the values in the function “shortcode_insert_button”. You’ll notice a few properties:
    $this->config['name']         = __('Text Block', 'avia_framework' );
    $this->config['tab']         = __('Content Elements', 'avia_framework' );
    $this->config['icon']        = AviaBuilder::$path['imagesURL']."sc-text_block.png";
    $this->config['order']       = 100;
    $this->config['target']          = 'avia-target-insert';
    $this->config['shortcode']        = 'av_textblock';
    $this->config['tinyMCE']       = array('disable' => true);
    $this->config['tooltip']       = __('Creates a simple text block', 'avia_framework' );
    $this->config['preview']      = "large";

Customizing your new component

From the properties above I think you should focus on a few:

  • “name” – I think it’s obvious, this is the name of the block which is displayed in the builder
  • “tab” – this is the tab of elements, by default you have 3 tabs in the builder to group similar elements. You can even create a new tab.
  • “icon” – obvious, you can see they also have a nice helper function so you can check out the path at /wp-content/themes/enfold/config-templatebuilder/avia-template-builder/images for other icons available, or use custom one from your child theme/plugin.
  • “order” – a number used to order the elements, you can look at the other elements to figure out where to place it. It works similarly to the WordPress custom menu item order.
  • “shortcode” – the most important option which I highly encourage you to change if you don’t want to override an existing element. Use a prefix to make sure you don’t override an existing shortcode.
  • “tooltip” – this is the text displayed when you hover over the element in the builder.

Adding new options

The reason you created a new element is to add custom options, right? This can be done from the “popup_elements” function which contains an array of arrays defining each field.

Listing all the available fields and their options would require a separate, long, article. I usually just go through other components and look at what fields are available and copy them over to my custom element.

Using the new options

The good news is that once you define a new element in this array it will automatically be added to the shortcode. This means that if you add, for example, a new text input for a caption, or a subtitle, you can use it directly. Take this code as example:

   'name'            => esc_html__( 'Subtitle', 'm_text' ),
   'id'              => 'subtitle',
   'container_class' => 'avia-element-fullwidth',
   'std'             => esc_html__( 'What are you thinking?', 'm_text' ),
   'type'            => 'input',

This will create a new property, “subtitle”, in the generated shortcode, which means you can go ahead in the “shortcode_handler” function.

You can use it by calling:


Use that in the generated html. That’s all!

A few tips

There are some special elements used for layouts – you’ll notice this:

      "type"     => "tab_container", 'nodescription' => true
      "type"     => "tab",
      "name"  => __("Content" , 'avia_framework'),
      'nodescription' => true

Very useful to have the elements clearly separated.

Another one I wanted to point out is the “linkpicker”. If you’re familiar with ACF, it works similarly to the “relationship” field. The tabs are also used similarly to ACF as you just list them and when a new one is added it creates a new tab.

Photo by Ant Rozetsky on Unsplash

WooCommerce variation data in SearchWP results

SearchWP is, in my opinion, the best solution when it comes to search in your WordPress website. Besides providing a great user experience by actually returning good results, it’s well written and allows some nice extensions.

The situation which I’m going to provide a solution for is this: you have a WooCommerce website with variable products. Those products have some custom characteristics which you want to allow your users to search by.

Let’s go with an even more specific example. Let’s say the products are books, and each book has an ISBN. They are variable maybe in edition.

And you want to allow your customers to search by ISBN.

Indexing the data with SearchWP

If you’re not aware, SearchWP’s system is based on an index. The index goes through all the items/posts in the background and creates a structure which makes searching more efficient. But at the same time it allows you to set priorities for each info.

The first step to index the data properly is to make SearchWP aware of it. In order to do that we’ll need a bit of code added to either functions.php in your current theme or small custom plugin. I always recommend a custom plugin because in case you make a typo the plugin will be deactivated and you won’t kill the whole website.

In order to index the data, I used the hook “searchwp_extra_metadata“. This hook allows you to add extra data to be indexed for each post.

Now for the actual code:

As you can see, this is pretty straight-forward and give you great power on what data to associate to each post. You could also use this for example to associate relevant posts to one another or even data from taxonomies.

Resetting the index

Just adding the code above won’t do anything. You’ll need to go to the WordPress admin, navigate to Settings > Search WP. Select the post type you wish to change ( in our case Products ) and at the bottom click on “Add Custom Field”.

If the code is working properly, you will see the newly added key in that list ( in our case “m_product_isbns” ). Select that field, set its priority and save the settings.

Next, go to the “Advanced” tab and click on Reset Index. When the index finishes re-indexing the data, you’ll have the data properly attached to the products.

Sync 2 WordPress websites using REST API custom endpoints

Luckily, I recently had to find a solution to sync data between 2 WordPress websites. I say luckily because it gave me the chance to use WP REST API’s custom endpoints.

The data to be synced was not very complex fortunately, mostly basic post data. In this particular case I had to sync 2 custom post types, actually some custom fields, the post status and the permalink.

Adding custom endpoints

I must admit, for me, this as clear as it can be. Especially in a WordPress environment, the structure for adding a custom endpoint is very straight-forward.

This is something similar to what I used:

register_rest_route( 'm_api/v1', '/custom', array(
   'methods'  => 'POST',
   'callback' => array( $this, 'handle_api_request' ), // In a class
) );

What this does is:

  1. It adds a new route in the form of: http://your-website.com/wp-json/m_api/v1/custom – of course, you can use whichever structure you wish.
  2. It only passes through POST requests unless otherwise specified.
  3. And also has support for custom variables in the url ( ids and such ) – more on this in the documentation.

In this case – being a “closed circuit” situation, I used a secret key to sign all requests and make sure nobody gets in the middle. Along with HTTPS and considering no secret data was being sent, it was enough. You might want to use different types of authentication.

I’m not going to share the rest of the plugin because this is the only relevant part to this subject. What I am going to share is how I handled things from the other plugin ( on the other website ).

Connecting to the your new endpoint

In the “client” plugin, which I used to initiate the updates, I used a very simple structure.

First, I hooked on the save_post action to listen for a change in the post. After I had the data collected and validated from the post, I used this function to make the call:

public static function make_request( $data ) {
   if ( ! empty( $data ) ) {
      $data['token'] = self::get_token( $data );
      wp_remote_post( self::API_URL, array(
         'body' => $data,
      ) );

As mentioned above, I use a secret key to sign the data and use the very nice function wp_remote_post to send the data to the other website.

On the other website, the endpoint takes over and passes the data to the assigned function to process it.

I find this structure very easy to set up with 2 small plugins: safe & simple.

Gravity Forms entries quick view

Gravity Forms is a great plugin many WordPress websites use. I’ve used it many client projects in the past and I’ve always missed a feature!

If you are a OS X user you are surely familiar with the “quick view” action – pressing space after selecting an item in Finder. I find this almost instinctive for me and miss it in many situations.

This feature is something which I miss in the list of GF entries. So I set out to build a plugin that does exactly that. This article will also include a step-by-step guide on how I built the plugin.

You can browse the code here or download the plugin here. If you also want to see how it’s built, read on.

Getting started

You should be comfortable coding WordPress plugins and I recommend using and IDE ( like PhpStorm ). This will make navigating a large plugin like Gravity Forms much simpler.

Finding a hook ?

First thing I did was to search for a hook to add the preview button to the list of entries. Easiest way, in my opinion, inspect the table and find something specific:

See that id there? “gf_entry_list” – next step is I went in the plugin folder and searched all the files:

Which is where I found the hook we are going to use: gform_entries_first_column_actions. This allows us to add an extra custom button next to the “edit”, “delete”, etc buttons.

Maybe going through the documentation is faster for some people but I find this method to be the most efficient for me.

Adding the button

The next step is going to be to add a button as the preview trigger. Because we are not in a OS interface I think it makes sense to have a click trigger.

Using the hook found above we add the button to the list of actions:

All the code is available at the end of this article.

This will add the button ad the end of the list of actions:

xt step is to add the id of the entry to the button and move on to the JS part. In this case, the $lead array contains the entry data ( as reflected by the PHPDoc comments ).

The actual functionality

Next we’ll need to add some JS into that page which will handle the loading of the preview. In these cases I usually start writing the code in a separate JS file, but if it turns out to be small I just use the proper hooks to load it only in that page. I’m not a fan of making an extra request although it is easier to maintain.

Adding scripts

Using the hook “admin_enqueue_scripts” the following function came to life:

Make sure you use the proper hook to avoid loading these scripts on other pages.

The JavaScript

As WP-admin already has it loaded, I used jQuery. Make sure to use the “promise” structure for the Ajax call as the old one is deprecated. Here’s the basic structure which we’ll use to go and define the Ajax handler in PHP.

Next up: the PHP which will handle the Ajax call and retrieve the GF entry data.

The PHP part of the Ajax call

For Ajax calls, WordPress has a very nice system in place which allows you to hook using the prefix “wp_ajax_” – if you you’re not familiar with it read more here.

Getting the entry data is not a big deal as GF has a proper API and we can use this function:

GFAPI::get_entry( $entry_id );

The only problem here is that the data has no human-readable labels, so it makes no sense.

In order to get over this, we’ll also need the form fields. In the end I decided to load the markup for the pop-up directly with the form table structure ( to avoid loading the form structure each time ).

You can find the form structure easily using:

GFAPI::get_form( $form_id );

In the array retrieved there there will be one entry for the “fields”. Just looping through them and through the entry data is enough. Luckily, GF takes care of ordering things properly for the API.

The markup

A good hook to load the markup of the quick-view panel is “gform_post_entry_list“. This is called at the end of the list and we can pre-load the table there and hide it with CSS.

I’ve loaded a simple markup there to display the info. Using the function mentioned above to retrieve the form structure we end up with something like this:

Linking it all together

Now that all components are in place we just need to send the entry data using the Ajax function and populate the html with it.

First we send the data using wp_send_json to make sure it goes out ok. Next, we loop through the list of labels and populate them with the data in the JSON.Now we can take care of the styles and using a CSS class we can toggle the visibility of the table. The final touch is to also allow users to close that table.

If you want to see the plugin in action you can browse the code here or download it here.

Adding custom commissions to WC Vendors

Let’s say for some reason you want to add custom commissions to WC Vendors. The main thing you’ll need is the filter “wcv_commission_rate“.

The way this filter works is that it allows you to add on top of the calculated commission by also passing along the product price.

Use cases & code

Let’s say for example that you want your vendors to cover the credit card commissions. You’d have to check the gateway used for checkout on that specific order and update the commission.

You can see the code below:

Please note that the gateway may not approve of this practice! Always check their terms before doing this.

Another nice use case would be to give vendors different commissions based on the order location. So let’s say that you want to give them more of the sale for countries in which you have less sales.

In this case you’d have something among the lines of:

Notice that in this case, the commission gets added to the initial commission so the vendor actually gets MORE.

Be careful though – if you are going to set options for this, don’t allow users to go over 100%. I would also add a check directly in the function above in such a case.

Another nice use case I just thought of would be to check if the customer is new on the website and give the vendor a bonus like – no commission for the first purchase!

Let me know in the comments if that would be a good idea for a plugin.

WordPress TinyMCE button for shortcode

For those of you who didn’t know, TinyMCE has a straight-forward way to include a form in a modal window which you can use to generate shortcodes.

This is great news because it will make WordPress editors much less prone to error not having to write shortcodes by hand.

How do you do it?

So the approach in the WordPress way to do this is:

  1. Add the button to the WordPress TinyMCE toolbar using the “mce_buttons” ( or others ) filter.
  2. Ask TinyMCE to load a new JavaScript plugin for the editor which will handle the button.
  3. In the TinyMCE JavaScript plugin add the button and handle its events.
  4. Optionally if you have a custom shortcode, define it with its arguments.

In my example I have created a small plugin, which can be found on Github.

The plugin will add a button on the first row of the editor which when clicked will open a modal. The modal is handled by the WindowManager class included in TinyMCE. Another great part of using this approach is that you already have what is needed to generate a form.

After that, getting the parameters from the form and generating a shortcode to be inserted in the content is pretty easy.

You can get the whole plugin here.

I think the code is self-explanatory for the most part.

Things to watch out for

The code can be easily included in another plugin and extended to generate multiple buttons.

One issue I found not very intuitive at first is that if you add another button you will need to define another plugin for it to be taken into consideration, even if it’s in the same file.

So in the function where you add the js plugins you’ll end up with:

function add_embed_button_js( $plugin_array ) {
   $plugin_array['msb_button'] = plugin_dir_url( MSB_PLUGIN_FILE ) . 'assets/js/embed_button.js';
   $plugin_array['msb_button_2'] = plugin_dir_url( MSB_PLUGIN_FILE ) . 'assets/js/embed_button.js';
   return $plugin_array;

I trust that TinyMCE won’t attempt to load the same file 2 times. Also I am aware it might not be the right approach but it works!

Also, as mentioned in the plugin README – by default the plugin will add a button with no icon so you might miss it.

Extend wp-admin search to use custom fields

UPDATE: For the WooCommerce-friendly version of this, see this article.

I think the title is self-explanatory but let’s detail the situation a bit:

Let’s presume you have a custom post type for Cars and for each car you have the VIN number in a custom field. You want to allow users to search from the admin directly by that field. Also, you need them to use the default search input:

Wp-admin search

The code

First we have to find the right hook to extend the search with. In our case I found the best results with the posts_search filter.

Next, the logic! Keep in mind this filter is being called in the get_posts function of the WP_Query class, so everywhere. That results in adding a check to see if we are on the right page.

Also, keep in mind that we are altering the “where” part of the actual SQL query.

Further usage

Like I mentioned before – this snippet checks if the search is performed in the admin, but that also means you can use it in the frontend. So if you’d like to extend the default WordPress search to enable custom field searches you can change the logic at the top. This can be easily switched to enable WooCommerce products search by SKU or similar.

Using WordPress with a database in the cloud

Looking for a way to speed up a WordPress website with a very large database? One solution might be to use an external database in the cloud.

The first thing that came to my mind was to look at Amazon AWS for their solution. I found that it’s called Amazon RDS and you can use it as a replacement for your local database. Of course there are also other similar solutions offered by Google and Microsoft Azure.

Setting it up

The setup is fairly easy, I used the steps described here and although the AWS interface has changed, the process is pretty similar. You have to login to the AWS dashboard and choose RDS from the Services dropdown. On that page click on the “Launch a DB instance” button.

A sidenote: The interesting part is on the next page, you can choose from multiple types of databases and what caught my eye was the Amazon Aurora option which is MySQL compatible! (which means you can just import an SQL dump ). Digging more into it I found that WordPress linked to an Amazon Aurora DB has proven to give great results.

If you choose either Aurora or MySQL you will have similar steps to set up and you can choose the processing power and set a master username and password to connect to the db server.

After the setup it will take a few minutes for the server to come online. Afterwards you can connect to it directly and import your database ( if you have an existing website ) – on OS X I recommend using Sequel Pro. For the server use the “endpoint” from the dashboard and the username and password you set in the setup.

Next you just change the database details in the wp-config.php file to the ones you find in the Amazon RDS dashboard. If everything went well you should have an WordPress website running on a cloud database, cool!

Some notes

Be careful which pack you choose as an Aurora server tends to get expensive quickly. From my estimates, the cheapest goes to around 200$ per month.

For the regular MySQL db you can go for as low as 12$ per month from what I have read.

Also make sure that you choose an AWS region that is close to your website’s host server. This will greatly influence the loading times and might cause more problems than improvements.