Last updated September 14th, 2024 at 05:12 pm
MemberPress is a great tool for creating membership websites, but it doesn’t offer much in the way of reporting functionality. This deficit is an opportunity for developers. Availing myself of that opportunity, I’ve created custom front-end member listings for some of my clients’ MemberPress sites. In this article I dive a bit into the custom front-end member listing I created for the website of the Southeastern Bluegrass Association (“SEBA”). SEBA has two memberships (Personal and Business) and accepts two payment methods (Online via PayPal and payments by check).
You may want to start this tour by watching this short demonstration video.
Member Listing Data
The member listing is an all-purpose, at-a-glance view of current members. This page is restricted; Only admins and users with the custom role of “Membership Assistant” can access it. One specific purpose of the listing is to help SEBA officers and website administrators attend to customer service inquiries (such as “I just received a notification that my membership is expiring next week, but I thought I renewed last month…”).

Taking a look at the table, here are the columns of data:
- Sequential Number
- Member’s User ID
- Name (Last, First)
- Icon for Membership Type
- Abbreviation for Membership Type
- Date first registered
- Date of most recent transaction
- New or Renewal?
- Expiration/Renewal Date
- Number of days before expiration/renewal date
- Payment Gateway/Method (Check or PayPal)
- Auto-Renewal Icon
- Email (clickable, for triggering email send)
- Username
- Telephone (clickable, for triggering outgoing call on supported devices)
- Edit User Link
- View Transactions Link
Filter and Sort Widgets
Above the table are two widgets for filtering the listing plus a widget for sorting it. A dynamically generated message immediately above the table indicates which filters are active and how many members the current filter includes.
Filters

Filter by Membership Type
This is useful for a quick, at-a-glance view (and count) of members of each type.
Filter by Payment Method
By definition, an online payment via PayPal is auto-renewing. Since SEBA’s directors have the goal of maximizing the number of online, recurring memberships and minimizing the number of memberships paid for by check, this filter allows users to see whom they might target for some gentle persuasion to start paying online.
Sort

Sort by name
The obvious purpose is to make it easy to find members.
Sort by most recent transaction date
Aside from the obvious benefit of displaying the most recent purchases or renewals in one place at the top, this makes the monthly newsletter editor’s job easier (for the regular feature of welcoming new members).
Sort by expiration date
Sample use case: SEBA administrator Bob notices that Randy Jones’ non-auto-renewing membership expires in three days. Bob could easily call or email Randy (clicking on either the telephone link or the email link), thanking Randy for supporting the organization and suggesting that Randy renew online when the time comes.
Sort by email address
Once again, a useful way to locate members, especially when their email addresses don’t resemble their names.
Some Code
I’m including in this section a somewhat arbitrary selection of code snippets. It’s hard to know what people might want to see, so I’ll leave it to you to let me know in the comments below if you’d like to see specific code or markup.
Active Transactions
A MySQL query to obtain active transactions kicks off the chain of events.
function jc_get_active_transactions() {
global $wpdb;
$limit = '9999';
$table_1 = $wpdb->prefix . 'mepr_transactions';
$query = "select
id, total, user_id, product_id, status, subscription_id, gateway, created_at, expires_at
from $table_1
where status = 'complete' and expires_at > now() and
user_id > 0
order by expires_at ASC LIMIT $limit";
$results = $wpdb->get_results($query);
return $results;
}
Assemble the member listing array
Line 4 calls the function shown above.
<?php
function jc_assemble_active_members_array() {
$output = '';
$data = jc_get_active_transactions();
$members = array(); // init
for ( $i=0; $i<count($data); $i++ ) {
$user_object = get_user_by('id', $data[$i]->user_id);
$members[$i]['last_name'] = get_user_meta($data[$i]->user_id, 'last_name', true);
$members[$i]['first_name'] = get_user_meta($data[$i]->user_id, 'first_name', true);
$members[$i]['user_email'] = trim($user_object->user_email);
$members[$i]['user_login'] = $user_object->user_login;
$members[$i]['registered'] = $user_object->user_registered;
$members[$i]['telephone'] = get_user_meta($data[$i]->user_id, 'mepr_telephone', true);
$members[$i]['address'] = get_user_meta($data[$i]->user_id, 'mepr-address-state', true);
$members[$i]['created_at'] = $data[$i]->created_at;
$members[$i]['expires_at'] = $data[$i]->expires_at;
$members[$i]['transaction_id'] = $data[$i]->id;
$members[$i]['user_id'] = $user_id = $data[$i]->user_id;
$members[$i]['product_id'] = $data[$i]->product_id;
$members[$i]['gateway'] = $data[$i]->gateway;
$members[$i]['gateway_name'] = jc_convert_gateway($data[$i]->gateway); // new at 2024-08-18 08:25:08
$members[$i]['subscription_Id'] = $data[$i]->subscription_id;
// *** Compute whether New or Renew at 2024-08-15 10:48:05
$members[$i]['new_renew'] = ( date('Y-m-d', strtotime($members[$i]['registered'])) == date('Y-m-d', strtotime($members[$i]['created_at'])) ) ? '<span class="is-new">New</span>' : '<span class="is-renewal">Renewal</span>';
}
return $members;
}
Sort the listing
For sorting the member listing, I’m using this function which utilizes the PHP array_multisort() function. Here’s the official documentation for array_multisort(), and here’s a blog article I published about the function.
The sorting is triggered by the presence of a query string that includes the string sort={sort_parameter}, where sort_parameter is one of the values in the case blocks within the switch statement.
<?php
function jc_sort_members($members, $atts) {
$atts = shortcode_atts( array(
'sort' => 'name',
), $atts, 'jc_members' );
if ( isset($_GET['sort']) ) {
$sort = $_GET['sort'];
} else {
$sort = $atts['sort'];
}
$output = '';
$utility = array();
switch ( $sort ) {
case 'name' :
default :
foreach ( $members as $member) {
$utility[] = strtolower($member['last_name']) . strtolower($member['first_name']);
}
array_multisort($utility, SORT_ASC, $members, SORT_STRING);
$sort_cos = 'Sorted by last name, first name';
break;
case 'email' :
foreach ( $members as $member) {
$utility[] = strtolower($member['user_email']);
}
array_multisort($utility, SORT_ASC, $members, SORT_STRING);
$sort_cos = 'Sorted by email address';
break;
case 'mrt' :
foreach ( $members as $member) {
$utility[] = $member['created_at'];
}
array_multisort($utility, SORT_DESC, $members, SORT_NUMERIC);
$sort_cos = 'Sorted by transaction date (desc)';
break;
case 'expires' :
foreach ( $members as $member) {
$utility[] = $member['expires_at'];
}
array_multisort($utility, SORT_ASC, $members, SORT_NUMERIC);
$sort_cos = 'Sorted by expiration/renewal date (desc)';
break;
case 'uid' :
foreach ( $members as $member) {
$utility[] = $member['user_id'];
}
array_multisort($utility, SORT_ASC, $members, SORT_NUMERIC);
$sort_cos = 'Sorted by User ID (asc)';
break;
}
$array = array(
'members' => $members,
'sort_cos' => $sort_cos,
);
return $array;
}
Other Membership Reports?
Is this helpful?
I welcome your comments
In the course of creating this membership listing view (and this blog post about it), ideas have come to mind about other custom MemberPress reports that might be useful. I welcome your ideas about such reports.
Like what you see? Share with others and join my mailing list. No long-term commitment, unsubscribe any time.

Leave a Reply