GeckoGrafix
11/15/2018 - 1:48 PM

CPT for Paid Membership Pro

Plugin for Paid Membership Pro to enable custom post types to be shown or hidden in line with respected meta box

<?php
/**
 * Plugin Name: Paid Memberships Pro - Custom Post Type Add On
 * Plugin URI: https://www.paidmembershipspro.com/add-ons/custom-post-type-membership-access/
 * Description: Add the PMPro meta box to CPTs and redirects non-members to a selected page.
 * Version: .2.1
 * Author: Paid Memberships Pro
 * Author URI: https://www.paidmembershipspro.com/
 */
define( 'PMPRO_CPT_BASENAME', plugin_basename( __FILE__ ) );
/**
 * pmprocpt_page_meta_wrapper Wrapper to add meta boxes
 *
 * @return [type] [description]
 */
function pmprocpt_page_meta_wrapper() {
	$selected_cpts = pmprocpt_getCPTs();
	foreach ( $selected_cpts as $selected_cpt ) {
		add_meta_box( 'pmpro_page_meta', 'Require Membership', 'pmpro_page_meta', $selected_cpt, 'side' );
	}
}
/**
 * pmprocpt_template_redirect Redirect the restricted CPTs to the selected redirect page.
 *
 * @return [type] [description]
 */
function pmprocpt_template_redirect() {
	$selected_cpts = pmprocpt_getCPTs();
	if ( empty( $selected_cpts ) ) {
		return;
	}
	$options = get_option( 'pmprocpt_options' );
	$redirect_to = isset( $options['redirect_to'][0] ) ? intval( $options['redirect_to'][0] ) : '';
	if ( ! empty( $redirect_to ) ) {
		$redirect_to = get_permalink( $redirect_to );
	} else {
		$redirect_to = pmpro_url( 'levels' );
	}
	/**
	 * Filter the URL redirected to when accessing a restricted CPT
	 *
	 * @since  .2
	 */
	$redirect_to = apply_filters( 'pmprocpt_redirect_to', $redirect_to, $selected_cpts, $options );
	if ( ! pmpro_has_membership_access() && is_singular( $selected_cpts ) && ! empty( $redirect_to ) ) {
		wp_redirect( $redirect_to );
		exit;
	}
}
add_action( 'template_redirect', 'pmprocpt_template_redirect' );
/**
 * pmprocpt_getCPTs Get the array of selected CPTs from the settings page.
 *
 * @return array An arry of the selected Custom Post Type names to restrict and redirect from.
 */
function pmprocpt_getCPTs() {
	$options = get_option( 'pmprocpt_options' );
	if ( isset( $options['cpt_selections'] ) && is_array( $options['cpt_selections'] ) ) {
		return $options['cpt_selections'];
	} else {
		return array();
	}
}
/**
 * pmprocpt_init Add Settings Page to WordPress admin.
 *
 * @return [type] [description]
 */
function pmprocpt_init() {
	if ( is_admin() ) {
		add_action( 'admin_menu', 'pmprocpt_page_meta_wrapper' );
	}
}
add_action( 'init', 'pmprocpt_init', 20 );
/**
 * pmprocpt_admin_init Register settings page and fields for the plugin.
 *
 * @return [type] [description]
 */
function pmprocpt_admin_init() {
	// setup settings
	register_setting( 'pmprocpt_options', 'pmprocpt_options', 'pmprocpt_options_validate' );
	add_settings_section( 'pmprocpt_section_general', 'Settings', 'pmprocpt_section_general', 'pmprocpt_options' );
	add_settings_field( 'pmprocpt_option_cpt_selections', 'Select CPTs', 'pmprocpt_option_cpt_selections', 'pmprocpt_options', 'pmprocpt_section_general' );
	add_settings_field( 'pmprocpt_option_redirect_to', 'Redirect to', 'pmprocpt_option_redirect_to', 'pmprocpt_options', 'pmprocpt_section_general' );
}
add_action( 'admin_init', 'pmprocpt_admin_init' );
/**
 * pmprocpt_option_cpt_selections Display the multi-select settings field to select CPTs for restriction.
 *
 * @return [type] [description]
 */
