Skip to content

Instantly share code, notes, and snippets.

@sc0ttkclark
Last active August 24, 2021 12:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sc0ttkclark/b116c2cde3175c408f399ffdd7dcd7d0 to your computer and use it in GitHub Desktop.
Save sc0ttkclark/b116c2cde3175c408f399ffdd7dcd7d0 to your computer and use it in GitHub Desktop.
PMPro snippet to allow inherited levels based on a configuration. If a member has any level that matches, they will automatically inherit access to other membership levels as configured.
<?php // do not copy this line.
/**
* This recipe allows level access to be inherited depending on a member's level.
*
* For example, if your membership levels are tiered like Patreon,
* you may also want to give 'higher' levels access to everything the lower levels have too.
*
* You can add this recipe to your site by creating a custom plugin
* or using the Code Snippets plugin available for free in the WordPress repository.
* Read this companion article for step-by-step directions on either method.
* https://www.paidmembershipspro.com/create-a-plugin-for-pmpro-customizations/
*/
/**
* The configuration of inherited levels to use.
*
* @return array List of inherited level mapping.
*/
function my_pmpro_inherit_levels() {
// @todo Modify this list based on your needs.
return [
[
// The level ID that will inherit other levels.
'level_id' => 3,
// The list of level IDs that will be inherited.
'also_give_access_to' => [
1,
2,
],
],
[
// The level ID that will inherit other levels.
'level_id' => 4,
// The list of level IDs that will be inherited.
'also_give_access_to' => [
1,
],
],
];
}
/**
* Add additional inherited levels to the list of levels a user has access to.
*
* @param object[] $levels The list of level objects.
* @param int $user_id The user ID.
*
* @return object[] The list of level objects.
*/
function my_pmpro_inherit_levels_filter( $levels, $user_id ) {
$inherit_levels = my_pmpro_inherit_levels();
$original_level_ids = wp_list_pluck( $levels, 'ID', 'ID' );
$levels_to_fetch = [];
// Determine if we have any levels to fetch and add to the $levels list.
foreach ( $inherit_levels as $inherit_level ) {
// Skip if the inherit level is not in the current levels list.
if ( ! isset( $original_level_ids[ $inherit_level['level_id'] ] ) ) {
continue;
}
// Maybe add levels to be fetched.
foreach ( $inherit_level['also_give_access_to'] as $also_give_access_to ) {
// If the level is not yet provided, we need to fetch level information.
if ( ! isset( $original_level_ids[ $also_give_access_to ] ) ) {
$levels_to_fetch[] = $also_give_access_to;
}
}
}
// Check if we have additional levels to fetch.
if ( ! $levels_to_fetch ) {
return $levels;
}
global $wpdb;
/**
* We are going to see if cache is set before doing the query and use that if it is.
*
* In a default environment with no external object cache, the value is cached in that request and
* reduces future MySQL requests. If there is an external object cache like Redis then it will be
* persisted until the user level changes.
**/
$cache_key = 'user_' . $user_id . '_additional_levels';
$additional_levels = wp_cache_get( $cache_key, 'pmpro' );
if ( false === $additional_levels ) {
$levels_in = implode( ' OR ', array_fill( 0, count( $levels_to_fetch ), '%d' ) );
$additional_levels = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
l.id AS ID,
l.id as id,
mu.id as subscription_id,
l.name,
l.description,
l.confirmation,
l.expiration_number,
l.expiration_period,
mu.initial_payment,
mu.billing_amount,
mu.cycle_number,
mu.cycle_period,
mu.billing_limit,
mu.trial_amount,
mu.trial_limit,
mu.code_id as code_id,
UNIX_TIMESTAMP(CONVERT_TZ(startdate, '+00:00', @@global.time_zone)) as startdate,
UNIX_TIMESTAMP(CONVERT_TZ(enddate, '+00:00', @@global.time_zone)) as enddate
FROM
{$wpdb->pmpro_membership_levels} AS l
LEFT JOIN
{$wpdb->pmpro_memberships_users} AS mu
ON mu.membership_id = l.id
WHERE
l.id IN ( {$levels_in} )
GROUP BY
ID
",
$levels_to_fetch
)
);
wp_cache_set( $cache_key, $additional_levels, 'pmpro', 3600 );
}
// Check if we need to process any additional levels.
if ( empty( $additional_levels ) ) {
return $levels;
}
// Add the additional levels to the list.
foreach ( $additional_levels as $additional_level ) {
$additional_level->initial_payment = pmpro_round_price( $additional_level->initial_payment );
$additional_level->billing_amount = pmpro_round_price( $additional_level->billing_amount );
$additional_level->trial_amount = pmpro_round_price( $additional_level->trial_amount );
// Add the additional level to the list.
$levels[] = $additional_level;
}
return $levels;
}
add_filter( 'pmpro_get_membership_levels_for_user', 'my_pmpro_inherit_levels_filter', 10, 2 );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment