Restore to commit 74e578279624c6045ca440a3459ebfa1f8d54191

This commit is contained in:
southseact-3d
2026-02-07 20:32:41 +00:00
commit ed67b7741b
252 changed files with 99814 additions and 0 deletions

View File

@@ -0,0 +1,225 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class PC_Membership_Access_Control {
public static function init() {
add_action( 'wp', array( __CLASS__, 'check_access' ) );
add_action( 'template_redirect', array( __CLASS__, 'handle_restricted_access' ) );
}
public static function check_access() {
if ( is_admin() ) {
return;
}
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
return;
}
$content_id = 0;
$content_type = '';
if ( is_singular( 'post' ) ) {
$content_id = get_the_ID();
$content_type = 'post';
} elseif ( is_singular( 'page' ) ) {
$content_id = get_the_ID();
$content_type = 'page';
} elseif ( is_category() || is_archive() ) {
$cat = get_queried_object();
if ( $cat && isset( $cat->term_id ) ) {
$content_id = $cat->term_id;
$content_type = 'category';
}
}
if ( empty( $content_id ) || empty( $content_type ) ) {
return;
}
$rule = self::get_access_rule( $content_type, $content_id );
if ( ! $rule ) {
return;
}
if ( self::user_has_access( $rule ) ) {
return;
}
self::redirect_user( $rule );
}
private static function get_access_rule( $content_type, $content_id ) {
global $wpdb;
return $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}pc_membership_access_rules WHERE content_type = %s AND content_id = %d",
$content_type,
$content_id
) );
}
private static function user_has_access( $rule ) {
if ( ! is_user_logged_in() ) {
return false;
}
$plan_ids = maybe_unserialize( $rule->plan_ids );
if ( ! is_array( $plan_ids ) ) {
$plan_ids = array( $plan_ids );
}
if ( empty( $plan_ids ) ) {
return true;
}
$user_id = get_current_user_id();
global $wpdb;
$subscription = $wpdb->get_row( $wpdb->prepare(
"SELECT plan_id FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d AND status = 'active'",
$user_id
) );
if ( ! $subscription ) {
return false;
}
return in_array( $subscription->plan_id, $plan_ids );
}
private static function redirect_user( $rule ) {
$redirect_url = '';
switch ( $rule->redirect_type ) {
case 'custom':
$redirect_url = ! empty( $rule->custom_url ) ? $rule->custom_url : self::get_default_redirect();
break;
case 'login':
$redirect_url = self::get_page_url( 'login' );
break;
default:
$redirect_url = self::get_page_url( 'checkout' );
}
if ( ! $redirect_url ) {
$redirect_url = home_url();
}
wp_redirect( $redirect_url );
exit;
}
private static function get_default_redirect() {
return self::get_page_url( 'checkout' );
}
private static function get_page_url( $page_type ) {
$options = get_option( 'pc_membership_options' );
$page_id = isset( $options[ $page_type . '_page_id' ] ) ? absint( $options[ $page_type . '_page_id' ] ) : 0;
return $page_id ? get_permalink( $page_id ) : '';
}
public static function handle_restricted_access() {
if ( ! is_user_logged_in() ) {
return;
}
global $post;
if ( ! $post ) {
return;
}
$content_type = $post->post_type === 'page' ? 'page' : 'post';
$rule = self::get_access_rule( $content_type, $post->ID );
if ( ! $rule ) {
return;
}
if ( self::user_has_access( $rule ) ) {
return;
}
self::redirect_user( $rule );
}
public static function is_content_restricted( $content_id, $content_type = 'post' ) {
$rule = self::get_access_rule( $content_type, $content_id );
return ! empty( $rule );
}
public static function can_access_content( $user_id, $content_id, $content_type = 'post' ) {
$rule = self::get_access_rule( $content_type, $content_id );
if ( ! $rule ) {
return true;
}
if ( ! $user_id ) {
return false;
}
$plan_ids = maybe_unserialize( $rule->plan_ids );
if ( ! is_array( $plan_ids ) ) {
$plan_ids = array( $plan_ids );
}
global $wpdb;
$subscription = $wpdb->get_row( $wpdb->prepare(
"SELECT plan_id FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d AND status = 'active'",
$user_id
) );
if ( ! $subscription ) {
return false;
}
return in_array( $subscription->plan_id, $plan_ids );
}
public static function restrict_post( $post_id, $plan_ids, $redirect_type = 'checkout', $custom_url = '' ) {
global $wpdb;
$content_type = get_post_type( $post_id ) === 'page' ? 'page' : 'post';
$existing = $wpdb->get_var( $wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}pc_membership_access_rules WHERE content_type = %s AND content_id = %d",
$content_type,
$post_id
) );
if ( $existing ) {
return $wpdb->update( $wpdb->prefix . 'pc_membership_access_rules', array(
'plan_ids' => maybe_serialize( $plan_ids ),
'redirect_type' => $redirect_type,
'custom_url' => $redirect_type === 'custom' ? $custom_url : '',
), array( 'id' => $existing ) );
}
return $wpdb->insert( $wpdb->prefix . 'pc_membership_access_rules', array(
'content_type' => $content_type,
'content_id' => $post_id,
'plan_ids' => maybe_serialize( $plan_ids ),
'redirect_type' => $redirect_type,
'custom_url' => $redirect_type === 'custom' ? $custom_url : '',
) );
}
public static function unrestrict_post( $post_id ) {
global $wpdb;
$content_type = get_post_type( $post_id ) === 'page' ? 'page' : 'post';
return $wpdb->delete( $wpdb->prefix . 'pc_membership_access_rules', array(
'content_type' => $content_type,
'content_id' => $post_id,
) );
}
}