function pmprocpt_option_cpt_selections() {
	global $pmprocpt_cpts;
	$options = get_option( 'pmprocpt_options' );
	$selected_cpts = pmprocpt_getCPTs();
	if ( ! empty( $pmprocpt_cpts ) ) {
		echo "<select style='min-width: 30%; height: 200px;' multiple='yes' name=\"pmprocpt_options[cpt_selections][]\">";
		foreach ( $pmprocpt_cpts as $cpt ) {
			if ( in_array( $cpt, array( 'post', 'page', 'attachment', 'revision', 'nav_menu_item', 'forum', 'topic', 'reply', 'product_variation', 'shop_order', 'shop_order_refund', 'shop_coupon', 'shop_webhook', 'plugin_filter', 'plugin_group' ) ) ) {
				continue;
			} else {
				echo "<option value='" . $cpt . "' ";
				if ( in_array( $cpt, $selected_cpts ) ) {
					echo "selected='selected'";
				}
				echo '>' . $cpt . '</option>';
			}
		}
		echo '</select>';
	} else {
		echo 'No CPTs found.';
	}
}
/**
 * pmprocpt_option_redirect_to Display the dropdown settings field to select the redirection page for restricted CPTs.
 *
 * @return [type] [description]
 */
function pmprocpt_option_redirect_to() {
	$options = get_option( 'pmprocpt_options' );
	if ( isset( $options['redirect_to'] ) ) {
		$redirect_to = $options['redirect_to'][0];
	} else {
		$redirect_to = '';
	}
	wp_dropdown_pages(
		array(
			'name' => 'pmprocpt_options[redirect_to]',
			'echo' => 1,
			'show_option_none' => __( '&mdash; Do Not Redirect &mdash;' ),
			'option_none_value' => '0',
			'selected' => $redirect_to,
		)
	);
}
/**
 * pmprocpt_section_general Display an information message at the top of the settings page.
 *
 * @return string Paragraph description
 */
function pmprocpt_section_general() {
	echo '<p>';
	_e( 'Select the CPTs (custom post types) from the box below to add the "Require Membership" meta box. Then, select the page to redirect to if a non-member attempts to access a protected CPT.' );
	echo '</p>';
}
/**
 * pmprocpt_options_validate Validate our options
 *
 * @param  [type] $input [description]
 *
 * @return [type]        [description]
 */
function pmprocpt_options_validate( $input ) {
	// selected CPTs
	if ( ! empty( $input['cpt_selections'] ) && is_array( $input['cpt_selections'] ) ) {
		$count = count( $input['cpt_selections'] );
		for ( $i = 0; $i < $count; $i++ ) {
			$newinput['cpt_selections'][] = trim( preg_replace( '[^a-zA-Z0-9\-]', '', $input['cpt_selections'][ $i ] ) );
		};
	}
	if ( ! empty( $input['redirect_to'] ) ) {
		$newinput['redirect_to'][] = trim( preg_replace( '[^a-zA-Z0-9\-]', '', $input['redirect_to'] ) );
		;
	}
	return $newinput;
}
/**
 * pmprocpt_admin_add_page Add the admin options page
 *
 * @return [type] [description]
 */
function pmprocpt_admin_add_page() {
	add_options_page( 'PMPro CPTs', 'PMPro CPTs', 'manage_options', 'pmprocpt_options', 'pmprocpt_options_page' );
}
add_action( 'admin_menu', 'pmprocpt_admin_add_page' );
/**
 * pmprocpt_options_page HTML for options page
 *
 * @return [type] [description]
 */
function pmprocpt_options_page() {
	global $pmprocpt_cpts, $msg, $msgt;
	// get options
	$options = get_option( 'pmprocpt_options' );
	$pmprocpt_cpts = get_post_types( '', 'names' );
	$cpt_selections = pmprocpt_getCPTs();
?>
<div class="wrap">
	<div id="icon-options-general" class="icon32"><br></div>
	<h2>Paid Memberships Pro - Custom Post Type Membership Access</h2>		
	
	<?php if ( ! empty( $msg ) ) { ?>
		<div class="message <?php echo $msgt; ?>"><p><?php echo $msg; ?></p></div>
	<?php } ?>
	
	<form action="options.php" method="post">
		
		<p>This plugin will add the PMPro "Require Membership" meta box to all CPTs selected. If a non-member visits that single CPT (either a logged out visitor or a logged in user without membership access) they will be redirected to the selected page.</p>
		<hr />
		
		<?php settings_fields( 'pmprocpt_options' ); ?>
		<?php do_settings_sections( 'pmprocpt_options' ); ?>

		<p><br /></p>
						
		<div class="bottom-buttons">
			<input type="hidden" name="pmprocpt_options[set]" value="1" />
			<input type="submit" name="submit" class="button-primary" value="<?php esc_attr_e( 'Save Settings' ); ?>">
		</div>
		<p><br /></p>
		<hr />
		<p><strong>Notes:</strong></p>
		<p>This redirection will also apply to a search engine indexing your site.</p>
		<p>Setting membership access restrictions for a single CPT will not necessarily hide it from archives, search, or other custom template built into your theme.</p>
	</form>
</div>
<?php
}
/**
 * Register activation hook.
 */
