Programmatically creating pages in WordPress and displaying them

Programmatically creating pages in WordPress and displaying them

Hello, dear blog readers!

Today we’ll cover another important topic — programmatically creating pages in the WordPress engine, and displaying them at a specified URL.

At first glance, this functionality may seem completely unnecessary. But! What if you need to add some text content on a plugin view page? Sure, we can use our plugin (for example, a contact form) in the form of a shortcode and insert it into the page content. But there are situations when a single shortcode isn’t enough. You may need to create a separate page displaying both a form (e.g., for registration or ordering) and textual instructions. And it’s very important that this text be editable through the admin panel. Why? For example, if it's an order form page, the explanation text might contain current discount information, which can change seasonally or according to the client’s preferences. I believe the idea is clear and the task is understandable (or feel free to comment).

Programmatically creating a page

This is done very easily, using a single function — “wp_insert_post”. In our tutorial, we’ll create a page right after the plugin is installed:

register_activation_hook(__FILE__, function(){
	global $user_ID;

	wp_insert_post(array(
		'post_type'		=> 'page',
		'post_title'		=> 'Солнце',
		'post_content'		=> file_get_contents(__DIR__.'/page.html'),
		'comment_status'	=> 'closed',
		'post_status'		=> 'private',
		'ping_status'		=> 'closed',
		'post_author'		=> $user_ID,
		'post_name'		=> 'module-name-page-sun',
		'post_password'	=> time(),
	));
});

where the array keys are:

post_type — type of the post (in our case, a page)
post_title — title of the post
post_content — content of the post (in the example above, content is read from an HTML file)
comment_status — comments disabled
post_status — post status (private, published, draft, etc.). We set it to private, since there's no need to display the form’s description as a regular page.
ping_status — ping status (disabled in our case)
post_author — ID of the post author (in our case, it's the user installing the plugin)
post_name — slug of the article (i.e. the part of the URL where the page will be displayed), this is important!
post_password — password for accessing the post (just in case)

That’s it for page creation. After installing the module, the page will be visible in the appropriate section:

Programmatically created WordPress page

How to display a page by URL in WordPress

Here’s the code to start with:

if((strpos($_SERVER["REQUEST_URI"], '/some-module-page') !== false))
{
	add_filter('the_posts', function($_posts = '', $_query = '')
	{
		global $wp_query;
		
		if(empty($_posts) == false)
		{
			return $_posts;
		}
		
		$Page = get_page_by_path('module-name-page-sun');
		if(is_object($Page) == false)
		{
			wp_die('Page not found');
		}
		
		$posts[] =
			(object) array(
				'ID'                    => '9999999',
				'post_author'           => '1',
				'post_date'             => '2001-01-01 01:01:01',
				'post_date_gmt'         => '2001-01-01 01:01:01',
				'post_title'            => $Page -> post_title,
				'post_content'          => $Page -> post_content,
				'post_excerpt'          => '',
				'post_status'           => 'publish',
				'comment_status'        => 'closed',
				'ping_status'           => 'closed',
				'post_password'         => '',
				'to_ping'               => '',
				'pinged'                => '',
				'post_modified'         => '2001-01-01 01:01:01',
				'post_modified_gmt'     => '2001-01-01 01:01:01',
				'post_content_filtered' => '',
				'post_parent'           => '0',
				'menu_order'            => '0',
				'post_type'             => 'page',
				'post_mime_type'        => '',
				'post_category'         => '0',
				'comment_count'         => '0',
				'filter'                => 'raw',
				'guid'                  => get_bloginfo('url').'/?page_id=9999999',
				'post_name'             => get_bloginfo('url').'/?page_id=9999999',
				'ancestors'             => array()
			);
		
			$wp_query -> is_page   = true;
			$wp_query -> is_single = false;
			$wp_query -> is_home   = false;
			$wp_query -> comments  = false;
			unset($wp_query -> query['error']);
			$wp_query -> query_vars['error'] = '';
			$wp_query -> is_404	   = false;

			remove_filter('the_content', 'wpautop');
		
		return $posts;
	}, 10, 2);
}

To determine if we’ve landed on the desired page, perform a check:

if((strpos($_SERVER["REQUEST_URI"], '/some-module-page') !== false))

And if everything matches — yes, we’re on the right page 🙂

Next, we create a filter on the_posts:

add_filter('the_posts', function($_posts = '', $_query = '')
{

}, 10, 2);

This allows us to insert our custom page.

Since “the_post” is called in multiple places (menu rendering, post listing, etc.), we perform a check:

if(empty($_posts) == false)
{
	return $_posts;
}

i.e. if $_posts already contains something — exit the filter and return the existing post/page object.

Otherwise, we can render our own content. In our example — the page we created earlier. But first, we need to retrieve it from the database:

$Page = get_page_by_path('module-name-page-sun');
if(is_object($Page) == false)
{
	wp_die('Page not found');
}

Using the “get_page_by_path” function and the “post_name” parameter, we fetch the page content. Then we perform a check — since the page may have been deleted from the admin panel.

And then display it using a “pseudo” post object:

$posts[] =
	(object) array(
		'ID'                    => '9999999',
		'post_author'           => '1',
		'post_date'             => '2001-01-01 01:01:01',
		'post_date_gmt'         => '2001-01-01 01:01:01',
		'post_title'            => $Page -> post_title,
		'post_content'          => $Page -> post_content,
		'post_excerpt'          => '',
		'post_status'           => 'publish',
		'comment_status'        => 'closed',
		'ping_status'           => 'closed',
		'post_password'         => '',
		'to_ping'               => '',
		'pinged'                => '',
		'post_modified'         => '2001-01-01 01:01:01',
		'post_modified_gmt'     => '2001-01-01 01:01:01',
		'post_content_filtered' => '',
		'post_parent'           => '0',
		'menu_order'            => '0',
		'post_type'             => 'page',
		'post_mime_type'        => '',
		'post_category'         => '0',
		'comment_count'         => '0',
		'filter'                => 'raw',
		'guid'                  => get_bloginfo('url').'/?page_id=9999999',
		'post_name'             => get_bloginfo('url').'/?page_id=9999999',
		'ancestors'             => array()
	);

	$wp_query -> is_page   = true;
	$wp_query -> is_single = false;
	$wp_query -> is_home   = false;
	$wp_query -> comments  = false;
	unset($wp_query -> query['error']);
	$wp_query -> query_vars['error'] = '';
	$wp_query -> is_404	   = false;

	remove_filter('the_content', 'wpautop');

return $posts;

Where “$posts” is our new post object.

That’s all for now. Thanks for your attention!

Posts on similar topics

Are you having problems with your WordPress site? Do you need additional functionality? A custom plugin or a new page?
Then write to me via the feedback form, and I will try to help you.

Write a comment

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