View File

@@ -0,0 +1,128 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class PC_Membership_Activator {
public static function activate() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_plans = $wpdb->prefix . 'pc_membership_plans';
$table_subscriptions = $wpdb->prefix . 'pc_membership_subscriptions';
$table_payments = $wpdb->prefix . 'pc_membership_payments';
$table_access_rules = $wpdb->prefix . 'pc_membership_access_rules';
$sql = "CREATE TABLE $table_plans (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
description TEXT NULL,
price DECIMAL(10,2) NOT NULL DEFAULT 0.00,
is_subscription TINYINT(1) NOT NULL DEFAULT 0,
billing_interval VARCHAR(20) NULL,
trial_days INT(11) NOT NULL DEFAULT 0,
benefits TEXT NULL,
role VARCHAR(100) NULL,
stripe_price_id VARCHAR(255) NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY name (name)
) $charset_collate;\n";
$sql .= "CREATE TABLE $table_subscriptions (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT(20) UNSIGNED NOT NULL,
plan_id BIGINT(20) UNSIGNED NOT NULL,
stripe_customer_id VARCHAR(255) NULL,
stripe_subscription_id VARCHAR(255) NULL,
status VARCHAR(50) NOT NULL DEFAULT 'pending',
started_at DATETIME NOT NULL,
expires_at DATETIME NULL,
cancelled_at DATETIME NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY user_id (user_id),
KEY plan_id (plan_id),
KEY status (status),
KEY stripe_subscription_id (stripe_subscription_id)
) $charset_collate;\n";
$sql .= "CREATE TABLE $table_payments (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT(20) UNSIGNED NOT NULL,
subscription_id BIGINT(20) UNSIGNED NULL,
plan_id BIGINT(20) UNSIGNED NOT NULL,
stripe_payment_intent VARCHAR(255) NULL,
stripe_invoice_id VARCHAR(255) NULL,
amount DECIMAL(10,2) NOT NULL DEFAULT 0.00,
currency VARCHAR(10) NOT NULL DEFAULT 'usd',
status VARCHAR(50) NOT NULL DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY user_id (user_id),
KEY subscription_id (subscription_id),
KEY plan_id (plan_id)
) $charset_collate;\n";
$sql .= "CREATE TABLE $table_access_rules (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
content_type VARCHAR(20) NOT NULL,
content_id BIGINT(20) UNSIGNED NOT NULL,
plan_ids TEXT NOT NULL,
redirect_type VARCHAR(20) NOT NULL DEFAULT 'checkout',
custom_url VARCHAR(500) NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY content_type (content_type),
KEY content_id (content_id),
UNIQUE KEY content_rule (content_type, content_id)
) $charset_collate;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
self::create_default_plans();
self::set_plugin_version();
}
private static function create_default_plans() {
global $wpdb;
$plans_count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}pc_membership_plans" );
if ( $plans_count > 0 ) {
return;
}
$wpdb->insert( $wpdb->prefix . 'pc_membership_plans', array(
'name' => __( 'Basic', 'pc-membership-abc123' ),
'description' => __( 'Get started with basic membership features.', 'pc-membership-abc123' ),
'price' => 9.99,
'is_subscription' => 1,
'billing_interval' => 'month',
'trial_days' => 0,
'benefits' => __( "Access to basic content\nEmail support\nMonthly newsletter", 'pc-membership-abc123' ),
'role' => 'subscriber',
) );
$wpdb->insert( $wpdb->prefix . 'pc_membership_plans', array(
'name' => __( 'Premium', 'pc-membership-abc123' ),
'description' => __( 'Unlock all premium features and content.', 'pc-membership-abc123' ),
'price' => 29.99,
'is_subscription' => 1,
'billing_interval' => 'month',
'trial_days' => 14,
'benefits' => __( "Access to all content\nPriority support\nExclusive webinars\nDownload resources\n24/7 chat support", 'pc-membership-abc123' ),
'role' => 'pc_member_1',
) );
}
private static function set_plugin_version() {
update_option( 'pc_membership_version', PC_MEMBERSHIP_VERSION );
}
}

