This website uses cookies to allow us to see how the site is used. If you continue to use this site, we assume that you are okay with this. If you want to use the sites without cookies, please see our privacy policy.

Allow Cross-Origin API Requests

Web browsers do not allow websites to make cross-origin requests (requests from one domain to another) unless the target website explicitly allows these types of requests.

As a result, if you intend for the REST API on your WordPress site to be publicly available for others to use, you will need to allow cross-origin requests. You can be explicit and only allow requests from a specific domain, or you can allow requests from any domain.

This is how you’d allow it for any external domain:

<?php

add_action( 'rest_api_init', function() {
   
	remove_filter( 'rest_pre_serve_request', 'rest_send_cors_headers' );
  
	add_filter( 'rest_pre_serve_request', function( $value ) {
		header( 'Access-Control-Allow-Origin: *' );
		header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, DELETE' );
		header( 'Access-Control-Allow-Credentials: true' );

		return $value;
		
	});
  
}, 12 );

To make this specific to a particular domain, just replace the * with the domain.

Internal REST API Calls

The WordPress REST API is great, but sometimes we want to load an initial data set to bootstrap a JS application from the API via PHP.

Here is how you can make an API request in PHP without HTTP:

<?php

$request = new WP_REST_Request( 'GET', $route );
$request->set_query_params( $params );
$response = rest_do_request( $request );
$data = rest_get_server()->response_to_data( $response, false );

More details: https://wpscholar.com/blog/internal-wp-rest-api-calls/

Auto-Redirect Root-Level Posts on Permalink Change

The use case here is when you’ve made the decision to switch your blog post URLs from being at the root-level (e.g. /hello-world) to using a base path (e.g. /blog/hello-world).

Typically, you’d have to carefully map out the redirects and set them up in your .htaccess file, a WordPress plugin, or in your web host’s redirect manager. Creating a generic regex solution won’t work since pages also are at the root-level.

Here is some drop-in code that will automatically detect 404’s and will redirect these root-level posts to the new URL:

<?php
add_action( 'template_redirect', function () {
	/**
	 * @var WP $wp
	 */
	global $wp;
	/**
	 * @var WP_Query $wp_query
	 */
	global $wp_query;
	
	if ( $wp_query->is_404() ) {
		$query = new WP_Query( array(
			'post_type'      => 'post',
			'post_status'    => 'publish',
			'name'           => $wp->request,
			'posts_per_page' => 1,
			'nopaging'       => true,
			'no_found_rows'  => true,
		) );
		if ( $query->found_posts ) {
			$redirect_url = add_query_arg( $wp->query_string, '', get_the_permalink( $query->post ) );
			wp_safe_redirect( $redirect_url, 301 );
		}
	}
} );

Append Items to a Nav Menu

One of the things that is common when working with WordPress clients is they have a tendency to forget their login URL.  Appending an ‘Admin’ link to the end of the footer that the user can’t remove is one way to ensure your client can always find the admin without having to give you a call.

/**
* Add a custom link to the end of a specific menu that uses the wp_nav_menu() function
*/
add_filter('wp_nav_menu_items', 'add_admin_link', 10, 2);
function add_admin_link($items, $args){
    if( $args->theme_location == 'footer_menu' ){
        $items = $items . '<li><a title="Admin" href="'. admin_url() .'">' . __( 'Admin' ) . '</a></li>';
    }
    return $items;
}

https://gist.github.com/woodent/1249995

With a few alterations, you can append ( or prepend ) anything to a nav menu.  A few examples would be search fields, dynamically generated ‘Log In’ and ‘Log Out’ links, ‘User Profile’ or ‘User Account’ links, fancy images or icon fonts, and the list goes on…

Show Custom Post Types on the Homepage

Custom post types are commonly used on WordPress sites, but they don’t show on the homepage or in the archive pages unless you write code to do that.  I’ve put together some code that is smart about detecting your public custom post types and automatically adding them to your homepage and archive pages:

/**
 * Show WordPress custom post types on the main blog and archive pages
 *
 * @param WP_Query $query
 **/
function show_custom_post_types( $query ) {

  // Show all custom post types on main blog and archive pages
  if ( $query->is_main_query() && ( is_home() || ( is_archive() && !is_post_type_archive() ) ) ) {

    $custom_post_types = get_post_types( array(
       'public' => true,
       '_builtin' => false,
    ) );
    $post_types = array_merge( array('post'), $custom_post_types );
    $query->set( 'post_type', $post_types );
   }

   return $query;
}

add_filter( 'pre_get_posts', 'show_custom_post_types' );

https://gist.github.com/woodent/2068729

Get a list of WordPress post types that support a feature

Need to be able to fetch a list of post types that support a specific feature, like thumbnails, excerpts, etc?  This nifty little function will let you do just that:

/**
 * Get a list of post types that support a specific feature.
 * 
 * @param $feature
 * @return array
 */
function get_post_types_that_support( $feature ) {
	global $_wp_post_type_features;
	$post_types = array_keys(
		wp_filter_object_list( $_wp_post_type_features, array( $feature => true ) )
	);
	return $post_types;
}

https://gist.github.com/woodent/6273186