726 lines
44 KiB
PHP
726 lines
44 KiB
PHP
<?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' ),
|
|
),
|
|
) );
|
|
}
|
|
}
|