Skip to main content
WordPress made easy with the drag & drop Total WordPress Theme!Learn More

Create WordPress Posts And Pages Using PHP – A 101 Tutorial

Last updated on:
  1. 1. Currently Reading: Create WordPress Posts And Pages Using PHP – A 101 Tutorial
  2. 2. Manage WordPress Posts with PHP – Create and Update

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.

Subscribe to the Newsletter

Get our latest news, tutorials, guides, tips & deals delivered to your inbox.

12 Comments

  1. AJ Clarke

    Welcome and thanks a lot for sharing Harri. This is super useful! We look forward to seeing more awesome content from you on our blog 😉

  2. S anand

    I dont even know that dummy data can be automated.Thanks for this superb article.Must use it

    • Harri Bell-Thomas

      Thanks for checking my tutorial out! I’d recommend having a look at the more advanced (and stable) PHP Class I’ve written for the second part of this tutorial. Find it on Github.

  3. aragornsmum

    Really useful – thanks! I have given it a try and it has worked brilliantly!

  4. joemillano

    Hi , Love this idea – But.. I am unsure of the usage… I want to use this standalone , then call the standalone file when Im posting content.

    I tried add “require( dirname( __FILE__ ) . ‘/wp-blog-header.php’ );” to my posting standalone file but no joy.

    Ive I include this in my theme file – How am i to call standalone?

    Cheers!

  5. Saurabh kumar

    Thanks for sharing such an Awesome tutorial, will help me to include php in my site.

  6. grails

    Simple but useful code. Thanks for sharing

  7. Skip Bin Hire Solutions

    This is simply fantastic. Something I have been looking for all day on how to do this.

    How do I go about setting up multiple pages and posts? I have tried to add a second PostCreator but it does not work.

  8. franigoldas

    Superb work, thanks so much 🙂

  9. Bob

    Harri,

    Thank you for this very helpful article – I haven’t yet tried it out but it looks to be exactly what I need.
    In scanning the code I did come up with one question regarding your GitHub listing Lines 37-40 shown below:

    if ($this->PC_type == ‘page’)
    $post = get_page_by_title( $this->PC_title, ‘OBJECT’, $this->PC_type );
    else
    $post = get_page_by_title( $this->PC_title, ‘OBJECT’, $this->PC_type );
    

    It appears that the same code is executed whether the if statement is ‘true’ or ‘false’. Is this what you intended?
    Thanks again.

  10. ben

    Hi Harri
    Great tutoriel !!!
    can this work with Woocommerce as well ?

  11. rhinorck

    Thank you! You’ve saved me hours of work trying to figure this out. Live long and prosper.

Leave a Reply

Your email address will not be published. Required fields are marked *

Learn how your comment data is processed by viewing our privacy policy here.