PluginProbe ʕ •ᴥ•ʔ
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress / trunk
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress vtrunk
4.16.18 4.16.17 4.16.16 trunk 1.0 1.0.1 1.0.2 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5a 1.1.6 1.1.7 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4 1.4.1 1.4.2 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.7 1.7.1 1.7.2 1.8 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.1.9 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.2 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 3.0 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.13.3 4.13.4 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.15.0 4.15.1 4.15.10 4.15.11 4.15.12 4.15.13 4.15.14 4.15.15 4.15.16 4.15.17 4.15.18 4.15.19 4.15.2 4.15.20 4.15.20.1 4.15.21 4.15.22 4.15.23 4.15.24 4.15.25 4.15.3 4.15.4 4.15.5 4.15.6 4.15.7 4.15.8 4.15.9 4.16.0 4.16.1 4.16.10 4.16.11 4.16.12 4.16.13 4.16.14 4.16.15 4.16.2 4.16.3 4.16.4 4.16.5 4.16.6 4.16.7 4.16.8 4.16.9 4.2.0 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.7.0 4.8.0 4.9.0
wp-user-avatar / src / ContentProtection / Frontend / SearchAndAPI.php
wp-user-avatar / src / ContentProtection / Frontend Last commit date
Checker.php 1 year ago PostContent.php 9 months ago Redirect.php 1 year ago RestrictionShortcode.php 3 months ago SearchAndAPI.php 1 year ago index.php 5 years ago restricted-template.php 1 year ago
SearchAndAPI.php
317 lines
1 <?php
2
3 namespace ProfilePress\Core\ContentProtection\Frontend;
4
5 use ProfilePress\Core\Classes\PROFILEPRESS_sql;
6 use ProfilePress\Core\ContentProtection\SettingsPage;
7
8 class SearchAndAPI
9 {
10 public function __construct()
11 {
12 add_action('pre_get_posts', [$this, 'exclude_protected_posts']);
13 }
14
15 public function exclude_protected_posts($query)
16 {
17 // Determine if this query is for a frontend WP search or a REST API search.
18 if (
19 apply_filters('ppress_is_search_and_api_exclude_posts', true) &&
20 (
21 ( ! is_admin() && $query->is_main_query() && $query->is_search()) ||
22 (defined('REST_REQUEST') && REST_REQUEST && strpos($_SERVER['REQUEST_URI'], '/wp/v2/search') !== false)
23 )
24 ) {
25
26 $metas = PROFILEPRESS_sql::get_meta_data_by_key(SettingsPage::META_DATA_KEY);
27
28 if (is_array($metas)) {
29
30 foreach ($metas as $meta) {
31
32 $meta = ppress_var($meta, 'meta_value', []);
33
34 if ( ! in_array(ppress_var($meta, 'is_active', true), ['true', true], true)) continue;
35
36 $access_condition = ppress_var($meta, 'access_condition', []);
37
38 $who_can_access = ppress_var($access_condition, 'who_can_access', 'everyone');
39
40 $access_roles = ppress_var($access_condition, 'access_roles', []);
41
42 $access_wp_users = ppress_var($access_condition, 'access_wp_users', []);
43
44 $access_membership_plans = ppress_var($access_condition, 'access_membership_plans', []);
45
46 if (Checker::is_blocked($who_can_access, $access_roles, $access_wp_users, $access_membership_plans)) {
47
48 $restricted_content = $this->get_restricted_post_ids_for_user($meta['content']);
49
50 if ( ! empty($restricted_content['cpt_is_all']) && is_array($restricted_content['cpt_is_all'])) {
51
52 $excluded_post_types = $restricted_content['cpt_is_all'];
53
54 // Get the current post types being queried.
55 $post_type = $query->get('post_type');
56
57 // Retrieve all registered public post types.
58 $all_post_types = get_post_types(['public' => true]);
59
60 // Remove the excluded post types from the list.
61 $allowed_post_types = array_diff($all_post_types, $excluded_post_types);
62
63 if (is_string($post_type) && in_array($post_type, $excluded_post_types, true)) {
64 // If the query explicitly requests an excluded post type, return no posts.
65 // we using 'post__in' => [0] or similar techniques to ensure the query returns no posts. Here's the corrected version:
66 $query->set('post__in', [0]);
67
68 } elseif ($post_type === 'any' || empty($post_type)) {
69 // If querying "any" post type or not specified, exclude the excluded post types.
70 $query->set('post_type', array_values($allowed_post_types));
71
72 } elseif (is_array($post_type)) {
73
74 // If querying multiple post types, exclude the excluded post types.
75 $new_post_type = array_diff($post_type, $excluded_post_types);
76 // if empty array, it means we don't want any post type, so let's use eg 'zznonezz' which does not exist
77 if (empty($new_post_type)) {
78 $new_post_type = 'zznonezz';
79 }
80 $query->set('post_type', $new_post_type);
81 }
82 }
83
84 /* $excluded_posts structure is below
85 [
86 "post" => [
87 10087,
88 10012,
89 ],
90 "page" => [
91 1008,
92 1001,
93 ],
94 ]
95 */
96 $excluded_posts = [];
97
98
99 if ( ! empty($restricted_content['cpt_posts']) && is_array($restricted_content['cpt_posts'])) {
100 $excluded_posts = array_merge_recursive($excluded_posts, $restricted_content['cpt_posts']);
101 }
102
103 if ( ! empty($restricted_content['cpt_post_children']) && is_array($restricted_content['cpt_post_children'])) {
104 $excluded_posts = array_merge_recursive($excluded_posts, $restricted_content['cpt_post_children']);
105 }
106
107 if ( ! empty($restricted_content['cpt_post_parents']) && is_array($restricted_content['cpt_post_parents'])) {
108 $excluded_posts = array_merge_recursive($excluded_posts, $restricted_content['cpt_post_parents']);
109 }
110
111 if ( ! empty($restricted_content['template_cpt_posts']) && is_array($restricted_content['template_cpt_posts'])) {
112 $excluded_posts = array_merge_recursive($excluded_posts, $restricted_content['template_cpt_posts']);
113 }
114
115 if ( ! empty($excluded_posts)) {
116
117 // Get the current post types being queried.
118 $post_type = $query->get('post_type');
119
120 // Build a list of post IDs to exclude based on the query's post types.
121 $post__not_in = $query->get('post__not_in') ?: [];
122
123 if ($post_type === 'any' || empty($post_type)) {
124 // Exclude IDs for all specified post types if no specific post type is queried.
125 $post__not_in = array_merge($post__not_in, ...array_values($excluded_posts));
126
127 } elseif (is_string($post_type) && isset($excluded_posts[$post_type])) {
128 // Exclude IDs for a single queried post type.
129 $post__not_in = array_merge($post__not_in, $excluded_posts[$post_type]);
130 } elseif (is_array($post_type)) {
131 // Exclude IDs for multiple queried post types.
132 foreach ($post_type as $type) {
133 if (isset($excluded_posts[$type])) {
134 $post__not_in = array_merge($post__not_in, $excluded_posts[$type]);
135 }
136 }
137 }
138
139 // Set the updated list of excluded post IDs.
140 $query->set('post__not_in', array_unique($post__not_in));
141 }
142 }
143 }
144 }
145 }
146 }
147
148 private function get_restricted_post_ids_for_user($rule_content)
149 {
150 $cache_key = hash('sha256', wp_json_encode($rule_content));
151
152 $cache_bucket = [];
153
154 if ( ! isset($cache_bucket[$cache_key])) {
155
156 // do not recursively hook our callback again or things will go awry.
157 remove_action('pre_get_posts', [$this, 'exclude_protected_posts']);
158
159 $response = [
160 'cpt_is_all' => [], // array of CPT whose all posts are protected
161 'cpt_posts' => [],
162 'cpt_post_children' => [],
163 'cpt_post_parents' => [],
164 'template_cpt_posts' => []
165 ];
166
167 if (is_array($rule_content) && ! empty($rule_content)) {
168
169 foreach ($rule_content as $group => $conditions) {
170
171 foreach ($conditions as $condition) {
172
173 if (isset($condition['condition'])) {
174
175 if (strstr($condition['condition'], '_all') !== false) {
176 $response['cpt_is_all'][] = str_replace('_all', '', $condition['condition']);
177 }
178
179 if (strstr($condition['condition'], '_selected') !== false && ! empty($condition['value'])) {
180 $cpt = str_replace('_selected', '', $condition['condition']);
181 $existing_val = isset($response['cpt_posts'][$cpt]) && is_array($response['cpt_posts'][$cpt]) ? $response['cpt_posts'][$cpt] : [];
182 $response['cpt_posts'][$cpt] = array_merge($existing_val, array_map('absint', $condition['value']));
183 }
184
185 if (strstr($condition['condition'], '_children') !== false && ! empty($condition['value'])) {
186
187 $parent_posts = array_map('absint', $condition['value']);
188
189 $cpt = str_replace('_children', '', $condition['condition']);
190
191 foreach ($parent_posts as $parent_post_id) {
192 $existing_val = isset($response['cpt_post_children'][$cpt]) && is_array($response['cpt_post_children'][$cpt]) ? $response['cpt_post_children'][$cpt] : [];
193 $response['cpt_post_children'][$cpt] = array_merge($existing_val, $this->get_child_post_ids($parent_post_id, $cpt));
194 }
195 }
196
197 if (strstr($condition['condition'], '_ancestors') !== false && ! empty($condition['value'])) {
198
199 $child_posts = array_map('absint', $condition['value']);
200
201 $cpt = str_replace('_ancestors', '', $condition['condition']);
202
203 foreach ($child_posts as $child_post_id) {
204 $existing_val = isset($response['cpt_post_parents'][$cpt]) && is_array($response['cpt_post_parents'][$cpt]) ? $response['cpt_post_parents'][$cpt] : [];
205 $response['cpt_post_parents'][$cpt] = array_merge($existing_val, $this->get_parent_post_ids($child_post_id));
206 }
207 }
208
209 if (strstr($condition['condition'], '_template') !== false && ! empty($condition['value'])) {
210
211 $templates = $condition['value'];
212
213 $cpt = str_replace('_template', '', $condition['condition']);
214
215 foreach ($templates as $template) {
216 $existing_val = isset($response['template_cpt_posts'][$cpt]) && is_array($response['template_cpt_posts'][$cpt]) ? $response['template_cpt_posts'][$cpt] : [];
217 $response['template_cpt_posts'][$cpt] = array_merge($existing_val, $this->get_post_ids_by_template($template, $cpt));
218 }
219 }
220 }
221 }
222 }
223 }
224
225 $cache_bucket[$cache_key] = $response;
226 }
227
228 return $cache_bucket[$cache_key];
229 }
230
231 /**
232 * Get all child post IDs of a specific parent post ID in WordPress.
233 *
234 * @param int $parent_id The parent post ID.
235 * @param string $post_type The parent post type
236 *
237 * @return array List of child post IDs.
238 */
239 private function get_child_post_ids($parent_id, $post_type): array
240 {
241 // Validate the parent ID.
242 if ( ! is_numeric($parent_id) || $parent_id <= 0) return [];
243
244 // Query for child posts.
245 $child_posts = new \WP_Query([
246 'post_parent' => $parent_id,
247 'post_type' => $post_type,
248 'posts_per_page' => 1000,
249 'fields' => 'ids',
250 'post_status' => 'any'
251 ]);
252
253 return $child_posts->posts;
254 }
255
256 /**
257 * Get all parent post IDs of a specific post ID in WordPress.
258 *
259 * @param int $post_id The ID of the post.
260 *
261 * @return array List of parent post IDs (from closest to root).
262 */
263 private function get_parent_post_ids($post_id)
264 {
265 if ( ! is_numeric($post_id) || $post_id <= 0) return [];
266
267 return get_post_ancestors($post_id);
268 }
269
270 /**
271 * Get all post IDs using a specific template file.
272 *
273 * @param string $template_filename The filename of the template (e.g., 'template-custom.php').
274 * @param string $post_type The post type to filter by (default is 'any').
275 *
276 * @return array List of post IDs using the specified template.
277 */
278 private function get_post_ids_by_template($template_filename, $post_type)
279 {
280 global $wpdb;
281
282 // Sanitize the input.
283 $template_filename = sanitize_text_field($template_filename);
284
285 if (empty($template_filename)) return [];
286
287 // Query for posts with the specified template.
288 $query = $wpdb->prepare(
289 "SELECT p.ID
290 FROM $wpdb->posts p
291 INNER JOIN $wpdb->postmeta pm ON p.ID = pm.post_id
292 WHERE pm.meta_key = '_wp_page_template'
293 AND pm.meta_value = %s
294 AND p.post_type = %s
295 AND p.post_status = 'publish'",
296 $template_filename,
297 $post_type
298 );
299
300 // Fetch results.
301 $post_ids = $wpdb->get_col($query);
302
303 return is_array($post_ids) && ! empty($post_ids) ? $post_ids : [];
304 }
305
306
307 public static function get_instance()
308 {
309 static $instance = null;
310
311 if (is_null($instance)) {
312 $instance = new self();
313 }
314
315 return $instance;
316 }
317 }