View File

@@ -0,0 +1,13 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Handles plugin deactivation tasks.
*/
class PC_Membership_Deactivator {
public static function deactivate() {
// No specific actions needed on deactivation currently.
}
}
?>

View File

@@ -0,0 +1,191 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
function pc_membership_format_price( $price, $currency = null ) {
if ( is_null( $currency ) ) {
$options = get_option( 'pc_membership_options' );
$currency = isset( $options['currency'] ) ? $options['currency'] : 'usd';
}
$symbols = array(
'usd' => '$',
'eur' => '€',
'gbp' => '£',
);
$symbol = isset( $symbols[ $currency ] ) ? $symbols[ $currency ] : $currency;
return $symbol . number_format( (float) $price, 2 );
}
function pc_membership_get_plan( $plan_id ) {
global $wpdb;
return $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $plan_id ) );
}
function pc_membership_get_all_plans() {
global $wpdb;
return $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}pc_membership_plans ORDER BY price ASC" );
}
function pc_membership_get_user_subscription( $user_id ) {
global $wpdb;
return $wpdb->get_row( $wpdb->prepare(
"SELECT s.*, p.name as plan_name, p.role, p.is_subscription, p.billing_interval
FROM {$wpdb->prefix}pc_membership_subscriptions s
LEFT JOIN {$wpdb->prefix}pc_membership_plans p ON s.plan_id = p.id
WHERE s.user_id = %d AND s.status = 'active'
ORDER BY s.id DESC LIMIT 1",
$user_id
) );
}
function pc_membership_is_user_on_plan( $user_id, $plan_id ) {
$subscription = pc_membership_get_user_subscription( $user_id );
return $subscription && $subscription->plan_id == $plan_id;
}
function pc_membership_has_active_subscription( $user_id ) {
return (bool) pc_membership_get_user_subscription( $user_id );
}
function pc_membership_get_page_url( $page_type ) {
$options = get_option( 'pc_membership_options' );
$page_id = isset( $options[ $page_type . '_page_id' ] ) ? absint( $options[ $page_type . '_page_id' ] ) : 0;
return $page_id ? get_permalink( $page_id ) : home_url();
}
function pc_membership_redirect_to_checkout() {
$checkout_url = pc_membership_get_page_url( 'checkout' );
if ( $checkout_url ) {
wp_redirect( $checkout_url );
exit;
}
}
function pc_membership_redirect_to_login() {
$login_url = pc_membership_get_page_url( 'login' );
if ( $login_url ) {
wp_redirect( $login_url );
exit;
}
wp_redirect( wp_login_url() );
exit;
}
function pc_membership_register_user( $user_login, $user_email, $user_password ) {
$errors = new WP_Error();
if ( username_exists( $user_login ) ) {
$errors->add( 'username_exists', __( 'Username already exists.', 'pc-membership-abc123' ) );
}
if ( email_exists( $user_email ) ) {
$errors->add( 'email_exists', __( 'Email already registered.', 'pc-membership-abc123' ) );
}
if ( ! is_email( $user_email ) ) {
$errors->add( 'invalid_email', __( 'Invalid email address.', 'pc-membership-abc123' ) );
}
if ( ! validate_username( $user_login ) ) {
$errors->add( 'invalid_username', __( 'Invalid username.', 'pc-membership-abc123' ) );
}
if ( strlen( $user_password ) < 8 ) {
$errors->add( 'weak_password', __( 'Password must be at least 8 characters.', 'pc-membership-abc123' ) );
}
if ( $errors->has_errors() ) {
return $errors;
}
$user_id = wp_create_user( $user_login, $user_password, $user_email );
if ( is_wp_error( $user_id ) ) {
return $user_id;
}
wp_update_user( array(
'ID' => $user_id,
'display_name' => $user_login,
) );
$user = get_userdata( $user_id );
$user->set_role( 'subscriber' );
do_action( 'pc_membership_user_registered', $user_id, $user_login, $user_email );
return $user_id;
}
function pc_membership_authenticate_user( $user_login, $user_password ) {
$user = wp_authenticate_username_password( null, $user_login, $user_password );
if ( is_wp_error( $user ) ) {
return $user;
}
wp_set_auth_cookie( $user->ID, true );
do_action( 'wp_login', $user_login, $user );
return $user;
}
function pc_membership_create_checkout_session( $plan_id, $user_id = null ) {
if ( ! class_exists( 'PC_Membership_Stripe' ) ) {
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/stripe-handler.php';
}
return PC_Membership_Stripe::create_checkout_session( $plan_id, $user_id );
}
function pc_membership_restrict_content( $content_id, $plan_ids, $redirect = 'checkout' ) {
if ( ! class_exists( 'PC_Membership_Access_Control' ) ) {
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/access-control.php';
}
return PC_Membership_Access_Control::restrict_post( $content_id, $plan_ids, $redirect );
}
function pc_membership_unrestrict_content( $content_id ) {
if ( ! class_exists( 'PC_Membership_Access_Control' ) ) {
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/access-control.php';
}
return PC_Membership_Access_Control::unrestrict_post( $content_id );
}
function pc_membership_get_stats() {
global $wpdb;
$stats = array(
'active_members' => 0,
'active_subscriptions' => 0,
'total_plans' => 0,
'revenue_this_month' => 0,
'revenue_last_month' => 0,
);
$stats['active_members'] = $wpdb->get_var( "SELECT COUNT(DISTINCT user_id) FROM {$wpdb->prefix}pc_membership_subscriptions WHERE status = 'active'" );
$stats['active_subscriptions'] = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}pc_membership_subscriptions WHERE status = 'active'" );
$stats['total_plans'] = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}pc_membership_plans" );
$current_month = date( 'Y-m-01' );
$last_month = date( 'Y-m-01', strtotime( '-1 month' ) );
$stats['revenue_this_month'] = $wpdb->get_var( $wpdb->prepare(
"SELECT COALESCE(SUM(amount), 0) FROM {$wpdb->prefix}pc_membership_payments WHERE status = 'succeeded' AND created_at >= %s",
$current_month
) );
$stats['revenue_last_month'] = $wpdb->get_var( $wpdb->prepare(
"SELECT COALESCE(SUM(amount), 0) FROM {$wpdb->prefix}pc_membership_payments WHERE status = 'succeeded' AND created_at >= %s AND created_at < %s",
$last_month,
$current_month
) );
return $stats;
}

