How to Create a Changelog Page in WordPress

There are a few reasons you may want a changelog or “Recent Updates” page on your WordPress site. If you’ve worked on any sort of team before, chances are someone has made a mistake at some point. A changelog page can help keep team members accountable for their edits on a site. Or maybe you run a membership based site and you want to show off that you’re constantly updating and improving the content on the site.

Whatever your motivations are, the easiest way (in my opinion) to make a changelog page is to create a shortcode that you can use anywhere you want. The example below shows a shortcode [recent-updates] that will return a table with the last 20 updated posts, pages, or custom post types.

/* Query for Changelog Page */
function rose_recent_updates() {
	// Get the 20 most recently edited posts/pages/custom post type.
	$recent_updates = '';
	$args = array(
		'post_type' => 'any',
		'post_status' => array(
			'publish',
			'private',
			'draft'
		),
		'orderby' => 'modified',
		'posts_per_page' => 20,
		'ignore_sticky_posts' => '1'
	);

	$recent_loop = new WP_Query( $args );
	if ( $recent_loop->have_posts() ) {
		$recent_updates = '<table><tr><th width="42%">Last 20 Updates</th><th width="12%">Post Type</th><th width="30%">Last Modified</th><th width="16%">Modified By</th></tr>';
		while( $recent_loop->have_posts() ) : $recent_loop->the_post();
			// Get Modified By OR Created By
			$mod_author = get_the_modified_author( $recent_loop->post->ID );
			if ( $mod_author != '' ) {
				$author = $mod_author;
			} else {
				$author = get_the_author( $recent_loop->post->ID );
			}
			$recent_updates .= '<tr><td><a href="' . get_permalink( $recent_loop->post->ID ) . '">' . get_the_title( $recent_loop->post->ID ) . '</a></td><td>' . $recent_loop->post->post_type . '</td><td>'. get_the_modified_date( 'D, M d, Y \a\t g:iA' ) .'</td><td>' . $author . '</td></tr>';
		endwhile;
		$recent_updates .= '</table>';
	}

	wp_reset_postdata();
	return $recent_updates;
}
add_shortcode('recent-updates', 'rose_recent_updates');

If you read through it, it’s pretty self-explanatory, but basically you’re telling WordPress to loop through and grab the 20 most recent modified of “any” post type. Then inside the loop we ask for further things, for example, the modified author OR if we don’t have that, the original author.

If you need to alter this to be a more public-facing version, you may want to change the post_status argument and alter what’s shown in the table. So something like this would be good for anything that’s accessible to the users:

function rose_public_updates() {
	// Get the 20 most recent edited public posts/pages/custom post type.
	$recent_updates = '';
	$args = array(
		'post_type' => 'any',
		'post_status' => array(
			'publish'
		),
		'orderby' => 'modified',
		'posts_per_page' => 20,
		'ignore_sticky_posts' => '1'
	);

	$recent_loop = new WP_Query( $args );
	if ( $recent_loop->have_posts() ) {
		$recent_updates = '<table><tr><th width="42%">Last 20 Updates</th><th width="30%">Last Modified</th></tr>';
		while( $recent_loop->have_posts() ) : $recent_loop->the_post();
			$recent_updates .= '<tr><td><a href="' . get_permalink( $recent_loop->post->ID ) . '">' . get_the_title( $recent_loop->post->ID ) . '</a></td><td>'. get_the_modified_date( 'D, M d, Y \a\t g:iA' ) .'</td></tr>';
		endwhile;
		$recent_updates .= '</table>';
	}

	wp_reset_postdata();
	return $recent_updates;
}
add_shortcode('public-updates', 'rose_public_updates');

Implementing this PHP is as easy as updating your functions file (if it’s your own theme or child theme), or writing it into a plugin.