Restore to commit 74e578279624c6045ca440a3459ebfa1f8d54191
This commit is contained in:
725
chat/templates/Membership/admin/admin.php
Normal file
725
chat/templates/Membership/admin/admin.php
Normal file
@@ -0,0 +1,725 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class PC_Membership_Admin {
|
||||
|
||||
public static function init() {
|
||||
add_action( 'admin_menu', array( __CLASS__, 'add_admin_menu' ) );
|
||||
add_action( 'admin_init', array( __CLASS__, 'register_settings' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
|
||||
add_action( 'wp_ajax_pc_membership_save_plan', array( __CLASS__, 'ajax_save_plan' ) );
|
||||
add_action( 'wp_ajax_pc_membership_delete_plan', array( __CLASS__, 'ajax_delete_plan' ) );
|
||||
add_action( 'wp_ajax_pc_membership_get_plan', array( __CLASS__, 'ajax_get_plan' ) );
|
||||
add_action( 'wp_ajax_pc_membership_get_stats', array( __CLASS__, 'ajax_get_stats' ) );
|
||||
add_action( 'wp_ajax_pc_membership_save_pages', array( __CLASS__, 'ajax_save_pages' ) );
|
||||
add_action( 'wp_ajax_pc_membership_save_access_rule', array( __CLASS__, 'ajax_save_access_rule' ) );
|
||||
add_action( 'wp_ajax_pc_membership_delete_access_rule', array( __CLASS__, 'ajax_delete_access_rule' ) );
|
||||
add_action( 'wp_ajax_pc_membership_get_content_for_rule', array( __CLASS__, 'ajax_get_content_for_rule' ) );
|
||||
}
|
||||
|
||||
public static function add_admin_menu() {
|
||||
add_menu_page(
|
||||
__( 'Membership', 'pc-membership-abc123' ),
|
||||
__( 'Membership', 'pc-membership-abc123' ),
|
||||
'manage_options',
|
||||
'pc-membership',
|
||||
array( __CLASS__, 'dashboard_page' ),
|
||||
'dashicons-id',
|
||||
81
|
||||
);
|
||||
|
||||
add_submenu_page( 'pc-membership', __( 'Dashboard', 'pc-membership-abc123' ), __( 'Dashboard', 'pc-membership-abc123' ), 'manage_options', 'pc-membership', array( __CLASS__, 'dashboard_page' ) );
|
||||
add_submenu_page( 'pc-membership', __( 'Plans', 'pc-membership-abc123' ), __( 'Plans', 'pc-membership-abc123' ), 'manage_options', 'pc-membership-plans', array( __CLASS__, 'plans_page' ) );
|
||||
add_submenu_page( 'pc-membership', __( 'Pages', 'pc-membership-abc123' ), __( 'Pages', 'pc-membership-abc123' ), 'manage_options', 'pc-membership-pages', array( __CLASS__, 'pages_page' ) );
|
||||
add_submenu_page( 'pc-membership', __( 'Access Rules', 'pc-membership-abc123' ), __( 'Access Rules', 'pc-membership-abc123' ), 'manage_options', 'pc-membership-access', array( __CLASS__, 'access_page' ) );
|
||||
add_submenu_page( 'pc-membership', __( 'Settings', 'pc-membership-abc123' ), __( 'Settings', 'pc-membership-abc123' ), 'manage_options', 'pc-membership-settings', array( __CLASS__, 'settings_page' ) );
|
||||
}
|
||||
|
||||
public static function register_settings() {
|
||||
register_setting( 'pc_membership_options', 'pc_membership_options', array( __CLASS__, 'sanitize_options' ) );
|
||||
|
||||
add_settings_section( 'pc_membership_stripe', __( 'Stripe Configuration', 'pc-membership-abc123' ), '__return_false', 'pc-membership-settings' );
|
||||
add_settings_field( 'test_publishable_key', __( 'Test Publishable Key', 'pc-membership-abc123' ), array( __CLASS__, 'field_publishable_key' ), 'pc-membership-settings', 'pc_membership_stripe', array( 'key_type' => 'test' ) );
|
||||
add_settings_field( 'test_secret_key', __( 'Test Secret Key', 'pc-membership-abc123' ), array( __CLASS__, 'field_secret_key' ), 'pc-membership-settings', 'pc_membership_stripe', array( 'key_type' => 'test' ) );
|
||||
add_settings_field( 'live_publishable_key', __( 'Live Publishable Key', 'pc-membership-abc123' ), array( __CLASS__, 'field_publishable_key' ), 'pc-membership-settings', 'pc_membership_stripe', array( 'key_type' => 'live' ) );
|
||||
add_settings_field( 'live_secret_key', __( 'Live Secret Key', 'pc-membership-abc123' ), array( __CLASS__, 'field_secret_key' ), 'pc-membership-settings', 'pc_membership_stripe', array( 'key_type' => 'live' ) );
|
||||
add_settings_field( 'webhook_secret', __( 'Webhook Secret', 'pc-membership-abc123' ), array( __CLASS__, 'field_webhook_secret' ), 'pc-membership-settings', 'pc_membership_stripe' );
|
||||
add_settings_field( 'mode', __( 'Mode', 'pc-membership-abc123' ), array( __CLASS__, 'field_mode' ), 'pc-membership-settings', 'pc_membership_stripe' );
|
||||
|
||||
add_settings_section( 'pc_membership_general', __( 'General Settings', 'pc-membership-abc123' ), '__return_false', 'pc-membership-settings' );
|
||||
add_settings_field( 'currency', __( 'Currency', 'pc-membership-abc123' ), array( __CLASS__, 'field_currency' ), 'pc-membership-settings', 'pc_membership_general' );
|
||||
}
|
||||
|
||||
public static function sanitize_options( $input ) {
|
||||
$output = array();
|
||||
foreach ( array( 'test_publishable_key', 'test_secret_key', 'live_publishable_key', 'live_secret_key', 'webhook_secret' ) as $key ) {
|
||||
if ( isset( $input[ $key ] ) ) {
|
||||
$output[ $key ] = sanitize_text_field( $input[ $key ] );
|
||||
}
|
||||
}
|
||||
if ( isset( $input['mode'] ) && in_array( $input['mode'], array( 'test', 'live' ) ) ) {
|
||||
$output['mode'] = $input['mode'];
|
||||
}
|
||||
if ( isset( $input['currency'] ) && in_array( $input['currency'], array( 'usd', 'eur', 'gbp' ) ) ) {
|
||||
$output['currency'] = $input['currency'];
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
public static function field_publishable_key( $args ) {
|
||||
$options = get_option( 'pc_membership_options' );
|
||||
$key = $args['key_type'] . '_publishable_key';
|
||||
$value = isset( $options[ $key ] ) ? esc_attr( $options[ $key ] ) : '';
|
||||
echo '<input type="text" name="pc_membership_options[' . esc_attr( $key ) . ']" value="' . $value . '" class="regular-text" placeholder="pk_test_..." />';
|
||||
echo '<p class="description">' . esc_html__( 'Your Stripe publishable key from the Stripe dashboard.', 'pc-membership-abc123' ) . '</p>';
|
||||
}
|
||||
|
||||
public static function field_secret_key( $args ) {
|
||||
$options = get_option( 'pc_membership_options' );
|
||||
$key = $args['key_type'] . '_secret_key';
|
||||
$value = isset( $options[ $key ] ) ? esc_attr( $options[ $key ] ) : '';
|
||||
echo '<input type="password" name="pc_membership_options[' . esc_attr( $key ) . ']" value="' . $value . '" class="regular-text" autocomplete="new-password" placeholder="sk_test_..." />';
|
||||
echo '<p class="description">' . esc_html__( 'Your Stripe secret key from the Stripe dashboard.', 'pc-membership-abc123' ) . '</p>';
|
||||
}
|
||||
|
||||
public static function field_webhook_secret() {
|
||||
$options = get_option( 'pc_membership_options' );
|
||||
$value = isset( $options['webhook_secret'] ) ? esc_attr( $options['webhook_secret'] ) : '';
|
||||
echo '<input type="text" name="pc_membership_options[webhook_secret]" value="' . $value . '" class="regular-text" placeholder="whsec_..." />';
|
||||
echo '<p class="description">' . esc_html__( 'Webhook secret for handling Stripe events.', 'pc-membership-abc123' ) . '</p>';
|
||||
}
|
||||
|
||||
public static function field_mode() {
|
||||
$options = get_option( 'pc_membership_options' );
|
||||
$mode = isset( $options['mode'] ) ? $options['mode'] : 'test';
|
||||
echo '<select name="pc_membership_options[mode]">';
|
||||
echo '<option value="test"' . selected( $mode, 'test', false ) . '>' . esc_html__( 'Test Mode', 'pc-membership-abc123' ) . '</option>';
|
||||
echo '<option value="live"' . selected( $mode, 'live', false ) . '>' . esc_html__( 'Live Mode', 'pc-membership-abc123' ) . '</option>';
|
||||
echo '</select>';
|
||||
echo '<p class="description">' . esc_html__( 'Use test mode for development. Switch to live mode when ready for production.', 'pc-membership-abc123' ) . '</p>';
|
||||
}
|
||||
|
||||
public static function field_currency() {
|
||||
$options = get_option( 'pc_membership_options' );
|
||||
$currency = isset( $options['currency'] ) ? $options['currency'] : 'usd';
|
||||
echo '<select name="pc_membership_options[currency]">';
|
||||
echo '<option value="usd"' . selected( $currency, 'usd', false ) . '>USD ($)</option>';
|
||||
echo '<option value="eur"' . selected( $currency, 'eur', false ) . '>EUR (€)</option>';
|
||||
echo '<option value="gbp"' . selected( $currency, 'gbp', false ) . '>GBP (£)</option>';
|
||||
echo '</select>';
|
||||
}
|
||||
|
||||
public static function dashboard_page() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_die( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
?>
|
||||
<div class="wrap pc-membership-admin-wrap">
|
||||
<h1><?php esc_html_e( 'Membership Dashboard', 'pc-membership-abc123' ); ?></h1>
|
||||
<div class="pc-membership-dashboard-cards">
|
||||
<div class="pc-membership-card">
|
||||
<div class="pc-membership-card-header">
|
||||
<span class="dashicons dashicons-groups"></span>
|
||||
<h3><?php esc_html_e( 'Active Members', 'pc-membership-abc123' ); ?></h3>
|
||||
</div>
|
||||
<div class="pc-membership-card-body">
|
||||
<div class="pc-membership-stat" id="pc-members-count">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pc-membership-card">
|
||||
<div class="pc-membership-card-header">
|
||||
<span class="dashicons dashicons-cart"></span>
|
||||
<h3><?php esc_html_e( 'Active Subscriptions', 'pc-membership-abc123' ); ?></h3>
|
||||
</div>
|
||||
<div class="pc-membership-card-body">
|
||||
<div class="pc-membership-stat" id="pc-subscriptions-count">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pc-membership-card">
|
||||
<div class="pc-membership-card-header">
|
||||
<span class="dashicons dashicons-chart-area"></span>
|
||||
<h3><?php esc_html_e( 'Revenue This Month', 'pc-membership-abc123' ); ?></h3>
|
||||
</div>
|
||||
<div class="pc-membership-card-body">
|
||||
<div class="pc-membership-stat" id="pc-revenue">-</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pc-membership-card">
|
||||
<div class="pc-membership-card-header">
|
||||
<span class="dashicons dashicons-pressthis"></span>
|
||||
<h3><?php esc_html_e( 'Total Plans', 'pc-membership-abc123' ); ?></h3>
|
||||
</div>
|
||||
<div class="pc-membership-card-body">
|
||||
<div class="pc-membership-stat" id="pc-plans-count">-</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pc-membership-dashboard-section">
|
||||
<h2><?php esc_html_e( 'Recent Subscriptions', 'pc-membership-abc123' ); ?></h2>
|
||||
<div class="pc-membership-table-wrapper">
|
||||
<table class="widefat fixed striped pc-membership-table" id="pc-recent-subscriptions">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'User', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Plan', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Status', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Started', 'pc-membership-abc123' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td colspan="4"><?php esc_html_e( 'Loading...', 'pc-membership-abc123' ); ?></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function plans_page() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_die( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$plans = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}pc_membership_plans ORDER BY id DESC" );
|
||||
?>
|
||||
<div class="wrap pc-membership-admin-wrap">
|
||||
<h1><?php esc_html_e( 'Membership Plans', 'pc-membership-abc123' ); ?>
|
||||
<a href="#" class="page-title-action pc-membership-add-plan-btn"><?php esc_html_e( 'Add New Plan', 'pc-membership-abc123' ); ?></a>
|
||||
</h1>
|
||||
|
||||
<?php if ( empty( $plans ) ) : ?>
|
||||
<div class="pc-membership-empty-state">
|
||||
<span class="dashicons dashicons-pressthis" style="font-size: 48px; height: 48px; width: 48px;"></span>
|
||||
<h3><?php esc_html_e( 'No plans yet', 'pc-membership-abc123' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Create your first membership plan to get started.', 'pc-membership-abc123' ); ?></p>
|
||||
<button class="button button-primary pc-membership-add-plan-btn"><?php esc_html_e( 'Add First Plan', 'pc-membership-abc123' ); ?></button>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<table class="widefat fixed striped pc-membership-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'ID', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Name', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Type', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Price', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Billing', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Members', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Actions', 'pc-membership-abc123' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ( $plans as $plan ) :
|
||||
$type_label = $plan->is_subscription ? __( 'Subscription', 'pc-membership-abc123' ) : __( 'One-time', 'pc-membership-abc123' );
|
||||
$billing_label = $plan->is_subscription ? sprintf( '%s / %s', pc_membership_format_price( $plan->price ), $plan->billing_interval ) : pc_membership_format_price( $plan->price );
|
||||
$members_count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->prefix}pc_membership_subscriptions WHERE plan_id = %d AND status = 'active'", $plan->id ) );
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( $plan->id ); ?></td>
|
||||
<td><strong><?php echo esc_html( $plan->name ); ?></strong></td>
|
||||
<td><?php echo esc_html( $type_label ); ?></td>
|
||||
<td><?php echo esc_html( pc_membership_format_price( $plan->price ) ); ?></td>
|
||||
<td><?php echo esc_html( $billing_label ); ?></td>
|
||||
<td><?php echo esc_html( (string) $members_count ); ?></td>
|
||||
<td>
|
||||
<button class="button pc-membership-edit-plan" data-plan-id="<?php echo esc_attr( $plan->id ); ?>"><?php esc_html_e( 'Edit', 'pc-membership-abc123' ); ?></button>
|
||||
<button class="button pc-membership-delete-plan" data-plan-id="<?php echo esc_attr( $plan->id ); ?>"><?php esc_html_e( 'Delete', 'pc-membership-abc123' ); ?></button>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="pc-membership-plan-modal" class="pc-membership-modal" style="display: none;">
|
||||
<div class="pc-membership-modal-content">
|
||||
<div class="pc-membership-modal-header">
|
||||
<h2><?php esc_html_e( 'Membership Plan', 'pc-membership-abc123' ); ?></h2>
|
||||
<button class="pc-membership-modal-close">×</button>
|
||||
</div>
|
||||
<form id="pc-membership-plan-form" method="post">
|
||||
<?php wp_nonce_field( 'pc_membership_save_plan', 'pc_membership_plan_nonce' ); ?>
|
||||
<input type="hidden" name="plan_id" id="plan_id" value="">
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="plan_name"><?php esc_html_e( 'Plan Name', 'pc-membership-abc123' ); ?> *</label>
|
||||
<input type="text" name="name" id="plan_name" required class="regular-text">
|
||||
</div>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="plan_description"><?php esc_html_e( 'Description', 'pc-membership-abc123' ); ?></label>
|
||||
<textarea name="description" id="plan_description" rows="3" class="regular-text"></textarea>
|
||||
</div>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="plan_type"><?php esc_html_e( 'Pricing Type', 'pc-membership-abc123' ); ?></label>
|
||||
<select name="is_subscription" id="plan_type">
|
||||
<option value="0"><?php esc_html_e( 'One-time Payment', 'pc-membership-abc123' ); ?></option>
|
||||
<option value="1"><?php esc_html_e( 'Subscription', 'pc-membership-abc123' ); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="plan_price"><?php esc_html_e( 'Price', 'pc-membership-abc123' ); ?> *</label>
|
||||
<input type="number" name="price" id="plan_price" step="0.01" min="0" required class="regular-text">
|
||||
</div>
|
||||
<div class="pc-membership-form-row" id="billing_interval_row" style="display: none;">
|
||||
<label for="plan_billing_interval"><?php esc_html_e( 'Billing Interval', 'pc-membership-abc123' ); ?></label>
|
||||
<select name="billing_interval" id="plan_billing_interval">
|
||||
<option value="day"><?php esc_html_e( 'Daily', 'pc-membership-abc123' ); ?></option>
|
||||
<option value="week"><?php esc_html_e( 'Weekly', 'pc-membership-abc123' ); ?></option>
|
||||
<option value="month" selected><?php esc_html_e( 'Monthly', 'pc-membership-abc123' ); ?></option>
|
||||
<option value="year"><?php esc_html_e( 'Yearly', 'pc-membership-abc123' ); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="plan_trial_days"><?php esc_html_e( 'Trial Period (Days)', 'pc-membership-abc123' ); ?></label>
|
||||
<input type="number" name="trial_days" id="plan_trial_days" min="0" value="0" class="regular-text">
|
||||
<p class="description"><?php esc_html_e( 'Number of free trial days before billing starts. Set to 0 for no trial.', 'pc-membership-abc123' ); ?></p>
|
||||
</div>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="plan_benefits"><?php esc_html_e( 'Benefits', 'pc-membership-abc123' ); ?></label>
|
||||
<textarea name="benefits" id="plan_benefits" rows="5" class="regular-text" placeholder="- Unlimited access - Priority support"></textarea>
|
||||
<p class="description"><?php esc_html_e( 'Enter one benefit per line.', 'pc-membership-abc123' ); ?></p>
|
||||
</div>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="plan_role"><?php esc_html_e( 'User Role', 'pc-membership-abc123' ); ?></label>
|
||||
<select name="role" id="plan_role">
|
||||
<?php foreach ( self::get_available_roles() as $role_key => $role_name ) : ?>
|
||||
<option value="<?php echo esc_attr( $role_key ); ?>"><?php echo esc_html( $role_name ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pc-membership-form-actions">
|
||||
<button type="submit" class="button button-primary"><?php esc_html_e( 'Save Plan', 'pc-membership-abc123' ); ?></button>
|
||||
<button type="button" class="button pc-membership-modal-cancel"><?php esc_html_e( 'Cancel', 'pc-membership-abc123' ); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
private static function get_available_roles() {
|
||||
$roles = get_editable_roles();
|
||||
$options = array();
|
||||
foreach ( $roles as $role_key => $role_data ) {
|
||||
$options[ $role_key ] = translate_user_role( $role_data['name'] );
|
||||
}
|
||||
return $options;
|
||||
}
|
||||
|
||||
public static function ajax_save_plan() {
|
||||
check_ajax_referer( 'pc_membership_save_plan', 'nonce' );
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$plan_id = isset( $_POST['plan_id'] ) ? absint( $_POST['plan_id'] ) : 0;
|
||||
$name = sanitize_text_field( wp_unslash( $_POST['name'] ) );
|
||||
$description = isset( $_POST['description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['description'] ) ) : '';
|
||||
$price = isset( $_POST['price'] ) ? floatval( $_POST['price'] ) : 0;
|
||||
$is_subscription = isset( $_POST['is_subscription'] ) ? absint( $_POST['is_subscription'] ) : 0;
|
||||
$billing_interval = isset( $_POST['billing_interval'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_interval'] ) ) : 'month';
|
||||
$trial_days = isset( $_POST['trial_days'] ) ? absint( $_POST['trial_days'] ) : 0;
|
||||
$benefits = isset( $_POST['benefits'] ) ? sanitize_textarea_field( wp_unslash( $_POST['benefits'] ) ) : '';
|
||||
$role = isset( $_POST['role'] ) ? sanitize_text_field( wp_unslash( $_POST['role'] ) ) : 'subscriber';
|
||||
|
||||
if ( empty( $name ) || $price < 0 ) {
|
||||
wp_send_json_error( __( 'Invalid input data', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'name' => $name,
|
||||
'description' => $description,
|
||||
'price' => $price,
|
||||
'is_subscription' => $is_subscription,
|
||||
'billing_interval' => $is_subscription ? $billing_interval : '',
|
||||
'trial_days' => $trial_days,
|
||||
'benefits' => $benefits,
|
||||
'role' => $role,
|
||||
);
|
||||
|
||||
if ( $plan_id ) {
|
||||
$result = $wpdb->update( $wpdb->prefix . 'pc_membership_plans', $data, array( 'id' => $plan_id ) );
|
||||
} else {
|
||||
$result = $wpdb->insert( $wpdb->prefix . 'pc_membership_plans', $data );
|
||||
$plan_id = $wpdb->insert_id;
|
||||
}
|
||||
|
||||
if ( $result === false ) {
|
||||
wp_send_json_error( __( 'Failed to save plan', 'pc-membership-abc123' ) );
|
||||
}
|
||||
wp_send_json_success( array( 'plan_id' => $plan_id ) );
|
||||
}
|
||||
|
||||
public static function ajax_get_plan() {
|
||||
check_ajax_referer( 'pc_membership_save_plan', 'nonce' );
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$plan_id = isset( $_POST['plan_id'] ) ? absint( $_POST['plan_id'] ) : 0;
|
||||
if ( ! $plan_id ) {
|
||||
wp_send_json_error( __( 'Invalid plan ID', '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 ) {
|
||||
wp_send_json_error( __( 'Plan not found', 'pc-membership-abc123' ) );
|
||||
}
|
||||
wp_send_json_success( array( 'plan' => $plan ) );
|
||||
}
|
||||
|
||||
public static function ajax_delete_plan() {
|
||||
check_ajax_referer( 'pc_membership_save_plan', 'nonce' );
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$plan_id = isset( $_POST['plan_id'] ) ? absint( $_POST['plan_id'] ) : 0;
|
||||
if ( ! $plan_id ) {
|
||||
wp_send_json_error( __( 'Invalid plan ID', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$wpdb->delete( $wpdb->prefix . 'pc_membership_subscriptions', array( 'plan_id' => $plan_id ) );
|
||||
$result = $wpdb->delete( $wpdb->prefix . 'pc_membership_plans', array( 'id' => $plan_id ) );
|
||||
|
||||
if ( $result === false ) {
|
||||
wp_send_json_error( __( 'Failed to delete plan', 'pc-membership-abc123' ) );
|
||||
}
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
public static function ajax_get_stats() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$active_members = $wpdb->get_var( "SELECT COUNT(DISTINCT user_id) FROM {$wpdb->prefix}pc_membership_subscriptions WHERE status = 'active'" );
|
||||
$active_subscriptions = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}pc_membership_subscriptions WHERE status = 'active'" );
|
||||
$total_plans = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}pc_membership_plans" );
|
||||
$current_month = date( 'Y-m-01' );
|
||||
$revenue = $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 ) );
|
||||
$recent_subs = $wpdb->get_results( "SELECT s.*, u.display_name, u.user_login, p.name as plan_name FROM {$wpdb->prefix}pc_membership_subscriptions s LEFT JOIN {$wpdb->users} u ON s.user_id = u.ID LEFT JOIN {$wpdb->prefix}pc_membership_plans p ON s.plan_id = p.id ORDER BY s.created_at DESC LIMIT 10" );
|
||||
|
||||
wp_send_json_success( array(
|
||||
'active_members' => $active_members,
|
||||
'active_subscriptions' => $active_subscriptions,
|
||||
'total_plans' => $total_plans,
|
||||
'revenue' => pc_membership_format_price( $revenue ),
|
||||
'recent_subscriptions' => $recent_subs,
|
||||
) );
|
||||
}
|
||||
|
||||
public static function ajax_save_pages() {
|
||||
check_ajax_referer( 'pc_membership_save_pages', 'nonce' );
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
if ( isset( $_POST['pc_membership_options'] ) ) {
|
||||
$options = get_option( 'pc_membership_options', array() );
|
||||
foreach ( $_POST['pc_membership_options'] as $key => $value ) {
|
||||
$options[ $key ] = absint( $value );
|
||||
}
|
||||
update_option( 'pc_membership_options', $options );
|
||||
}
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
public static function pages_page() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_die( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$options = get_option( 'pc_membership_options', array() );
|
||||
$page_fields = array(
|
||||
'checkout' => __( 'Checkout Page', 'pc-membership-abc123' ),
|
||||
'login' => __( 'Login Page', 'pc-membership-abc123' ),
|
||||
'register' => __( 'Registration Page', 'pc-membership-abc123' ),
|
||||
'account' => __( 'Account Page', 'pc-membership-abc123' ),
|
||||
'success' => __( 'Success Page', 'pc-membership-abc123' ),
|
||||
'cancel' => __( 'Cancel Page', 'pc-membership-abc123' ),
|
||||
);
|
||||
$pages = get_pages( array( 'post_status' => 'publish' ) );
|
||||
?>
|
||||
<div class="wrap pc-membership-admin-wrap">
|
||||
<h1><?php esc_html_e( 'Membership Pages', 'pc-membership-abc123' ); ?></h1>
|
||||
<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=pc-membership-pages' ) ); ?>">
|
||||
<?php wp_nonce_field( 'pc_membership_save_pages', 'pc_membership_pages_nonce' ); ?>
|
||||
<div class="pc-membership-page-settings">
|
||||
<?php foreach ( $page_fields as $key => $label ) :
|
||||
$selected = isset( $options[ $key . '_page_id' ] ) ? absint( $options[ $key . '_page_id' ] ) : 0;
|
||||
?>
|
||||
<div class="pc-membership-page-setting">
|
||||
<label for="<?php echo esc_attr( 'page_' . $key ); ?>"><strong><?php echo esc_html( $label ); ?></strong></label>
|
||||
<select name="pc_membership_options[<?php echo esc_attr( $key . '_page_id' ); ?>]" id="<?php echo esc_attr( 'page_' . $key ); ?>">
|
||||
<option value="0"><?php esc_html_e( '-- Select --', 'pc-membership-abc123' ); ?></option>
|
||||
<?php foreach ( $pages as $page ) : ?>
|
||||
<option value="<?php echo esc_attr( $page->ID ); ?>" <?php selected( $selected, $page->ID ); ?>>
|
||||
<?php echo esc_html( $page->post_title ); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php submit_button( __( 'Save Page Settings', 'pc-membership-abc123' ) ); ?>
|
||||
</form>
|
||||
<hr>
|
||||
<h2><?php esc_html_e( 'Quick Create Pages', 'pc-membership-abc123' ); ?></h2>
|
||||
<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=pc-membership-pages' ) ); ?>">
|
||||
<?php wp_nonce_field( 'pc_membership_create_pages', 'pc_membership_create_pages_nonce' ); ?>
|
||||
<input type="hidden" name="pc_membership_create_pages" value="1">
|
||||
<?php submit_button( __( 'Create All Pages', 'pc-membership-abc123' ), 'secondary' ); ?>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
if ( isset( $_POST['pc_membership_create_pages'] ) && check_admin_referer( 'pc_membership_create_pages', 'pc_membership_create_pages_nonce' ) ) {
|
||||
self::create_default_pages();
|
||||
}
|
||||
}
|
||||
|
||||
private static function create_default_pages() {
|
||||
$pages = array(
|
||||
'checkout' => array( 'title' => __( 'Membership Checkout', 'pc-membership-abc123' ), 'content' => '[pc_membership_checkout]' ),
|
||||
'login' => array( 'title' => __( 'Member Login', 'pc-membership-abc123' ), 'content' => '[pc_membership_login]' ),
|
||||
'register' => array( 'title' => __( 'Member Registration', 'pc-membership-abc123' ), 'content' => '[pc_membership_register]' ),
|
||||
'account' => array( 'title' => __( 'My Account', 'pc-membership-abc123' ), 'content' => '[pc_membership_account]' ),
|
||||
'success' => array( 'title' => __( 'Payment Successful', 'pc-membership-abc123' ), 'content' => '[pc_membership_success]' ),
|
||||
'cancel' => array( 'title' => __( 'Payment Cancelled', 'pc-membership-abc123' ), 'content' => '[pc_membership_cancel]' ),
|
||||
);
|
||||
|
||||
$options = get_option( 'pc_membership_options', array() );
|
||||
foreach ( $pages as $key => $page_data ) {
|
||||
$existing_id = isset( $options[ $key . '_page_id' ] ) ? absint( $options[ $key . '_page_id' ] ) : 0;
|
||||
if ( ! $existing_id || ! get_post( $existing_id ) ) {
|
||||
$page_id = wp_insert_post( array( 'post_title' => $page_data['title'], 'post_content' => $page_data['content'], 'post_status' => 'publish', 'post_type' => 'page' ) );
|
||||
if ( $page_id && ! is_wp_error( $page_id ) ) {
|
||||
$options[ $key . '_page_id' ] = $page_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
update_option( 'pc_membership_options', $options );
|
||||
echo '<div class="notice notice-success"><p>' . esc_html__( 'Membership pages created successfully!', 'pc-membership-abc123' ) . '</p></div>';
|
||||
}
|
||||
|
||||
public static function access_page() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_die( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$plans = $wpdb->get_results( "SELECT id, name FROM {$wpdb->prefix}pc_membership_plans" );
|
||||
$rules = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}pc_membership_access_rules ORDER BY id DESC" );
|
||||
?>
|
||||
<div class="wrap pc-membership-admin-wrap">
|
||||
<h1><?php esc_html_e( 'Access Rules', 'pc-membership-abc123' ); ?></h1>
|
||||
<div class="pc-membership-access-rules">
|
||||
<h2><?php esc_html_e( 'Add New Rule', 'pc-membership-abc123' ); ?></h2>
|
||||
<form id="pc-membership-access-form" class="pc-membership-access-form">
|
||||
<?php wp_nonce_field( 'pc_membership_save_access_rule', 'pc_membership_access_nonce' ); ?>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="access_content_type"><?php esc_html_e( 'Content Type', 'pc-membership-abc123' ); ?></label>
|
||||
<select name="content_type" id="access_content_type" required>
|
||||
<option value="page"><?php esc_html_e( 'Page', 'pc-membership-abc123' ); ?></option>
|
||||
<option value="post"><?php esc_html_e( 'Post', 'pc-membership-abc123' ); ?></option>
|
||||
<option value="category"><?php esc_html_e( 'Category', 'pc-membership-abc123' ); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="access_content_id"><?php esc_html_e( 'Select Content', 'pc-membership-abc123' ); ?></label>
|
||||
<select name="content_id" id="access_content_id" required>
|
||||
<option value=""><?php esc_html_e( '-- Select --', 'pc-membership-abc123' ); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="access_plan_ids"><?php esc_html_e( 'Required Plans', 'pc-membership-abc123' ); ?></label>
|
||||
<select name="plan_ids[]" id="access_plan_ids" multiple required>
|
||||
<?php foreach ( $plans as $plan ) : ?>
|
||||
<option value="<?php echo esc_attr( $plan->id ); ?>"><?php echo esc_html( $plan->name ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pc-membership-form-row">
|
||||
<label for="access_redirect"><?php esc_html_e( 'Redirect Non-Members To', 'pc-membership-abc123' ); ?></label>
|
||||
<select name="redirect" id="access_redirect">
|
||||
<option value="checkout"><?php esc_html_e( 'Checkout Page', 'pc-membership-abc123' ); ?></option>
|
||||
<option value="login"><?php esc_html_e( 'Login Page', 'pc-membership-abc123' ); ?></option>
|
||||
<option value="custom"><?php esc_html_e( 'Custom URL', 'pc-membership-abc123' ); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="pc-membership-form-row" id="custom_redirect_row" style="display: none;">
|
||||
<label for="access_custom_url"><?php esc_html_e( 'Custom URL', 'pc-membership-abc123' ); ?></label>
|
||||
<input type="url" name="custom_url" id="access_custom_url" class="regular-text" placeholder="https://...">
|
||||
</div>
|
||||
<div class="pc-membership-form-actions">
|
||||
<button type="submit" class="button button-primary"><?php esc_html_e( 'Add Rule', 'pc-membership-abc123' ); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
<h2><?php esc_html_e( 'Existing Rules', 'pc-membership-abc123' ); ?></h2>
|
||||
<table class="widefat fixed striped pc-membership-table" id="pc-access-rules-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Content', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Required Plans', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Redirect', 'pc-membership-abc123' ); ?></th>
|
||||
<th><?php esc_html_e( 'Actions', 'pc-membership-abc123' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ( empty( $rules ) ) : ?>
|
||||
<tr><td colspan="4"><?php esc_html_e( 'No access rules defined yet.', 'pc-membership-abc123' ); ?></td></tr>
|
||||
<?php else : ?>
|
||||
<?php foreach ( $rules as $rule ) :
|
||||
$content_title = '';
|
||||
if ( $rule->content_type === 'category' ) {
|
||||
$cat = get_term( $rule->content_id );
|
||||
$content_title = $cat ? $cat->name : sprintf( __( 'Category #%d', 'pc-membership-abc123' ), $rule->content_id );
|
||||
} else {
|
||||
$post = get_post( $rule->content_id );
|
||||
$content_title = $post ? $post->post_title : sprintf( __( '%s #%d', 'pc-membership-abc123' ), $rule->content_type, $rule->content_id );
|
||||
}
|
||||
$plan_ids = maybe_unserialize( $rule->plan_ids );
|
||||
if ( ! is_array( $plan_ids ) ) { $plan_ids = array( $plan_ids ); }
|
||||
$plan_names = array();
|
||||
foreach ( $plan_ids as $plan_id ) {
|
||||
$plan = $wpdb->get_var( $wpdb->prepare( "SELECT name FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $plan_id ) );
|
||||
if ( $plan ) { $plan_names[] = $plan; }
|
||||
}
|
||||
$redirect_text = $rule->redirect_type === 'custom' ? esc_html__( 'Custom URL', 'pc-membership-abc123' ) : ( $rule->redirect_type === 'checkout' ? esc_html__( 'Checkout', 'pc-membership-abc123' ) : esc_html__( 'Login', 'pc-membership-abc123' ) );
|
||||
?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( $content_title ) . ' <span class="description">(' . esc_html( $rule->content_type ) . ')</span>'; ?></td>
|
||||
<td><?php echo esc_html( implode( ', ', $plan_names ) ); ?></td>
|
||||
<td><?php echo $redirect_text; ?></td>
|
||||
<td><button class="button pc-membership-delete-rule" data-rule-id="<?php echo esc_attr( $rule->id ); ?>"><?php esc_html_e( 'Delete', 'pc-membership-abc123' ); ?></button></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function ajax_save_access_rule() {
|
||||
check_ajax_referer( 'pc_membership_save_access_rule', 'nonce' );
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$content_type = sanitize_text_field( wp_unslash( $_POST['content_type'] ) );
|
||||
$content_id = absint( $_POST['content_id'] );
|
||||
$plan_ids = array_map( 'absint', (array) $_POST['plan_ids'] );
|
||||
$redirect = sanitize_text_field( wp_unslash( $_POST['redirect'] ) );
|
||||
$custom_url = isset( $_POST['custom_url'] ) ? esc_url_raw( wp_unslash( $_POST['custom_url'] ) ) : '';
|
||||
|
||||
if ( ! in_array( $content_type, array( 'page', 'post', 'category' ) ) || empty( $plan_ids ) ) {
|
||||
wp_send_json_error( __( 'Invalid input', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$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, $content_id ) );
|
||||
|
||||
if ( $existing ) {
|
||||
wp_send_json_error( __( 'A rule for this content already exists.', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$result = $wpdb->insert( $wpdb->prefix . 'pc_membership_access_rules', array(
|
||||
'content_type' => $content_type,
|
||||
'content_id' => $content_id,
|
||||
'plan_ids' => maybe_serialize( $plan_ids ),
|
||||
'redirect_type' => $redirect,
|
||||
'custom_url' => $redirect === 'custom' ? $custom_url : '',
|
||||
) );
|
||||
|
||||
if ( ! $result ) {
|
||||
wp_send_json_error( __( 'Failed to save rule', 'pc-membership-abc123' ) );
|
||||
}
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
public static function ajax_delete_access_rule() {
|
||||
check_ajax_referer( 'pc_membership_save_access_rule', 'nonce' );
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$rule_id = absint( $_POST['rule_id'] );
|
||||
global $wpdb;
|
||||
$result = $wpdb->delete( $wpdb->prefix . 'pc_membership_access_rules', array( 'id' => $rule_id ) );
|
||||
|
||||
if ( ! $result ) {
|
||||
wp_send_json_error( __( 'Failed to delete rule', 'pc-membership-abc123' ) );
|
||||
}
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
public static function ajax_get_content_for_rule() {
|
||||
check_ajax_referer( 'pc_membership_admin_nonce', 'nonce' );
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$content_type = isset( $_POST['content_type'] ) ? sanitize_text_field( wp_unslash( $_POST['content_type'] ) ) : 'page';
|
||||
$items = array();
|
||||
|
||||
if ( $content_type === 'page' ) {
|
||||
$pages = get_pages( array( 'post_status' => 'publish' ) );
|
||||
foreach ( $pages as $page ) { $items[] = array( 'id' => $page->ID, 'title' => $page->post_title ); }
|
||||
} elseif ( $content_type === 'post' ) {
|
||||
$posts = get_posts( array( 'post_status' => 'publish', 'posts_per_page' => -1 ) );
|
||||
foreach ( $posts as $post ) { $items[] = array( 'id' => $post->ID, 'title' => $post->post_title ); }
|
||||
} elseif ( $content_type === 'category' ) {
|
||||
$categories = get_categories( array( 'hide_empty' => false ) );
|
||||
foreach ( $categories as $cat ) { $items[] = array( 'id' => $cat->term_id, 'title' => $cat->name ); }
|
||||
}
|
||||
|
||||
wp_send_json_success( array( 'items' => $items ) );
|
||||
}
|
||||
|
||||
public static function settings_page() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_die( __( 'Unauthorized', 'pc-membership-abc123' ) );
|
||||
}
|
||||
?>
|
||||
<div class="wrap pc-membership-admin-wrap">
|
||||
<h1><?php esc_html_e( 'Membership Settings', 'pc-membership-abc123' ); ?></h1>
|
||||
<form method="post" action="options.php">
|
||||
<?php settings_fields( 'pc_membership_options' ); do_settings_sections( 'pc-membership-settings' ); submit_button(); ?>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function enqueue_assets( $hook ) {
|
||||
if ( strpos( $hook, 'pc-membership' ) === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style( 'pc-membership-admin-style', PC_MEMBERSHIP_PLUGIN_URL . 'admin/css/admin-style.css', array(), PC_MEMBERSHIP_VERSION );
|
||||
wp_enqueue_script( 'pc-membership-admin-script', PC_MEMBERSHIP_PLUGIN_URL . 'admin/js/admin-script.js', array( 'jquery', 'jquery-ui-dialog' ), PC_MEMBERSHIP_VERSION, true );
|
||||
|
||||
wp_localize_script( 'pc-membership-admin-script', 'pcMembershipAdmin', array(
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'pc_membership_admin_nonce' ),
|
||||
'i18n' => array(
|
||||
'save' => __( 'Save', 'pc-membership-abc123' ),
|
||||
'cancel' => __( 'Cancel', 'pc-membership-abc123' ),
|
||||
'delete' => __( 'Delete', 'pc-membership-abc123' ),
|
||||
'confirmDelete' => __( 'Are you sure you want to delete this plan?', 'pc-membership-abc123' ),
|
||||
'loading' => __( 'Loading...', 'pc-membership-abc123' ),
|
||||
'success' => __( 'Saved successfully', 'pc-membership-abc123' ),
|
||||
'error' => __( 'An error occurred', 'pc-membership-abc123' ),
|
||||
),
|
||||
) );
|
||||
}
|
||||
}
|
||||
222
chat/templates/Membership/admin/css/admin-style.css
Normal file
222
chat/templates/Membership/admin/css/admin-style.css
Normal file
@@ -0,0 +1,222 @@
|
||||
.pc-membership-admin-wrap {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.pc-membership-admin-wrap h1 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-dashboard-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.pc-membership-card {
|
||||
background: #fff;
|
||||
border: 1px solid #c3c4c7;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.pc-membership-card-header {
|
||||
background: #f0f0f1;
|
||||
padding: 12px 15px;
|
||||
border-bottom: 1px solid #c3c4c7;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.pc-membership-card-header .dashicons {
|
||||
color: #2271b1;
|
||||
}
|
||||
|
||||
.pc-membership-card-header h3 {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.pc-membership-card-body {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pc-membership-stat {
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
color: #2271b1;
|
||||
}
|
||||
|
||||
.pc-membership-dashboard-section {
|
||||
margin-top: 30px;
|
||||
background: #fff;
|
||||
border: 1px solid #c3c4c7;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-table-wrapper {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.pc-membership-empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
background: #fff;
|
||||
border: 1px solid #c3c4c7;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.pc-membership-empty-state h3 {
|
||||
margin: 15px 0 10px;
|
||||
}
|
||||
|
||||
.pc-membership-empty-state p {
|
||||
color: #646970;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-page-settings {
|
||||
background: #fff;
|
||||
border: 1px solid #c3c4c7;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
max-width: 600px;
|
||||
}
|
||||
|
||||
.pc-membership-page-setting {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-page-setting label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.pc-membership-page-setting select {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.pc-membership-modal {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.pc-membership-modal-content {
|
||||
background: #fff;
|
||||
border-radius: 4px;
|
||||
width: 90%;
|
||||
max-width: 600px;
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.pc-membership-modal-header {
|
||||
padding: 15px 20px;
|
||||
border-bottom: 1px solid #c3c4c7;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #f0f0f1;
|
||||
}
|
||||
|
||||
.pc-membership-modal-header h2 {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.pc-membership-modal-close {
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 24px;
|
||||
cursor: pointer;
|
||||
color: #646970;
|
||||
padding: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.pc-membership-modal-close:hover {
|
||||
color: #23282d;
|
||||
}
|
||||
|
||||
#pc-membership-plan-form,
|
||||
.pc-membership-access-form {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-form-row {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-form-row label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.pc-membership-form-row input[type="text"],
|
||||
.pc-membership-form-row input[type="number"],
|
||||
.pc-membership-form-row input[type="url"],
|
||||
.pc-membership-form-row textarea,
|
||||
.pc-membership-form-row select {
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.pc-membership-form-actions {
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-form-actions .button {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.pc-membership-access-rules {
|
||||
background: #fff;
|
||||
border: 1px solid #c3c4c7;
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-access-rules h2 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.pc-membership-access-form {
|
||||
background: #f0f0f1;
|
||||
padding: 20px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.pc-membership-access-form .pc-membership-form-row {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.pc-membership-access-form select[multiple] {
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 782px) {
|
||||
.pc-membership-dashboard-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
251
chat/templates/Membership/admin/js/admin-script.js
Normal file
251
chat/templates/Membership/admin/js/admin-script.js
Normal file
@@ -0,0 +1,251 @@
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
var PCMembershipAdmin = {
|
||||
init: function() {
|
||||
this.bindEvents();
|
||||
this.loadStats();
|
||||
this.initPlanModal();
|
||||
this.initAccessForm();
|
||||
},
|
||||
|
||||
bindEvents: function() {
|
||||
$(document).on('click', '.pc-membership-add-plan-btn', $.proxy(this.openPlanModal, this));
|
||||
$(document).on('click', '.pc-membership-edit-plan', $.proxy(this.editPlan, this));
|
||||
$(document).on('click', '.pc-membership-delete-plan', $.proxy(this.deletePlan, this));
|
||||
$(document).on('click', '.pc-membership-modal-close, .pc-membership-modal-cancel', $.proxy(this.closePlanModal, this));
|
||||
$(document).on('submit', '#pc-membership-plan-form', $.proxy(this.savePlan, this));
|
||||
$(document).on('change', '#plan_type', $.proxy(this.toggleBillingInterval, this));
|
||||
$(document).on('click', '.pc-membership-delete-rule', $.proxy(this.deleteAccessRule, this));
|
||||
$(document).on('submit', '#pc-membership-access-form', $.proxy(this.saveAccessRule, this));
|
||||
$(document).on('change', '#access_redirect', $.proxy(this.toggleCustomRedirect, this));
|
||||
$(document).on('change', '#access_content_type', $.proxy(this.loadContentOptions, this));
|
||||
},
|
||||
|
||||
loadStats: function() {
|
||||
$.ajax({
|
||||
url: pcMembershipAdmin.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'pc_membership_get_stats',
|
||||
nonce: pcMembershipAdmin.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
var data = response.data;
|
||||
$('#pc-members-count').text(data.active_members);
|
||||
$('#pc-subscriptions-count').text(data.active_subscriptions);
|
||||
$('#pc-revenue').text(data.revenue);
|
||||
$('#pc-plans-count').text(data.total_plans);
|
||||
|
||||
if (data.recent_subscriptions && data.recent_subscriptions.length > 0) {
|
||||
var tbody = $('#pc-recent-subscriptions tbody');
|
||||
tbody.empty();
|
||||
$.each(data.recent_subscriptions, function(i, sub) {
|
||||
var display_name = sub.display_name || sub.user_login || 'User #' + sub.user_id;
|
||||
tbody.append(
|
||||
'<tr>' +
|
||||
'<td>' + display_name + '</td>' +
|
||||
'<td>' + sub.plan_name + '</td>' +
|
||||
'<td>' + sub.status + '</td>' +
|
||||
'<td>' + sub.started_at.substring(0, 10) + '</td>' +
|
||||
'</tr>'
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
initPlanModal: function() {
|
||||
$('#pc-membership-plan-modal').dialog({
|
||||
autoOpen: false,
|
||||
modal: true,
|
||||
width: '90%',
|
||||
maxWidth: 600,
|
||||
closeText: ''
|
||||
});
|
||||
},
|
||||
|
||||
openPlanModal: function(e) {
|
||||
if (e) e.preventDefault();
|
||||
$('#pc-membership-plan-form')[0].reset();
|
||||
$('#plan_id').val('');
|
||||
$('#pc-membership-plan-modal').dialog('open');
|
||||
this.toggleBillingInterval();
|
||||
},
|
||||
|
||||
editPlan: function(e) {
|
||||
e.preventDefault();
|
||||
var planId = $(e.currentTarget).data('plan-id');
|
||||
|
||||
$.ajax({
|
||||
url: pcMembershipAdmin.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'pc_membership_get_plan',
|
||||
plan_id: planId,
|
||||
nonce: pcMembershipAdmin.nonce
|
||||
},
|
||||
success: $.proxy(function(response) {
|
||||
if (response.success && response.data.plan) {
|
||||
var plan = response.data.plan;
|
||||
$('#plan_id').val(plan.id);
|
||||
$('#plan_name').val(plan.name);
|
||||
$('#plan_description').val(plan.description || '');
|
||||
$('#plan_price').val(plan.price);
|
||||
$('#plan_type').val(plan.is_subscription);
|
||||
$('#plan_billing_interval').val(plan.billing_interval || 'month');
|
||||
$('#plan_trial_days').val(plan.trial_days || 0);
|
||||
$('#plan_benefits').val(plan.benefits || '');
|
||||
$('#plan_role').val(plan.role || 'subscriber');
|
||||
$('#pc-membership-plan-modal').dialog('open');
|
||||
this.toggleBillingInterval();
|
||||
}
|
||||
}, this)
|
||||
});
|
||||
},
|
||||
|
||||
savePlan: function(e) {
|
||||
e.preventDefault();
|
||||
var $form = $('#pc-membership-plan-form');
|
||||
var formData = $form.serialize();
|
||||
|
||||
$.ajax({
|
||||
url: pcMembershipAdmin.ajax_url,
|
||||
type: 'POST',
|
||||
data: formData + '&action=pc_membership_save_plan&nonce=' + pcMembershipAdmin.nonce,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
$('#pc-membership-plan-modal').dialog('close');
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(pcMembershipAdmin.i18n.error + ': ' + (response.data || 'Unknown error'));
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert(pcMembershipAdmin.i18n.error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
deletePlan: function(e) {
|
||||
e.preventDefault();
|
||||
if (!confirm(pcMembershipAdmin.i18n.confirmDelete)) return;
|
||||
|
||||
var planId = $(e.currentTarget).data('plan-id');
|
||||
|
||||
$.ajax({
|
||||
url: pcMembershipAdmin.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'pc_membership_delete_plan',
|
||||
plan_id: planId,
|
||||
nonce: pcMembershipAdmin.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(pcMembershipAdmin.i18n.error);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
closePlanModal: function(e) {
|
||||
if (e) e.preventDefault();
|
||||
$('#pc-membership-plan-modal').dialog('close');
|
||||
},
|
||||
|
||||
toggleBillingInterval: function() {
|
||||
var isSubscription = $('#plan_type').val() === '1';
|
||||
$('#billing_interval_row').toggle(isSubscription);
|
||||
},
|
||||
|
||||
initAccessForm: function() {
|
||||
this.loadContentOptions();
|
||||
},
|
||||
|
||||
loadContentOptions: function() {
|
||||
var contentType = $('#access_content_type').val();
|
||||
var $select = $('#access_content_id');
|
||||
|
||||
$select.html('<option value="">Loading...</option>');
|
||||
|
||||
var data = {
|
||||
action: 'pc_membership_get_content_for_rule',
|
||||
content_type: contentType,
|
||||
nonce: pcMembershipAdmin.nonce
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: pcMembershipAdmin.ajax_url,
|
||||
type: 'POST',
|
||||
data: data,
|
||||
success: function(response) {
|
||||
$select.empty();
|
||||
$select.append('<option value="">-- Select --</option>');
|
||||
if (response.success && response.data.items) {
|
||||
$.each(response.data.items, function(i, item) {
|
||||
$select.append('<option value="' + item.id + '">' + item.title + '</option>');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
saveAccessRule: function(e) {
|
||||
e.preventDefault();
|
||||
var $form = $('#pc-membership-access-form');
|
||||
|
||||
$.ajax({
|
||||
url: pcMembershipAdmin.ajax_url,
|
||||
type: 'POST',
|
||||
data: $form.serialize() + '&action=pc_membership_save_access_rule&nonce=' + pcMembershipAdmin.nonce,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(pcMembershipAdmin.i18n.error + ': ' + (response.data || 'Unknown error'));
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
deleteAccessRule: function(e) {
|
||||
e.preventDefault();
|
||||
if (!confirm('Are you sure you want to delete this rule?')) return;
|
||||
|
||||
var ruleId = $(e.currentTarget).data('rule-id');
|
||||
|
||||
$.ajax({
|
||||
url: pcMembershipAdmin.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'pc_membership_delete_access_rule',
|
||||
rule_id: ruleId,
|
||||
nonce: pcMembershipAdmin.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(pcMembershipAdmin.i18n.error);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
toggleCustomRedirect: function() {
|
||||
var redirect = $('#access_redirect').val();
|
||||
$('#custom_redirect_row').toggle(redirect === 'custom');
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
PCMembershipAdmin.init();
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
225
chat/templates/Membership/includes/access-control.php
Normal file
225
chat/templates/Membership/includes/access-control.php
Normal 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,
|
||||
) );
|
||||
}
|
||||
}
|
||||
128
chat/templates/Membership/includes/activator.php
Normal file
128
chat/templates/Membership/includes/activator.php
Normal 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 );
|
||||
}
|
||||
}
|
||||
13
chat/templates/Membership/includes/deactivator.php
Normal file
13
chat/templates/Membership/includes/deactivator.php
Normal 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.
|
||||
}
|
||||
}
|
||||
?>
|
||||
191
chat/templates/Membership/includes/helpers.php
Normal file
191
chat/templates/Membership/includes/helpers.php
Normal 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;
|
||||
}
|
||||
520
chat/templates/Membership/includes/stripe-handler.php
Normal file
520
chat/templates/Membership/includes/stripe-handler.php
Normal 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();
|
||||
}
|
||||
}
|
||||
131
chat/templates/Membership/includes/user-roles.php
Normal file
131
chat/templates/Membership/includes/user-roles.php
Normal 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' );
|
||||
}
|
||||
}
|
||||
}
|
||||
96
chat/templates/Membership/pc-membership-abc123.php
Normal file
96
chat/templates/Membership/pc-membership-abc123.php
Normal file
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: PC Membership Plugin
|
||||
* Plugin URI: https://plugincompass.com/plugins/pc-membership-abc123
|
||||
* Description: Complete membership system with custom pages, Stripe payments (one-time & subscriptions), plan management, and access control.
|
||||
* Version: 1.0.0
|
||||
* Author: Plugin Compass
|
||||
* Author URI: https://plugincompass.com
|
||||
* Text Domain: pc-membership-abc123
|
||||
* Domain Path: /languages
|
||||
* Update URI: false
|
||||
* License: GPL v2 or later
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
define( 'PC_MEMBERSHIP_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
|
||||
define( 'PC_MEMBERSHIP_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
|
||||
define( 'PC_MEMBERSHIP_SLUG', 'pc-membership-abc123' );
|
||||
define( 'PC_MEMBERSHIP_VERSION', '1.0.0' );
|
||||
|
||||
spl_autoload_register( function( $class ) {
|
||||
if ( strpos( $class, 'PC_Membership_' ) !== 0 ) {
|
||||
return;
|
||||
}
|
||||
$relative_class = substr( $class, strlen( 'PC_Membership_' ) );
|
||||
$file = PC_MEMBERSHIP_PLUGIN_DIR . 'includes/' . strtolower( str_replace( '_', '-', $relative_class ) ) . '.php';
|
||||
if ( file_exists( $file ) ) {
|
||||
require_once $file;
|
||||
}
|
||||
} );
|
||||
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/activator.php';
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/deactivator.php';
|
||||
|
||||
register_activation_hook( __FILE__, array( 'PC_Membership_Activator', 'activate' ) );
|
||||
register_deactivation_hook( __FILE__, array( 'PC_Membership_Deactivator', 'deactivate' ) );
|
||||
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'admin/admin.php';
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'public/public.php';
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/access-control.php';
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/user-roles.php';
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/helpers.php';
|
||||
|
||||
function pc_membership_init() {
|
||||
load_plugin_textdomain( 'pc-membership-abc123', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
|
||||
|
||||
PC_Membership_Admin::init();
|
||||
PC_Membership_Public::init();
|
||||
PC_Membership_Access_Control::init();
|
||||
PC_Membership_User_Roles::init();
|
||||
}
|
||||
add_action( 'plugins_loaded', 'pc_membership_init' );
|
||||
|
||||
add_action( 'init', 'pc_membership_register_webhook_endpoint' );
|
||||
function pc_membership_register_webhook_endpoint() {
|
||||
add_rewrite_rule( '^pc-membership-webhook/?$', 'index.php?pc_membership_webhook=1', 'top' );
|
||||
}
|
||||
|
||||
add_filter( 'query_vars', 'pc_membership_webhook_query_vars' );
|
||||
function pc_membership_webhook_query_vars( $vars ) {
|
||||
$vars[] = 'pc_membership_webhook';
|
||||
return $vars;
|
||||
}
|
||||
|
||||
add_action( 'template_redirect', 'pc_membership_handle_webhook' );
|
||||
function pc_membership_handle_webhook() {
|
||||
if ( intval( get_query_var( 'pc_membership_webhook' ) ) === 1 ) {
|
||||
if ( ! class_exists( 'PC_Membership_Stripe' ) ) {
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/stripe-handler.php';
|
||||
}
|
||||
PC_Membership_Stripe::handle_webhook();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
register_activation_hook( __FILE__, 'pc_membership_flush_rewrites' );
|
||||
function pc_membership_flush_rewrites() {
|
||||
pc_membership_register_webhook_endpoint();
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
register_deactivation_hook( __FILE__, 'pc_membership_flush_rewrites' );
|
||||
function pc_membership_deactivation_flush() {
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
add_filter( 'site_transient_update_plugins', function( $value ) {
|
||||
$plugin_file = plugin_basename( __FILE__ );
|
||||
if ( isset( $value->response[ $plugin_file ] ) ) {
|
||||
unset( $value->response[ $plugin_file ] );
|
||||
}
|
||||
return $value;
|
||||
} );
|
||||
449
chat/templates/Membership/public/css/public-style.css
Normal file
449
chat/templates/Membership/public/css/public-style.css
Normal file
@@ -0,0 +1,449 @@
|
||||
.pc-membership-checkout-wrapper {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-pricing-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 24px;
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
.pc-membership-pricing-card {
|
||||
background: #fff;
|
||||
border: 2px solid #e5e5e5;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pc-membership-pricing-card:hover {
|
||||
border-color: #2271b1;
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.pc-membership-pricing-card.featured {
|
||||
border-color: #2271b1;
|
||||
transform: scale(1.02);
|
||||
}
|
||||
|
||||
.pc-membership-pricing-card.featured::before {
|
||||
content: 'Popular';
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
background: #2271b1;
|
||||
color: #fff;
|
||||
padding: 4px 16px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.pc-membership-pricing-header {
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.pc-membership-plan-name {
|
||||
font-size: 24px;
|
||||
margin: 0 0 15px;
|
||||
color: #23282d;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.pc-membership-plan-price {
|
||||
color: #2271b1;
|
||||
}
|
||||
|
||||
.pc-membership-price-amount {
|
||||
font-size: 42px;
|
||||
font-weight: 700;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.pc-membership-price-interval {
|
||||
font-size: 16px;
|
||||
color: #646970;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.pc-membership-trial-badge {
|
||||
display: inline-block;
|
||||
background: #46b450;
|
||||
color: #fff;
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.pc-membership-plan-description {
|
||||
color: #646970;
|
||||
margin-bottom: 20px;
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.pc-membership-plan-benefits {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0 0 24px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.pc-membership-plan-benefits li {
|
||||
padding: 10px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
color: #3c434a;
|
||||
border-bottom: 1px solid #f0f0f1;
|
||||
}
|
||||
|
||||
.pc-membership-plan-benefits li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.pc-membership-plan-benefits .dashicons {
|
||||
color: #46b450;
|
||||
font-size: 20px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.pc-membership-select-plan-btn,
|
||||
.pc-membership-checkout-btn {
|
||||
width: 100%;
|
||||
padding: 14px 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.pc-membership-checkout-form-wrapper {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 30px;
|
||||
margin-top: 30px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.pc-membership-login-wrapper,
|
||||
.pc-membership-register-wrapper,
|
||||
.pc-membership-account-wrapper {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.pc-membership-login-form-container,
|
||||
.pc-membership-register-form-container,
|
||||
.pc-membership-account-wrapper {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 40px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.pc-membership-login-form-container h2,
|
||||
.pc-membership-register-form-container h2,
|
||||
.pc-membership-account-wrapper h2,
|
||||
.pc-membership-account-wrapper h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 24px;
|
||||
color: #23282d;
|
||||
}
|
||||
|
||||
.pc-membership-form-group {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-form-group label {
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
margin-bottom: 6px;
|
||||
color: #3c434a;
|
||||
}
|
||||
|
||||
.pc-membership-form-group input[type="text"],
|
||||
.pc-membership-form-group input[type="email"],
|
||||
.pc-membership-form-group input[type="password"] {
|
||||
width: 100%;
|
||||
padding: 12px;
|
||||
border: 1px solid #c3c4c7;
|
||||
border-radius: 4px;
|
||||
font-size: 16px;
|
||||
transition: border-color 0.2s ease;
|
||||
}
|
||||
|
||||
.pc-membership-form-group input:focus {
|
||||
outline: none;
|
||||
border-color: #2271b1;
|
||||
box-shadow: 0 0 0 3px rgba(34, 113, 177, 0.1);
|
||||
}
|
||||
|
||||
.pc-membership-remember-me {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.pc-membership-remember-me input {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.pc-membership-login-btn,
|
||||
.pc-membership-register-btn {
|
||||
width: 100%;
|
||||
padding: 14px 24px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.pc-membership-login-links {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.pc-membership-login-links a {
|
||||
display: inline-block;
|
||||
margin: 0 10px;
|
||||
color: #2271b1;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.pc-membership-login-links a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.pc-membership-login-message,
|
||||
.pc-membership-register-message {
|
||||
margin-top: 15px;
|
||||
padding: 12px;
|
||||
border-radius: 4px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.pc-membership-login-message.success,
|
||||
.pc-membership-register-message.success {
|
||||
background: #dff0d8;
|
||||
border: 1px solid #d6e9c6;
|
||||
color: #3c763d;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pc-membership-login-message.error,
|
||||
.pc-membership-register-message.error {
|
||||
background: #f2dede;
|
||||
border: 1px solid #ebccd1;
|
||||
color: #a94442;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pc-membership-account-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.pc-membership-account-header h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pc-membership-subscription-details {
|
||||
background: #f0f0f1;
|
||||
border-radius: 8px;
|
||||
padding: 24px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.pc-membership-subscription-details h3 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-subscription-info {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-subscription-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 10px 0;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.pc-membership-subscription-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.pc-membership-label {
|
||||
color: #646970;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.pc-membership-value {
|
||||
font-weight: 600;
|
||||
color: #23282d;
|
||||
}
|
||||
|
||||
.pc-membership-status-active {
|
||||
color: #46b450;
|
||||
}
|
||||
|
||||
.pc-membership-status-cancelled,
|
||||
.pc-membership-status-expired,
|
||||
.pc-membership-status-past_due {
|
||||
color: #dc3232;
|
||||
}
|
||||
|
||||
.pc-membership-status-pending {
|
||||
color: #f56e28;
|
||||
}
|
||||
|
||||
.pc-membership-subscription-actions {
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.pc-membership-no-subscription {
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
background: #f0f0f1;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.pc-membership-no-subscription p {
|
||||
margin-bottom: 20px;
|
||||
color: #646970;
|
||||
}
|
||||
|
||||
.pc-membership-account-section {
|
||||
margin-top: 30px;
|
||||
padding-top: 30px;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.pc-membership-account-section h3 {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-success-wrapper,
|
||||
.pc-membership-cancel-wrapper {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 60px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pc-membership-success-message,
|
||||
.pc-membership-cancel-message {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 50px 40px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.pc-membership-success-icon,
|
||||
.pc-membership-cancel-icon {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.pc-membership-success-message h2,
|
||||
.pc-membership-cancel-message h2 {
|
||||
margin: 0 0 15px;
|
||||
color: #23282d;
|
||||
}
|
||||
|
||||
.pc-membership-success-message p,
|
||||
.pc-membership-cancel-message p {
|
||||
color: #646970;
|
||||
margin-bottom: 30px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.pc-membership-message {
|
||||
padding: 15px 20px;
|
||||
border-radius: 4px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.pc-membership-message-info {
|
||||
background: #d9edf7;
|
||||
border: 1px solid #bce8f1;
|
||||
color: #31708f;
|
||||
}
|
||||
|
||||
.pc-membership-message-success {
|
||||
background: #dff0d8;
|
||||
border: 1px solid #d6e9c6;
|
||||
color: #3c763d;
|
||||
}
|
||||
|
||||
.pc-membership-message-error {
|
||||
background: #f2dede;
|
||||
border: 1px solid #ebccd1;
|
||||
color: #a94442;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
.pc-membership-pricing-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.pc-membership-pricing-card.featured {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.pc-membership-login-form-container,
|
||||
.pc-membership-register-form-container,
|
||||
.pc-membership-account-wrapper {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.pc-membership-account-header {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pc-membership-subscription-row {
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.pc-membership-pricing-card,
|
||||
.pc-membership-select-plan-btn,
|
||||
.pc-membership-pricing-card:hover {
|
||||
transition: none;
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-contrast: high) {
|
||||
.pc-membership-pricing-card {
|
||||
border-width: 3px;
|
||||
}
|
||||
|
||||
.pc-membership-plan-benefits .dashicons {
|
||||
color: #006600;
|
||||
}
|
||||
}
|
||||
207
chat/templates/Membership/public/js/public-script.js
Normal file
207
chat/templates/Membership/public/js/public-script.js
Normal file
@@ -0,0 +1,207 @@
|
||||
(function($) {
|
||||
'use strict';
|
||||
|
||||
var PCMembership = {
|
||||
stripe: null,
|
||||
|
||||
init: function() {
|
||||
this.bindEvents();
|
||||
this.initStripe();
|
||||
},
|
||||
|
||||
bindEvents: function() {
|
||||
$(document).on('click', '.pc-membership-select-plan-btn', $.proxy(this.selectPlan, this));
|
||||
$(document).on('submit', '#pc-membership-login-form', $.proxy(this.handleLogin, this));
|
||||
$(document).on('submit', '#pc-membership-register-form', $.proxy(this.handleRegister, this));
|
||||
$(document).on('submit', '#pc-membership-profile-form', $.proxy(this.handleProfileUpdate, this));
|
||||
$(document).on('click', '#pc-membership-cancel-subscription', $.proxy(this.cancelSubscription, this));
|
||||
$(document).on('click', '#pc-membership-update-payment-method', $.proxy(this.updatePaymentMethod, this));
|
||||
},
|
||||
|
||||
initStripe: function() {
|
||||
if (typeof Stripe !== 'undefined' && pcMembership.stripe_key) {
|
||||
this.stripe = Stripe(pcMembership.stripe_key);
|
||||
}
|
||||
},
|
||||
|
||||
selectPlan: function(e) {
|
||||
e.preventDefault();
|
||||
var planId = $(e.currentTarget).data('plan-id');
|
||||
|
||||
if (!planId) {
|
||||
alert(pcMembership.i18n.selectPlan);
|
||||
return;
|
||||
}
|
||||
|
||||
var $button = $(e.currentTarget);
|
||||
var originalText = $button.text();
|
||||
$button.text(pcMembership.i18n.processing).prop('disabled', true);
|
||||
|
||||
$.ajax({
|
||||
url: pcMembership.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'pc_membership_create_checkout',
|
||||
plan_id: planId,
|
||||
nonce: pcMembership.nonce
|
||||
},
|
||||
success: $.proxy(function(response) {
|
||||
if (response.success && response.data.url) {
|
||||
window.location.href = response.data.url;
|
||||
} else {
|
||||
alert(pcMembership.i18n.error + ': ' + (response.data || 'Unknown error'));
|
||||
$button.text(originalText).prop('disabled', false);
|
||||
}
|
||||
}, this),
|
||||
error: $.proxy(function() {
|
||||
alert(pcMembership.i18n.error);
|
||||
$button.text(originalText).prop('disabled', false);
|
||||
}, this)
|
||||
});
|
||||
},
|
||||
|
||||
handleLogin: function(e) {
|
||||
e.preventDefault();
|
||||
var $form = $('#pc-membership-login-form');
|
||||
var $message = $('#pc-membership-login-message');
|
||||
var formData = $form.serialize();
|
||||
|
||||
$message.removeClass('success error').hide();
|
||||
|
||||
$.ajax({
|
||||
url: pcMembership.ajax_url,
|
||||
type: 'POST',
|
||||
data: formData + '&action=pc_membership_login&nonce=' + pcMembership.nonce,
|
||||
success: $.proxy(function(response) {
|
||||
if (response.success) {
|
||||
$message.addClass('success').text(pcMembership.i18n.success).show();
|
||||
setTimeout(function() {
|
||||
window.location.href = response.data.redirect || pcMembership.account_url;
|
||||
}, 1000);
|
||||
} else {
|
||||
$message.addClass('error').text(response.data || pcMembership.i18n.error).show();
|
||||
}
|
||||
}, this),
|
||||
error: function() {
|
||||
$message.addClass('error').text(pcMembership.i18n.error).show();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleRegister: function(e) {
|
||||
e.preventDefault();
|
||||
var $form = $('#pc-membership-register-form');
|
||||
var $message = $('#pc-membership-register-message');
|
||||
var formData = $form.serialize();
|
||||
|
||||
var password = $('#user_password').val();
|
||||
var passwordConfirm = $('#user_password_confirm').val();
|
||||
|
||||
if (password !== passwordConfirm) {
|
||||
$message.addClass('error').text('Passwords do not match').show();
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.length < 8) {
|
||||
$message.addClass('error').text('Password must be at least 8 characters').show();
|
||||
return;
|
||||
}
|
||||
|
||||
$message.removeClass('success error').hide();
|
||||
|
||||
$.ajax({
|
||||
url: pcMembership.ajax_url,
|
||||
type: 'POST',
|
||||
data: formData + '&action=pc_membership_register&nonce=' + pcMembership.nonce,
|
||||
success: $.proxy(function(response) {
|
||||
if (response.success) {
|
||||
$message.addClass('success').text(pcMembership.i18n.success).show();
|
||||
setTimeout(function() {
|
||||
window.location.href = response.data.redirect || pcMembership.account_url;
|
||||
}, 1000);
|
||||
} else {
|
||||
$message.addClass('error').text(response.data || pcMembership.i18n.error).show();
|
||||
}
|
||||
}, this),
|
||||
error: function() {
|
||||
$message.addClass('error').text(pcMembership.i18n.error).show();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
handleProfileUpdate: function(e) {
|
||||
e.preventDefault();
|
||||
var $form = $('#pc-membership-profile-form');
|
||||
|
||||
$.ajax({
|
||||
url: pcMembership.ajax_url,
|
||||
type: 'POST',
|
||||
data: $form.serialize() + '&action=pc_membership_update_profile&nonce=' + pcMembership.nonce,
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
alert('Profile updated successfully');
|
||||
} else {
|
||||
alert(response.data || 'Error updating profile');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
cancelSubscription: function(e) {
|
||||
e.preventDefault();
|
||||
if (!confirm(pcMembership.i18n.confirmCancel)) return;
|
||||
|
||||
var subscriptionId = $(e.currentTarget).data('subscription-id');
|
||||
var $button = $(e.currentTarget);
|
||||
|
||||
$button.text(pcMembership.i18n.processing).prop('disabled', true);
|
||||
|
||||
$.ajax({
|
||||
url: pcMembership.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'pc_membership_cancel_subscription',
|
||||
subscription_id: subscriptionId,
|
||||
nonce: pcMembership.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert(pcMembership.i18n.error);
|
||||
$button.text(pcMembership.i18n.cancel).prop('disabled', false);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert(pcMembership.i18n.error);
|
||||
$button.text(pcMembership.i18n.cancel).prop('disabled', false);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
updatePaymentMethod: function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
url: pcMembership.ajax_url,
|
||||
type: 'POST',
|
||||
data: {
|
||||
action: 'pc_membership_update_payment_method',
|
||||
nonce: pcMembership.nonce
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success && response.data.url) {
|
||||
window.location.href = response.data.url;
|
||||
} else {
|
||||
alert(pcMembership.i18n.error);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
PCMembership.init();
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
656
chat/templates/Membership/public/public.php
Normal file
656
chat/templates/Membership/public/public.php
Normal file
@@ -0,0 +1,656 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class PC_Membership_Public {
|
||||
|
||||
public static function init() {
|
||||
add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_assets' ) );
|
||||
|
||||
add_shortcode( 'pc_membership_checkout', array( __CLASS__, 'checkout_shortcode' ) );
|
||||
add_shortcode( 'pc_membership_login', array( __CLASS__, 'login_shortcode' ) );
|
||||
add_shortcode( 'pc_membership_register', array( __CLASS__, 'register_shortcode' ) );
|
||||
add_shortcode( 'pc_membership_account', array( __CLASS__, 'account_shortcode' ) );
|
||||
add_shortcode( 'pc_membership_success', array( __CLASS__, 'success_shortcode' ) );
|
||||
add_shortcode( 'pc_membership_cancel', array( __CLASS__, 'cancel_shortcode' ) );
|
||||
add_shortcode( 'pc_membership_pricing', array( __CLASS__, 'pricing_shortcode' ) );
|
||||
|
||||
add_action( 'wp_ajax_pc_membership_create_checkout', array( __CLASS__, 'ajax_create_checkout' ) );
|
||||
add_action( 'wp_ajax_nopriv_pc_membership_create_checkout', array( __CLASS__, 'ajax_create_checkout' ) );
|
||||
|
||||
add_action( 'wp_ajax_pc_membership_cancel_subscription', array( __CLASS__, 'ajax_cancel_subscription' ) );
|
||||
add_action( 'wp_ajax_nopriv_pc_membership_cancel_subscription', array( __CLASS__, 'ajax_cancel_subscription' ) );
|
||||
|
||||
add_action( 'wp_ajax_pc_membership_update_payment_method', array( __CLASS__, 'ajax_update_payment_method' ) );
|
||||
add_action( 'wp_ajax_nopriv_pc_membership_update_payment_method', array( __CLASS__, 'ajax_update_payment_method' ) );
|
||||
|
||||
add_action( 'wp_ajax_pc_membership_login', array( __CLASS__, 'ajax_login' ) );
|
||||
add_action( 'wp_ajax_nopriv_pc_membership_login', array( __CLASS__, 'ajax_login' ) );
|
||||
|
||||
add_action( 'wp_ajax_pc_membership_register', array( __CLASS__, 'ajax_register' ) );
|
||||
add_action( 'wp_ajax_nopriv_pc_membership_register', array( __CLASS__, 'ajax_register' ) );
|
||||
|
||||
add_action( 'wp_ajax_pc_membership_update_profile', array( __CLASS__, 'ajax_update_profile' ) );
|
||||
|
||||
add_action( 'template_redirect', array( __CLASS__, 'handle_stripe_return' ) );
|
||||
}
|
||||
|
||||
public static function enqueue_assets() {
|
||||
if ( ! self::is_membership_page() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style( 'pc-membership-public-style', PC_MEMBERSHIP_PLUGIN_URL . 'public/css/public-style.css', array(), PC_MEMBERSHIP_VERSION );
|
||||
wp_enqueue_script( 'pc-membership-stripe-js', 'https://js.stripe.com/v3/', array(), null, true );
|
||||
wp_enqueue_script( 'pc-membership-public-script', PC_MEMBERSHIP_PLUGIN_URL . 'public/js/public-script.js', array( 'jquery', 'pc-membership-stripe-js' ), PC_MEMBERSHIP_VERSION, true );
|
||||
|
||||
$options = get_option( 'pc_membership_options' );
|
||||
$publishable_key = '';
|
||||
|
||||
if ( ! empty( $options ) ) {
|
||||
$mode = isset( $options['mode'] ) ? $options['mode'] : 'test';
|
||||
$publishable_key = isset( $options[ $mode . '_publishable_key' ] ) ? $options[ $mode . '_publishable_key' ] : '';
|
||||
}
|
||||
|
||||
wp_localize_script( 'pc-membership-public-script', 'pcMembership', array(
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'pc_membership_nonce' ),
|
||||
'stripe_key' => $publishable_key,
|
||||
'i18n' => array(
|
||||
'processing' => __( 'Processing...', 'pc-membership-abc123' ),
|
||||
'selectPlan' => __( 'Please select a plan', 'pc-membership-abc123' ),
|
||||
'error' => __( 'An error occurred. Please try again.', 'pc-membership-abc123' ),
|
||||
'success' => __( 'Success!', 'pc-membership-abc123' ),
|
||||
'cancel' => __( 'Cancel Subscription', 'pc-membership-abc123' ),
|
||||
'confirmCancel'=> __( 'Are you sure you want to cancel your subscription?', 'pc-membership-abc123' ),
|
||||
),
|
||||
) );
|
||||
}
|
||||
|
||||
private static function is_membership_page() {
|
||||
if ( ! is_singular() && ! is_page() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$options = get_option( 'pc_membership_options', array() );
|
||||
$page_ids = array(
|
||||
isset( $options['checkout_page_id'] ) ? $options['checkout_page_id'] : 0,
|
||||
isset( $options['login_page_id'] ) ? $options['login_page_id'] : 0,
|
||||
isset( $options['register_page_id'] ) ? $options['register_page_id'] : 0,
|
||||
isset( $options['account_page_id'] ) ? $options['account_page_id'] : 0,
|
||||
isset( $options['success_page_id'] ) ? $options['success_page_id'] : 0,
|
||||
isset( $options['cancel_page_id'] ) ? $options['cancel_page_id'] : 0,
|
||||
);
|
||||
|
||||
return in_array( get_the_ID(), array_filter( $page_ids ) );
|
||||
}
|
||||
|
||||
public static function checkout_shortcode( $atts ) {
|
||||
ob_start();
|
||||
self::render_checkout_page();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public static function render_checkout_page() {
|
||||
global $wpdb;
|
||||
|
||||
$plans = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}pc_membership_plans ORDER BY price ASC" );
|
||||
|
||||
if ( empty( $plans ) ) {
|
||||
echo '<div class="pc-membership-message pc-membership-message-info">';
|
||||
esc_html_e( 'No membership plans available at this time.', 'pc-membership-abc123' );
|
||||
echo '</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
$options = get_option( 'pc_membership_options' );
|
||||
$mode = isset( $options['mode'] ) ? $options['mode'] : 'test';
|
||||
|
||||
echo '<div class="pc-membership-checkout-wrapper">';
|
||||
echo '<div class="pc-membership-pricing-cards">';
|
||||
|
||||
foreach ( $plans as $plan ) {
|
||||
$benefits = array_filter( array_map( 'trim', explode( "\n", $plan->benefits ) ) );
|
||||
$billing_label = $plan->is_subscription
|
||||
? sprintf( '%s / %s', pc_membership_format_price( $plan->price ), $plan->billing_interval )
|
||||
: pc_membership_format_price( $plan->price );
|
||||
|
||||
echo '<div class="pc-membership-pricing-card" data-plan-id="' . esc_attr( $plan->id ) . '">';
|
||||
echo '<div class="pc-membership-pricing-header">';
|
||||
echo '<h3 class="pc-membership-plan-name">' . esc_html( $plan->name ) . '</h3>';
|
||||
echo '<div class="pc-membership-plan-price">';
|
||||
echo '<span class="pc-membership-price-amount">' . esc_html( pc_membership_format_price( $plan->price ) ) . '</span>';
|
||||
if ( $plan->is_subscription ) {
|
||||
echo '<span class="pc-membership-price-interval"> / ' . esc_html( $plan->billing_interval ) . '</span>';
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
if ( $plan->trial_days > 0 ) {
|
||||
echo '<div class="pc-membership-trial-badge">';
|
||||
printf( esc_html__( '%d Day Free Trial', 'pc-membership-abc123' ), $plan->trial_days );
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
if ( $plan->description ) {
|
||||
echo '<div class="pc-membership-plan-description">' . wp_kses_post( $plan->description ) . '</div>';
|
||||
}
|
||||
|
||||
if ( ! empty( $benefits ) ) {
|
||||
echo '<ul class="pc-membership-plan-benefits">';
|
||||
foreach ( $benefits as $benefit ) {
|
||||
echo '<li><span class="dashicons dashicons-yes-alt"></span>' . esc_html( $benefit ) . '</li>';
|
||||
}
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
echo '<button class="pc-membership-select-plan-btn button button-primary" data-plan-id="' . esc_attr( $plan->id ) . '">';
|
||||
esc_html_e( 'Select Plan', 'pc-membership-abc123' );
|
||||
echo '</button>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
echo '<div class="pc-membership-checkout-form-wrapper" style="display: none;">';
|
||||
echo '<div id="pc-membership-checkout-form-container"></div>';
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
public static function login_shortcode( $atts ) {
|
||||
if ( is_user_logged_in() ) {
|
||||
$account_page = self::get_page_url( 'account' );
|
||||
if ( $account_page ) {
|
||||
wp_redirect( $account_page );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
ob_start();
|
||||
self::render_login_form();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public static function render_login_form() {
|
||||
$options = get_option( 'pc_membership_options' );
|
||||
$register_page = isset( $options['register_page_id'] ) ? get_permalink( $options['register_page_id'] ) : false;
|
||||
$account_page = self::get_page_url( 'account' );
|
||||
?>
|
||||
<div class="pc-membership-login-wrapper">
|
||||
<div class="pc-membership-login-form-container">
|
||||
<h2><?php esc_html_e( 'Member Login', 'pc-membership-abc123' ); ?></h2>
|
||||
|
||||
<form id="pc-membership-login-form" method="post">
|
||||
<?php wp_nonce_field( 'pc_membership_login', 'pc_membership_login_nonce' ); ?>
|
||||
|
||||
<div class="pc-membership-form-group">
|
||||
<label for="user_login"><?php esc_html_e( 'Username or Email', 'pc-membership-abc123' ); ?></label>
|
||||
<input type="text" name="user_login" id="user_login" required class="regular-text">
|
||||
</div>
|
||||
|
||||
<div class="pc-membership-form-group">
|
||||
<label for="user_password"><?php esc_html_e( 'Password', 'pc-membership-abc123' ); ?></label>
|
||||
<input type="password" name="user_password" id="user_password" required class="regular-text">
|
||||
</div>
|
||||
|
||||
<div class="pc-membership-form-group">
|
||||
<label class="pc-membership-remember-me">
|
||||
<input type="checkbox" name="rememberme" value="forever">
|
||||
<?php esc_html_e( 'Remember me', 'pc-membership-abc123' ); ?>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="button button-primary pc-membership-login-btn">
|
||||
<?php esc_html_e( 'Log In', 'pc-membership-abc123' ); ?>
|
||||
</button>
|
||||
|
||||
<div class="pc-membership-login-links">
|
||||
<?php if ( $register_page ) : ?>
|
||||
<a href="<?php echo esc_url( $register_page ); ?>">
|
||||
<?php esc_html_e( 'Create an account', 'pc-membership-abc123' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<a href="<?php echo esc_url( wp_lostpassword_url() ); ?>">
|
||||
<?php esc_html_e( 'Forgot password?', 'pc-membership-abc123' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div id="pc-membership-login-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function register_shortcode( $atts ) {
|
||||
if ( is_user_logged_in() ) {
|
||||
$account_page = self::get_page_url( 'account' );
|
||||
if ( $account_page ) {
|
||||
wp_redirect( $account_page );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
ob_start();
|
||||
self::render_registration_form();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public static function render_registration_form() {
|
||||
$options = get_option( 'pc_membership_options' );
|
||||
$login_page = isset( $options['login_page_id'] ) ? get_permalink( $options['login_page_id'] ) : false;
|
||||
?>
|
||||
<div class="pc-membership-register-wrapper">
|
||||
<div class="pc-membership-register-form-container">
|
||||
<h2><?php esc_html_e( 'Create Account', 'pc-membership-abc123' ); ?></h2>
|
||||
|
||||
<form id="pc-membership-register-form" method="post">
|
||||
<?php wp_nonce_field( 'pc_membership_register', 'pc_membership_register_nonce' ); ?>
|
||||
|
||||
<div class="pc-membership-form-group">
|
||||
<label for="user_login"><?php esc_html_e( 'Username', 'pc-membership-abc123' ); ?> *</label>
|
||||
<input type="text" name="user_login" id="user_login" required class="regular-text" minlength="4">
|
||||
</div>
|
||||
|
||||
<div class="pc-membership-form-group">
|
||||
<label for="user_email"><?php esc_html_e( 'Email', 'pc-membership-abc123' ); ?> *</label>
|
||||
<input type="email" name="user_email" id="user_email" required class="regular-text">
|
||||
</div>
|
||||
|
||||
<div class="pc-membership-form-group">
|
||||
<label for="user_password"><?php esc_html_e( 'Password', 'pc-membership-abc123' ); ?> *</label>
|
||||
<input type="password" name="user_password" id="user_password" required class="regular-text" minlength="8">
|
||||
</div>
|
||||
|
||||
<div class="pc-membership-form-group">
|
||||
<label for="user_password_confirm"><?php esc_html_e( 'Confirm Password', 'pc-membership-abc123' ); ?> *</label>
|
||||
<input type="password" name="user_password_confirm" id="user_password_confirm" required class="regular-text">
|
||||
</div>
|
||||
|
||||
<button type="submit" class="button button-primary pc-membership-register-btn">
|
||||
<?php esc_html_e( 'Create Account', 'pc-membership-abc123' ); ?>
|
||||
</button>
|
||||
|
||||
<div class="pc-membership-login-links">
|
||||
<?php if ( $login_page ) : ?>
|
||||
<a href="<?php echo esc_url( $login_page ); ?>">
|
||||
<?php esc_html_e( 'Already have an account? Log in', 'pc-membership-abc123' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div id="pc-membership-register-message"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function account_shortcode( $atts ) {
|
||||
if ( ! is_user_logged_in() ) {
|
||||
$login_page = self::get_page_url( 'login' );
|
||||
if ( $login_page ) {
|
||||
wp_redirect( $login_page );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
ob_start();
|
||||
self::render_account_page();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public static function render_account_page() {
|
||||
$user = wp_get_current_user();
|
||||
$subscription = self::get_user_subscription( $user->ID );
|
||||
?>
|
||||
<div class="pc-membership-account-wrapper">
|
||||
<div class="pc-membership-account-header">
|
||||
<h2><?php printf( esc_html__( 'Welcome, %s', 'pc-membership-abc123' ), esc_html( $user->display_name ) ); ?></h2>
|
||||
<a href="<?php echo esc_url( wp_logout_url( self::get_page_url( 'login' ) ) ); ?>" class="button">
|
||||
<?php esc_html_e( 'Log Out', 'pc-membership-abc123' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<?php if ( $subscription ) : ?>
|
||||
<?php
|
||||
global $wpdb;
|
||||
$plan = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pc_membership_plans WHERE id = %d", $subscription->plan_id ) );
|
||||
?>
|
||||
|
||||
<div class="pc-membership-subscription-details">
|
||||
<h3><?php esc_html_e( 'Your Subscription', 'pc-membership-abc123' ); ?></h3>
|
||||
|
||||
<div class="pc-membership-subscription-info">
|
||||
<div class="pc-membership-subscription-row">
|
||||
<span class="pc-membership-label"><?php esc_html_e( 'Plan', 'pc-membership-abc123' ); ?>:</span>
|
||||
<span class="pc-membership-value"><?php echo $plan ? esc_html( $plan->name ) : esc_html__( 'Unknown', 'pc-membership-abc123' ); ?></span>
|
||||
</div>
|
||||
|
||||
<div class="pc-membership-subscription-row">
|
||||
<span class="pc-membership-label"><?php esc_html_e( 'Status', 'pc-membership-abc123' ); ?>:</span>
|
||||
<span class="pc-membership-value pc-membership-status-<?php echo esc_attr( $subscription->status ); ?>">
|
||||
<?php echo esc_html( ucfirst( $subscription->status ) ); ?>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="pc-membership-subscription-row">
|
||||
<span class="pc-membership-label"><?php esc_html_e( 'Started', 'pc-membership-abc123' ); ?>:</span>
|
||||
<span class="pc-membership-value"><?php echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $subscription->started_at ) ) ); ?></span>
|
||||
</div>
|
||||
|
||||
<?php if ( $subscription->expires_at ) : ?>
|
||||
<div class="pc-membership-subscription-row">
|
||||
<span class="pc-membership-label"><?php esc_html_e( 'Expires', 'pc-membership-abc123' ); ?>:</span>
|
||||
<span class="pc-membership-value"><?php echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $subscription->expires_at ) ) ); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( $subscription->status === 'active' && $plan && $plan->is_subscription ) : ?>
|
||||
<div class="pc-membership-subscription-actions">
|
||||
<button type="button" id="pc-membership-cancel-subscription" class="button button-secondary" data-subscription-id="<?php echo esc_attr( $subscription->id ); ?>">
|
||||
<?php esc_html_e( 'Cancel Subscription', 'pc-membership-abc123' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else : ?>
|
||||
<div class="pc-membership-no-subscription">
|
||||
<p><?php esc_html_e( 'You don\'t have an active membership subscription.', 'pc-membership-abc123' ); ?></p>
|
||||
<a href="<?php echo esc_url( self::get_page_url( 'checkout' ) ); ?>" class="button button-primary">
|
||||
<?php esc_html_e( 'Choose a Plan', 'pc-membership-abc123' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="pc-membership-account-section">
|
||||
<h3><?php esc_html_e( 'Profile Information', 'pc-membership-abc123' ); ?></h3>
|
||||
<form id="pc-membership-profile-form" method="post">
|
||||
<?php wp_nonce_field( 'pc_membership_update_profile', 'pc_membership_profile_nonce' ); ?>
|
||||
|
||||
<div class="pc-membership-form-group">
|
||||
<label for="display_name"><?php esc_html_e( 'Display Name', 'pc-membership-abc123' ); ?></label>
|
||||
<input type="text" name="display_name" id="display_name" value="<?php echo esc_attr( $user->display_name ); ?>" class="regular-text">
|
||||
</div>
|
||||
|
||||
<div class="pc-membership-form-group">
|
||||
<label for="user_email"><?php esc_html_e( 'Email', 'pc-membership-abc123' ); ?></label>
|
||||
<input type="email" name="user_email" id="user_email" value="<?php echo esc_attr( $user->user_email ); ?>" class="regular-text" readonly>
|
||||
<p class="description"><?php esc_html_e( 'Email cannot be changed.', 'pc-membership-abc123' ); ?></p>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="button button-primary">
|
||||
<?php esc_html_e( 'Update Profile', 'pc-membership-abc123' ); ?>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public static function success_shortcode( $atts ) {
|
||||
ob_start();
|
||||
?>
|
||||
<div class="pc-membership-success-wrapper">
|
||||
<div class="pc-membership-success-message">
|
||||
<div class="pc-membership-success-icon">
|
||||
<span class="dashicons dashicons-yes-alt" style="font-size: 64px; height: 64px; width: 64px; color: #46b450;"></span>
|
||||
</div>
|
||||
<h2><?php esc_html_e( 'Payment Successful!', 'pc-membership-abc123' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Thank you for your purchase. Your membership is now active.', 'pc-membership-abc123' ); ?></p>
|
||||
<a href="<?php echo esc_url( self::get_page_url( 'account' ) ); ?>" class="button button-primary">
|
||||
<?php esc_html_e( 'Go to My Account', 'pc-membership-abc123' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public static function cancel_shortcode( $atts ) {
|
||||
ob_start();
|
||||
?>
|
||||
<div class="pc-membership-cancel-wrapper">
|
||||
<div class="pc-membership-cancel-message">
|
||||
<div class="pc-membership-cancel-icon">
|
||||
<span class="dashicons dashicons-dismiss" style="font-size: 64px; height: 64px; width: 64px; color: #dc3232;"></span>
|
||||
</div>
|
||||
<h2><?php esc_html_e( 'Payment Cancelled', 'pc-membership-abc123' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Your payment was cancelled. No charges were made.', 'pc-membership-abc123' ); ?></p>
|
||||
<a href="<?php echo esc_url( self::get_page_url( 'checkout' ) ); ?>" class="button button-primary">
|
||||
<?php esc_html_e( 'Try Again', 'pc-membership-abc123' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
public static function pricing_shortcode( $atts ) {
|
||||
ob_start();
|
||||
self::render_checkout_page();
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
private static function get_user_subscription( $user_id ) {
|
||||
global $wpdb;
|
||||
return $wpdb->get_row( $wpdb->prepare(
|
||||
"SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE user_id = %d AND status = 'active' ORDER BY id DESC LIMIT 1",
|
||||
$user_id
|
||||
) );
|
||||
}
|
||||
|
||||
public static function ajax_create_checkout() {
|
||||
check_ajax_referer( 'pc_membership_nonce', 'nonce' );
|
||||
|
||||
$plan_id = isset( $_POST['plan_id'] ) ? absint( $_POST['plan_id'] ) : 0;
|
||||
|
||||
if ( ! $plan_id ) {
|
||||
wp_send_json_error( __( 'Invalid plan', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'PC_Membership_Stripe' ) ) {
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/stripe-handler.php';
|
||||
}
|
||||
|
||||
$result = PC_Membership_Stripe::create_checkout_session( $plan_id );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
wp_send_json_error( $result->get_error_message() );
|
||||
}
|
||||
|
||||
wp_send_json_success( array( 'url' => $result->url ) );
|
||||
}
|
||||
|
||||
public static function ajax_cancel_subscription() {
|
||||
check_ajax_referer( 'pc_membership_nonce', 'nonce' );
|
||||
|
||||
if ( ! is_user_logged_in() ) {
|
||||
wp_send_json_error( __( 'Must be logged in', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$subscription_id = isset( $_POST['subscription_id'] ) ? absint( $_POST['subscription_id'] ) : 0;
|
||||
|
||||
if ( ! $subscription_id ) {
|
||||
wp_send_json_error( __( 'Invalid subscription', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$subscription = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}pc_membership_subscriptions WHERE id = %d AND user_id = %d", $subscription_id, get_current_user_id() ) );
|
||||
|
||||
if ( ! $subscription ) {
|
||||
wp_send_json_error( __( 'Subscription not found', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'PC_Membership_Stripe' ) ) {
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/stripe-handler.php';
|
||||
}
|
||||
|
||||
$result = PC_Membership_Stripe::cancel_subscription( $subscription->stripe_subscription_id );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
wp_send_json_error( $result->get_error_message() );
|
||||
}
|
||||
|
||||
$wpdb->update( $wpdb->prefix . 'pc_membership_subscriptions', array( 'status' => 'cancelled' ), array( 'id' => $subscription_id ) );
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
public static function ajax_update_payment_method() {
|
||||
check_ajax_referer( 'pc_membership_nonce', 'nonce' );
|
||||
|
||||
if ( ! is_user_logged_in() ) {
|
||||
wp_send_json_error( __( 'Must be logged in', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'PC_Membership_Stripe' ) ) {
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/stripe-handler.php';
|
||||
}
|
||||
|
||||
$result = PC_Membership_Stripe::create_portal_session();
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
wp_send_json_error( $result->get_error_message() );
|
||||
}
|
||||
|
||||
wp_send_json_success( array( 'url' => $result->url ) );
|
||||
}
|
||||
|
||||
public static function ajax_login() {
|
||||
check_ajax_referer( 'pc_membership_login', 'nonce' );
|
||||
|
||||
$user_login = isset( $_POST['user_login'] ) ? sanitize_text_field( wp_unslash( $_POST['user_login'] ) ) : '';
|
||||
$user_password = isset( $_POST['user_password'] ) ? $_POST['user_password'] : '';
|
||||
|
||||
if ( empty( $user_login ) || empty( $user_password ) ) {
|
||||
wp_send_json_error( __( 'Please enter username and password', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$user = wp_authenticate_username_password( null, $user_login, $user_password );
|
||||
|
||||
if ( is_wp_error( $user ) ) {
|
||||
wp_send_json_error( $user->get_error_message() );
|
||||
}
|
||||
|
||||
wp_set_auth_cookie( $user->ID, true );
|
||||
|
||||
$redirect_url = self::get_page_url( 'account' );
|
||||
|
||||
wp_send_json_success( array( 'redirect' => $redirect_url ) );
|
||||
}
|
||||
|
||||
public static function ajax_register() {
|
||||
check_ajax_referer( 'pc_membership_register', 'nonce' );
|
||||
|
||||
$user_login = isset( $_POST['user_login'] ) ? sanitize_text_field( wp_unslash( $_POST['user_login'] ) ) : '';
|
||||
$user_email = isset( $_POST['user_email'] ) ? sanitize_email( wp_unslash( $_POST['user_email'] ) ) : '';
|
||||
$user_password = isset( $_POST['user_password'] ) ? $_POST['user_password'] : '';
|
||||
$user_password_confirm = isset( $_POST['user_password_confirm'] ) ? $_POST['user_password_confirm'] : '';
|
||||
|
||||
if ( empty( $user_login ) || empty( $user_email ) || empty( $user_password ) ) {
|
||||
wp_send_json_error( __( 'All fields are required', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
if ( ! is_email( $user_email ) ) {
|
||||
wp_send_json_error( __( 'Invalid email address', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
if ( $user_password !== $user_password_confirm ) {
|
||||
wp_send_json_error( __( 'Passwords do not match', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
if ( strlen( $user_password ) < 8 ) {
|
||||
wp_send_json_error( __( 'Password must be at least 8 characters', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
if ( username_exists( $user_login ) ) {
|
||||
wp_send_json_error( __( 'Username already exists', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
if ( email_exists( $user_email ) ) {
|
||||
wp_send_json_error( __( 'Email already registered', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$user_id = wp_create_user( $user_login, $user_password, $user_email );
|
||||
|
||||
if ( is_wp_error( $user_id ) ) {
|
||||
wp_send_json_error( $user_id->get_error_message() );
|
||||
}
|
||||
|
||||
wp_update_user( array(
|
||||
'ID' => $user_id,
|
||||
'display_name' => $user_login,
|
||||
) );
|
||||
|
||||
$user = get_userdata( $user_id );
|
||||
$user->set_role( 'subscriber' );
|
||||
|
||||
wp_set_auth_cookie( $user_id, true );
|
||||
|
||||
do_action( 'pc_membership_user_registered', $user_id, $user_login, $user_email );
|
||||
|
||||
$redirect_url = self::get_page_url( 'account' );
|
||||
|
||||
wp_send_json_success( array( 'redirect' => $redirect_url ) );
|
||||
}
|
||||
|
||||
public static function ajax_update_profile() {
|
||||
check_ajax_referer( 'pc_membership_update_profile', 'nonce' );
|
||||
|
||||
if ( ! is_user_logged_in() ) {
|
||||
wp_send_json_error( __( 'Must be logged in', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$display_name = isset( $_POST['display_name'] ) ? sanitize_text_field( wp_unslash( $_POST['display_name'] ) ) : '';
|
||||
|
||||
if ( empty( $display_name ) ) {
|
||||
wp_send_json_error( __( 'Display name is required', 'pc-membership-abc123' ) );
|
||||
}
|
||||
|
||||
$result = wp_update_user( array(
|
||||
'ID' => get_current_user_id(),
|
||||
'display_name' => $display_name,
|
||||
) );
|
||||
|
||||
if ( is_wp_error( $result ) ) {
|
||||
wp_send_json_error( $result->get_error_message() );
|
||||
}
|
||||
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
public static function handle_stripe_return() {
|
||||
if ( ! isset( $_GET['session_id'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$session_id = sanitize_text_field( wp_unslash( $_GET['session_id'] ) );
|
||||
|
||||
if ( ! class_exists( 'PC_Membership_Stripe' ) ) {
|
||||
require_once PC_MEMBERSHIP_PLUGIN_DIR . 'includes/stripe-handler.php';
|
||||
}
|
||||
|
||||
$session = PC_Membership_Stripe::retrieve_session( $session_id );
|
||||
|
||||
if ( is_wp_error( $session ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$success_page = self::get_page_url( 'success' );
|
||||
if ( $success_page ) {
|
||||
wp_redirect( $success_page );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
chat/templates/Membership/uninstall.php
Normal file
19
chat/templates/Membership/uninstall.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* Uninstall script for PC Membership Plugin.
|
||||
* Removes custom tables created by the plugin.
|
||||
*/
|
||||
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
|
||||
exit; // Prevent direct access.
|
||||
}
|
||||
global $wpdb;
|
||||
$tables = array(
|
||||
$wpdb->prefix . 'pc_membership_plans',
|
||||
$wpdb->prefix . 'pc_membership_subscriptions',
|
||||
);
|
||||
foreach ( $tables as $table ) {
|
||||
$wpdb->query( "DROP TABLE IF EXISTS `$table`" );
|
||||
}
|
||||
// Option cleanup.
|
||||
delete_option( 'pc_membership_options' );
|
||||
?>
|
||||
Reference in New Issue
Block a user