Create WordPress Posts And Pages Using PHP – A 101 Tutorial

No doubt you have seen WordPress Themes and Plugins which claim to automatically install ‘dummy data’ for you when you install them, so that you immediately have a fully functioning website. I am going to show you a method of achieving this using only PHP functions.

This could be useful if:

  • Your theme or plugin requires certain posts or pages.
  • You want to provide a premium dummy install as described above.
  • You want to automate post creation.
  • You just want to learn.

In this tutorial we will create a simple beginner’s function to achieve a ‘quick and dirty’ working solution. Later on in a different tutorial, we’ll learn how to extend what we have learn’t here to create a robust and easy to use posting system.

For those of you who prefer to play with pre-existing code instead of reading all the how-to, here is our final function along with an example of its usage and notes.

if ( ! function_exists( 'PostCreator' ) ) {

	function PostCreator(
		$name      = 'AUTO POST',
		$type      = 'post',
		$content   = 'DUMMY CONTENT',
		$category  = array(1,2),
		$template  = NULL,
		$author_id = '1',
		$status    = 'publish'
	) {

		define( POST_NAME, $name );
		define( POST_TYPE, $type );
		define( POST_CONTENT, $content );
		define( POST_CATEGORY, $category );
		define( POST_TEMPLATE, '' );
		define( POST_AUTH_ID, $author_id );
		define( POST_STATUS, $status );

		if ( $type == 'page' ) {
			$post      = get_page_by_title( POST_NAME, 'OBJECT', $type );
			$post_id   = $post->ID;
			$post_data = get_page( $post_id );
			define( POST_TEMPLATE, $template );
		} else {
			$post      = get_page_by_title( POST_NAME, 'OBJECT', $type );
			$post_id   = $post->ID;
			$post_data = get_post( $post_id );
		}

		function hbt_create_post() {
			$post_data = array(
				'post_title'    => wp_strip_all_tags( POST_NAME ),
				'post_content'  => POST_CONTENT,
				'post_status'   => POST_STATUS,
				'post_type'     => POST_TYPE,
				'post_author'   => POST_AUTH_ID,
				'post_category' => POST_CATEGORY,
				'page_template' => POST_TEMPLATE
			);
			wp_insert_post( $post_data, $error_obj );
		}

		if ( ! isset( $post ) ) {
			add_action( 'admin_init', 'hbt_create_post' );
			return $error_obj;
		}

	}
}

/* All available options for PostCreator()

PostCreator( 'TITLE' , 'POST TYPE' , 'POST CONTENT' , 'POST CATEGORY' , 'TEMPLATE FILE NAME' , 'AUTHOR ID NUMBER' , 'POST STATUS');

TITLE - HTML Stripped Out. Simple String.
POST TYPE - Post type slug. Eg 'post' or 'page'. Custom Post Types are supported.
POST CONTENT - Content of the Post/Page. HTML allowed.
POST CATEGORY - An array of the integer ID's of the category/categories you want to link to your post
TEMPLATE FILE NAME - File name of the template. Only for Pages. In the format 'file_name.php'.
AUTHOR ID NUMBER - Integer value. Default is 1.
POST STATUS - Available options; [ 'draft' | 'publish' | 'pending'| 'future' | 'private' | custom registered status ]

If successful, PostCreator() returns nothing.
If there is an error PostCreator() returns a WP_error object.

*/

PostCreator( 'My Lorem Ipsum', 'page', 'With a sizable serving of Dolor. This was created using Harri Bell-Thomas\'s PostCreator function.' );

Step by Step Guide

We will be creating a PHP function called PostCreator(), and we will need it to take certain parameters. Each parameter has been given a default, so technically when calling the function you don’t need to specify any of them, but hey, where is the fun in that?

function PostCreator(

	$name      = 'AUTO POST',
	$type      = 'post',
	$content   = 'DUMMY CONTENT',
	$category  = array(1,2),
	$template  = NULL,
	$author_id = '1',
	$status    = 'publish'
) {

	// function output here

}

