Creating pages automatically on plugin activation in WordPress

If you are creating a WordPress plugin, often times you will need to reference a specific page in order to display some kind of data or other information. Although it is possible to manually create pages in WordPress, required by a plugin, creating pages automatically on plugin activation will ensure your plugin works out of the box.

The first step is to register a function in your plugin that will fire upon activation. The following code uses the register_activation_hook function. The function accepts two parameters $file and $function. $file is a string representing the path to the main plugin file; $function is a reference to the function that will contain our activation code.

define( 'BEARDBOT_PLUGIN_FILE', __FILE__ );
register_activation_hook( BEARDBOT_PLUGIN_FILE, 'beardbot_plugin_activation' );

function beardbot_plugin_activation() {
  // activation code goes here
}

The first line uses a constant to store the path to the main plugin file. This will usually be a file in the plugin root directory with the same name as the plugin folder. Next we use the register_activation_hook function to register our activation function, referencing the path to the plugin file.

The first thing we do on activation is check that the current user is allowed to activate plugins. We do this using the current_user_can function. The first and only required parameter accepts a string representing a role or capability that you would like to check that the current user has. A detailed list of roles and their associated capabilities can be found here.

define( 'BEARDBOT_PLUGIN_FILE', __FILE__ );
register_activation_hook( BEARDBOT_PLUGIN_FILE, 'beardbot_plugin_activation' );
function beardbot_plugin_activation() {
  if ( ! current_user_can( 'activate_plugins' ) ) return;
}

Finally, we create our new page, after we check that a page with the same name does not exist.

define( 'BEARDBOT_PLUGIN_FILE', __FILE__ );
register_activation_hook( BEARDBOT_PLUGIN_FILE, 'beardbot_plugin_activation' );
function beardbot_plugin_activation() {
  
  if ( ! current_user_can( 'activate_plugins' ) ) return;
  
  global $wpdb;
  
  if ( null === $wpdb->get_row( "SELECT post_name FROM {$wpdb->prefix}posts WHERE post_name = 'new-page-slug'", 'ARRAY_A' ) ) {
     
    $current_user = wp_get_current_user();
    
    // create post object
    $page = array(
      'post_title'  => __( 'New Page' ),
      'post_status' => 'publish',
      'post_author' => $current_user->ID,
      'post_type'   => 'page',
    );
    
    // insert the post into the database
    wp_insert_post( $page );
  }
}

Here is a full list of parameters accepted by the wp_insert_post function.

Creating pages automatically on plugin activation in WordPress is the best way to ensure maximum compatibility with any WordPress website.

References

Handle POST and GET requests in WordPress using admin-post.php

Today we are going to learn how to handle POST and GET requests in WordPress using custom functions and admin-post.php. There are various ways to process and handle POST requests in WordPress. You could use a page template or even a custom script. When using a custom script, you do not have access to WordPress or its functions by default. If you are using a page template, you jeopardise maintainability by mixing logic and display code. WordPress offers an elegant method for processing POST (or GET) requests using custom functions via admin-post.php.

In this example we will be processing POST data from a simple contact form submission. We first add the HTML for our form.

<form method="post" action="<?php admin_url( 'admin-post.php' )' ?>">
  <input type="hidden" name="action" value="process_form">
  <label for="name">Name:</label>
  <input type="text" name="name" id="name">
  <label for="email">Email:</label>
  <input type="text" name="email" id="email">
  <input type="submit" name="submit" value="Submit">
</form>

As mentioned earlier we will be processing the post request via admin-post.php. To get the URL for this script we use the WordPress function admin_url() and add it to our forms action attribute. The hidden input element will be used to hook into the admin-post.php script and our custom form processing function.

Next we will create a custom function for processing the form data and hook it into our form submission via the admin_post hook.

<?php
add_action( 'admin_post_nopriv_process_form', 'process_form_data' );
add_action( 'admin_post_process_form', 'process_form_data' );
function process_form_data() {
  // form processing code here
}
?>

We mentioned earlier that the hidden input element in our form would allow us to hook into admin_post. The first 2 lines above use the format admin_post_nopriv_$action and admin_post_$action respectively as the hook, where $action is the value of the hidden input in our form. The hidden input element must have action as the name attribute’s value for this to work.

admin_post_$action fires when a user is logged in and admin_post_nopriv_$action fires when a user is not logged in, which means you can create multiple custom functions to handle requests, depending on whether a user is logged in or not.

