| 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 |
|