| Server IP : 43.141.50.122 / Your IP : 113.219.202.173 Web Server : Apache System : Linux VM-8-5-opencloudos 6.6.34-9.oc9.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Jun 19 19:35:45 CST 2024 x86_64 User : www ( 1000) PHP Version : 8.1.27 Disable Function : passthru,exec,system,putenv,chroot,chgrp,chown,shell_exec,popen,proc_open,pcntl_exec,ini_alter,ini_restore,dl,openlog,syslog,readlink,symlink,popepassthru,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,imap_open,apache_setenv MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /www/wwwroot/www.ucppt.com/wp-content/plugins/wpcom-member-pro/includes/ |
Upload File : |
<?php
namespace WPCOM\Member;
defined( 'ABSPATH' ) || exit;
class VIP {
public $vip_action_type = array(
'new' => '开通',
'renew' => '续费',
'upgrade' => '升级'
);
public $vip_lifetime = array(
'week' => '周付',
'month' => '月付',
'season' => '季付',
'halfyear' => '半年付',
'year' => '年付',
'lifetime' => '终身'
);
function __construct(){
add_filter( 'wpcom_user_display_name', array( $this, 'display_name' ), 8, 3);
add_filter( 'wpcom_is_login', array( $this, 'show_vip_flag' ));
add_filter( 'wpcom_init_plugin_options', array( $this, 'vip_settings' ));
add_filter( 'wpcom_setup_exists_order', array( $this, 'check_exists_order'), 10, 3);
add_filter( 'wpcom_order_types', array( $this, 'vip_order_types') );
add_filter( 'wpcom_themer_get_taxs', array( $this, 'get_roles'), 10, 2 );
add_filter( 'wp_insert_post_data', array( $this, 'pre_insert_post'), 10 ,2 );
add_filter( 'rest_pre_insert_post', array( $this, 'rest_pre_insert_post') );
add_filter( 'authenticate', array( $this, 'authenticate' ), 100 );
add_filter( 'wpcom_tougao_notice', array( $this, 'tougao_notice'), 10, 2);
add_filter( 'get_comment_author', array($this, 'comment_author_vip_flag'), 20, 3);
add_filter( 'comment_author', array($this, 'comment_author_vip_flag'), 20, 2);
add_filter( 'the_author', array($this, 'author_vip_flag'), 20);
add_filter( 'manage_pages_columns', array($this, 'change_author_column') );
add_filter( 'manage_posts_columns', array($this, 'change_author_column') );
add_action( 'init', array($this, 'init') );
add_action( 'admin_init', array($this, 'schedule_event') );
add_action( 'wpcom_vip_schedule_event', array( $this, 'cron_action') );
add_action( 'show_user_profile', array( $this, 'edit_user_vip' ) );
add_action( 'edit_user_profile', array( $this, 'edit_user_vip' ) );
add_action( 'personal_options_update', array( $this, 'save_user_vip' ) );
add_action( 'edit_user_profile_update', array( $this, 'save_user_vip' ) );
add_action( 'wpcom_member_account_after_dio', array( $this, 'show_vip_info' ), 8 );
add_action( 'wpcom_member_account_after_dio', array( $this, 'show_vip_info_close' ), 20 );
add_action( 'wp_ajax_wpcom_vip_modal', array($this, 'vip_modal'));
add_action( 'wp_ajax_nopriv_wpcom_vip_modal', array($this, 'vip_modal'));
add_action( 'wp_ajax_wpcom_get_vip_data', array($this, 'get_vip_data'));
add_action( 'wp_ajax_nopriv_wpcom_get_vip_data', array($this, 'get_vip_data'));
add_action( 'wp_ajax_wpcom_vip_unlock', array($this, 'vip_unlock'));
add_action( 'wp_ajax_nopriv_wpcom_vip_unlock', array($this, 'vip_unlock'));
add_action( 'wpcom_order_item_detail_vip-new', array($this, 'show_in_order'));
add_action( 'wpcom_order_item_detail_vip-renew', array($this, 'show_in_order'));
add_action( 'wpcom_order_item_detail_vip-upgrade', array($this, 'show_in_order'));
add_action( 'wpcom_vip-new_payment_complete', array($this, 'payment_complete'), 10, 2);
add_action( 'wpcom_vip-renew_payment_complete', array($this, 'payment_complete'), 10, 2);
add_action( 'wpcom_vip-upgrade_payment_complete', array($this, 'payment_complete'), 10, 2);
add_action( 'admin_notices', array($this, 'post_limit_error') );
add_action( 'manage_pages_custom_column', array($this, 'author_column'), 10, 2 );
add_action( 'manage_posts_custom_column', array($this, 'author_column'), 10, 2 );
if(defined('WWA_VERSION')){
add_action('rest_api_init', array($this, 'for_rest_api') );
add_filter('WWA_rest_user_metas', array($this, 'rest_user_metas'), 10, 2);
}
}
function init(){
register_block_type('wpcom/vip', array(
'render_callback' => function ($attr, $content) {
global $wpcom_member;
$user_id = get_current_user_id();
$attr['is_vip'] = $user_id && VIP::get_user_vip($user_id);
$attr['content'] = $attr['is_vip'] && isset($attr['vip_content']) && trim($attr['vip_content']) !== '' ? $attr['vip_content'] : $attr['content'];
$output = $wpcom_member->load_template('vip-block', $attr);
return '<div class="wp-block-wpcom-vip'.(trim($attr['content']) === '' ? ' without-desc' : '').'">' . $output . '</div>';
}
));
}
function schedule_event(){
if (!wp_next_scheduled ( 'wpcom_vip_schedule_event' )) wp_schedule_event(time(), 'hourly', 'wpcom_vip_schedule_event');
}
function cron_action(){
global $wpdb;
// 重置昨天过期会员的用户分组
$args = array(
'meta_key' => $wpdb->get_blog_prefix() . 'vip_end_date',
'meta_value' => date('Y-m-d', time() - 86400),
'meta_compare' => '=',
'number' => 200
);
$users = get_users($args);
if($users && isset($users[0])){
foreach($users as $user){
if(isset($user->ID)) $this->update_role($user->ID, true);
}
}
}
public static function vip_btn_text($type = 'new'){
global $wpmx_options;
$texts = [
'new' => '开通会员',
'renew' => '会员续费',
'upgrade' => '会员升级'
];
if($type && $wpmx_options && isset($wpmx_options['vip_btn_'. $type]) && trim($wpmx_options['vip_btn_' . $type]) !== ''){
return $wpmx_options['vip_btn_' . $type];
}else if($type && isset($texts[$type])) {
return $texts[$type];
}
}
public static function display_name($name, $user_id, $type=''){
if($type === 'full' || $type === 'vip'){
$vip = self::get_user_vip($user_id);
if ( $vip && $vip['icon']) {
$name .= '<span class="user-vip-flag"><span class="user-vip-flag-inner"><img class="user-vip-flag-icon j-lazy" src="'.esc_url($vip['icon']).'" alt="'.esc_attr($vip['title']).'" title="'.esc_attr($vip['title']).'"></span></span>';
}
}
return $name;
}
function show_vip_flag($res){
$user_id = get_current_user_id();
if($user_id && $vip = $this->get_user_vip($user_id)){
$res['vip'] = array(
'id' => $vip['id'],
'icon' => $vip['icon'],
'title' => $vip['title']
);
}
return $res;
}
// 同时兼容 get_comment_author 和 comment_author 过滤器
function comment_author_vip_flag($anthor, $comment_ID, $comment = null){
$comment = $comment ?? get_comment($comment_ID);
if($comment->user_id){
$comment_author = preg_match('/class="user-vip-flag"/i', $anthor) ? $comment->comment_author : $anthor;
$anthor = $this->display_name($comment_author, $comment->user_id, 'full');
}
return $anthor;
}
function author_vip_flag($display_name){
global $authordata;
if ( is_admin() && ! wp_doing_ajax() ) {
return $display_name;
}
if($display_name !== null && is_object( $authordata )){
$display_name = $this->display_name($display_name, $authordata->ID, 'full');
}
return $display_name;
}
function change_author_column($columns){
if($columns && isset($columns['author'])){
$_columns = [];
foreach($columns as $key => $val){
if($key === 'author'){
$_columns['custom_author'] = $val;
}else{
$_columns[$key] = $val;
}
}
$columns = $_columns;
}
return $columns;
}
function author_column($column, $post_id){
if ( $column === 'custom_author' ) {
global $authordata;
$display_name = $authordata->display_name ?? '';
if ( ! empty( $display_name ) ) {
$post = get_post($post_id);
$args = array(
'post_type' => $post->post_type,
'author' => get_the_author_meta( 'ID' ),
);
if($display_name !== null && is_object( $authordata )){
$display_name = $this->display_name($display_name, $authordata->ID, 'full');
}
echo $this->get_edit_link( $args, $display_name );
} else {
echo '<span aria-hidden="true">—</span><span class="screen-reader-text">' . __( '(no author)' ) . '</span>';
}
}
}
protected function get_edit_link( $args, $link_text, $css_class = '' ) {
$url = add_query_arg( $args, 'edit.php' );
$class_html = '';
$aria_current = '';
if ( ! empty( $css_class ) ) {
$class_html = sprintf(
' class="%s"',
esc_attr( $css_class )
);
if ( 'current' === $css_class ) {
$aria_current = ' aria-current="page"';
}
}
return sprintf(
'<a href="%s"%s%s>%s</a>',
esc_url( $url ),
$class_html,
$aria_current,
$link_text
);
}
public static function show_vip_info($tougao = true){
global $options, $tougao, $is_lifetime;
$user_id = get_current_user_id();
if($user_id && !empty(self::get_vip_types())){
$vip = self::get_user_vip($user_id);
$is_lifetime = $vip && isset($vip['expired']) && self::is_lifetime_vip($vip['expired']);
$tougao = $tougao && isset($options['tougao_on']) && $options['tougao_on']=='1';
if ( $vip ) {
echo '<div class="member-account-vip"><div class="member-account-vip-name">'.($vip['icon']?'<span class="user-vip-flag"><span class="user-vip-flag-inner"><img class="user-vip-flag-icon j-lazy" src="'.esc_url($vip['icon']).'" alt="'.esc_attr($vip['title']).'" title="'.esc_attr($vip['title']).'"></span></span>':'').$vip['title'].'</div><span class="member-account-vip-expired">有效期至<b>'. ($is_lifetime ? '终身' : $vip['expired']) . '</b></span></div>';
if(self::vip_can_upgrade($vip) && !$is_lifetime){
echo '<div class="member-account-vip-action"><a class="wpcom-btn btn-danger btn-block j-vip-renew" href="#">'. self::vip_btn_text('renew').'</a><a class="member-account-vip-btn wpcom-btn btn-vip-upgrade btn-block j-vip-upgrade" href="#">'. self::vip_btn_text('upgrade') .'</a></div>';
}else if(self::vip_can_upgrade($vip)){
if($tougao) echo '<div class="member-account-vip-action">';
echo '<a class="member-account-vip-btn wpcom-btn btn-vip-upgrade btn-block j-vip-upgrade" href="#">'. self::vip_btn_text('upgrade') .'</a>';
}else{
if($tougao && !$is_lifetime) echo '<div class="member-account-vip-action">';
if(!$is_lifetime) echo '<a class="wpcom-btn member-account-vip-btn btn-danger btn-block j-vip-renew" href="#">'. self::vip_btn_text('renew').'</a>';
}
}else{
if($tougao) echo '<div class="member-account-vip-action">';
echo '<a class="member-account-vip-btn wpcom-btn btn-danger btn-block j-vip-new" href="#">'.wpmx_icon('vip-crown', false).self::vip_btn_text('new').'</a>';
}
}
}
public static function show_vip_info_close(){
global $tougao, $is_lifetime;
$user_id = get_current_user_id();
if($user_id && isset($tougao) && $tougao && !empty(self::get_vip_types())){
$vip = self::get_user_vip($user_id);
if($vip){
if( (self::vip_can_upgrade($vip) && $is_lifetime) || (!self::vip_can_upgrade($vip) && !$is_lifetime)){
echo '</div>';
}
}else if(!$vip){
echo '</div>';
}
}
}
function vip_modal(){
global $wpcom_member;
$res = array('result' => 0);
$user_id = get_current_user_id();
$type = isset($_POST['type']) ? sanitize_text_field($_POST['type']) : 'new';
if($user_id || $type === 'new'){
$current_vip = self::get_user_vip();
if($current_vip && $type === 'new'){
$res['result'] = -3;
$res['msg'] = '您已是会员,无需重复开通!';
}else if(!$current_vip && $type !== 'new'){
$res['result'] = -4;
$res['msg'] = '您还不是会员,无法执行此操作!';
}else if($type === 'upgrade' && !$this->vip_can_upgrade($current_vip)){
$res['result'] = -5;
$res['msg'] = '抱歉,当前会员类型无法执行升级操作!';
}else if($current_vip && $type === 'renew' && $this->is_lifetime_vip($current_vip['expired'])){
$res['result'] = -6;
$res['msg'] = '抱歉,您已经是终身会员了!';
}else{
$vip_types = self::get_vip_types();
if($vip_types && !empty($vip_types)){
if($current_vip && isset($current_vip['expired'])){
$datetime = date_create($current_vip['expired'], wp_timezone());
$current_vip['expired'] = $datetime;
}
if($type === 'upgrade'){
$pass = false;
foreach($vip_types as $key => $val){
if($key === $current_vip['id'] || !$pass){
unset($vip_types[$key]);
$pass = true;
} else {
// 计算升级差价
$vip_types[$key]['upgrade_price'] = $this->vip_upgrade_price($current_vip, $val);
}
}
}
$args = array(
'type' => $type,
'current_vip' => $current_vip,
'vip_types' => $vip_types
);
$output = $wpcom_member->load_template('vip-modal', $args);
foreach($vip_types as $i => $_type){
if(isset($vip_types[$i]['privileges'])) unset($vip_types[$i]['privileges']);
}
$res['tpl'] = $output;
$res['data'] = $vip_types;
if($type === 'new'){
$res['timestamp'] = current_time('timestamp', 1);
}else if($current_vip['expired']){
$res['timestamp'] = $current_vip['expired']->getTimestamp();
}
}else{
$res['result'] = -2;
$res['msg'] = '暂无可开通的会员类型,请联系网站管理员';
}
}
}else{
$res['result'] = -1;
}
wp_send_json($res);
}
function get_vip_data($return = false){
$user_id = get_current_user_id();
$res = array('result' => 0);
if ($user_id) {
$action_type = isset($_POST['action_type']) ? sanitize_text_field($_POST['action_type']) : '';
$vip_type = isset($_POST['vip_type']) ? sanitize_text_field($_POST['vip_type']) : '';
$vip_lifetime = isset($_POST['vip_lifetime']) ? sanitize_text_field($_POST['vip_lifetime']) : '';
if (in_array($action_type, array('new', 'renew', 'upgrade')) && $vip_type && ($action_type === 'upgrade' || $vip_lifetime) ) {
$vip_types = self::get_vip_types();
$vip = $this->get_user_vip($user_id);
if($action_type === 'upgrade' && isset($vip_types[$vip_type]) && $vip){
$upgrade_price = $this->vip_upgrade_price($vip, $vip_types[$vip_type]);
if($upgrade_price && is_numeric($upgrade_price)){
$expired = date_create($vip['expired'], wp_timezone());
$expired_text = $expired && date_format($expired, 'Y') === '9999' ? '终身' : date_format($expired, 'Y年m月d日');
$items = array(
array(
'title' => $vip['title'] . $this->vip_action_type[$action_type] . $vip_types[$vip_type]['title'] . '-' . $expired_text,
'price' => number_format($upgrade_price ?: 0, 2, '.', ''),
'number' => 1,
'type' => 'vip-'.$action_type,
'type_id' => $vip_type.'::'.$vip['id']
)
);
$res['total'] = number_format($upgrade_price ?: 0, 2, '.', '');
$res['items'] = $items;
$res = Order::setup_order_data($res);
}
}else if(!empty($vip_types) && isset($vip_types[$vip_type]) && isset($vip_types[$vip_type]['time']) && in_array($vip_lifetime, $vip_types[$vip_type]['time'])){
$price = $vip_types[$vip_type][$vip_lifetime.'_price'];
if($action_type === 'new'){
$begin = current_time('Y-m-d');
}else if($action_type === 'renew'){
$end_date = $vip ? get_user_option('vip_end_date', $user_id) : '';
$begin = $end_date ? $end_date : current_time('Y-m-d');
}
$data = array(
'begin_date' => $begin,
'end_date' => $this->get_expired_date($begin, $vip_lifetime)
);
$items = array(
array(
'title' => $this->vip_action_type[$action_type] . $vip_types[$vip_type]['title'] . '-' . $this->vip_lifetime[$vip_lifetime],
'price' => number_format($price ?: 0, 2, '.', ''),
'number' => 1,
'type' => 'vip-'.$action_type,
'type_id' => $vip_type.'::'.$vip_lifetime,
'data' => $data
)
);
$res['total'] = number_format($price ?: 0, 2, '.', '');
$res['items'] = $items;
$res = Order::setup_order_data($res);
}else{
$res['result'] = -3;
$res['msg'] = '会员类型出错,请稍后再试';
}
} else {
$res['result'] = -2;
}
} else { // 未登录
$res['result'] = -1;
}
if($return){
return $res;
}else{
wp_send_json($res);
}
}
public function vip_unlock(){
$user_id = get_current_user_id();
$res = array('result' => 0);
if ($user_id) {
if(Order::check_sign($_POST)){
$type = isset($_POST['type']) ? sanitize_text_field($_POST['type']) : '';
$post_id = isset($_POST['post_id']) ? sanitize_text_field($_POST['post_id']) : 0;
$id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : '';
$type_id = $id ? $post_id.'::'.$id : $post_id;
$items = isset($_POST['items']) ? map_deep( $_POST['items'], 'sanitize_text_field' ) : array();
$total = isset($_POST['total']) ? sanitize_text_field($_POST['total']) : 0;
if(($total == 0 || $total === '0.00') && isset($items[0]) && isset($items[0]['type']) && $items[0]['type'] === $type && $items[0]['type_id'] == $type_id){
if(self::is_vip_visable($type . '/' . $type_id)){ // 可见,比如不限次数或者已经解锁
$res['result'] = 1;
}else{ // 不可见
$free_times = self::get_vip_unlock_times($user_id);
if($free_times > 0){
$flag = $user_id.'_' . current_time('Ymd');
$name = '_vip_' . $flag . '_' . $type . '/' . $type_id;
$value = '_vip_free_' . $flag;
if(!self::add_vip_unlock_log($name, $value)){
$res['result'] = -5;
$res['msg'] = '解锁失败,请稍后再试!';
}
}else{
$res['result'] = -4;
$res['msg'] = '今日的免费解锁次数已用尽';
}
}
}else{
$res['result'] = -3;
$res['total'] = $items[0]['type_id'] == $id;
$res['ww'] = $items[0]['type_id'];
$res['ee'] = $id;
$res['msg'] = '解锁信息校验失败,请重试';
}
}else{
$res['result'] = -2;
$res['msg'] = '解锁信息校验失败,请重试';
}
} else { // 未登录
$res['result'] = -1;
$res['msg'] = '请登录后操作!';
}
wp_send_json($res);
}
static public function get_vip_types(){
if(isset($GLOBALS['vip_types'])) return $GLOBALS['vip_types'];
$options = $GLOBALS['wpmx_options'];
$types = [];
if(isset($options['vip_id']) && !empty($options['vip_id']) && is_array($options['vip_id'])){
foreach($options['vip_id'] as $i => $id){
$privileges = [];
$_privileges = isset($options['vip_privileges']) && isset($options['vip_privileges'][$i]) ? $options['vip_privileges'][$i] : '';
if(!empty($_privileges)){
// 处理二选一选项
if(in_array('download_free', $_privileges) && in_array('download_discount', $_privileges)){
$key = array_search('download_discount', $_privileges);
unset($_privileges[$key]);
}
if(in_array('content_free', $_privileges) && in_array('content_discount', $_privileges)){
$key = array_search('content_discount',$_privileges);
unset($_privileges[$key]);
}
if(in_array('copy_free', $_privileges) && in_array('copy_discount', $_privileges)){
$key = array_search('copy_discount',$_privileges);
unset($_privileges[$key]);
}
}
if(!empty($_privileges)){
$free_limit = false;
foreach($_privileges as $v){
if($v){
switch($v){
case 'download_free':
$privileges['download'] = 0;
$free_limit = true;
break;
case 'download_discount':
$privileges['download'] = isset($options['vip_download_discount']) && isset($options['vip_download_discount'][$i]) ? (double)$options['vip_download_discount'][$i] : 10;
$privileges['download'] = $privileges['download'] / 10;
break;
case 'content_free':
$privileges['content'] = 0;
$free_limit = true;
break;
case 'content_discount':
$privileges['content'] = isset($options['vip_content_discount']) && isset($options['vip_content_discount'][$i]) ? (double)$options['vip_content_discount'][$i] : 10;
$privileges['content'] = $privileges['content'] / 10;
break;
case 'copy_free':
$privileges['copy'] = 0;
$free_limit = true;
break;
case 'copy_discount':
$privileges['copy'] = isset($options['vip_copy_discount']) && isset($options['vip_copy_discount'][$i]) ? (double)$options['vip_copy_discount'][$i] : 10;
$privileges['copy'] = $privileges['copy'] / 10;
break;
case 'publish_post':
$default_month_post_limit = isset($options['default_month_post_limit']) ? $options['default_month_post_limit'] : -1;
$default_day_post_limit = isset($options['default_day_post_limit']) ? $options['default_day_post_limit'] : -1;
$privileges['month_post_limit'] = isset($options['vip_month_post_limit']) && isset($options['vip_month_post_limit'][$i]) ? (int)$options['vip_month_post_limit'][$i] : $default_month_post_limit;
$privileges['day_post_limit'] = isset($options['vip_day_post_limit']) && isset($options['vip_day_post_limit'][$i]) ? (int)$options['vip_day_post_limit'][$i] : $default_day_post_limit;
break;
}
}
}
}
$type = [
'index' => $i,
'id' => $id,
'title' => isset($options['vip_title']) && isset($options['vip_title'][$i]) ? $options['vip_title'][$i] : '',
'icon' => isset($options['vip_icon']) && isset($options['vip_icon'][$i]) && $options['vip_icon'][$i] ? wp_get_attachment_url($options['vip_icon'][$i]) : '',
'time' => isset($options['vip_time']) && isset($options['vip_time'][$i]) ? $options['vip_time'][$i] : '',
'week_price' => isset($options['vip_week_price']) && isset($options['vip_week_price'][$i]) && is_numeric($options['vip_week_price'][$i]) ? number_format($options['vip_week_price'][$i], 2, '.', '') : '',
'month_price' => isset($options['vip_month_price']) && isset($options['vip_month_price'][$i]) && is_numeric($options['vip_month_price'][$i]) ? number_format($options['vip_month_price'][$i], 2, '.', '') : '',
'season_price' => isset($options['vip_season_price']) && isset($options['vip_season_price'][$i]) && is_numeric($options['vip_season_price'][$i]) ? number_format($options['vip_season_price'][$i], 2, '.', '') : '',
'halfyear_price' => isset($options['vip_halfyear_price']) && isset($options['vip_halfyear_price'][$i]) && is_numeric($options['vip_halfyear_price'][$i]) ? number_format($options['vip_halfyear_price'][$i], 2, '.', '') : '',
'year_price' => isset($options['vip_year_price']) && isset($options['vip_year_price'][$i]) && is_numeric($options['vip_year_price'][$i]) ? number_format($options['vip_year_price'][$i], 2, '.', '') : '',
'lifetime_price' => isset($options['vip_lifetime_price']) && isset($options['vip_lifetime_price'][$i]) && is_numeric($options['vip_lifetime_price'][$i]) ? number_format($options['vip_lifetime_price'][$i], 2, '.', '') : '',
'privileges' => $privileges,
'description' => isset($options['vip_desc']) && isset($options['vip_desc'][$i]) ? wp_kses_post(wpautop($options['vip_desc'][$i])) : ''
];
if($privileges && isset($privileges['day_post_limit'])){
$type['group'] = isset($options['vip_group']) && isset($options['vip_group'][$i]) ? $options['vip_group'][$i] : '';
$type['role'] = isset($options['vip_role']) && isset($options['vip_role'][$i]) ? $options['vip_role'][$i] : '';
}
if(isset($options['aff']) && $options['aff'] == '1'){
$aff_rate = isset($options['vip_aff_rate']) && isset($options['vip_aff_rate'][$i]) ? $options['vip_aff_rate'][$i] : '';
$type['aff_rate'] = trim($aff_rate) === '' ? '' : (float)$aff_rate;
}
if(isset($free_limit) && $free_limit){
$type['free_limit'] = isset($options['vip_free_limit']) && isset($options['vip_free_limit'][$i]) ? (int)$options['vip_free_limit'][$i] : 0;
}
$types[$id] = $type;
}
}
$GLOBALS['vip_types'] = $types;
return $types;
}
static public function get_user_vip($user_id = ''){
global $user_vip;
$user_id = $user_id ? $user_id : get_current_user_id();
if($user_id && $user_vip && isset($user_vip[$user_id])) return $user_vip[$user_id];
if(!$user_vip) $user_vip = array();
$types = self::get_vip_types();
if($user_id && !empty($types)){
$vip_type = (string) get_user_option( 'vip_type', $user_id );
$vip_expired = $vip_type ? get_user_option( 'vip_end_date', $user_id ) : '';
if($vip_expired && current_time('Y-m-d') <= $vip_expired){
foreach($types as $id => $type){
if((string) $id === $vip_type){
$type['begin'] = get_user_option( 'vip_begin_date', $user_id );
$type['expired'] = $vip_expired;
$user_vip[$user_id] = $type;
return $type;
}
}
}
}
$user_vip[$user_id] = false;
return false;
}
static public function get_vip_price($price, $vip_price, $type, $vip = ''){
$types = self::get_vip_types();
if(!empty($types)){
if($vip){
if($vip_price && isset($vip_price[$vip.'_price']) && $vip_price[$vip.'_price'] !== ''){
return (float) $vip_price[$vip.'_price'];
}else if(isset($types[$vip]) && isset($types[$vip]['privileges'][$type])){
return (float) $price * $types[$vip]['privileges'][$type];
} else {
return (float) $price;
}
}else{
$prices = array();
foreach($types as $id => $vip){
$_price = array(
'info' => $vip
);
if($vip_price && isset($vip_price[$id.'_price']) && $vip_price[$id.'_price'] !== ''){
$_price['price'] = (float) $vip_price[$id.'_price'];
}else if($vip['privileges'] && isset($vip['privileges'][$type])){
$_price['price'] = (float) $price * $vip['privileges'][$type];
} else {
$_price['price'] = (float) $price;
}
$prices[$id] = $_price;
}
$_vip_price = false;
if(!empty($prices)){
foreach($prices as $_p){
if(isset($_p['price']) && $_p['price'] != (float) $price){
$_vip_price = true;
break;
}
}
// VIP专属商品价格会传0,避免会员价格也是0的情况
if((float) $price == 0 && !$_vip_price) $_vip_price = true;
}
return $_vip_price ? $prices : array();
}
}
return $price;
}
static public function get_vip_price_by_user($user_id, $price, $vip_price, $type){
$vip = self::get_user_vip($user_id);
if($vip && isset($vip['id']) && $vip_price && isset($vip_price[$vip['id'].'_price']) && $vip_price[$vip['id'].'_price'] !== ''){
return (float) $vip_price[$vip['id'].'_price'];
}else if($vip && isset($vip['id'])){
$types = self::get_vip_types();
if(isset($types[$vip['id']]) && isset($types[$vip['id']]['privileges'][$type])){
return (float) $price * $types[$vip['id']]['privileges'][$type];
}
}
return (float) $price;
}
function vip_upgrade_price($vip, $upgrade_vip){
if($vip['expired'] && !is_object($vip['expired'])) $vip['expired'] = date_create($vip['expired'], wp_timezone());
$is_lifetime = $this->is_lifetime_vip($vip['expired']);
if($is_lifetime){ // 终身会员直接计算两种会员终身价格的差价
if($upgrade_vip['time'] && in_array('lifetime', $upgrade_vip['time']) && isset($upgrade_vip['lifetime_price']) && $upgrade_vip['lifetime_price'] && isset($vip['lifetime_price']) && $vip['lifetime_price']){
$upgrade_price = $upgrade_vip['lifetime_price'] - $vip['lifetime_price'];
if($upgrade_price && is_numeric($upgrade_price) && $upgrade_price > 0){
return $upgrade_price;
}
}
}else if(!empty($upgrade_vip['time']) && ( !in_array('lifetime', $upgrade_vip['time']) || count($upgrade_vip['time']) >= 2) ){
if(in_array('lifetime', $upgrade_vip['time'])){
foreach($upgrade_vip['time'] as $i => $t){
if($t === 'lifetime') unset($upgrade_vip['time'][$i]);
}
}
$upgrade_vip['time'] = array_values($upgrade_vip['time']);
$lifes = array(
'week' => 7,
'month' => 31,
'season' => 91,
'halfyear' => 183,
'year' => 365
);
// 多种付款周期则根据开通时长计算最佳差价适合的周期
if(count($upgrade_vip['time']) >= 2){
$begin = $vip['begin'] ? date_create($vip['begin'], wp_timezone()) : date_create('now', wp_timezone());
foreach(array_reverse($lifes) as $key => $val){
$need_days = intval($val * 0.85);
if(in_array($key, $upgrade_vip['time']) && in_array($key, $vip['time'])){
$vip_days = ($vip['expired']->getTimestamp() - $begin->getTimestamp()) / 86400;
if($vip_days && $vip_days >= $need_days && $upgrade_vip[$key . '_price'] && $vip[$key . '_price']) {
$price = ($upgrade_vip[$key . '_price'] - $vip[$key . '_price']) / $val;
break;
}
}
}
if(!isset($price)) {
$_life = $upgrade_vip['time'][count($upgrade_vip['time'])-1];
if($_life && isset($lifes[$_life]) && in_array($_life, $vip['time']) && $upgrade_vip[$_life . '_price'] && $vip[$_life . '_price']){
$price = ($upgrade_vip[$_life . '_price'] - $vip[$_life . '_price']) / $lifes[$_life];
}
}
}else{
$_time = $upgrade_vip['time'][0];
if($_time && isset($lifes[$_time]) && in_array($_time, $vip['time'])){
$price = ($upgrade_vip[$_time . '_price'] - $vip[$_time . '_price']) / $lifes[$_time];
}
}
if(isset($price) && is_numeric($price) && $price > 0){
$today = date_create(current_time('Y-m-d'), wp_timezone());
$days = ($vip['expired']->getTimestamp() - $today->getTimestamp()) / 86400;
if(is_numeric($days)){
$days = round($days, 0);
return number_format($days * $price, 2, '.', '');
}
}
}
return false;
}
static public function get_vip_price_html($price, $vip_price, $type, $points = false){
$price = $price ? $price : 0;
$vip_price = $vip_price && is_array($vip_price) ? $vip_price : array();
$prices = self::get_vip_price($price, $vip_price, $type);
$html = '';
if($prices && !empty($prices) && is_array($prices)){
$icon = $points ? '<span class="vip-price-icon" aria-label="积分">' . wpmx_icon('points', false) . '</span>' : '<span>¥</span>';
foreach($prices as $_price){
if(isset($_price['price'])){
$_vip_price = is_numeric($_price['price']) ? (float) $_price['price'] : $price;
$_vip_price = $_vip_price == 0 ? '免费' : number_format($_vip_price, $points ? 0 : 2, '.', '');
$html .= '<div class="vip-price-item" vip-index="'.$_price['info']['index'].'" vip-id="'.$_price['info']['id'].'">';
if(isset($_price['info']) && $_price['info']['icon']){
$html .= '<img class="vip-flag-icon j-lazy no-lightbox" src="'.esc_url($_price['info']['icon']).'" alt="'.esc_attr($_price['info']['title']).'">';
}
$html .= $_price['info']['title'] . '<span class="vip-price">' . ($_vip_price !== '免费' ? $icon : '') . $_vip_price . '</span></div>';
}
}
}
return apply_filters('wpcom_get_vip_price_html', $html, $price, $vip_price, $type);
}
static public function vip_can_upgrade($vip){
global $wpmx_options;
if(isset($wpmx_options['vip_upgrade']) && $wpmx_options['vip_upgrade'] && $vip && isset($vip['id'])){
$vips = self::get_vip_types();
if($vips && is_array($vips)){
return end($vips)['id'] !== $vip['id'];
}
return true;
}
return false;
}
static public function is_vip_free($price, $vip_price, $type, $user_id=''){
$user_id = $user_id ? $user_id : get_current_user_id();
if($user_id && self::get_user_vip($user_id)){
$_price = (float)self::get_vip_price_by_user($user_id, $price, $vip_price, $type);
return $_price == 0;
}
return false;
}
static public function is_vip_visable($content_id, $user_id = ''){
global $wpdb;
$user_id = $user_id ? $user_id : get_current_user_id();
if($user_id && $content_id && $vip = self::get_user_vip($user_id)){
if((isset($vip['free_limit']) && $vip['free_limit'] <= 0) || !isset($vip['free_limit'])){
return true;
}
$table = $wpdb->prefix . 'wpcom_sessions';
$flag = $user_id . '_' . current_time('Ymd');
$value = '_vip_free_' . $flag;
$name = '_vip_' . $flag . '_' . $content_id;
$option = @$wpdb->get_row( $wpdb->prepare("SELECT * FROM `$table` WHERE name = %s AND value = %s", $name, $value) );
if($option && isset($option->value)) {
return true;
}
}
return false;
}
static function get_vip_unlock_count($user_id=''){
global $wpdb;
$user_id = $user_id ? $user_id : get_current_user_id();
$table = $wpdb->prefix . 'wpcom_sessions';
$value = '_vip_free_' . $user_id . '_' . current_time('Ymd');
return $wpdb->get_var( $wpdb->prepare("SELECT count(*) FROM `$table` WHERE value = %s", $value) );
}
function add_vip_unlock_log($name, $value){
global $wpdb;
$table = $wpdb->prefix . 'wpcom_sessions';
$session = [];
$session['name'] = $name;
$session['value'] = $value;
$session['expired'] = 24*60*60;
$session['time'] = current_time( 'mysql', 1 );
$option = @$wpdb->get_row( $wpdb->prepare("SELECT * FROM `$table` WHERE name = %s AND value = %s", $name, $value) );
if($option && isset($option->value)) {
$res = $wpdb->update($table, $session, ['ID' => $option->ID]);
}else{
$res = $wpdb->insert($table, $session);
}
return $res;
}
static public function get_vip_unlock_times($user_id = ''){
$user_id = $user_id ? $user_id : get_current_user_id();
if($user_id){
$vip = self::get_user_vip($user_id);
$total = isset($vip['free_limit']) && $vip['free_limit'] ? (int) $vip['free_limit'] : 0;
$used = (int) self::get_vip_unlock_count($user_id);
$unlock_times = $total - $used;
$unlock_times = $unlock_times > 0 ? $unlock_times : 0;
return apply_filters('wpcom_vip_unlock_times', $unlock_times, $user_id);
}
}
function get_expired_date($begin, $lifetime){
$end_date = '';
if($lifetime === 'lifetime'){
$end_date = '9999-09-09';
}else if($begin = date_create($begin, wp_timezone())){
$begin = $begin->getTimestamp();
if($lifetime === 'week'){
$end_date = $begin + 7*24*60*60;
$end_date = wp_date('Y-m-d', $end_date);
}if($lifetime === 'month'){
$end_date = $begin + 31*24*60*60;
$end_date = wp_date('Y-m-d', $end_date);
}if($lifetime === 'season'){
$end_date = $begin + 91*24*60*60;
$end_date = wp_date('Y-m-d', $end_date);
}if($lifetime === 'halfyear'){
$end_date = $begin + 183*24*60*60;
$end_date = wp_date('Y-m-d', $end_date);
}else if($lifetime === 'year'){
$end_date = (1 + wp_date('Y', $begin)) . wp_date('-m-d', $begin);
}
}
return $end_date;
}
public function payment_complete($item, $order){
if($order && $order->user && $order->status === 'paid' && isset($item->type) && $actin_type = str_replace('vip-', '', $item->type)){
$type_id = explode('::', $item->type_id);
$user_id = (int)$order->user;
if($type_id && isset($type_id[0]) && isset($type_id[1])){
$vip_type = $type_id[0];
$vip_lifetime = $type_id[1]; // 付费周期,升级的话此参数为升级前会员类型
if($actin_type === 'new' || $actin_type === 'renew'){
$data = $item->data ? json_decode($item->data) : null;
if($data && $data->begin_date && $data->end_date){
$begin_date = $data->begin_date;
$end_date = $data->end_date;
if($actin_type === 'renew'){
$vip_begin_date = get_user_option('vip_begin_date', $user_id);
$begin_date = $vip_begin_date ? $vip_begin_date : $begin_date;
}
}else{
if($actin_type === 'new'){
$begin_time = current_time('timestamp', 1);
$begin_date = wp_date('Y-m-d', $begin_time);
$end_date = $this->get_expired_date($begin_date, $vip_lifetime);
}else{
$vip_begin_date = get_user_option('vip_begin_date', $user_id);
$vip_end_date = get_user_option('vip_end_date', $user_id);
$begin_date = $vip_begin_date ? $vip_begin_date : current_time('Y-m-d');
$_begin_time = $vip_end_date ? $vip_end_date : current_time('Y-m-d');
$end_date = $this->get_expired_date($_begin_time, $vip_lifetime);
}
}
update_user_option($user_id, 'vip_type', $vip_type);
update_user_option($user_id, 'vip_begin_date', $begin_date);
update_user_option($user_id, 'vip_end_date', $end_date);
$this->update_role($user_id);
}else if($actin_type === 'upgrade'){
// 升级仅更新等级信息
update_user_option($user_id, 'vip_type', $vip_type);
$this->update_role($user_id);
}
}
}
}
function update_role($user_id, $force = false){
if(!$user_id || (!$force && user_can( $user_id, 'publish_posts' ))) return false; // 已有权限用户跳过
$vip = $this->get_user_vip($user_id);
if(class_exists(User_Groups::class) && $vip && isset($vip['group']) && $vip['group']){ // 会员,用户分组
$user_group = wpcom_get_user_group($user_id);
wp_set_object_terms($user_id, array((int)$vip['group']), 'user-groups', false);
clean_object_term_cache($user_id, 'user-groups');
$_role = get_term_meta((int)$vip['group'], 'wpcom_sys_role', true);
if($user_group && isset($user_group->term_id)){
update_user_option($user_id, '__user_group', $user_group->term_id);
}
}else if($vip && isset($vip['role']) && $vip['role']){ // 会员,用户角色
$_role = $vip['role'];
update_user_option($user_id, '__user_role', $_role);
}else if(!$vip && $force){ // 不是会员,重置
$__user_group = get_user_option('__user_group', $user_id);
if($__user_group && is_numeric($__user_group)){
wp_set_object_terms($user_id, array((int)$__user_group), 'user-groups', false);
clean_object_term_cache($user_id, 'user-groups');
$_role = get_term_meta((int)$__user_group, 'wpcom_sys_role', true);
delete_user_option($user_id, '__user_group');
}else if($__user_role = get_user_option('__user_role', $user_id)){
$_role = $__user_role;
delete_user_option($user_id, '__user_role');
}
}
if(isset($_role) && $_role){
$user = get_user_by('ID', $user_id);
$default_roles = array('subscriber', 'contributor', 'author', 'editor', 'administrator');
$roles = $user->roles;
if (!$roles) $roles = array();
if (in_array($_role, $default_roles) && !in_array($_role, $roles)) { // 权限和当前用户组权限不一样
foreach ($roles as $role) {
if (in_array($role, $default_roles)) {
$user->remove_role($role);
}
}
if (in_array($_role, $default_roles)) $user->add_role($_role);
}
}
}
function authenticate($user){
if( $user instanceof \WP_User){
$this->update_role($user->ID);
}
return $user;
}
function check_exists_order($res, $order, $items){
if(!empty($items) && isset($items[0]) && $items[0]['order_id'] === $order->ID && in_array($items[0]['type'], array('vip-new', 'vip-renew', 'vip-upgrade'))){
// 已有订单需要重新检查并更新下开通和过期时间
$order_time = date_create($order->time, wp_timezone());
$vip = $this->get_user_vip($order->user);
$vip_types = $this->get_vip_types();
$type_id = explode('::', $items[0]['type_id']);
if(empty($vip_types) || !isset($vip_types[$type_id[0]])){
$res['result'] = -8;
$res['msg'] = '订单已过期,会员信息获取失败!';
}else if($vip && $items[0]['type'] === 'vip-new'){ // 已经开通订单,无法重复开通
$res['result'] = -8;
$res['msg'] = '订单已过期,无法重复开通会员!';
}else if($items[0]['type'] === 'vip-new'){
$begin_date = current_time('Y-m-d');
$items[0]['data'] = array(
'begin_date' => $begin_date,
'end_date' => $this->get_expired_date($begin_date, $type_id[1])
);
}else if(!$vip && $items[0]['type'] === 'vip-renew'){ // 会员过期,无法续费
$res['result'] = -8;
$res['msg'] = '检测到您当前并无会员,无法进行续费操作!';
}else if($vip && $items[0]['type'] === 'vip-renew'){
if($type_id && $type_id[0] && $type_id[0] === $vip['id']){
if(current_time('Y-m-d') !== date_format($order_time, 'Y-m-d')){ // 时间不一致,需要更新下时间
$end_date = $vip ? get_user_option('vip_end_date', $order->user) : '';
$begin_date = $end_date ? $end_date : current_time('Y-m-d');
$items[0]['data'] = array(
'begin_date' => $begin_date,
'end_date' => $this->get_expired_date($begin_date, $type_id[1])
);
}
}else{
$res['result'] = -8;
$res['msg'] = '订单已过期,当前无法续费会员!';
}
}else if($items[0]['type'] === 'vip-upgrade'){
if(!$vip){
$res['result'] = -8;
$res['msg'] = '检测到您当前并无会员,无法进行升级操作!';
}else if(current_time('Y-m-d') !== date_format($order_time, 'Y-m-d') || $vip['id'] !== $type_id[1]){ // 时间或者当前会员类型不一致,无法升级
$res['result'] = -8;
$res['msg'] = '订单已过期,请重新创建升级订单进行操作!';
}
}
if($res['result'] == 0 && $items[0]['data'] && $_items = Order::get_order_items($order->ID)){
global $wpdb;
if(isset($_items[0]) && isset($_items[0]->ID)){
if ($items[0]['data'] && version_compare(PHP_VERSION, '5.4.0', '<')) {
$data = wp_json_encode($items[0]['data']);
} else if ($items[0]['data']) {
$data = wp_json_encode($items[0]['data'], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
$wpdb->update($wpdb->order_item_table, array('data' => $data), array('ID' => $_items[0]->ID));
}
}
}
return $res;
}
public function show_in_order($item) {
if ($item->type_id && $ids = explode('::', $item->type_id)) {
$actin_type = str_replace('vip-', '', $item->type);
$vip_type = $ids[0];
$vip_lifetime = $ids[1];
$vip_types = $this->get_vip_types();
if ($vip_type && isset($this->vip_action_type[$actin_type])) { ?>
<ul class="member-account-order">
<li class="member-account-order-item">
<div class="member-account-order-label">购买项目:</div>
<div class="member-account-order-value"><?php echo $this->vip_action_type[$actin_type];?>会员</div>
</li>
<li class="member-account-order-item">
<div class="member-account-order-label">会员类型:</div>
<div class="member-account-order-value"><?php echo isset($vip_types[$vip_type]) ? $vip_types[$vip_type]['title'] : '-';?></div>
</li>
<?php if($actin_type === 'upgrade'){ ?>
<li class="member-account-order-item">
<div class="member-account-order-label">升级前会员类型:</div>
<div class="member-account-order-value"><?php echo isset($vip_types[$vip_lifetime]) ? $vip_types[$vip_lifetime]['title'] : '-';?></div>
</li>
<?php }else{ ?>
<li class="member-account-order-item">
<div class="member-account-order-label">付费周期:</div>
<div class="member-account-order-value"><?php echo $this->vip_lifetime[$vip_lifetime];?></div>
</li>
<li class="member-account-order-item">
<div class="member-account-order-label">有效期至:</div>
<div class="member-account-order-value"><?php
$data = $item->data ? json_decode($item->data) : '';
$date = $data && isset($data->end_date) ? $data->end_date : '-';
$date = preg_match('/^9999-/', $date) ? '终身' : $date;
echo $date;?></div>
</li>
<?php } ?>
</ul>
<?php }
}
}
public static function is_lifetime_vip($expired){
if($expired && !is_object($expired)) $expired = date_create($expired, wp_timezone());
if($expired && is_object($expired)){
$year = date_format($expired, 'Y');
return $year && $year == '9999';
}
return false;
}
function edit_user_vip($user){
if (!current_user_can('edit_user')) return;
$vip_type = get_user_option( 'vip_type', $user->ID );
$vip_begin_date = get_user_option( 'vip_begin_date', $user->ID );
$vip_end_date = get_user_option( 'vip_end_date', $user->ID );
$types = $this->get_vip_types(); ?>
<h3>会员设置</h3>
<table class="form-table">
<tr>
<th><label for="vip_type">会员类型</label></th>
<td>
<select name="vip_type">
<option value="">选择会员</option>
<?php
if (!empty($types)) {
foreach ($types as $id => $type) { ?>
<option value="<?php echo esc_attr($id); ?>" <?php echo($id===$vip_type ? 'selected' : '') ?>><?php echo $type['title']; ?></option>
<?php }
} ?>
</select>
</td>
</tr>
<tr>
<th><label>会员有效期</label></th>
<td>
<span>从</span>
<label for=""><input type="date" name="vip_begin_date" value="<?php echo $vip_begin_date;?>"></label>
<span> 至 </span>
<label for=""><input type="date" name="vip_end_date" value="<?php echo $vip_end_date;?>"></label>
<p class="description">分别为开通时间和到期时间;终身/无到期时间时请将到期时间设置为<b>9999年的任意日期</b>即可(日期控件不好选择的话可以直接手动输入)</p>
</td>
</tr>
</table>
<?php }
function save_user_vip($user_id){
if (!current_user_can('edit_user', $user_id)) return false;
if (isset($_POST['vip_type'])) update_user_option($user_id, 'vip_type', sanitize_text_field($_POST['vip_type']));
if (isset($_POST['vip_begin_date'])) update_user_option($user_id, 'vip_begin_date', sanitize_text_field($_POST['vip_begin_date']));
if (isset($_POST['vip_end_date'])) update_user_option($user_id, 'vip_end_date', sanitize_text_field($_POST['vip_end_date']));
}
function vip_settings($res){
if($res && isset($res['type']) && $res['type'] === 'post' && isset($res['plugin-slug']) && $res['plugin-slug'] === 'wpcom-member-pro'){
$vips = $this->get_vip_types();
if($vips && is_array($vips)){
$res['hooks'] = $res['hooks'] ?? [];
$res['hooks']['vip_price'] = $res['hooks']['vip_price'] ?? [];
$res['hooks']['copy_vip_price'] = $res['hooks']['copy_vip_price'] ?? [];
$options = $GLOBALS['wpmx_options'];
if(isset($options['points_on']) && $options['points_on'] == '1'){
$res['hooks']['vip_price'][] = array(
'f' => 'unlock_type:5',
'n' => 'pay_type',
'l' => '使用积分购买',
't' => 't',
'ux' => 1,
's' => 0,
'd' => '如果开启积分功能则可设置使用积分的方式购买;开启后下列价格选项单位均为积分',
);
}
foreach($vips as $vip){
$res['hooks']['vip_price'][] = array(
'f' => 'unlock_type:5',
'n' => $vip['id'] . '_price',
'l' => $vip['title'] . '价格',
'd' => '设置为0或者留空表示当前会员类型免费'
);
$res['hooks']['vip_price'][] = array(
'f' => 'unlock_type:3',
'n' => $vip['id'] . '_price',
'l' => $vip['title'] . '价格',
'd' => '设置为0表示免费,留空则按会员类型里面会员特权选项设置的免费或者折扣自动计算'
);
$res['hooks']['copy_vip_price'][] = array(
'n' => $vip['id'] . '_copy_post_price',
'l' => $vip['title'] . '价格',
'd' => '设置为0表示免费,留空则按会员类型里面会员特权选项设置的免费或者折扣自动计算'
);
}
}
}
return $res;
}
public function vip_order_types($types){
$_types = self::get_vip_types();
if(!empty($_types)){
$types['vip-new'] = '会员开通';
$types['vip-renew'] = '会员续费';
$types['vip-upgrade'] = '会员升级';
}
return $types;
}
public function get_roles($res, $taxs){
if( current_user_can( 'edit_posts' ) ){
foreach ($taxs as $tax){
if($tax && $tax === 'wp_roles') {
$_roles = wp_roles();
$roles = $_roles->role_names;
if(!empty($roles)){
foreach ($roles as $name => $role) {
$roles[$name] = translate_user_role($role);
}
}
$res[$tax] = $roles;
}
}
}
return $res;
}
public function for_rest_api(){
register_rest_route('wpcom/v1', '/vip', array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'rest_get_vip_data'),
'args' => $this->rest_get_params(),
'permission_callback' => array( $this, 'rest_permission_check' )
),
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array($this, 'rest_create_vip_order'),
'args' => $this->rest_post_params(),
'permission_callback' => array( $this, 'rest_permission_check' )
)
));
register_rest_route('wpcom/v1', '/vip-unlock', array(
array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array($this, 'rest_vip_unlock'),
'args' => array(
'type' => array(
'type' => 'string',
'required' => true
),
'post_id' => array(
'type' => 'integer',
'required' => true
),
'id' => array(
'type' => 'string'
),
'items' => array(
'required' => true,
'type' => 'array',
'validate_callback' => 'rest_validate_request_arg',
'items' => array(
'type' => 'object',
'properties' => array(
'title' => array(
'type' => 'string'
),
'number' => array(
'type' => 'integer',
'default' => 1
),
'price' => array(
'type' => 'string',
'required' => true
),
'type' => array(
'type' => 'string',
'required' => true
),
'type_id' => array(
'type' => 'string',
'required' => true
),
'url' => array(
'type' => 'string'
)
)
)
),
'total' => array(
'type' => 'string',
'required' => true
),
'sign' => array(
'type' => 'string',
'required' => true
),
'timestamp' => array(
'type' => 'integer',
'required' => true
)
),
'permission_callback' => array( $this, 'rest_permission_check' )
)
));
}
function rest_get_params(){
return array(
'type' => array(
'required' => true,
'type' => 'string',
'enum' => array('new', 'renew', 'upgrade'),
'validate_callback' => 'rest_validate_request_arg',
)
);
}
function rest_post_params(){
return array(
'action_type' => array(
'required' => true,
'type' => 'string',
'enum' => array('new', 'renew', 'upgrade'),
'validate_callback' => 'rest_validate_request_arg',
),
'vip_type' => array(
'required' => true,
'default' => '',
'type' => 'string',
'validate_callback' => 'rest_validate_request_arg',
),
'vip_lifetime' => array(
'default' => '',
'type' => 'string',
'validate_callback' => 'rest_validate_request_arg',
)
);
}
function rest_get_vip_data($request){
$res = array('result' => 0);
$user_id = get_current_user_id();
$type = isset($request['type']) ? sanitize_text_field($request['type']) : 'new';
if($user_id){
$current_vip = self::get_user_vip();
if($current_vip && $type === 'new'){
$res['result'] = -3;
$res['msg'] = '您已是会员,无需重复开通!';
}else if(!$current_vip && $type !== 'new'){
$res['result'] = -4;
$res['msg'] = '您还不是会员,无法执行此操作!';
}else if($type === 'upgrade' && !$this->vip_can_upgrade($current_vip)){
$res['result'] = -5;
$res['msg'] = '抱歉,当前会员类型无法执行升级操作!';
}else if($current_vip && $type === 'renew' && $this->is_lifetime_vip($current_vip['expired'])){
$res['result'] = -6;
$res['msg'] = '抱歉,您已经是终身会员了!';
}else{
$vip_types = self::get_vip_types();
if($vip_types && !empty($vip_types)){
if($current_vip && isset($current_vip['expired'])){
$datetime = date_create($current_vip['expired'], wp_timezone());
$current_vip['expired'] = $datetime;
}
if($type === 'upgrade'){
$pass = false;
foreach($vip_types as $key => $val){
if($key === $current_vip['id'] || !$pass){
unset($vip_types[$key]);
$pass = true;
} else {
// 计算升级差价
$vip_types[$key]['upgrade_price'] = $this->vip_upgrade_price($current_vip, $val);
}
}
}
if($type === 'renew' || $type === 'upgrade') {
$res['current_vip'] = $current_vip;
$res['current_vip']['expired'] = $current_vip['expired']->getTimestamp();
}
$_vip_types = array();
foreach($vip_types as $vtype){
$_vip_types[] = $vtype;
}
$res['data'] = $_vip_types;
if($type === 'new'){
$res['timestamp'] = current_time('timestamp', 1);
}else if($current_vip['expired']){
$res['timestamp'] = $current_vip['expired']->getTimestamp();
}
}else{
$res['result'] = -2;
$res['msg'] = '暂无可开通的会员类型,请联系网站管理员';
}
}
}else{
$res['result'] = -1;
}
return rest_ensure_response( $res );
}
function rest_create_vip_order($request){
$_POST = $_POST ?: array();
$_POST['action_type'] = $request['action_type'];
$_POST['vip_type'] = $request['vip_type'];
$_POST['vip_lifetime'] = $request['vip_lifetime'];
$data = $this->get_vip_data(true);
$data['nonce'] = wp_create_nonce('wpcom_payment_form');
return rest_ensure_response( $data );
}
function rest_vip_unlock($request){
$_POST = $request;
$this->vip_unlock();
}
function rest_permission_check(){
if ( get_current_user_id() ) {
return true;
} else {
return new \WP_Error( 'rest_user_cannot_view', '请登录后操作!', array( 'status' => 200 ) );
}
}
function rest_user_metas($metas, $object){
if($object['id'] && $object['id'] === get_current_user_id()){
$vip = self::get_user_vip($object['id']);
$metas['vip'] = false;
if($vip && isset($vip['id'])){
$metas['vip'] = array(
'index' => $vip['index'],
'id' => $vip['id'],
'icon' => $vip['icon'],
'title' => $vip['title'],
'expired' => $vip['expired'],
'upgrade' => self::vip_can_upgrade($vip)
);
}
}
return $metas;
}
function pre_insert_post($data, $attr, $rest = 0){
global $wpdb, $post_notice;
$user = wp_get_current_user();
if($user && $user->ID && $data && isset($data['post_status']) && in_array($data['post_status'], ['pending', 'publish']) && !current_user_can('edit_others_posts')){
$options = $GLOBALS['wpmx_options'];
$vip = $this->get_user_vip($user->ID);
$privileges = $vip && isset($vip['privileges']) ? $vip['privileges'] : false;
$default_day_post_limit = isset($options['default_day_post_limit']) ? $options['default_day_post_limit'] : -1;
$default_month_post_limit = isset($options['default_month_post_limit']) ? $options['default_month_post_limit'] : -1;
$per_day = $privileges && isset($privileges['day_post_limit']) ? $privileges['day_post_limit'] : $default_day_post_limit;
$per_month = $privileges && isset($privileges['month_post_limit']) ? $privileges['month_post_limit'] : $default_month_post_limit;
$stop = 0;
$post_id = isset($attr['ID']) ? $attr['ID'] : 0;
// 月或者日额度为0则为不允许发布
if($per_day == 0 || $per_month == 0) $stop = 1;
if($stop === 0 && $per_day > 0 && is_numeric($per_day)){
$sql_day = $wpdb->prepare("SELECT count(ID) FROM $wpdb->posts WHERE post_status IN ('pending', 'publish') AND post_type = 'post' AND post_author = %d AND ID != %d AND DATE_FORMAT(post_date, '%%Y-%%m-%%d') = %s", array($user->ID, $post_id, wp_date('Y-m-d', current_time('timestamp', 1))));
$_day = $wpdb->get_var( $sql_day );
if($_day && $_day >= $per_day){
$stop = 1;
}
}
if($stop === 0 && $per_month > 0 && is_numeric($per_month)){
$sql_month = $wpdb->prepare("SELECT count(ID) FROM $wpdb->posts WHERE post_status IN ('pending', 'publish') AND post_type = 'post' AND post_author = %d AND ID != %d AND DATE_FORMAT(post_date, '%%Y-%%m') = %s", array($user->ID, $post_id, wp_date('Y-m', current_time('timestamp', 1))));
$_month = $wpdb->get_var( $sql_month );
if($_month && $_month >= $per_month){
$stop = 1;
}
}
if ( $stop ){
$post_notice = isset($options['post_limit_msg']) && $options['post_limit_msg'] ? $options['post_limit_msg'] : '发布失败:超出发帖限额';
$post_save = isset($options['post_limit_save']) && $options['post_limit_save'] == '1' ? false : true;
$data['post_status'] = $post_save ? 'draft' : 'inherit';
if($rest){
$err = new \WP_Error( 'vip_publish_limit', $post_notice);
$err->add_data( array( 'status' => 400 ) );
return $err;
}else{
add_filter('redirect_post_location', array( $this, 'redirect_post_location_filter'), 99);
}
}
}
return $data;
}
function rest_pre_insert_post($post){
$_post = json_decode(json_encode($post), true);
$res = $this->pre_insert_post($_post, $_post, 1);
if(is_wp_error($res)){
return $res;
}else{
return $post;
}
}
function redirect_post_location_filter($location){
remove_filter('redirect_post_location', __FUNCTION__, 99);
$location = add_query_arg('message', 8899, $location);
return $location;
}
function post_limit_error(){
if(isset( $_GET['message'] ) && isset( $_GET['post'] ) && $_GET['message'] == '8899'){
$options = $GLOBALS['wpmx_options'];
$post_notice = isset($options['post_limit_msg']) && $options['post_limit_msg'] ? $options['post_limit_msg'] : '发布失败:超出发帖限额'; ?>
<div class="notice error is-dismissible" >
<?php echo wp_kses_post(wpautop($post_notice));?>
</div>
<?php }
}
function tougao_notice($notice, $post){
global $post_notice;
$options = $GLOBALS['wpmx_options'];
if(!isset($post_notice) && $post->post_status === 'inherit'){
$post_notice = isset($options['post_limit_msg']) && $options['post_limit_msg'] ? $options['post_limit_msg'] : '发布失败:超出发帖限额';
}
if($post_notice && $post && isset($post->post_status) && ($post->post_status === 'draft' || $post->post_status === 'inherit')){
$notice = '<div class="wpcom-alert alert-warning alert-dismissible fade in" role="alert">';
$notice .= '<div class="wpcom-close" data-wpcom-dismiss="alert" aria-label="Close">' . wpmx_icon('close', 0) . '</div>';
$notice .= $post_notice;
$notice .= '</div>';
}
return $notice;
}
public static function get_total_vip($period = 'total', $start = '', $end = '') {
global $wpdb;
$prefix = $wpdb->get_blog_prefix();
$today = current_time('Y-m-d');
$cache_key = 'wpcom_total_vip_' . substr(md5(serialize([$period, $start, $end])), 0, 12);
$cached = get_transient($cache_key);
if ($cached !== false) {
return $cached;
}
$types = self::get_vip_types();
if (empty($types)) {
return $period === 'total' ? ['total' => 0, 'active' => 0] : 0;
}
$vip_type_ids = array_map('strval', array_keys($types));
// 构建 SQL 条件
$conditions = [
$wpdb->prepare("vt.meta_value IN (" . implode(',', array_fill(0, count($vip_type_ids), '%s')) . ")", ...$vip_type_ids)
];
if ($period !== 'total' || $start || $end) {
if (!$start && !$end) {
if ($period === 'today') {
$start = $today;
$end = $today;
} elseif ($period === 'month') {
$start = date_i18n('Y-m-01');
$end = $today;
} elseif ($period === 'year') {
$start = date_i18n('Y-01-01');
$end = $today;
}
}
$start_full = $start && strlen($start) === 10 ? $start . ' 00:00:00' : $start;
$end_full = $end && strlen($end) === 10 ? $end . ' 23:59:59' : $end;
if ($start_full && $end_full) {
$conditions[] = $wpdb->prepare("vb.meta_value BETWEEN %s AND %s", $start_full, $end_full);
} elseif ($start_full) {
$conditions[] = $wpdb->prepare("vb.meta_value >= %s", $start_full);
} elseif ($end_full) {
$conditions[] = $wpdb->prepare("vb.meta_value <= %s", $end_full);
}
}
$where = implode(' AND ', $conditions);
// 构建 SQL:JOIN vip_type, vip_begin_date, vip_end_date
$sql = "
SELECT
COUNT(DISTINCT vt.user_id) as total,
COUNT(DISTINCT CASE WHEN ve.meta_value >= %s THEN ve.user_id ELSE NULL END) as active
FROM {$wpdb->usermeta} vt
LEFT JOIN {$wpdb->usermeta} vb ON vb.user_id = vt.user_id AND vb.meta_key = %s
LEFT JOIN {$wpdb->usermeta} ve ON ve.user_id = vt.user_id AND ve.meta_key = %s
WHERE vt.meta_key = %s AND $where
";
$result = $wpdb->get_row(
$wpdb->prepare(
$sql,
$today,
$prefix . 'vip_begin_date',
$prefix . 'vip_end_date',
$prefix . 'vip_type'
),
ARRAY_A
);
$data = $period === 'total'
? ['total' => (int) ($result['total'] ?? 0), 'active' => (int) ($result['active'] ?? 0)]
: (int) ($result['total'] ?? 0);
// 缓存 10 分钟
set_transient($cache_key, $data, MINUTE_IN_SECONDS * 10);
return $data;
}
}
class_alias(VIP::class, 'WPCOM_VIP');
new VIP();