You will now have access to the form data via the $_POST (or $_GET) array(s) in your custom function(s). Once you have processed, validated or sanitised the form data you can redirect to a front-end page using wp_redirect.

Using this method to handle POST and GET requests in WordPress, when submitting a form, will prevent browsers from displaying a form re-submission warning when a user hits the back button after submission.

References

Cache busting CSS and JS assets in WordPress

Today we are going to learn about cache busting CSS and JS assets in WordPress the easy way.

Have you ever struggled to make sure updated versions of your CSS or JavaScript assets are being sent to users of your WordPress website? One way of solving this problem in the past, was to give each asset a unique name after updating it, forcing browsers to grab the new version when users visited your website. If you have ever done this, you will know it is a tedious process. Thankfully there is a much easier way by using the file meta data for each assets and the handy PHP function filemtime.

WordPress gives us the tools out of the box, to append unique version numbers to our CSS and JS assets, in the form of a query string. The wp_enqueue_style and wp_enqueue_script functions have a version parameter. With the use of the filemtime PHP function, we can automate the entire process by passing the file modified string as the value for the version parameter.

The filemtime function returns the file modified time from a files meta data. By using the $ver parameter of both the wp_enqueue_style and wp_enqueue_script WordPress functions, we can append the file modified time to our CSS and JS asset URLs.

The method for adding the file modified time to your stylesheets is shown below.

wp_enqueue_style(
  'theme-styles', // $handle
  get_bloginfo( 'stylesheet_url' ), // $src
  array(), // $deps
  filemtime( get_stylesheet_directory() . '/style.css' ) // $ver
);

The method for adding the file modified time to your scripts is shown below.

wp_enqueue_script(
  'theme-scripts', // $handle
  get_template_directory_uri() . '/js/scripts.js', // $src
  array( 'jquery' ), // $deps
  filemtime( get_template_directory() . '/js/scripts.js' ), // $ver
  true // $in_footer
);

This method of cache busting CSS and JS assets in WordPress means you will never have to worry about users not seeing updates you have made.

References

Making an AJAX call to a custom WordPress plugin script

Today we are going to learn about making an AJAX call to a custom WordPress plugin. This method will allow you to make a call to your plugin using JavaScript. The call will be processed by a custom PHP function and a response returned.

To make AJAX calls to a custom plugin script, that has access to WordPress objects and functions, two hooks must be used; wp_ajax_$action and wp_ajax_nopriv_$action; where $action refers to an AJAX requests action property.

Each AJAX request must be made to the admin-ajax.php script. To get the URL for the admin-ajax.php script, the admin_url() function can be used, as shown below.

$ajax_url = admin_url( 'admin-ajax.php' );

The plugin function that will process the AJAX request must be hooked to both of the wp_ajax actions above. custom_action_name should match the AJAX requests action property and custom_function_name is the name of the plugin function that will process the AJAX request, as shown below.

add_action( 'wp_ajax_custom_action_name', 'custom_function_name' );
add_action( 'wp_ajax_nopriv_custom_action_name', 'custom_function_name' );

function custom_function_name() {
  // code to process AJAX request
}

In order to make the URL to the admin-ajax.php script available in your JavaScript file you can use the wp_localize_script function after registering, but before enqueueing a script, as shown below.

wp_register_script( 'ajax-script', plugin_dir_url(__FILE__) . 'js/ajax-script-name.js' );
$wp_vars = array(
  'ajax_url' => admin_url( 'admin-ajax.php' ) ,
);
wp_localize_script( 'ajax-script', 'wp_vars', $wp_vars );
wp_enqueue_script( 'ajax-script' );

The admin-ajax.php URL can now be accessed inside your JavaScript file as a property of the wp_vars object, as shown below.

var ajax_url = wp_vars.ajax_url;

Now all that’s left to do is to make the AJAX request. For brevity I will not go into the complexities of creating a cross-browser AJAX request. The code below should work in most modern browsers.

var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  if( xhr.readyState === 4 && xhr.status === 200 ) {
    console.log( xhr.responseText );
  }
}
var ajax_url = wp_vars.ajax_url;
xhr.open( 'POST', ajax_url, true );
xhr.setRequestHeader( 'Content-type', 'application/x-www-form-urlencoded' );
var params = 'action=custom_action_name';
xhr.send( params );

By using a few built-in WordPress functions, making an AJAX call to a custom WordPress plugin script is made possible.

References

Sorting WordPress posts using multiple meta keys

Today we are going to learn about sorting WordPress posts using multiple meta keys. The method uses WP_Query and can be used in page templates, shortcodes functions, custom plugin scripts and a variety of other ways.

