SkyVerge WooCommerce Extensions

This post is inspired by a neat question we got from a Memberships user recently: How can I share messages on-site when a membership is about to expire?

Typically our member content blocks or member shortcodes can be used with a “delay” attribute to achieve this, as you could show content 355 days after a year-long membership starts. However, if you manually (or programmatically) change membership end dates, you may not have all expiration dates nicely aligned for this approach to work.

In this case, it would be helpful to have a message shown based on the end date or expiration date for the membership, rather than when the membership started. This could let you offer a renewal coupon, or a message on key pages asking the member to renew as they view your content, to avoid lapsed memberships.

Let’s take a look at how we can create a shortcode that shows content based on membership expiration.

⚠️ This tutorial assumes you have basic PHP development knowledge. Not sure how to add custom code to your site? Check out our tutorial for help. Need some help implementing or taking this code further? We recommend Codeable for small custom projects.

Create the expiration message shortcode

I’m going to add a shortcode to show an expiration-based piece of content to site visitors. So, what information will I need for this shortcode?

  • the message to show (content)
  • when we should start showing the message
  • when we should stop showing the message (if we should stop)

These will form my shortcode attributes, so keep these in mind!

ℹ️ See our guide to creating your first shortcode for a more in-depth explanation of shortcode components.

Before we start writing code, though, there is one other thing to think about: the message start and end are not absolute dates, but instead are relative times, based on the expiry date. So, I’ll also need the membership expiration date to know when to show this message.

Needing the end date for comparison poses a tiny problem: a member can have more than one membership, so feasibly, they might have more than one end date. How should we handle this—should content be shown if any membership has an end date that falls in our message window? What if more than one end date is in our message window—how should we compare against the start and end times?

Since these comparisons could get messy, I’m going to simplify this just a tad: I’ll require a membership plan in the shortcode as well. This will tell me that I’m looking for an end date only for memberships in that plan, and makes these comparisons more straightforward.

Users can then determine the plan, start time, and end time to show the expiration message.

Now, I should also think about conditions: what should stop me from showing the message?

  • There is no content to show.
  • There is no plan selected.
  • There is no start time for the message window. (We can probably safely allow no end date, though, and just keep showing the message.)
  • The start date must be before the end date (if one is set).

I’ll add these pre-flight checks first, then I can show the message if we’re within the message window for a member:

 * Adds an expiry message shortcode, show content N days before or after expiry. Only "end" is optional!
 * [wcm_expiry_message plan="plan-slug" start="+10 days" end="+15 days"] (start 10 days after expiry)
 * [wcm_expiry_message plan="plan-slug" start="-10 days" end="+2 days"] (start 10 days before expiry)
 * @param array $atts shortcode arguments
 * @param null|string $content the shortcode content
 * @return string formatted discount HTML
add_shortcode( 'wcm_expiry_message', function( $atts, $content = null ) {

	$a = shortcode_atts( [
		'plan'  => null,
		'start' => null,
		'end'   => null,
	], $atts );

	// doesn't matter if we don't have one of these, bail out
	if ( empty( $content ) || ! a['plan'] || ! $a['start'] ) {
		return '';

	// final check: start must be before end, if there's an end
	if ( $a['end'] && ( (float) $a['start'] > (float) $a['end'] ) ) {
		return '';

	$plan       = trim( $a['plan'] );
	$has_plan   = wc_memberships_is_user_member( get_current_user_id(), $plan );
	$membership = wc_memberships_get_user_membership( get_current_user_id(), $plan );

	if ( $has_plan && $membership ) {

		$end_date  = $membership->get_end_date( 'timestamp' );
		$msg_start = strtotime( date( 'Y-m-d H:i:s', $end_date ) . $a['start'] );
		$msg_end   = $a['end'] ? strtotime( date( 'Y-m-d H:i:s', $end_date ) . $a['end'] ) : null;

		// show if we've passed the start, but are before end (if there is an end)
		if ( time() > $msg_start && ( empty( $msg_end ) || time() < $msg_end ) ) {


			echo '<p>' . wp_kses_post( do_shortcode( $content ) ) . '</p>';

			return ob_get_clean();

	return '';

}, 10, 2 );

ℹ️ You could remove the <p> tags wrapping the content if you want to omit spacing.

Now we’ve put it all together, and you can view the full code here. ????

We’ve added pre-flight checks, established the message window (based on time before and after the end date), and then we show the message if right now is within that window.

Use the expiration message shortcode

Now we’re ready to use the shiny new shortcode on the site. The basic shortcode is: [wcm_expiry_message]Message content[/wcm_expiry_message]

We also have a few attributes we should use:

  • plan: the membership plan ID or slug this message is for. The message will show to members in this plan, if their expiry date is in our window.
  • start: the time before or after the expiration date we want to start to show this message.
  • end: the time before or after the expiration date we want to stop showing this message. (Optional)

Both start and end can use a positive date to indicate it’s after the membership end date, or a negative date to indicate it’s before the membership end date. So, if we want to start showing a message 10 days before a membership ends, and stop 5 days after it ends, we could do this:

[wcm_expiry_message plan="plan-slug" start="-10 days" end="+5 days"]The message to show.[/wcm_expiry_message]
Using the shortcode on a page

So let’s take a member whose access expired 7 days ago (at the time I wrote this):

An expired member

Because there are two messages on my sample page that apply, I’ll see both of these when logged in as that member:

The member messages

That’s a wrap! Use on-site expiration and renewal prompts to help retain your members—share a renewal coupon, ask for feedback, or provide a gentle nudge to renew early to avoid losing access.

ℹ️ You can also consider sending pre- and post-expiration notices to your members via email. Use the built-in Memberships emails, or for more advanced emails that can include a personal, generated coupon code to renew, check out the Memberships integration with Jilt.

Published by Beka Rice

Beka leads product direction for SkyVerge and technical documentation. She spends a lot of time on research and interviews, but likes to write so she has an excuse to spend more time jamming out to anything from The Clash to Lady Gaga.


  1. I appreciate the SkyVerge team for making such quality plugins and listening to customer feedback patiently.

    Thanks, Beka.


  2. Thanks Beka Rice.

    Nice explain and quite clean code 🙂


Leave a Reply

Your email address will not be published.