PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 260917
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v260917
260917 260913 260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 111216 111220 120213 All 189 releases
s2member / src / includes / classes / utils-gets.inc.php

utils-gets.inc.php in s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions 260917, at src/includes/classes/utils-gets.inc.php

516 lines 26.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // @codingStandardsIgnoreFile
3 /**
4 * Get utilities.
5 *
6 * Copyright: © 2009-2011
7 * {@link http://websharks-inc.com/ WebSharks, Inc.}
8 * (coded in the USA)
9 *
10 * Released under the terms of the GNU General Public License.
11 * You should have received a copy of the GNU General Public License,
12 * along with this software. In the main directory, see: /licensing/
13 * If not, see: {@link http://www.gnu.org/licenses/}.
14 *
15 * @package s2Member\Utilities
16 * @since 3.5
17 */
18 if(!defined('WPINC')) // MUST have WordPress.
19 exit ('Do not access this file directly.');
20
21 if(!class_exists('c_ws_plugin__s2member_utils_gets'))
22 {
23 /**
24 * Get utilities.
25 *
26 * @package s2Member\Utilities
27 * @since 3.5
28 */
29 class c_ws_plugin__s2member_utils_gets
30 {
31 /**
32 * Retrieves a unique array of all Category IDs in the database.
33 *
34 * @package s2Member\Utilities
35 * @since 3.5
36 *
37 * @uses {@link http://codex.wordpress.org/Function_Reference/get_terms get_terms()}
38 *
39 * @return array Unique array of all Category IDs *(as integers)*.
40 */
41 public static function get_all_category_ids()
42 {
43 if(!($category_ids = wp_cache_get('all_category_ids', 'category')))
44 {
45 $category_ids = get_terms('category', array('fields' => 'ids', 'get' => 'all'));
46 wp_cache_add('all_category_ids', $category_ids, 'category');
47 }
48 if(is_array($category_ids)) // Use a WP function for this.
49 $category_ids = c_ws_plugin__s2member_utils_arrays::force_integers((array)$category_ids);
50
51 return (!empty($category_ids) && is_array($category_ids)) ? array_unique($category_ids) : array();
52 }
53
54 /**
55 * Retrieves a unique array of all child Category IDs, within a specific parent Category.
56 *
57 * @package s2Member\Utilities
58 * @since 3.5
59 *
60 * @param int|string $parent_category A numeric Category ID.
61 *
62 * @return array Unique array of all Category IDs *(as integers)* in ``$parent_category``.
63 */
64 public static function get_all_child_category_ids($parent_category = 0)
65 {
66 if(is_numeric($parent_category) && $parent_category && is_array($child_categories = get_categories('child_of='.$parent_category.'&hide_empty=0')))
67 foreach($child_categories as $child_category) // Go through child Categories.
68 $child_category_ids[] = (int)$child_category->term_id;
69
70 return (!empty($child_category_ids) && is_array($child_category_ids)) ? array_unique($child_category_ids) : array();
71 }
72
73 /**
74 * Retrieves a unique array of all Tag IDs in the database.
75 *
76 * @package s2Member\Utilities
77 * @since 3.5
78 *
79 * @return array Unique array of all Tag IDs *(as integers)*.
80 */
81 public static function get_all_tag_ids()
82 {
83 foreach((array)get_tags('hide_empty=0') as $tag)
84 $tag_ids[] = (int)$tag->term_id; // Collect Tag's ID.
85
86 return (!empty($tag_ids) && is_array($tag_ids)) ? array_unique($tag_ids) : array();
87 }
88
89 /**
90 * Converts a comma-delimited list of: Tag slugs/names/ids, into a unique array of all IDs.
91 *
92 * @package s2Member\Utilities
93 * @since 111101
94 *
95 * @param string $tags Tag slugs/names/IDs; comma-delimited.
96 *
97 * @return array Unique array of Tag IDs *(as integers)*. With Tag slugs/names converted to IDs.
98 */
99 public static function get_tags_converted_to_ids($tags = '')
100 {
101 foreach(preg_split('/['."\r\n\t".';,]+/', (string)$tags) as $tag)
102 {
103 if(($tag = trim($tag)) && is_numeric($tag)) // Force integers.
104 $tag_ids[] = ($tag_id = (int)$tag); // Force integer values here.
105
106 else if($tag && is_string($tag)) // A string (i.e., a tag name or a tag slug)?
107 {
108 if(is_object($term = get_term_by('name', $tag, 'post_tag')))
109 $tag_ids[] = (int)$term->term_id;
110
111 else if(is_object($term = get_term_by('slug', $tag, 'post_tag')))
112 $tag_ids[] = (int)$term->term_id;
113 }
114 }
115 return (!empty($tag_ids) && is_array($tag_ids)) ? array_unique($tag_ids) : array();
116 }
117
118 /**
119 * Retrieves a unique array of all published Post IDs in the database.
120 *
121 * @package s2Member\Utilities
122 * @since 3.5
123 *
124 * @param string $post_type Optional. If provided, return all Post IDs of a specific Post Type.
125 * Otherwise, return all Post IDs that are NOT of these Post Types: `page|attachment|nav_menu_item|revision`.
126 *
127 * @return array Unique array of all Post IDs *(as integers)*, including Custom Post Types; or all Post IDs of a specific Post Type.
128 */
129 public static function get_all_post_ids($post_type = '')
130 {
131 /** @var wpdb $wpdb WordPress DB object instance. */
132 global $wpdb; // Global DB object reference.
133
134 //260914.1643 Query-level access checks can request the same published Post IDs many times per page load, so cache each Posts-table/Post-Type combination for this request; including the table keeps switched Multisite blogs isolated.
135 static $_post_ids = array(), $_post_changes = array();
136 $_cache_key = $wpdb->posts.'|'.(string)$post_type;
137
138 //260914.1643 Refresh after normal WordPress post mutations so a write followed by another access check in the same request cannot reuse stale published Post IDs.
139 $_changes = did_action('save_post') + did_action('deleted_post');
140 if(!isset($_post_ids[$_cache_key]) || !isset($_post_changes[$_cache_key]) || $_post_changes[$_cache_key] !== $_changes)
141 {
142 $post_ids = $wpdb->get_col("SELECT `ID` FROM `".$wpdb->posts."` WHERE `post_status` = 'publish' AND ".(($post_type) ? "`post_type` = '".esc_sql((string)$post_type)."'" : "`post_type` NOT IN('page','attachment','nav_menu_item','revision')"));
143 if(is_array($post_ids)) $post_ids = c_ws_plugin__s2member_utils_arrays::force_integers($post_ids);
144
145 $_post_ids[$_cache_key] = (!empty($post_ids) && is_array($post_ids)) ? array_unique($post_ids) : array();
146 $_post_changes[$_cache_key] = $_changes;
147 }
148 return $_post_ids[$_cache_key];
149 }
150
151 /**
152 * Retrieves a unique array of all published Child Post IDs in the database.
153 *
154 * @package s2Member\Utilities
155 * @since 3.5
156 *
157 * @param int|string|array $parent_ids One or more parent IDs to collect children for.
158 *
159 * @param string $post_type Optional. If provided, return all Post IDs of a specific Post Type.
160 * Otherwise, return all Post IDs that are NOT of these Post Types: `page|attachment|nav_menu_item|revision`.
161 *
162 * @return array Unique array of all Child Post IDs *(as integers)*, including Custom Post Types; or all Child Post IDs of a specific Post Type.
163 */
164 public static function get_all_child_post_ids($parent_ids = array(), $post_type = '')
165 {
166 /** @var wpdb $wpdb WordPress DB object instance. */
167 global $wpdb; // Global DB object reference.
168
169 if(($parent_ids = (array)$parent_ids)) // Force an array value.
170 if(is_array($post_ids = $wpdb->get_col("SELECT `ID` FROM `".$wpdb->posts."` WHERE `post_status` = 'publish'".
171 " AND ".($post_type ? "`post_type` = '".esc_sql((string)$post_type)."'" : "`post_type` NOT IN('page','attachment','nav_menu_item','revision')").
172 " AND `post_parent` IN('".implode("','", $parent_ids)."')"))
173 ) $post_ids = c_ws_plugin__s2member_utils_arrays::force_integers($post_ids);
174
175 return (!empty($post_ids) && is_array($post_ids)) ? array_unique($post_ids) : array();
176 }
177
178 /**
179 * Retrieves a unique array of all published Page IDs in the database.
180 *
181 * @package s2Member\Utilities
182 * @since 3.5
183 *
184 * @return array Unique array of all Page IDs *(as integers)*.
185 */
186 public static function get_all_page_ids()
187 {
188 /** @var wpdb $wpdb WordPress DB object instance. */
189 global $wpdb; // Global DB object reference.
190
191 //260914.1643 Query-level access checks can request the complete published Page-ID list repeatedly in one page load, so cache it per Posts table for this request; the table key also isolates switched Multisite blogs.
192 static $_page_ids = array(), $_post_changes = array();
193 $_cache_key = $wpdb->posts;
194
195 //260914.1643 Refresh after normal WordPress post mutations so Pages created, deleted, or changed earlier in this request are reflected by later access checks.
196 $_changes = did_action('save_post') + did_action('deleted_post');
197 if(!isset($_page_ids[$_cache_key]) || !isset($_post_changes[$_cache_key]) || $_post_changes[$_cache_key] !== $_changes)
198 {
199 $page_ids = $wpdb->get_col("SELECT `ID` FROM `".$wpdb->posts."` WHERE `post_status` = 'publish' AND `post_type` = 'page'");
200 if(is_array($page_ids)) $page_ids = c_ws_plugin__s2member_utils_arrays::force_integers($page_ids);
201
202 $_page_ids[$_cache_key] = (!empty($page_ids) && is_array($page_ids)) ? array_unique($page_ids) : array();
203 $_post_changes[$_cache_key] = $_changes;
204 }
205 return $_page_ids[$_cache_key];
206 }
207
208 /**
209 * Retrieves a unique array of all Singular IDs in the database that require Custom Capabilities.
210 *
211 * @package s2Member\Utilities
212 * @since 111101
213 *
214 * @return array Unique array of all Singular IDs *(as integers)* that require Custom Capabilities.
215 */
216 public static function get_all_singular_ids_with_ccaps()
217 {
218 /** @var wpdb $wpdb WordPress DB object instance. */
219 global $wpdb; // Global DB object reference.
220
221 if(is_array($singular_ids = $wpdb->get_col("SELECT `post_id` FROM `".$wpdb->postmeta."` WHERE `meta_key` = 's2member_ccaps_req' AND `meta_value` != ''")))
222 $singular_ids = c_ws_plugin__s2member_utils_arrays::force_integers($singular_ids);
223
224 return (!empty($singular_ids) && is_array($singular_ids)) ? array_unique($singular_ids) : array();
225 }
226
227 /**
228 * Retrieves a unique array of unavailable Singular IDs that require Custom Capabilities.
229 *
230 * Only returns Singular IDs that require Custom Capabilities;
231 * and ONLY those which are NOT satisfied by ``$user``.
232 *
233 * @package s2Member\Utilities
234 * @since 111101
235 *
236 * @param WP_User $user Optional. A `WP_User` object. If this is a valid `WP_User` object, test against this ``$user``, else all are unavailable.
237 *
238 * @return array Unique array of all Singular IDs *(as integers)* NOT available to ``$user``, due to Custom Capability Restrictions.
239 */
240 public static function get_unavailable_singular_ids_with_ccaps($user = NULL)
241 {
242 /** @var wpdb $wpdb WordPress DB object instance. */
243 global $wpdb; // Global DB object reference.
244
245 //260914.2132 Keep both the SQL rows and their lazily unserialized CCAP requirements for this request. The parsed cache is reset whenever post-meta changes invalidate the SQL rows, and anonymous visitors never pay the unserialization cost.
246 static $_results = array(), $_result_ccaps = array(), $_meta_changes = array();
247 $_cache_key = $wpdb->posts.'|'.$wpdb->postmeta;
248 $_changes = did_action('added_post_meta') + did_action('updated_post_meta') + did_action('deleted_post_meta');
249 if(!isset($_results[$_cache_key]) || !isset($_meta_changes[$_cache_key]) || $_meta_changes[$_cache_key] !== $_changes)
250 {
251 $_results[$_cache_key] = $wpdb->get_results("SELECT `".$wpdb->postmeta."`.`post_id`, `".$wpdb->postmeta."`.`meta_value`, `".$wpdb->posts."`.`post_type`".
252 " FROM `".$wpdb->posts."`, `".$wpdb->postmeta."` WHERE `".$wpdb->posts."`.`ID` = `".$wpdb->postmeta."`.`post_id`".
253 " AND `".$wpdb->postmeta."`.`meta_key` = 's2member_ccaps_req' AND `".$wpdb->postmeta."`.`meta_value` != ''");
254 $_result_ccaps[$_cache_key] = array();
255 $_meta_changes[$_cache_key] = $_changes;
256 }
257 $results = $_results[$_cache_key];
258 $result_ccaps = &$_result_ccaps[$_cache_key];
259 unset($_cache_key, $_changes); //260901 Request-local SQL cache.
260
261 if(is_array($results))
262 {
263 $bbpress_restrictions_enable = apply_filters('ws_plugin__s2member_bbpress_restrictions_enable', TRUE);
264 $bbpress_installed = c_ws_plugin__s2member_utils_conds::bbp_is_installed(); // bbPress is installed?
265 $bbpress_forum_post_type = $bbpress_installed ? bbp_get_forum_post_type() : ''; // Acquire the current post type for forums.
266 $bbpress_topic_post_type = $bbpress_installed ? bbp_get_topic_post_type() : ''; // Acquire the current post type for topics.
267 //260914.2132 Cache each distinct CCAP decision only for this helper invocation; many protected Posts share the same CCAP, but a later query pass can still receive a different filtered capability result.
268 $ccap_access = array();
269
270 foreach($results as $_result_index => $r) // Now we need to check Custom Capabilities against ``$user``. If ``$user`` is a valid `WP_User` object, else all are unavailable.
271 {
272 if(!is_object($user) || empty($user->ID)) // No ``$user`` object? Maybe not logged-in?.
273 $singular_ids[] = (int)$r->post_id; // It's NOT available. There is no ``$user``.
274
275 else
276 {
277 if(!array_key_exists($_result_index, $result_ccaps))
278 $result_ccaps[$_result_index] = c_ws_plugin__s2member_utils_arrays::maybe_unserialize($r->meta_value);
279
280 if(is_array($ccaps = $result_ccaps[$_result_index]))
281 {
282 foreach($ccaps as $ccap) // Test for Custom Capability Restrictions now.
283 {
284 $ccap = (string)$ccap;
285 if(strlen($ccap) && !(isset($ccap_access[$ccap]) ? $ccap_access[$ccap] : ($ccap_access[$ccap] = (bool)$user->has_cap('access_s2member_ccap_'.$ccap))))
286 {
287 $singular_ids[] = (int)$r->post_id; // It's NOT available.
288 break; // Break now, no need to continue in this loop.
289 }
290 }
291 }
292 }
293 if($bbpress_restrictions_enable && $bbpress_installed && $r->post_type === $bbpress_forum_post_type)
294 if(!empty($singular_ids) && in_array((int)$r->post_id, $singular_ids, TRUE))
295 {
296 if(is_array($child_results = $wpdb->get_results("SELECT `".$wpdb->posts."`.`ID` as `post_id` FROM `".$wpdb->posts."`".
297 " WHERE `".$wpdb->posts."`.`post_parent` = '".esc_sql($r->post_id)."'".
298 " AND `".$wpdb->posts."`.`post_type` = '".esc_sql($bbpress_topic_post_type)."'")))
299 foreach($child_results as $child_r) $singular_ids[] = (int)$child_r->post_id;
300 }
301 }
302 }
303 return (!empty($singular_ids) && is_array($singular_ids)) ? array_unique($singular_ids) : array();
304 }
305
306 /**
307 * Retrieves a unique array of all Singular IDs that require Specific Post/Page Access.
308 *
309 * @package s2Member\Utilities
310 * @since 111101
311 *
312 * @param bool $exclude_conflicts Optional. Defaults to false. If true, return ONLY those which are NOT in conflict with any other Restriction Types.
313 * The ``$exclude_conflicts`` argument should be used whenever we introduce a list of option values to a site owner. Helping them avoid mishaps.
314 * Please note, the ``$exclude_conflicts`` argument implements a resource-intensive processing routine.
315 *
316 * @return array Unique array of all Singular IDs *(as integers)* that require Specific Post/Page Access.
317 */
318 public static function get_all_singular_ids_with_sp($exclude_conflicts = FALSE)
319 {
320 if(is_array(($singular_ids = ($GLOBALS['WS_PLUGIN__']['s2member']['o']['specific_ids'] && is_array($singular_ids = preg_split('/['."\r\n\t".'\s;,]+/', $GLOBALS['WS_PLUGIN__']['s2member']['o']['specific_ids']))) ? $singular_ids : array())))
321 $singular_ids = c_ws_plugin__s2member_utils_arrays::force_integers($singular_ids);
322
323 if(!empty($singular_ids) && is_array($singular_ids) && $exclude_conflicts /* Return ONLY those which are NOT in conflict with other Restrictions? */)
324 {
325 $x_ids = array($GLOBALS['WS_PLUGIN__']['s2member']['o']['login_welcome_page'], $GLOBALS['WS_PLUGIN__']['s2member']['o']['membership_options_page'], $GLOBALS['WS_PLUGIN__']['s2member']['o']['file_download_limit_exceeded_page']);
326
327 $x_ids = array_merge($x_ids, c_ws_plugin__s2member_utils_gets::get_all_singular_ids_with_ccaps());
328
329 for($n = 0; $n <= $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels']; $n++)
330 {
331 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['level'.$n.'_catgs'] === 'all')
332 {
333 $catgs = c_ws_plugin__s2member_utils_gets::get_all_category_ids();
334 $x_ids = array_merge($x_ids, c_ws_plugin__s2member_utils_gets::get_singular_ids_in_terms($catgs));
335 continue; // Continue. The `all` specification is absolute. There's nothing more.
336 }
337 foreach(($catgs = preg_split('/['."\r\n\t".'\s;,]+/', $GLOBALS['WS_PLUGIN__']['s2member']['o']['level'.$n.'_catgs'])) as $catg)
338 $catgs = array_merge($catgs, c_ws_plugin__s2member_utils_gets::get_all_child_category_ids($catg));
339
340 $x_ids = array_merge($x_ids, c_ws_plugin__s2member_utils_gets::get_singular_ids_in_terms($catgs));
341 unset ($catgs, $catg); // Just a little housekeeping here.
342 }
343 for($n = 0; $n <= $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels']; $n++)
344 {
345 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['level'.$n.'_ptags'] === 'all')
346 {
347 $tags = c_ws_plugin__s2member_utils_gets::get_all_tag_ids();
348 $x_ids = array_merge($x_ids, c_ws_plugin__s2member_utils_gets::get_singular_ids_in_terms($tags));
349 continue; // Continue. The `all` specification is absolute. There's nothing more.
350 }
351 $tags = c_ws_plugin__s2member_utils_gets::get_tags_converted_to_ids($GLOBALS['WS_PLUGIN__']['s2member']['o']['level'.$n.'_ptags']);
352
353 $x_ids = array_merge($x_ids, c_ws_plugin__s2member_utils_gets::get_singular_ids_in_terms($tags));
354 unset ($tags); // Just a little housekeeping here.
355 }
356 for($n = 0; $n <= $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels']; $n++)
357 {
358 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['level'.$n.'_posts'] === 'all')
359 {
360 $x_ids = array_merge($x_ids, c_ws_plugin__s2member_utils_gets::get_all_post_ids());
361 continue; // Continue. The `all` specification is absolute. There's nothing more.
362 }
363 foreach(($posts = preg_split('/['."\r\n\t".'\s;,]+/', $GLOBALS['WS_PLUGIN__']['s2member']['o']['level'.$n.'_posts'])) as $p)
364 if(strpos($p, 'all-') === 0 && preg_match('/^all-(.+)$/', $p, $m) /* Protecting `all-` of a specific Post Type? */)
365 if((is_array($p_of_type = c_ws_plugin__s2member_utils_gets::get_all_post_ids($m[1])) || (substr($m[1], -1) === 's' && is_array($_p_of_type = c_ws_plugin__s2member_utils_gets::get_all_post_ids(substr($m[1], 0, -1))))) && !empty($p_of_type))
366 $x_ids = array_merge($x_ids, $p_of_type); // Merge all Posts of this Post Type.
367
368 $x_ids = array_merge($x_ids, $posts); // Merge together.
369 unset ($posts, $p, $m, $p_of_type); // Just a little housekeeping here.
370 }
371 for($n = 0; $n <= $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels']; $n++)
372 {
373 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['level'.$n.'_pages'] === 'all')
374 {
375 $x_ids = array_merge($x_ids, c_ws_plugin__s2member_utils_gets::get_all_page_ids());
376 continue; // Continue. The `all` specification is absolute. There's nothing more.
377 }
378 $pages = preg_split('/['."\r\n\t".'\s;,]+/', $GLOBALS['WS_PLUGIN__']['s2member']['o']['level'.$n.'_pages']);
379
380 $x_ids = array_merge($x_ids, $pages); // Merge.
381 unset ($pages); // Just a little housekeeping here.
382 }
383 $x_ids = array_unique(c_ws_plugin__s2member_utils_arrays::force_integers($x_ids));
384 $singular_ids = array_diff($singular_ids, $x_ids);
385 }
386 return (!empty($singular_ids) && is_array($singular_ids)) ? array_unique($singular_ids) : array();
387 }
388
389 /**
390 * Retrieves a unique array of unavailable Singular IDs that require Specific Post/Page Access.
391 *
392 * Only returns Singular IDs that require Specific Post/Page Access;
393 * and ONLY those which are NOT satisfied by the current Visitor.
394 *
395 * @package s2Member\Utilities
396 * @since 111101
397 *
398 * @param bool $exclude_conflicts Optional. Defaults to false. If true, return ONLY those which are NOT in conflict with any other Restriction Types.
399 * The ``$exclude_conflicts`` argument should be used whenever we introduce a list of option values to a site owner. Helping them avoid mishaps.
400 * Please note, the ``$exclude_conflicts`` argument implements a resource-intensive processing routine.
401 *
402 * @return array Unique array of all Singular IDs *(as integers)* NOT available to current Visitor, due to Specific Post/Page Restrictions.
403 */
404 public static function get_unavailable_singular_ids_with_sp($exclude_conflicts = FALSE)
405 {
406 if($GLOBALS['WS_PLUGIN__']['s2member']['o']['specific_ids'])
407 {
408 //260915.0105 Parse/normalize configured Specific Post/Page IDs only once per distinct option value in this request; Alternative View filtering can call this helper many times on one page load.
409 static $_specific_ids_cache = array();
410 $_specific_ids = (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['specific_ids'];
411 if(!isset($_specific_ids_cache[$_specific_ids]))
412 {
413 $_specific_ids_cache[$_specific_ids] = array();
414 foreach((array)preg_split('/['."\r\n\t".'\s;,]+/', $_specific_ids) as $_specific_id)
415 if(is_numeric($_specific_id)) $_specific_ids_cache[$_specific_ids][] = (int)$_specific_id;
416 $_specific_ids_cache[$_specific_ids] = array_values(array_unique($_specific_ids_cache[$_specific_ids]));
417 }
418 $_singular_ids = $_specific_ids_cache[$_specific_ids];
419
420 //260915.0122 Most Alternative View requests have no Specific Access credential. Use WordPress's listener APIs instead of testing `$wp_filter` keys directly, because an empty retained hook object must not disable this fast path.
421 $_sp_access_customized = has_action('ws_plugin__s2member_before_sp_access')
422 || has_filter('ws_plugin__s2member_sp_access_excluded')
423 || has_filter('ws_plugin__s2member_sp_access_excluded_cap')
424 || has_filter('ws_plugin__s2member_sp_access')
425 || has_action('ws_plugin__s2member_before_sp_access_session')
426 || has_filter('ws_plugin__s2member_sp_access_session');
427 $_sp_access_credential = !empty($_GET['s2member_sp_access']) || !empty($_COOKIE['s2member_sp_access']);
428
429 if(!$_sp_access_customized && !$_sp_access_credential)
430 {
431 if(!current_user_can('edit_posts')) $singular_ids = $_singular_ids;
432 }
433 else foreach($_singular_ids as $_singular_id) // A link/session or SP customization requires the established per-ID access routine.
434 if(!c_ws_plugin__s2member_sp_access::sp_access($_singular_id, 'read-only'))
435 $singular_ids[] = (int)$_singular_id;
436 }
437
438 if(!empty($singular_ids) && is_array($singular_ids) && $exclude_conflicts)
439 {
440 $all_singular_ids_not_conflicting = c_ws_plugin__s2member_utils_gets::get_all_singular_ids_with_sp('exclude-conflicts');
441 foreach($singular_ids as $s => $singular_id) // Weed out anything that's in conflict here.
442 if(!in_array($singular_id, $all_singular_ids_not_conflicting))
443 unset($singular_ids[$s]); // Housekeeping.
444 }
445 return (!empty($singular_ids) && is_array($singular_ids)) ? array_unique($singular_ids) : array();
446 }
447
448 /**
449 * Retrieves a unique array of all published Singulars, protected with Specific Post/Page Access.
450 *
451 * @package s2Member\Utilities
452 * @since 111101
453 *
454 * @uses {@link http://codex.wordpress.org/Function_Reference/get_posts get_posts()}
455 *
456 * @param bool $exclude_conflicts Optional. Defaults to false. If true, return ONLY those which are NOT in conflict with any other Restriction Types.
457 * The ``$exclude_conflicts`` argument should be used whenever we introduce a list of option values to a site owner. Helping them avoid mishaps.
458 * Please note, the ``$exclude_conflicts`` argument implements a resource-intensive processing routine.
459 *
460 * @return array Unique array of all Singulars *(i.e., Posts/Pages )* protected with Specific Post/Page Access.
461 * Includes Custom Post Types also, as specified by site owner's Specific Post/Page Restrictions.
462 */
463 public static function get_all_singulars_with_sp($exclude_conflicts = FALSE)
464 {
465 $singulars = ($GLOBALS['WS_PLUGIN__']['s2member']['o']['specific_ids'] && is_array($singulars = get_posts('post_status=publish&post_type=any&include='.$GLOBALS['WS_PLUGIN__']['s2member']['o']['specific_ids']))) ? $singulars : array();
466
467 if(!empty($singulars) && is_array($singulars) && $exclude_conflicts)
468 {
469 $all_singular_ids_not_conflicting = c_ws_plugin__s2member_utils_gets::get_all_singular_ids_with_sp('exclude-conflicts');
470 foreach($singulars as $s => $singular) // Weed out anything that's in conflict here.
471 if(!in_array($singular->ID, $all_singular_ids_not_conflicting))
472 unset($singulars[$s]); // Housekeeping.
473 }
474 return (!empty($singulars) && is_array($singulars)) ? c_ws_plugin__s2member_utils_arrays::array_unique($singulars) : array();
475 }
476
477 /**
478 * Retrieves a unique array of Singular IDs in the database, within specific term IDs.
479 *
480 * Only returns Singular IDs that are within the ``$terms`` passed through this function.
481 *
482 * @package s2Member\Utilities
483 * @since 110912
484 *
485 * @param array $terms Required. An array of term IDs.
486 *
487 * @return array Unique array of all Singular IDs *(as integers)* within the ``$terms`` passed through this function.
488 */
489 public static function get_singular_ids_in_terms($terms = array())
490 {
491 /** @var wpdb $wpdb WordPress DB object instance. */
492 global $wpdb; // Global DB object reference.
493
494 if(empty($terms) || !is_array($terms)) return array();
495
496 //260914.1643 Term restrictions can request the same term-to-Singular lookup repeatedly in one page load. Normalize only the cache key so equivalent term sets share one result regardless of order or duplicates, while leaving the legacy SQL input unchanged.
497 static $_singular_ids = array(), $_term_changes = array();
498 $_cache_terms = array_values(array_unique(c_ws_plugin__s2member_utils_arrays::force_integers($terms)));
499 sort($_cache_terms, SORT_NUMERIC);
500 $_cache_key = $wpdb->term_relationships.'|'.$wpdb->term_taxonomy.'|'.implode(',', $_cache_terms);
501
502 //260914.1643 Refresh after normal WordPress object-term mutations so a relationship changed earlier in this request is visible to later access checks; table names in the key isolate switched Multisite blogs.
503 $_changes = did_action('set_object_terms') + did_action('deleted_term_relationships');
504 if(!isset($_singular_ids[$_cache_key]) || !isset($_term_changes[$_cache_key]) || $_term_changes[$_cache_key] !== $_changes)
505 {
506 $singular_ids = $wpdb->get_col("SELECT `object_id` FROM `".$wpdb->term_relationships."` WHERE `term_taxonomy_id` IN (SELECT `term_taxonomy_id` FROM `".$wpdb->term_taxonomy."` WHERE `term_id` IN('".implode("','", $terms)."'))");
507 if(is_array($singular_ids)) $singular_ids = c_ws_plugin__s2member_utils_arrays::force_integers($singular_ids);
508
509 $_singular_ids[$_cache_key] = (!empty($singular_ids) && is_array($singular_ids)) ? array_unique($singular_ids) : array();
510 $_term_changes[$_cache_key] = $_changes;
511 }
512 return $_singular_ids[$_cache_key];
513 }
514 }
515 }
516