Occasionally it may be necessary to custom order posts using multiple meta keys. This can be achieved using the meta_query parameter of the WP_Query object.

Below I will show you how to order a custom post type called member, inside a page template, using 2 meta keys; board_position and current_employer. The example also shows you how to sort the results using both meta values.

$args = array(
  'post_type' => 'member',
  'meta_query' => array(
    'relation' => 'AND',
    'board_position_query' => array(
      'key' => 'board_position',
    ) ,
    'current_employer_query' => array(
      'key' => 'current_employer',
    ) ,
  ) ,
  'orderby' => array(
    'board_position_query' => 'ASC',
    'current_employer_query' => 'ASC',
  ) ,
);
$member_posts = new WP_Query( $args );

By using the meta_query parameter we can pass an array of arrays containing the meta keys we want to sort our posts with. The key index of each nested array matches the meta_key stored in the wp_postmeta database table.

If you are using this query in a page template and want to make use of the loop, the functions have_posts() and the_post() must be made methods of the $member_post object, as shown below.

while( $member_posts->have_posts() ): $member_posts->the_post();
  // loop code goes here...
endwhile;

As you can see, sorting WordPress posts using multiple meta keys is a breeze thanks to WordPress.

References

Displaying custom post types on a WordPress blog page

Today we are going to learn about displaying custom post types on a WordPress blog page using the pre_get_posts hook.

If you are using custom post types via a theme or plugin you may want to display one or more custom post types on your site’s blog page.

Below I will show you how to modify the main query of a blog page using the pre_get_posts hook.

In the example below I will be modifying the main query to display the custom post type news. The benefit of using the pre_get_posts hook is that the query is modified before it is run, avoiding possible performance implications from rerunning the main query. To display the custom post type news add the following code to your site’s functions.php file.

add_action( 'pre_get_posts', 'custom_post_query_vars' );
function custom_post_query_vars( $query ) {
  if( $query->is_main_query() && is_home() ) {
    $query->set( 'post_type', 'news' );
  }
}

All parameters accepted by the WP_Query object can be used with the pre_get_posts hook via the $query->set() method to modify the main query.

The $query->is_main_query() method ensures that only the main query (such as the loop) is modified and not a secondary query.

The is_home() function returns true when the blog post index page is being displayed.

To display multiple custom posts types you can pass an array of custom post types to the $query->set() method. To display the post types post, news and reviews add the following to your site’s functions.php file.

add_action( 'pre_get_posts', 'custom_post_query_vars' );
function custom_post_query_vars( $query ) {
  if( $query->is_main_query() && is_home() ) {
    $query->set( 'post_type', array(
      'post',
      'news',
      'reviews'
    ));
  }
}

Displaying custom post types on a WordPress blog page is made easy using the pre_get_posts hook. If you would like additional information about any of the WordPress hooks or function used, please use the reference links provided below.

References

Hiding the Posts menu in the WordPress admin

Today we are going to learn about hiding the posts menu in the WordPress admin. We will remove the Posts menu item from the main menu, as well as the New Post menu item from the menu bar.

If you do not want your admin users to see the menu link to create standard posts, you can remove the Posts menu item from the WordPress admin menu. You may want to do this if you are making use of custom posts types via a theme or plugin or do not intend to use a blog on your WordPress site.

Below I will show you how to remove the Posts menu item from the main menu and the New Post menu item from the menu bar.

To remove the Posts menu item from the main menu, add the following code to your theme’s functions.php file.

add_action( 'admin_menu', 'hide_admin_post_main_menu' );
function hide_admin_post_main_menu() {
  remove_menu_page( 'edit.php' );
}

It is worth mentioning that this method does not stop a user accessing these screens. This method is purely aesthetic and is designed to simplify the UI for admin users. If you need to block access to these pages, you will need to use a plugin or some additional code to filter each user’s permissions.

To remove the New Posts menu item from the menu bar, add the following code to your theme’s functions.php file.

add_action( 'admin_bar_menu', 'hide_admin_post_bar_menu', 999 );
function hide_admin_post_bar_menu() {
  global $wp_admin_bar;
  $wp_admin_bar->remove_node( 'new-post' );
}

Hiding the posts menu in the WordPress admin is not crucial, but can allow you to improve the usability of your website’s admin by simplifying the admin UI.

It is usually a good idea to append a namespace to functions you add to your theme’s functions.php file to avoid conflicts with plugins and other code. For example; function adaptive_hide_admin_post_main_menu() {...}.

References