Building Client Reports with WordPress Custom Page Templates

Report | Building client reports in WordPress

A lot of the time, clients need reporting. “Can I download a CSV of X?” is one of the most common features clients ask me, and it always makes me wince slightly: I know it’s going to be a fair amount of custom data massaging, and I also don’t know a lot about building CSVs programmatically.

Here’s the thing, though: depending on the client, reporting can be quite simple. For many needs, you can just make a custom page template that kicks out a table with the data you need. This is exactly what I recently did for a client, and it was the perfect don’t-overthink-it solution.

Our Example Report: Seeing Which WPShout Comments have Replies

Since I can’t show you precisely what I did with my client, I’ve made a similar example. For this one, I’m the client, and I want to see something simple: A list of every comment in the last 100 WPShout posts that generated at least one reply. (Perhaps I want to encourage discussion on the site, and am looking to learn what kinds of comments people feel compelled to respond to.)

My one additional requirement is that I want to be able to access this report in Excel (or Google Docs), so I can do useful things like sort by a particular column.

The Solution: A Custom Page Template

To solve this need, I’ve created a page that outputs, for the last 100 WPShout posts, any comment that had at least one reply. It’s right on the site itself, and viewable in-browser:

And it pastes into Excel completely cleanly, so I, the client, can do all the sorting and analyzing I want:

How to Do It

The whole solution is contained inside a single PHP file that pastes into your site’s active theme. The file is up on GitHub, and I’m excerpting key parts below.

Here’s how it works:

We’re Using a Custom Page Template

For this report, we don’t want our report to look like the rest of the WPShout site—but we do want to be in the WordPress environment to do things like access posts through The Loop.

There’s a WordPress feature that offers this combination: custom page templates. With these, you control every aspect of the design, while still getting access to WordPress’s state and processes.

The key lines that register our PHP file as a custom page template are right at the top:

/* Template Name: Comments with Replies Report */

Admins Only

General users shouldn’t be able to see these kinds of reports. Preventing that is the job of these lines:

if( ! current_user_can( 'administrator' ) ) :
	wp_redirect( home_url() );
	echo '<script>window.location.replace("' . site_url() . '");</script>';

If you’re not logged in as a user with administrator privileges, the page will simply PHP redirect you to the site’s homepage. (Failing that, it’ll do the same thing using JavaScript, and then it’ll just shut down—but those two lines are extra, particularly the JavaScript one.)

Getting the Data We Want with a Custom WP_Query

Next, you’ll notice something we have to do: fetch our desired data from the site’s database, by executing a custom query using WP_Query:

// Start the loop.
$args = array(
	'post_type' => 'post',
	'posts_per_page' => 100,
$comment_query = new WP_Query( $args );

We have to do this because WordPress page templates expect a single post of type Page—the Page that’s using the template.

In our case, though, we want a list of our 100 most recent Posts—that is, “posts of type Post.” We don’t care about the Page’s content at all—which is why we can leave it totally empty:


The only thing the Page gives us is a URL at which to display our report.

Looping Through our WP_Query

The real meat of the page is in these lines:

while ( $comment_query->have_posts() ) : $comment_query->the_post();
	$args = 'post_id=' . get_the_ID();
	$comments = get_comments( $args ); 
	foreach( $comments as $comment ) :
		$current_parent = '';

		/* Find posts with parents */
		if( $comment->comment_parent != 0 ) :

			/* Don't list the same parent content multiple times */
			if( $current_parent == $comment->comment_parent ) :
			else :
				$current_parent = $comment->comment_parent;	

			/* Retrieve and list parent information */
			$parent = get_comment( $current_parent );
			echo '';
				echo '' . get_the_title() . '

‘; echo ‘

' . $parent->comment_ID . '

‘; echo ‘

' . $parent->comment_content . '

‘; echo ‘

‘; endif; endforeach; endwhile; ?>

The real point of this article is how to generate reports in general—not how to work with comments—so we won’t say too much here.

If this code is Greek to you, though, have a look at a few resources on writing custom WP_Querys, as well as on working with WordPress comment functions. (If you still need help after that, leave a comment! We’d love to reply and boost our numbers on this table. 🙂 )

It’s Table Markup! (Remember Table Markup?)

For this page template, I’ve taken the trouble of using HTML’s table markup. If you’re using tables a lot in your work, that’s a troubling sign—but they’re still the right solution for one thing: actual tables.

The benefit of using table markup is clear: the client can simply copy-paste the entire page content into Excel or Google Docs, as we saw above.

So if your client is comfortable enough with technology to be able to “Select All” and copy a webpage’s contents, and then paste into Excel, this kind of solution should be perfect.

Happy Reporting!

I hope this quick example has given you a look at how to generate custom reports for your clients. Again, these reports are pretty simple, so you wouldn’t want to use them for a client who’s paying you more than, say, seven million dollars to generate them—but for sub-seven-million-dollar small clients they’re often just what’s needed.

Thanks for reading!

Image credit: GotCredit