View File

@@ -0,0 +1,520 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class PC_Membership_Stripe {
private static function get_options() {
return get_option( 'pc_membership_options', array() );
}
private static function get_secret_key() {
$options = self::get_options();
$mode = isset( $options['mode'] ) ? $options['mode'] : 'test';
return isset( $options[ $mode . '_secret_key' ] ) ? $options[ $mode . '_secret_key' ] : '';
}
private static function get_publishable_key() {
$options = self::get_options();
$mode = isset( $options['mode'] ) ? $options['mode'] : 'test';
return isset( $options[ $mode . '_publishable_key' ] ) ? $options[ $mode . '_publishable_key' ] : '';
}
private static function get_currency() {
$options = self::get_options();
return isset( $options['currency'] ) ? $options['currency'] : 'usd';
}
public static function init() {
$secret_key = self::get_secret_key();
if ( empty( $secret_key ) ) {
return false;
}
if ( ! class_exists( '\Stripe\Stripe' ) ) {
if ( file_exists( PC_MEMBERSHIP_PLUGIN_DIR . 'vendor/autoload.php' ) ) {
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'vendor/autoload.php';
}
}
if ( class_exists( '\Stripe\Stripe' ) ) {
\Stripe\Stripe::setApiKey( $secret_key );
\Stripe\Stripe::setApiVersion( '2023-10-16' );
return true;
}
return false;
}
public static function create_checkout_session( $plan_id, $user_id = null, $customer_email = null ) {
if ( ! self::init() ) {
return new WP_Error( 'stripe_not_configured', __( 'Stripe is not configured properly.', 'pc-membership-abc123' ) );
}
global $wpdb;
$plan = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $plan_id ) );
if ( ! $plan ) {
return new WP_Error( 'plan_not_found', __( 'Plan not found.', 'pc-membership-abc123' ) );
}
$user = null;
$wp_user_id = null;
if ( $user_id ) {
$wp_user_id = $user_id;
} elseif ( is_user_logged_in() ) {
$wp_user_id = get_current_user_id();
}
$customer_id = null;
$session_data = array(
'payment_method_types' => array( 'card' ),
'line_items' => array(),
'success_url' => add_query_arg( array(
'session_id' => '{CHECKOUT_SESSION_ID}',
'plan_id' => $plan_id,
), self::get_success_url() ),
'cancel_url' => self::get_cancel_url(),
'metadata' => array(
'plan_id' => $plan_id,
'wp_user_id' => $wp_user_id ?: 0,
),
);
try {
if ( $wp_user_id ) {
$user = get_userdata( $wp_user_id );
if ( $user ) {
$customer_id = self::get_or_create_customer( $user, $wp_user_id );
if ( ! is_wp_error( $customer_id ) ) {
$session_data['customer'] = $customer_id;
} else {
$session_data['customer_email'] = $user->user_email;
}
}
} elseif ( $customer_email ) {
$session_data['customer_email'] = $customer_email;
}
if ( $plan->is_subscription ) {
$price_data = array(
'currency' => self::get_currency(),
'product_data' => array(
'name' => $plan->name,
'description' => $plan->description ? substr( $plan->description, 0, 500 ) : '',
),
'recurring' => array(
'interval' => $plan->billing_interval,
),
'unit_amount' => intval( $plan->price * 100 ),
);
$session_data['mode'] = 'subscription';
$session_data['line_items'] = array(
array(
'price_data' => $price_data,
'quantity' => 1,
),
);
if ( $plan->trial_days > 0 ) {
$session_data['subscription_data'] = array(
'trial_period_days' => $plan->trial_days,
);
}
} else {
$session_data['mode'] = 'payment';
$session_data['line_items'] = array(
array(
'price_data' => array(
'currency' => self::get_currency(),
'product_data' => array(
'name' => $plan->name,
'description' => $plan->description ? substr( $plan->description, 0, 500 ) : '',
),
'unit_amount' => intval( $plan->price * 100 ),
),
'quantity' => 1,
),
);
}
$session = \Stripe\Checkout\Session::create( $session_data );
return $session;
} catch ( \Exception $e ) {
return new WP_Error( 'stripe_error', $e->getMessage() );
}
}
public static function get_or_create_customer( $user, $wp_user_id ) {
global $wpdb;
$subscription = $wpdb->get_row( $wpdb->prepare(
"SELECT stripe_customer_id FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d ORDER BY id DESC LIMIT 1",
$wp_user_id
) );
if ( $subscription && ! empty( $subscription->stripe_customer_id ) ) {
return $subscription->stripe_customer_id;
}
try {
$customer = \Stripe\Customer::create( array(
'email' => $user->user_email,
'name' => $user->display_name,
'metadata' => array(
'wp_user_id' => $wp_user_id,
),
) );
return $customer->id;
} catch ( \Exception $e ) {
return new WP_Error( 'stripe_customer_error', $e->getMessage() );
}
}
public static function cancel_subscription( $stripe_subscription_id ) {
if ( ! self::init() ) {
return new WP_Error( 'stripe_not_configured', __( 'Stripe is not configured properly.', 'pc-membership-abc123' ) );
}
try {
$subscription = \Stripe\Subscription::retrieve( $stripe_subscription_id );
$subscription->cancel();
return true;
} catch ( \Exception $e ) {
return new WP_Error( 'stripe_error', $e->getMessage() );
}
}
public static function create_portal_session() {
if ( ! self::init() ) {
return new WP_Error( 'stripe_not_configured', __( 'Stripe is not configured properly.', 'pc-membership-abc123' ) );
}
if ( ! is_user_logged_in() ) {
return new WP_Error( 'not_logged_in', __( 'User must be logged in.', 'pc-membership-abc123' ) );
}
global $wpdb;
$subscription = $wpdb->get_row( $wpdb->prepare(
"SELECT stripe_customer_id FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d AND status = 'active' ORDER BY id DESC LIMIT 1",
get_current_user_id()
) );
if ( ! $subscription || empty( $subscription->stripe_customer_id ) ) {
return new WP_Error( 'no_customer', __( 'No Stripe customer found.', 'pc-membership-abc123' ) );
}
try {
$session = \Stripe\BillingPortal\Session::create( array(
'customer' => $subscription->stripe_customer_id,
'return_url' => self::get_page_url( 'account' ),
) );
return $session;
} catch ( \Exception $e ) {
return new WP_Error( 'stripe_error', $e->getMessage() );
}
}
public static function retrieve_session( $session_id ) {
if ( ! self::init() ) {
return new WP_Error( 'stripe_not_configured', __( 'Stripe is not configured properly.', 'pc-membership-abc123' ) );
}
try {
$session = \Stripe\Checkout\Session::retrieve( $session_id );
return $session;
} catch ( \Exception $e ) {
return new WP_Error( 'stripe_error', $e->getMessage() );
}
}
public static function handle_webhook() {
if ( ! self::init() ) {
return;
}
$options = get_option( 'pc_membership_options' );
$webhook_secret = isset( $options['webhook_secret'] ) ? $options['webhook_secret'] : '';
$payload = file_get_contents( 'php://input' );
$sig_header = isset( $_SERVER['HTTP_STRIPE_SIGNATURE'] ) ? $_SERVER['HTTP_STRIPE_SIGNATURE'] : '';
if ( empty( $webhook_secret ) || empty( $sig_header ) ) {
return;
}
try {
$event = \Stripe\Webhook::constructEvent( $payload, $sig_header, $webhook_secret );
} catch ( \Exception $e ) {
return;
}
self::process_webhook_event( $event );
}
private static function process_webhook_event( $event ) {
global $wpdb;
switch ( $event->type ) {
case 'checkout.session.completed':
self::handle_checkout_completed( $event->data->object );
break;
case 'customer.subscription.created':
case 'customer.subscription.updated':
self::handle_subscription_updated( $event->data->object );
break;
case 'customer.subscription.deleted':
self::handle_subscription_deleted( $event->data->object );
break;
case 'invoice.payment_succeeded':
self::handle_payment_succeeded( $event->data->object );
break;
case 'invoice.payment_failed':
self::handle_payment_failed( $event->data->object );
break;
}
}
private static function handle_checkout_completed( $session ) {
global $wpdb;
$plan_id = isset( $session->metadata->plan_id ) ? absint( $session->metadata->plan_id ) : 0;
$wp_user_id = isset( $session->metadata->wp_user_id ) ? absint( $session->metadata->wp_user_id ) : 0;
$customer_id = $session->customer;
$subscription_id = null;
if ( empty( $plan_id ) ) {
return;
}
$plan = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $plan_id ) );
if ( ! $plan ) {
return;
}
if ( $plan->is_subscription && ! empty( $session->subscription ) ) {
$subscription_id = $session->subscription;
try {
$stripe_subscription = \Stripe\Subscription::retrieve( $subscription_id );
$period_end = date( 'Y-m-d H:i:s', $stripe_subscription->current_period_end );
} catch ( \Exception $e ) {
$period_end = null;
}
} else {
$period_end = null;
}
if ( $wp_user_id && $customer_id ) {
$existing = $wpdb->get_var( $wpdb->prepare(
"SELECT id FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d AND plan_id = %d",
$wp_user_id,
$plan_id
) );
if ( $existing ) {
$wpdb->update( $wpdb->prefix . 'pc_membership_subscriptions', array(
'stripe_customer_id' => $customer_id,
'stripe_subscription_id' => $subscription_id ?: '',
'status' => 'active',
'expires_at' => $period_end,
), array( 'id' => $existing ) );
} else {
$wpdb->insert( $wpdb->prefix . 'pc_membership_subscriptions', array(
'user_id' => $wp_user_id,
'plan_id' => $plan_id,
'stripe_customer_id' => $customer_id,
'stripe_subscription_id' => $subscription_id ?: '',
'status' => 'active',
'started_at' => current_time( 'mysql' ),
'expires_at' => $period_end,
) );
if ( $plan->role ) {
$user = get_userdata( $wp_user_id );
if ( $user ) {
$user->set_role( $plan->role );
}
}
}
if ( $session->mode === 'payment' && isset( $session->amount_total ) ) {
$wpdb->insert( $wpdb->prefix . 'pc_membership_payments', array(
'user_id' => $wp_user_id,
'plan_id' => $plan_id,
'stripe_payment_intent' => $session->payment_intent ?: '',
'amount' => $session->amount_total / 100,
'currency' => self::get_currency(),
'status' => 'succeeded',
) );
}
}
}
private static function handle_subscription_updated( $subscription ) {
global $wpdb;
$stripe_sub_id = $subscription->id;
$customer_id = $subscription->customer;
$status = self::map_stripe_status( $subscription->status );
$period_end = date( 'Y-m-d H:i:s', $subscription->current_period_end );
$existing = $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE stripe_subscription_id = %s",
$stripe_sub_id
) );
if ( $existing ) {
$wpdb->update( $wpdb->prefix . 'pc_membership_subscriptions', array(
'status' => $status,
'expires_at' => $period_end,
), array( 'id' => $existing->id ) );
if ( $status === 'active' ) {
$plan = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $existing->plan_id ) );
if ( $plan && $plan->role ) {
$user = get_userdata( $existing->user_id );
if ( $user ) {
$user->set_role( $plan->role );
}
}
}
}
}
private static function handle_subscription_deleted( $subscription ) {
global $wpdb;
$stripe_sub_id = $subscription->id;
$existing = $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE stripe_subscription_id = %s",
$stripe_sub_id
) );
if ( $existing ) {
$wpdb->update( $wpdb->prefix . 'pc_membership_subscriptions', array(
'status' => 'cancelled',
), array( 'id' => $existing->id ) );
$user = get_userdata( $existing->user_id );
if ( $user ) {
$user->set_role( 'subscriber' );
}
}
}
private static function handle_payment_succeeded( $invoice ) {
global $wpdb;
if ( empty( $invoice->subscription ) ) {
return;
}
$stripe_sub_id = $invoice->subscription;
$subscription = $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE stripe_subscription_id = %s",
$stripe_sub_id
) );
if ( ! $subscription ) {
return;
}
$wpdb->insert( $wpdb->prefix . 'pc_membership_payments', array(
'user_id' => $subscription->user_id,
'plan_id' => $subscription->plan_id,
'stripe_payment_intent' => $invoice->payment_intent ?: '',
'amount' => $invoice->amount_paid / 100,
'currency' => strtolower( $invoice->currency ),
'status' => 'succeeded',
) );
if ( isset( $invoice->billing_reason ) && $invoice->billing_reason === 'subscription_cycle' ) {
$stripe_sub = \Stripe\Subscription::retrieve( $stripe_sub_id );
$period_end = date( 'Y-m-d H:i:s', $stripe_sub->current_period_end );
$wpdb->update( $wpdb->prefix . 'pc_membership_subscriptions', array(
'expires_at' => $period_end,
), array( 'id' => $subscription->id ) );
}
}
private static function handle_payment_failed( $invoice ) {
global $wpdb;
if ( empty( $invoice->subscription ) ) {
return;
}
$stripe_sub_id = $invoice->subscription;
$subscription = $wpdb->get_row( $wpdb->prepare(
"SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE stripe_subscription_id = %s",
$stripe_sub_id
) );
if ( $subscription ) {
$user = get_user_by( 'id', $subscription->user_id );
if ( $user ) {
wp_mail(
$user->user_email,
__( 'Payment Failed', 'pc-membership-abc123' ),
__( 'Your membership payment has failed. Please update your payment method to continue your subscription.', 'pc-membership-abc123' )
);
}
}
}
private static function map_stripe_status( $stripe_status ) {
$map = array(
'active' => 'active',
'past_due' => 'past_due',
'unpaid' => 'unpaid',
'canceled' => 'cancelled',
'incomplete' => 'pending',
'incomplete_expired' => 'expired',
'trialing' => 'active',
'paused' => 'paused',
);
return isset( $map[ $stripe_status ] ) ? $map[ $stripe_status ] : 'pending';
}
private static function get_success_url() {
$options = get_option( 'pc_membership_options' );
$page_id = isset( $options['success_page_id'] ) ? absint( $options['success_page_id'] ) : 0;
return $page_id ? get_permalink( $page_id ) : home_url();
}
private static function get_cancel_url() {
$options = get_option( 'pc_membership_options' );
$page_id = isset( $options['cancel_page_id'] ) ? absint( $options['cancel_page_id'] ) : 0;
return $page_id ? get_permalink( $page_id ) : home_url();
}
private static function get_page_url( $page_type ) {
$options = get_option( 'pc_membership_options' );
$page_id = isset( $options[ $page_type . '_page_id' ] ) ? absint( $options[ $page_type . '_page_id' ] ) : 0;
return $page_id ? get_permalink( $page_id ) : home_url();
}
}

