WordPress: How To Create a Custom Admin Button with ACF

Intermediate

This post covers WordPress, custom PHP, JavaScript, and HTML. Fundamentals of both JavaScript and PHP/WordPress is recommended.

There comes a time in a WordPress theme’s life where custom PHP is needed. This can be a packaged plugin that’s used across multiple client sites, or a single theme. There are several ways to approach a custom admin button. A common approach is invoking a JavaScript function on click, then using AJAX to send a request to a PHP file. Though this is a nice solution, there are alternative ways to approach it.

In this article, I go over how to utilize ACF to create button(s) on any field group that send POST data. The process is fairly straightforward, here are the steps:

  • Decide the best place for the button
  • Hook up a JavaScript file with your admin button
  • On click, append your inputs with optional data
  • In a PHP file, look at the $_POST array and perform your logic

From there, it’s up to you to add the logic you or your client wants. Setting it up is a multi-step process, but it’s not too much overhead and shouldn’t require any plugins. You technically don’t even need ACF to do this. However, I’ll use ACF as an example since it’s my favorite plugin. Let’s dig into it!

Where To Put The Admin Button(s)?

Technically, you can add buttons inside any <form> element. You can even use it outside of a form since we’re using JavaScript to append the <input> elements. Where you end up placing the button depends on usability. Will this button update a certain part of the site? Will it change how backend admin functionality works?

Let’s use an admin button that refreshes cached API data as an example. You want to refresh all testimonials on your site. I’m willing to bet you have a custom post type for it. If you have a field group for it too, you could add it there. If your button updates a single testimonial, just add it to each CPT field group. If it updates all testimonials, make a global options field under your Testimonials menu item.

If your button invokes general site-wide functionality, stick it in your global options page. At the end of the day, you should make it easier for whoever will actually be using it. It might be a client, and not you. Think about what would be easiest for them.

Introducing the ACF Message Field

If you haven’t heard of the message field already, it’s a great way to add instructions under any field group. While not the prettiest solution, you should be able to add markup to it.

For a simple button, this option provides a lot of flexibility for placement. A simple button will look like this:

<div id="refresh-button-container">
<button
    type="button"
    class="button-secondary"
    id="refresh-cache">Refresh Testimonial Data
</button>
</div>
This example produces a pretty simple button. However, you should be able to enqueue a style and make it as fancy as you want.

Using the message field, you can add this markup under any defined field group. So the button is in place.. now what?

Linking JavaScript to Your Admin Page

In order for the button to do anything.. it needs to perform an action on click. This obviously requires JavaScript, so let’s set that up. Doing so isn’t difficult and is already documented here.

We can use admin_enqueue_scripts to load a JavaScript file, but we only want to load it for the relevant admin page.

add_action( 'admin_enqueue_scripts', function ($hook) {
      //only load this script for a certain URL page slug
      if($hook == 'your-url-page-slug') {
          $path = asset_path('scripts/admin.js');
          wp_enqueue_script( 'textdomain/custom-admin-js', $path, ['jquery']);
    }
} );

Here’s what’s happening: We’re using the admin_enqueue_scripts parameter $hook to check which admin page to load the JavaScript. You can get a specific ACF page’s slug by checking the URL. It should be after the &page= query parameter.

Once the conditional passes, simply enqueue the script like any other. I placed this in a file called admin.php, but it can be loaded in your functions.php file. You can also load it from your plugin files if you’re packaging this up into a separate plugin.

From your JS file, test to make sure everything is working.

import $ from 'jquery';

$(document).ready(function($) {
    console.log('Im working!');
});

Appending Data To Your Form Using JavaScript/jQuery

In the last example, we loaded the JavaScript file with jQuery as a dependency. However, this solution is simple enough to use vanilla JS, if preferred. From here, it’s a two step process.

  • Add a click event listener to the admin button
  • Attach hidden input fields to the ACF <form> element.

Here’s the code to accomplish this:

import $ from 'jquery';

$(document).ready(function($) {
    Admin.init();
});

let Admin = {
    init() {
        this.setEventListeners();
    },
    setEventListeners() {
        $('#refresh-cache').click(Admin.refreshCache);
    },
    refreshCache() {
        //attach hidden input then submit the form
        Admin.attachData();
        $('#post').submit();
    },
    attachData() {
        let $buttonContainer = $('#refresh-button-container');
        let inputField = '<input type="hidden" name="refresh-cache" value="1" />';
        $buttonContainer.append(inputField);
    },
}

This is a basic example and only attaches a single input. Yours may need multiple pieces of data, so you could simply attach more <input> fields. Once the button is clicked, the JavaScript code will submit the form automatically. Once the form is submitted, the last step is to check the POST data that is sent through.

Processing POST Data in Your PHP Files

Where you perform PHP logic depends on your theme’s file structure. I’d recommend performing the logic in a separate file outside of functions.php, or even in its own packaged plugin. However you do it, the process is pretty straightforward.

//Here, we're only checking if the POST data has been sent through
//so we can outsource the logic to the refreshCache function
if($_POST['refresh-cache'] == 1) {
    refreshCache();
}

If you’re passing multiple bits of data, you should be able to access it using the $_POST array.

if($_POST['refresh-cache'] == 1) {
    $exampleArg1 = $_POST['example_data'];
    $exampleArg2 = $_POST['more_example_data'];
    refreshCache($exampleArg1, $exampleArg2);
}

From there, what logic you implement is up to you. That’s pretty much it! Have fun, and make something awesome.

Leave a Comment