Next I am going to define some constants which is necessary for the following embedded function. (This could be re-written to not use constants, but I have used them as I find them useful when extending the basic PostCreator() function, but that is a story for another tutorial.

define( POST_NAME, $name );
define( POST_TYPE, $type );
define( POST_CONTENT, $content );
define( POST_CATEGORY, $category );
define( POST_TEMPLATE, '' );
define( POST_AUTH_ID, $author_id );
define( POST_STATUS, $status );

OK, so far so good. Now, I have included some validation to prevent duplicate posts/pages being generated (which is a nightmare, trust me!). This validation checks if a post/page with the same name already exists. If it does, it doesn’t create a new one, but if it doesn’t, then it creates it for you.

The reason why I have chosen to check the post’s title is because that is all that is required by WordPress to generate a page (the rest is generated automatically). Other ways of performing this validation include checking against ‘slugs’ or post ID’s. All of this we will come onto in a later tutorial.

This is especially useful if the post/page is required by your plugin or theme. I first developed this for one of my plugins because it required a page to be present with a certain page template. With this function, I simply kept PostCreator() is WordPress’ ‘admin_init’, meaning that if someone tried to delete it (how dare they!) then it would be re-created immediately to prevent issues with the rest of the plugin.

Bear in mind that nobody wants their blog to be hijacked, so make sure you tell them clearly what is happening, and perhaps provide an option for them to turn it off.

Now back to the validation. Here is the next bit of code.

if ( $type == 'page' ) {
	$post      = get_page_by_title( POST_NAME, 'OBJECT', $type );
	$post_id   = $post->ID;
	$post_data = get_page( $post_id );
	define( POST_TEMPLATE, $template );
} else {
	$post      = get_page_by_title( POST_NAME, 'OBJECT', $type );
	$post_id   = $post->ID;
	$post_data = get_post( $post_id );
}

So what the heck is going on here?

Well, this is essentially the same process repeated twice. I do this because of how posts and pages are treated slightly differently. Also, the constant POST_TEMPLATE is only defined if you are trying to create a page, because only pages can accept that parameter (ie. It will be ignored if you are trying to create a standard post).

On the first line of the IF clause (its technical name is the ‘apodosis’ if you didn’t know already) the $post variable is defined. If there is a post/page with the same name as is trying to be created, then $post is populated with the existing entry’s data (as an object, not an array, but this can be changed if absolutely necessary). This variable is used to test whether your title is unique. The next two lines I have included because, again, they are very useful if you want to extend this function. An example of this could be updating the existing post if it already exists.

Next  is our nested function which will be added to the ‘admin_head’ hook. Here it is;

function hbt_create_post() {
	$post_data = array(
		'post_title'    => wp_strip_all_tags( POST_NAME ),
		'post_content'  => POST_CONTENT,
		'post_status'   => POST_STATUS,
		'post_type'     => POST_TYPE,
		'post_author'   => POST_AUTH_ID,
		'post_category' => POST_CATEGORY,
		'page_template' => POST_TEMPLATE
	);
	wp_insert_post( $post_data, $error_obj );
}

Simply, this is using WordPress’ inbuilt function (wp_insert_post) to generate our post/page. We populate $post_data with an array of our parameters (you can see our constants in use here). This is created and if there is an error, it generates a boolean value $error_obj. TRUE = A problem. FALSE = All fine. The last thing to do is to run the previous function on the admin head, but only if it passes validation, and return the error object.

if ( ! isset( $post ) ) {
	add_action( 'admin_init', 'hbt_create_post' );
	return $error_obj;
}

Great! Now we’ve created our awesome function, lets use it!

Usage

Simply include the PostCreator()  function and run it.

This will run using the default values, but what if we want customizability? Then we use our parameters.

PostCreator(
	'TITLE',
	'POST TYPE',
	'POST CONTENT',
	'POST CATEGORY',
	'TEMPLATE FILE NAME',
	'AUTHOR ID NUMBER',
	'POST STATUS'
);

With all of these options, take care using apostrophes. Make sure that if you want to use an apostrophe (except for those surrounding the parameters themselves) you prefix it with a backward slash. Eg;

PostCreator( 'Alex\'s Post' );

The TITLE Parameter accepts a string value. This is stripped of HTML tags.

The POST TYPE Parameter accepts the slug of the post type, for example; ‘post’ or ‘page’. Custom Post Types are supported.

PostCreator( 'Alex\'s Post', 'page' );

The POST CONTENT’ accepts a string value. This will be the content of the created post/page. HTML is allowed here.

PostCreator( 'Alex\'s Post', 'page', 'The force is strong with this one…' );

The POST CATEGORY accepts an array of integers. The integers correspond to the ID of the category/categories attributed to the post/page.

PostCreator( 'Alex\'s Post', 'page' , 'The force is strong with this one…' , array( 1, 2 ) );

The TEMPLATE FILE NAME is a string value defining the desired page template of your new page. This only works for pages. The format will be; ‘file_name.php’.

PostCreator(
	'Alex\'s Post',
	page',
	'The force is strong with this one…',
	array( 1, 2 ) ,
	'fullwidth_page.php'
);

The AUTHOR ID NUMBER is an integer value of the author’s ID.

PostCreator(
	'Alex\'s Post',
	'page',
	'The force is strong with this one…',
	array( 1, 2 ) ,
	'fullwidth_page.php',
	'1'
);

The POST STATUS allows you to define the state of the created post/page. By default it is ‘published’.

Available options; [ ‘draft’ | ‘publish’ | ‘pending’| ‘future’ | ‘private’ | custom registered status ]

PostCreator(
	'Alex\'s Post',
	'page',
	'The force is strong with this one…',
	array( 1, 2 ) ,
	'fullwidth_page.php',
	'1',
	'publish'
);

Wrapping Up

WordPress is an exceptionally powerful tool, but can definitely be unruly at times. I hope you find this simple snippet useful, perhaps learning a thing or two along the way. Stay tuned for the next one where I am going to convert what we have done already in this article to a PHP class, adding more functionality and stability. For a sneak preview, check out the code on Github: PostController

If you have any questions, just ask in the comment section below.