View File

@@ -0,0 +1,131 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class PC_Membership_User_Roles {
const MEMBER_ROLE_PREFIX = 'pc_member_';
public static function init() {
add_action( 'init', array( __CLASS__, 'register_member_roles' ) );
add_filter( 'editable_roles', array( __CLASS__, 'filter_editable_roles' ) );
add_action( 'pc_membership_subscription_activated', array( __CLASS__, 'on_subscription_activated' ), 10, 2 );
add_action( 'pc_membership_subscription_cancelled', array( __CLASS__, 'on_subscription_cancelled' ), 10, 2 );
}
public static function register_member_roles() {
$base_role = get_role( 'subscriber' );
if ( ! $base_role ) {
return;
}
$capabilities = $base_role->capabilities;
foreach ( range( 1, 10 ) as $level ) {
$role_name = self::MEMBER_ROLE_PREFIX . $level;
if ( ! get_role( $role_name ) ) {
add_role( $role_name, sprintf( __( 'Member Level %d', 'pc-membership-abc123' ), $level ), $capabilities );
}
}
}
public static function get_member_role_for_plan( $plan_id ) {
global $wpdb;
$plan = $wpdb->get_row( $wpdb->prepare( "SELECT role FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $plan_id ) );
if ( $plan && ! empty( $plan->role ) ) {
return $plan->role;
}
return self::MEMBER_ROLE_PREFIX . '1';
}
public static function set_user_member_role( $user_id, $plan_id ) {
$role = self::get_member_role_for_plan( $plan_id );
$user = get_userdata( $user_id );
if ( $user ) {
$user->set_role( $role );
}
}
public static function remove_member_role( $user_id ) {
$user = get_userdata( $user_id );
if ( $user ) {
$user->set_role( 'subscriber' );
}
}
public static function on_subscription_activated( $user_id, $plan_id ) {
self::set_user_member_role( $user_id, $plan_id );
}
public static function on_subscription_cancelled( $user_id, $plan_id ) {
self::remove_member_role( $user_id );
}
public static function filter_editable_roles( $roles ) {
foreach ( $roles as $role_key => $role_data ) {
if ( strpos( $role_key, self::MEMBER_ROLE_PREFIX ) === 0 ) {
unset( $roles[ $role_key ] );
}
}
return $roles;
}
public static function get_plan_for_user( $user_id ) {
global $wpdb;
$subscription = $wpdb->get_row( $wpdb->prepare(
"SELECT plan_id FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d AND status = 'active' ORDER BY id DESC LIMIT 1",
$user_id
) );
if ( ! $subscription ) {
return null;
}
return $subscription->plan_id;
}
public static function is_user_on_plan( $user_id, $plan_id ) {
$user_plan = self::get_plan_for_user( $user_id );
return $user_plan == $plan_id;
}
public static function user_has_active_subscription( $user_id ) {
global $wpdb;
$count = $wpdb->get_var( $wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d AND status = 'active'",
$user_id
) );
return $count > 0;
}
public static function add_member_capabilities() {
$role = get_role( 'administrator' );
if ( $role ) {
$role->add_cap( 'pc_membership_manage' );
$role->add_cap( 'pc_membership_view_stats' );
}
}
public static function remove_member_capabilities() {
$role = get_role( 'administrator' );
if ( $role ) {
$role->remove_cap( 'pc_membership_manage' );
$role->remove_cap( 'pc_membership_view_stats' );
}
}
}