register_activation_hook( PMPRO_CPT_BASENAME, 'pmprocpt_admin_notice_activation_hook' );
/**
 * pmprocpt_admin_notice_activation_hook Runs only when the plugin is activated.
 *
 * @since 0.1.0
 *
 * @return [type] [description]
 */
function pmprocpt_admin_notice_activation_hook() {
	// Create transient data.
	set_transient( 'pmprocpt-admin-notice', true, 5 );
}
/**
 * pmprocpt_admin_notice Admin Notice on Activation.
 *
 * @since 0.1.0
 *
 * @return [type] [description]
 */
function pmprocpt_admin_notice() {
	// Check transient, if available display notice.
	if ( get_transient( 'pmprocpt-admin-notice' ) ) {
	?>
		<div class="updated notice is-dismissible">
			<p><?php printf( __( 'Thank you for activating. <a href="%s">Visit the settings page</a> to get started with the CPT Add On.', 'pmpro-cpt' ), get_admin_url( null, 'options-general.php?page=pmprocpt_options' ) ); ?></p>
		</div>
		<?php
		// Delete transient, only display this notice once.
		delete_transient( 'pmprocpt-admin-notice' );
	}
}
add_action( 'admin_notices', 'pmprocpt_admin_notice' );
/**
 * pmprocpt_add_action_links Add links to the plugin action links
 *
 * @param  array $links Array of existing plugin action links.
 *
 * @return array $links Array of links to be shown in plugin action links.
 */
function pmprocpt_add_action_links( $links ) {
	$new_links = array(
		'<a href="' . get_admin_url( null, 'options-general.php?page=pmprocpt_options' ) . '">' . __( 'Settings', 'pmpro-cpt' ) . '</a>',
	);
	return array_merge( $new_links, $links );
}
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'pmprocpt_add_action_links' );
/**
 * pmprocpt_plugin_row_meta Function to add links to the plugin row meta
 *
 * @param array  $links Array of existing links in plugin meta.
 * @param string $file Filename of the plugin meta is being shown for.
 *
 * @return array  $links Array of links to be shown in plugin meta.
 */
function pmprocpt_plugin_row_meta( $links, $file ) {
	if ( strpos( $file, 'pmpro-cpt.php' ) !== false ) {
		$new_links = array(
			'<a href="' . esc_url( 'https://www.paidmembershipspro.com/add-ons/custom-post-type-membership-access/' ) . '" title="' . esc_attr( __( 'View Documentation', 'pmpro' ) ) . '">' . __( 'Docs', 'pmpro-cpt' ) . '</a>',
			'<a href="' . esc_url( 'https://www.paidmembershipspro.com/support/' ) . '" title="' . esc_attr( __( 'Visit Customer Support Forum', 'pmpro' ) ) . '">' . __( 'Support', 'pmpro-cpt' ) . '</a>',
		);
		$links     = array_merge( $links, $new_links );
	}
	return $links;
}
add_filter( 'plugin_row_meta', 'pmprocpt_plugin_row_meta', 10, 2 );
=== Paid Memberships Pro - Custom Post Type Add On ===
Contributors: strangerstudios
Tags: pmpro, paid memberships pro, members, custom post type, cpt, redirect
Requires at least: 3.5
Tested up to: 4.9.6
Stable tag: .2.1

Adds the 'Require Membership' meta box to all CPTs selected and redirects non-members to the selected page.

== Description ==

This plugin will add the PMPro "Require Membership" meta box to all CPTs selected. If a non-member visits that single CPT (either a logged out visitor or a logged in user without membership access) they will be redirected to the selected page.

== Settings == 
Navigate to Settings > PMPro CPTs in the WordPress Admin to select custom post types and set redirection rules.

== Changelog ==

= .2.1 =
* BUG FIX: Fixed redirect issue when no CPTs were selected on the settings page but the is_singular check was still returning true.
* ENHANCEMENT: WordPress Coding Standards and Improved PHPDoc Blocs

= .2 =
* BUG FIX: Fixed a warning when getting the redirect_to setting. (Thanks, Sarah Hines on GitHub)
* ENHANCEMENT: Added a pmprocpt_redirect_to filter that can be used to change what page the user is redirected to when accessing a restricted CPT they don't have the appropriate membership level for. See here for an example on how to use this filter: https://gist.github.com/strangerstudios/dd213f75c67935a447146ec430498c6d

= .1 =
* Initial commit.