diff --git a/api/functions.php b/api/functions.php index 67f884f..1aa62d5 100644 --- a/api/functions.php +++ b/api/functions.php @@ -27,7 +27,6 @@ function rua_get_user($user = null) /** * @since 2.1 * @param WP_Post|int $post - * * @return RUA_Level_Interface * @throws Exception */ @@ -48,22 +47,69 @@ function rua_get_level($post) * @since 2.1 * @param RUA_Level_Interface|WP_Post|int $level * @param RUA_User_Interface|WP_User|int|null $user null or omit for current user - * * @return RUA_User_Level_Interface + * @throws Exception */ function rua_get_user_level($level, $user = null) { + _deprecated_function(__FUNCTION__, '2.5', 'rua_get_user_levels()'); + if (!($level instanceof RUA_Level_Interface)) { $level = rua_get_level($level); } + if (!($user instanceof RUA_User_Interface)) { + $user = rua_get_user($user); + } + return $user->level_memberships()->get($level->get_id()); +} +/** + * @param RUA_User_Interface|WP_User|int|null $user null or omit for current user + * @return RUA_Collection + */ +function rua_get_user_levels($user) +{ if (!($user instanceof RUA_User_Interface)) { $user = rua_get_user($user); } - $user_level = new RUA_User_Level($user, $level); - $user_level->refresh(); - return $user_level; + $entities = get_comments([ + 'type' => 'rua_member', + 'user_id' => $user->get_id() + ]); + + $user_levels = new RUA_Collection(); + foreach ($entities as $entity) { + $user_level = new RUA_User_Level($entity); + $user_level->refresh(); + $user_levels->put($user_level->get_level_id(), $user_level); + } + return $user_levels; +} + +/** + * @param RUA_Level_Interface|WP_Post|int $level + * @param array $query + * @return RUA_Collection + * @throws Exception + */ +function rua_get_level_members($level, $query = []) +{ + if (!($level instanceof RUA_Level_Interface)) { + $level = rua_get_level($level); + } + + $query['type'] = 'rua_member'; + $query['status'] = [RUA_User_Level::STATUS_ACTIVE, RUA_User_Level::STATUS_EXPIRED]; + $query['post_id'] = $level->get_id(); + $entities = get_comments($query); + + $user_levels = new RUA_Collection(); + foreach ($entities as $entity) { + $user_level = new RUA_User_Level($entity); + $user_levels->put($user_level->get_user_id(), $user_level); + } + return $user_levels; } /** @@ -84,7 +130,7 @@ function rua_get_level_by_name($name) */ function rua_get_level_caps($level_id, $hierarchical = false) { - $levels = [ $level_id ]; + $levels = [$level_id]; if ($hierarchical) { $levels = array_merge($levels, get_post_ancestors((int) $level_id)); $levels = array_reverse($levels); diff --git a/db_updates.php b/db_updates.php index f85a0b2..ab339d6 100644 --- a/db_updates.php +++ b/db_updates.php @@ -18,6 +18,77 @@ $rua_db_updater->register_version_update('2.2.1', 'rua_update_to_221'); $rua_db_updater->register_version_update('2.4', 'rua_update_to_24'); $rua_db_updater->register_version_update('2.4.2', 'rua_update_to_242'); +$rua_db_updater->register_version_update('2.5', 'rua_update_to_25'); + +function rua_update_to_25() +{ + global $wpdb; + + $level_id_lookup = array_flip((array)$wpdb->get_col(" + SELECT ID FROM $wpdb->posts WHERE post_type = 'restriction' + ")); + $existing_user_level_lookup = array_flip((array)$wpdb->get_col(" + SELECT CONCAT(user_id, ':', comment_post_ID) FROM $wpdb->comments WHERE comment_type = 'rua_member' + ")); + + $blog_prefix = $wpdb->get_blog_prefix(); + $query = <<usermeta um +INNER JOIN $wpdb->usermeta u ON um.user_id = u.user_id AND u.meta_key = '{$blog_prefix}capabilities' +WHERE um.meta_key LIKE '_ca_level%' +QUERY; + + $usermeta = $wpdb->get_results($query); + + $data_new = []; + $data_meta_map = []; + + foreach ($usermeta as $meta) { + if ($meta->meta_key === '_ca_level') { + if (!isset($level_id_lookup[$meta->meta_value])) { + continue; + } + //prevent dupe + if (isset($existing_user_level_lookup[$meta->user_id . ':' . $meta->meta_value])) { + continue; + } + + $data_new[] = [ + 'comment_approved' => 'active', + 'comment_date' => '', + 'comment_type' => 'rua_member', + 'user_id' => $meta->user_id, + 'comment_post_ID' => $meta->meta_value, + 'comment_meta' => [], + ]; + } else { + $data_meta_map[$meta->user_id . ':' . $meta->meta_key] = $meta->meta_value; + } + } + + foreach ($data_new as $data) { + $user_id = $data['user_id']; + $level_id = $data['comment_post_ID']; + $insert = $data; + + //start date + if (isset($data_meta_map[$user_id . ':_ca_level_' . $level_id])) { + $insert['comment_date'] = date_i18n('Y-m-d H:i:s', $data_meta_map[$user_id . ':_ca_level_' . $level_id]); + } + //status + if (isset($data_meta_map[$user_id . ':_ca_level_status_' . $level_id])) { + $insert['comment_approved'] = $data_meta_map[$user_id . ':_ca_level_status_' . $level_id]; + } + //expiry date + if (isset($data_meta_map[$user_id . ':_ca_level_expiry_' . $level_id])) { + $insert['comment_meta']['_ca_member_expiry'] = $data_meta_map[$user_id . ':_ca_level_expiry_' . $level_id]; + } + + wp_insert_comment($insert); + wp_update_comment_count($level_id); + } +} /** * Enable legacy date module and diff --git a/level.php b/level.php index b5a5ab3..9a62c03 100644 --- a/level.php +++ b/level.php @@ -47,6 +47,10 @@ protected function add_actions() 'user_register', [$this,'registered_add_level'] ); + add_action( + 'parse_comment_query', + [$this, 'exclude_comment_type'] + ); } /** @@ -72,10 +76,40 @@ protected function add_filters() add_action('auth_redirect', [$this, 'authorize_admin_access']); } + add_filter( + 'pre_wp_update_comment_count_now', + [$this, 'update_member_count'], + 10, + 3 + ); + add_filter('get_edit_post_link', [$this,'get_edit_post_link'], 10, 3); add_filter('get_delete_post_link', [$this,'get_delete_post_link'], 10, 3); } + public function update_member_count($new, $old, $post_id) + { + $post = get_post($post_id); + if ($post->post_type !== RUA_App::TYPE_RESTRICT) { + return $new; + } + + global $wpdb; + return (int) $wpdb->get_var($wpdb->prepare("SELECT COUNT(*) FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id)); + } + + public function exclude_comment_type($query) + { + $type = 'rua_member'; + if (in_array($type, (array) $query->query_vars['type']) || + in_array($type, (array) $query->query_vars['type__in'])) { + return; + } + + $query->query_vars['type__not_in'] = (array) $query->query_vars['type__not_in']; + $query->query_vars['type__not_in'][] = $type; + } + /** * @param int $user_id * @return void diff --git a/list-members.php b/list-members.php index d67dadf..8bc2d15 100644 --- a/list-members.php +++ b/list-members.php @@ -305,13 +305,33 @@ public function prepare_items() $per_page = $this->get_items_per_page('members_per_page', 20); $current_page = $this->get_pagenum(); - $user_query = new WP_User_Query([ - 'meta_key' => RUA_App::META_PREFIX . 'level', - 'meta_value' => $this->level_id, - 'number' => $per_page, - 'offset' => ($current_page - 1) * $per_page + + $user_ids = ''; + if (!empty($_GET['s'])) { + $query_params['fields'] = 'ID'; + $query_params['count_total'] = false; + $query_params['search'] = '*' . $_GET['s'] . '*'; + $query_params['orderby'] = 'ID'; + if (false !== strpos($_GET['s'], '@')) { + $query_params['search_columns'] = ['user_email']; + } elseif (is_numeric($_GET['s'])) { + $query_params['search_columns'] = ['user_login', 'ID']; + } else { + $query_params['search_columns'] = ['user_nicename', 'user_login', 'display_name']; + } + $user_query = new WP_User_Query($query_params); + $user_ids = $user_query->get_results(); + } + + $total_items = get_comments([ + 'number' => 0, + 'offset' => 0, + 'user_id' => $user_ids, + 'count' => true, + 'post_id' => $this->level_id, + 'type' => 'rua_member', + 'status' => [RUA_User_Level::STATUS_ACTIVE, RUA_User_Level::STATUS_EXPIRED] ]); - $total_items = (int)$user_query->get_total(); $this->set_pagination_args([ 'total_items' => $total_items, @@ -319,10 +339,11 @@ public function prepare_items() 'per_page' => $per_page ]); - $this->items = []; - foreach ($user_query->get_results() as $user) { - $this->items[] = rua_get_user_level($this->level_id, $user); - } + $this->items = rua_get_level_members($this->level_id, [ + 'number' => $per_page, + 'offset' => ($current_page - 1) * $per_page, + 'user_id' => $user_ids + ])->all(); } /** diff --git a/models/user.php b/models/user.php index 1aea495..d03e6ea 100644 --- a/models/user.php +++ b/models/user.php @@ -14,7 +14,7 @@ class RUA_User implements RUA_User_Interface private $wp_user; /** - * @var RUA_Collection|RUA_User_Level[]|null + * @var RUA_Collection|RUA_User_Level_Interface[]|null */ private $level_memberships; @@ -65,22 +65,7 @@ public function has_global_access() public function level_memberships() { if (is_null($this->level_memberships)) { - $user_id = $this->get_id(); - $level_ids = []; - - if ($user_id) { - $level_ids = (array)get_user_meta($user_id, RUA_App::META_PREFIX . 'level', false); - } - - $this->level_memberships = new RUA_Collection(); - $level_ids = array_unique($level_ids); - foreach ($level_ids as $level_id) { - $level_id = (int)$level_id; - try { - $this->level_memberships->put($level_id, rua_get_user_level($level_id, $this)); - } catch (Exception $e) { - } - } + $this->level_memberships = rua_get_user_levels($this); } return $this->level_memberships; } @@ -122,20 +107,26 @@ public function get_level_ids( */ public function add_level($level_id) { - if($this->level_memberships()->has($level_id)) { + if ($this->level_memberships()->has($level_id)) { /** @var RUA_User_Level_Interface $user_level */ $user_level = $this->level_memberships()->get($level_id); + $user_level->update_status(RUA_User_Level::STATUS_ACTIVE); + $event = 'extended'; } else { - add_user_meta($this->get_id(), RUA_App::META_PREFIX . 'level', $level_id, false); - $user_level = rua_get_user_level($level_id, $this); - $user_level->update_start(time()); + $user_level = new RUA_User_Level(get_comment(wp_insert_comment([ + 'comment_approved' => RUA_User_Level::STATUS_ACTIVE, + 'comment_type' => 'rua_member', + 'user_id' => $this->get_id(), + 'comment_post_ID' => $level_id, + 'comment_meta' => [], + ]))); $this->level_memberships()->put($level_id, $user_level); + $event = 'added'; } - $user_level->update_status(RUA_User_Level::STATUS_ACTIVE); $user_level->reset_expiry(); $this->reset_caps_cache(); - do_action('rua/user_level/added', $this, $level_id); + do_action('rua/user_level/' . $event, $this, $level_id); return true; } @@ -145,15 +136,14 @@ public function add_level($level_id) */ public function remove_level($level_id) { - $user_id = $this->get_id(); - $this->reset_caps_cache(); - $deleted = delete_user_meta($user_id, RUA_App::META_PREFIX . 'level', $level_id); - - delete_user_meta($user_id, RUA_App::META_PREFIX . 'level_' . $level_id); - delete_user_meta($user_id, RUA_App::META_PREFIX . 'level_status_' . $level_id); - delete_user_meta($user_id, RUA_App::META_PREFIX . 'level_expiry_' . $level_id); + $level = $this->level_memberships()->get($level_id); + if (!($level instanceof RUA_User_Level_Interface)) { + return false; + } + $deleted = $level->delete(); if ($deleted) { + $this->reset_caps_cache(); $this->level_memberships()->remove($level_id); do_action('rua/user_level/removed', $this, $level_id); } diff --git a/models/user_level.php b/models/user_level.php index c291a4e..6c364b2 100644 --- a/models/user_level.php +++ b/models/user_level.php @@ -11,35 +11,25 @@ class RUA_User_Level implements RUA_User_Level_Interface const STATUS_ACTIVE = 'active'; const STATUS_EXPIRED = 'expired'; - const KEY_STATUS = 'level_status'; - const KEY_START = 'level'; - const KEY_EXPIRY = 'level_expiry'; - - /** - * @var RUA_User_Interface - */ + /** @var RUA_User_Interface */ private $user; - - /** - * @var RUA_Level_Interface - */ + /** @var RUA_Level_Interface */ private $level; + /** @var WP_Comment */ + private $wp_entity; /** - * @since 2.1 - * @param RUA_User_Interface $user - * @param RUA_Level_Interface $level + * @param WP_Comment $wp_entity */ - public function __construct(RUA_User_Interface $user, RUA_Level_Interface $level) + public function __construct(WP_Comment $wp_entity) { - $this->user = $user; - $this->level = $level; + $this->wp_entity = $wp_entity; } public function refresh() { if ($this->is_active() && $this->is_expired()) { - $this->update_meta(self::KEY_STATUS, self::STATUS_EXPIRED); + $this->update_status(self::STATUS_EXPIRED); } } @@ -48,7 +38,7 @@ public function refresh() */ public function get_user_id() { - return $this->user()->get_id(); + return (int)$this->wp_entity->user_id; } /** @@ -56,6 +46,9 @@ public function get_user_id() */ public function user() { + if (!($this->user instanceof RUA_User_Interface)) { + $this->user = rua_get_user($this->get_user_id()); + } return $this->user; } @@ -64,7 +57,7 @@ public function user() */ public function get_level_id() { - return $this->level()->get_id(); + return (int)$this->wp_entity->comment_post_ID; } /** @@ -80,6 +73,9 @@ public function get_level_extend_ids() */ public function level() { + if (!($this->level instanceof RUA_Level_Interface)) { + $this->level = rua_get_level($this->get_level_id()); + } return $this->level; } @@ -88,15 +84,7 @@ public function level() */ public function get_status() { - $status = $this->get_meta(self::KEY_STATUS); - - //fallback to calc - if (is_null($status)) { - $status = $this->is_expired() ? self::STATUS_EXPIRED : self::STATUS_ACTIVE; - $this->update_status($status); - } - - return $status; + return $this->wp_entity->comment_approved; } /** @@ -104,7 +92,21 @@ public function get_status() */ public function update_status($status) { - $this->update_meta(self::KEY_STATUS, $status); + if ($this->get_status() === $status) { + return $this; + } + + global $wpdb; + + $updated = $wpdb->update($wpdb->comments, ['comment_approved' => $status], ['comment_ID' => $this->wp_entity->comment_ID]); + if (!$updated) { + return $this; + } + + clean_comment_cache($this->wp_entity->comment_ID); + wp_update_comment_count($this->get_level_id()); + $this->wp_entity->comment_approved = $status; + return $this; } @@ -113,7 +115,7 @@ public function update_status($status) */ public function get_start() { - return (int)$this->get_meta(self::KEY_START, 0); + return strtotime($this->wp_entity->comment_date_gmt); } /** @@ -121,7 +123,19 @@ public function get_start() */ public function update_start($start) { - $this->update_meta(self::KEY_START, (int) $start); + if ($this->get_start() === $start) { + return $this; + } + + $date = date_i18n('Y-m-d H:i:s', $start); + $updated = wp_update_comment([ + 'comment_ID' => $this->wp_entity->comment_ID, + 'comment_date' => $date + ]); + if ($updated) { + $this->wp_entity->comment_date = $date; + $this->wp_entity->comment_date_gmt = get_gmt_from_date($date); + } return $this; } @@ -130,9 +144,9 @@ public function update_start($start) */ public function get_expiry() { - $expiry = $this->get_meta(self::KEY_EXPIRY); - if ($expiry) { - return (int) $expiry; + $unixtime = get_comment_meta($this->wp_entity->comment_ID, '_ca_member_expiry', true); + if (!empty($unixtime)) { + return (int) $unixtime; } //fallback to calc @@ -140,7 +154,7 @@ public function get_expiry() $duration = RUA_App::instance()->level_manager->metadata()->get('duration')->get_data($this->level()->get_id()); if (isset($duration['count'],$duration['unit']) && $time && $duration['count']) { $time = strtotime('+' . $duration['count'] . ' ' . $duration['unit'] . ' 23:59', $time); - $this->update_meta(self::KEY_EXPIRY, $time); + $this->update_expiry($time); return $time; } @@ -152,7 +166,7 @@ public function get_expiry() */ public function update_expiry($expiry) { - $this->update_meta(self::KEY_EXPIRY, (int) $expiry); + update_comment_meta($this->wp_entity->comment_ID, '_ca_member_expiry', $expiry); return $this; } @@ -189,33 +203,17 @@ public function can_add() /** * @return bool */ - private function is_expired() - { - $time_expire = $this->get_expiry(); - return $time_expire && time() > $time_expire; - } - - /** - * @since 1.0 - * @param string $key - * @param mixed|null $default_value - * - * @return mixed|null - */ - private function get_meta($key, $default_value = null) + public function delete() { - return $this->user()->get_attribute(RUA_App::META_PREFIX . $key . '_' . $this->get_level_id(), $default_value); + return wp_delete_comment($this->wp_entity, true); } /** - * @param string $key - * @param mixed $value - * * @return bool */ - private function update_meta($key, $value) + private function is_expired() { - $user_id = $this->get_user_id(); - return (bool)update_user_meta($user_id, RUA_App::META_PREFIX . $key . '_' . $this->get_level_id(), $value); + $time_expire = $this->get_expiry(); + return $time_expire && time() > $time_expire; } }