How to monetize an archive service with Membership 2 Pro?

Is there a line of code I can use to prevent posts from being filtered by the membership plugin if they have been published within the past 30 days? That is, posts published within the past 30 days would be exempt from the membership rules? I'm wanting to monetize an archive service.

It is occurring to me that the same outcome could be created by a line of code that assigns all posts (30 days after publishing) to an "archive" category that is protected by the plugin.

  • Nastia

    Hello xbladerunner , I hope you are doing well!

    I've searched for it, but there is no out of the box ready solution for this. I have asked a second level support to provide you feedback regarding this, because this will require some custom coding.

    Please note that the developer response will take more time than the usual staff response, because they are dealing with complex issues daily.

    Have a nice day and take care.

    Kind Regards,
    Nastia

  • Mahlamusa

    Hello xbladerunner,

    I hope you are doing well today.

    There is no out of the box solution for this but I have created the following code for you which I created to get each post and run a date check on it, after that if the post was published more than 30 days ago the the code will hook that post to be exempted from the membership rules.

    The only filter that can be used to exempt posts from membership rules is:

    'ms_rule_exclude_items-'.$rule

    Where $rule is the rule against which you want to exempt the old post, you can use this hook as follows:

    add_filter('ms_rule_exclude_items-'.$rule, 'exclude_old_posts');
    function exclude_old_posts($exclude){
           //get your posts
           //check the date for each post,
           //if the post is 31 days old add it to the $exclude array
           return $exclude;
    }

    To make this simple for you, I have created an mu-plugin for you. Create a new php file like 'exclude-old-posts.php' and copy the following code and paste it in the file you just created. Upload the file to your website into the folder 'wp-content/mu-plugins/'

    Here is the code:

    <?php
    
    //specify the rules to exclude
    $rules = array( 'post', 'page', 'category', 'media','menu', 'url', 'special', 'shortcode', 'replace_menu', 'replace_location' );
    
    //SUGGESTION: get all posts using wp_query and compare the dates and exclude if necessary
    
    function exclude_old_posts($exclude){
    	$id = get_the_ID();
    	$post_date = get_the_date( $format, $post_id );
    	$today = strtotime($today);
    	$post_date = strtotime($post_date);
    
    	$old_post_days = 31; //how old are the post you want to exclude.
    
    	$past_days = ($today - $post_date)/60/60/24; //number of seconds between the dates
    
    	if ( $old_post_days <= $past_days ){ //if days from today are greater than or equal to 31
    		$exclude[] = $id;
    	}
    
    	return $exclude;
    }
    
    foreach ( $rules as $rule ) {
    	add_filter('ms_rule_exclude_items-'.$rule, 'exclude_old_posts');
    }

    Please note that this code should be refined to suite your needs, also double check and verify if the dates are comparing correctly.

    That should do the trick if you want to exempt posts from the membership rules. If however you want to archive posts and then use membership rules to protect the archive, you should checkout this post

    I hope this helps you archive your goals. Please let us know if you need any further assistance with this issue.

    We sincerely apologize for the late reply from our side.

    Cheers,
    Mahlamusa

  • xbladerunner

    Thanks Mahlamusa! I appreciate you returning to this question.

    If I changed the following line of code from this:

    if ( $old_post_days <= $past_days ){ //if days from today are greater than or equal to 31
    		$exclude[] = $id;
    	}

    to this:

    if ( $old_post_days => $past_days ){ //if days from today are less than or equal to 31
    		$exclude[] = $id;
    	}

    Would I then have a situation where people only have to pay to see posts older than 31 days? Is that the only line of code I'd need to change, if so?

  • Mahlamusa

    Hello xbladerunner,

    I am not sure if I understand what you are saying but here is how it is:

    '$old_post_days' is the number of days you use to determine if a post is old or not.
    '$past_days' is the number of days passed since post was published.

    So if you you add a post to be exempted when its less than 31 days old, that means a post you publish today will be immediately exempted from the membership rules.

    If you want people to pay to see post older than 31 days, you may use the same logic but instead use the hooks:

    'ms_rule_include_items-'.$rule

    like so:

    add_filter('ms_rule_include_items-'.$rule, 'include_old_posts');
    function include_old_posts($include){
           //get your posts
           //check the date for each post,
           //if the post is 31 days old add it to the $include array
           return $include;
    }

    And that should force all the added posts to be protected by the membership rules.

    I hope that answers your question. Thank you for contacting us.

    Please let me know if you have any more questions.

    Cheers,
    Mahlamusa

  • xbladerunner

    Thanks Mahlamusa,

    I've spent a couple days trying to get this to work, to no avail. I have Membership 2 set up with the categories module, such that certain categories are protected from non members. I think I have your mu plugin set up to exclude young posts from the rules, but it's not working. I suspect I'm either making a mistake with the coding of your mu plugin (1st version), or my Membership 2 settings are overriding the ms_rule_exclude_items- filter... Do you have any insights into this?

    I did try your mu plugin (both version 1 and 2) as is, and couldn't get that to work either, so I'm wondering if there is a problem in the code (aside from what I've changed) or if filter doesn't work the way I'd expect it. Here's the code:

    <?php
    
    //specify the rules to exclude
    $rules = array( 'post', 'page', 'category', 'media','menu', 'url', 'special', 'shortcode', 'replace_menu', 'replace_location' );
    
    //SUGGESTION: get all posts using wp_query and compare the dates and exclude if necessary
    
    function exclude_young_posts($exclude){
    	$id = get_the_ID();
    	$post_date = get_the_date( $format, $post_id );
    	$today = strtotime($today);
    	$post_date = strtotime($post_date);
    
    	$old_post_days = 31; //how old are the post you want to exclude.
    
    	$past_days = ($today - $post_date) % 60 % 60 % 24; //number of seconds between the dates
    
    	if ( $old_post_days >= $past_days ){ //if days from today are less than or equal to 31
    		$exclude[] = $id;
    	}
    
    	return $exclude;
    }
    
    foreach ( $rules as $rule ) {
    	add_filter('ms_rule_exclude_items-'.$rule, 'exclude_young_posts');
    }

    The intention of the code, as adjusted, is to exclude young posts from the Membership rules, such that only older posts follow the rules.

  • xbladerunner

    Crap. Had a brief moment where I thought I understood things better, switching the this line

    if ( $old_post_days >= $past_days ){ //if days from today are less than or equal to 31
    		$exclude[] = $id;

    with this line

    if ( $old_post_days <= $past_days ){ //if days from today are less than or equal to 31
    		$exclude[] = $id;

    but I get the same result -- young posts are still not excluded from the rules. (my brief moment of hope came from using a category that was not excluded by the Membership rules... So still a mystery to me why this isn't working.

  • Mahlamusa

    Hi xbladerunner,

    I hope you are doing great today. I am sorry that the code is not working as it should for you.

    I have noticed one thing in the code that may stop things from working. The variable "$today" is not defined and so it will comparison of an empty string/null with a timestamp.

    The line
    $today = strtotime($today);
    Should be changed so that the '$today' variable is assigned to the current timestamp when the code is executed. This can be achieved as follows:

    $today = time();

    That should assign the current timestamp so that it can be used in the line

    $past_days = ($today - $post_date) % 60 % 60 % 24;

    You can also remove the line '$today = strtotime($today);' and change the line

    $past_days = ($today - $post_date) % 60 % 60 % 24;

    to

    $past_days = (time() - $post_date) % 60 % 60 % 24; //so this means you are subtracting the current timestamp from the $post_date timestamp

    I think the code was not working because the '$today' variable was not defined before it was used in the 'strtotime()' function which requires a valid date string.

    You can track what your code is doing by enabling debug logging on your website by editing your wp-config.php and replace the line.

    define('WP_DEBUG', false);

    With the lines

    define('WP_DEBUG', true);
    define('WP_DEBUG_LOG', true);
    define('WP_DEBUG_DISPLAY', false);
    @ini_set('display_errors', 0);

    After that you can add a line like this:
    error_log("Today timestamp : " .$today);

    If you check the file 'wp-content/debug.log' you should see the line written in that file with the $today variable replaced with its value, you can pass 'time()' if you are using that function directly instead of the variable. You can add more debug lines as you wish to track what you code is doing and what values it is using.

    Please try those changes and let me know how if you need more help and I will gladly assist.

    Please enjoy your day further.

    Cheers,
    Mahlamusa

  • xbladerunner

    Hi,
    I'm still struggling here. I've tried the changes suggested above and still am unable to get the Membership plugin to exclude young posts from the membership rules. I have Membership set up with the Categories Addon, so have my rules applying to categories.

    Here's the code I'm currently using:

    <?php
    
    //specify the rules to exclude
    $rules = array( 'post', 'page', 'category', 'media','menu', 'url', 'special', 'shortcode', 'replace_menu', 'replace_location' );
    
    //SUGGESTION: get all posts using wp_query and compare the dates and exclude if necessary
    
    function exclude_young_posts($exclude){
    	$id = get_the_ID();
    	$post_date = get_the_date( 'U' );
    
    	$old_post_days = time() + ('2678400'); //how old are the post you want to exclude, 31 x 24 x 60 x 60.
    
    	$past_days = (time() - $post_date); //number of seconds between the dates
    
    	if ( $old_post_days >= $past_days ){ //if days from today are less than or equal to 31
    		$exclude[] = $id;
    	}
    
    	return $exclude;
    }
    
    foreach ( $rules as $rule ) {
    	add_filter('ms_rule_exclude_items-'.$rule, 'exclude_young_posts');
    }

    Hoping someone else's eyes on this besides mine may see what I'm missing. I've tried moving the filter to the theme's function file, as well as in the mu folder, but can not get the most recent posts to be viewable by visitors, every article is considered restricted content.

  • Mahlamusa

    Hi xbladerunner,

    I hope you are having a great day and I am very sorry for the late reply.

    I am sorry I gave you code that you should use as a start for your requirements this means you should extend the code to make it do what you want. While going through your code, I noticed a few things that may cause the code not to run as it should.

    Firstly, the date in the line
    $post_date = get_the_date( 'U' );
    May cause errors if it comes out as a string, so if the line returns a string you should

    Secondly, the line
    $old_post_days = time() + ('2678400');
    seems to be a timestamp in the future but it should be in the past so that you can compare past days with the old_post_days. In my example code this was a number of days not a timestamp so that it can compare days with days. If you wish to work with timestamps throughout the code, that is fine but just make sure you you are not comparing future timestamps.

    I have also modified the code so it hooks to the 'init' action by adding as follows:
    add_action('init', 'add_rule_filters');

    Now the final code looks like this:

    <?php
    /*
    Plugin Name: Exclude Young Posts
    Description: Excludes young post from membership rules
    Version: 1.0.0
    Author: wpmudev
    */
    //TODO: get all posts using wp_query and compare the dates and exclude if necessary
    
    function exclude_young_posts($exclude){
    	global $post;
    	$id = get_the_ID();
    	$post = get_post( $id );
    	$post_date = get_the_date();	//can be past post object $post
    	$post_date = strtotime($post_date);
    
    	$today = time();
    	$old_post_days = 31; //how old are the post you want to exclude.
    	$past_days = ($today - $post_date)/60/60/24; //number of seconds between the dates
    
    	error_log("==== Debug: Excluding young posts");
    	error_log("Today is : " .$today);
    	error_log("Old post days = " . time() + ('2678400') ); //this should be less than or equal today
    	error_log("Past days: ".$past_days);
    
    	if ( $old_post_days >= $past_days ){ //if days from today are less than or equal to 31
    		$exclude[] = $id;
    		error_log( "Excluding post : ".$id);
    	}
    
    	error_log ("Day comparison : old day> " . $old_post_days . ', past day: ' .$past_days );
    	error_log("=== End debug");
    
    	return $exclude;
    }
    
    function get_all_memberships(){
    	$memberships = MS_Model_Membership::get_memberships();
    
    	return $memberships;
    }
    
    function add_rule_filters(){
    	//specify the rules to exclude
    	$rules = array( 'post', 'page', 'category', 'media','menu', 'url', 'special', 'shortcode', 'replace_menu', 'replace_location' );
    	foreach ( $rules as $rule ) {
    		if ( ! has_filter( 'ms_rule_exclude_items-'.$rule ) ){
    			error_log("Adding filter for rule : " .$rule);
    			add_filter('ms_rule_exclude_items-'.$rule, 'exclude_young_posts');
    		}else{
    			error_log("Filter already exists for rule: $rule");
    		}
    	}
    }
    
    add_action('init', 'add_rule_filters');
    
    ?>

    Would you please enable debug logging in your website by doing the following;

    Editing your wp-config.phpfile and replace the line:

    define('WP_DEBUG', false);

    With the lines:

    define('WP_DEBUG', true);
    define('WP_DEBUG_LOG', true);
    define('WP_DEBUG_DISPLAY', false);
    @ini_set('display_errors', 0);

    After that try the above code and see the output of the debug file located at 'wp-content/debug.log', this file should tell you what the code is doing at what point so that you can understand the steps and the values it is comparing.

    I hope this helps you. I am sorry once again for the delayed response.

    Cheers,
    Mahlamusa