function flt_get_pages($results, $args = array()) { $results = (array) $results; global $wpdb; // === BEGIN Role Scoper ADDITION: global var; various special case exemption checks === // global $scoper, $current_rs_user; // need to skip cache retrieval if QTranslate is filtering get_pages with a priority of 1 or less $no_cache = !defined('SCOPER_QTRANSLATE_COMPAT') && awp_is_plugin_active('qtranslate'); // buffer titles in case they were filtered previously $titles = scoper_get_property_array($results, 'ID', 'post_title'); // depth is not really a get_pages arg, but remap exclude arg to exclude_tree if wp_list_terms called with depth=1 if (!empty($args['exclude']) && empty($args['exclude_tree']) && !empty($args['depth']) && 1 == $args['depth']) { if (0 !== strpos($args['exclude'], ',')) { // work around wp_list_pages() bug of attaching leading comma if a plugin uses wp_list_pages_excludes filter $args['exclude_tree'] = $args['exclude']; } } // // === END Role Scoper ADDITION === // ================================= $defaults = array('child_of' => 0, 'sort_order' => 'ASC', 'sort_column' => 'post_title', 'hierarchical' => 1, 'exclude' => array(), 'include' => array(), 'meta_key' => '', 'meta_value' => '', 'authors' => '', 'parent' => -1, 'exclude_tree' => '', 'number' => '', 'offset' => 0, 'post_type' => 'page', 'post_status' => 'publish', 'depth' => 0, 'suppress_filters' => 0, 'remap_parents' => -1, 'enforce_actual_depth' => -1, 'remap_thru_excluded_parent' => -1); // Role Scoper arguments added above // === BEGIN Role Scoper ADDITION: support front-end optimization $post_type = isset($args['post_type']) ? $args['post_type'] : $defaults['post_type']; $use_post_types = (array) scoper_get_option('use_post_types'); if (empty($use_post_types[$post_type])) { return $results; } if ($scoper->is_front()) { if ('page' == $post_type && defined('SCOPER_GET_PAGES_LEAN')) { // custom types are likely to have custom fields $defaults['fields'] = "{$wpdb->posts}.ID, {$wpdb->posts}.post_title, {$wpdb->posts}.post_parent, {$wpdb->posts}.post_date, {$wpdb->posts}.post_date_gmt, {$wpdb->posts}.post_status, {$wpdb->posts}.post_name, {$wpdb->posts}.post_modified, {$wpdb->posts}.post_modified_gmt, {$wpdb->posts}.guid, {$wpdb->posts}.menu_order, {$wpdb->posts}.comment_count"; } else { $defaults['fields'] = "{$wpdb->posts}.*"; if (!defined('SCOPER_FORCE_PAGES_CACHE')) { $no_cache = true; } // serialization / unserialization of post_content for all pages is too memory-intensive for sites with a lot of pages } } else { // required for xmlrpc getpagelist method $defaults['fields'] = "{$wpdb->posts}.*"; if (!defined('SCOPER_FORCE_PAGES_CACHE')) { $no_cache = true; } } // === END Role Scoper MODIFICATION === $r = wp_parse_args($args, $defaults); extract($r, EXTR_SKIP); $number = (int) $number; $offset = (int) $offset; $child_of = (int) $child_of; // Role Scoper modification: null value will confuse children array check // Make sure the post type is hierarchical $hierarchical_post_types = get_post_types(array('public' => true, 'hierarchical' => true)); if (!in_array($post_type, $hierarchical_post_types)) { return $results; } // Make sure we have a valid post status if (!in_array($post_status, get_post_stati())) { return $results; } // for the page parent dropdown, return no available selections for a published main page if the logged user isn't allowed to de-associate it from Main if (!empty($name) && 'parent_id' == $name) { global $post; if (!$post->post_parent && !$GLOBALS['scoper_admin_filters']->user_can_associate_main($post_type)) { $status_obj = get_post_status_object($post->post_status); if ($status_obj->public || $status_obj->private) { return array(); } } if (!empty($post) && $post_type == $post->post_type) { if ($post->post_parent) { $append_page = get_post($post->post_parent); } $exclude_tree = $post->ID; } } //$scoper->last_get_pages_args = $r; // don't copy entire args array unless it proves necessary $scoper->last_get_pages_depth = $depth; $scoper->last_get_pages_suppress_filters = $suppress_filters; if ($suppress_filters) { return $results; } // === BEGIN Role Scoper MODIFICATION: wp-cache key and flag specific to access type and user/groups // if (!scoper_get_otype_option('use_object_roles', 'post', $post_type)) { return $results; } $key = md5(serialize(compact(array_keys($defaults)))); $ckey = md5($key . CURRENT_ACCESS_NAME_RS); $cache_flag = 'rs_get_pages'; $cache = $current_rs_user->cache_get($cache_flag); if (false !== $cache) { if (!is_array($cache)) { $cache = array(); } if (!$no_cache && isset($cache[$ckey])) { // alternate filter name (WP core already applied get_pages filter) return apply_filters('get_pages_rs', $cache[$ckey], $r); } } // // === END Role Scoper MODIFICATION === // ==================================== $inclusions = ''; if (!empty($include)) { $child_of = 0; //ignore child_of, parent, exclude, meta_key, and meta_value params if using include $parent = -1; $exclude = ''; $meta_key = ''; $meta_value = ''; $hierarchical = false; $incpages = wp_parse_id_list($include); if (!empty($incpages)) { foreach ($incpages as $incpage) { if (empty($inclusions)) { $inclusions = ' AND ( ID = ' . intval($incpage) . ' '; } else { $inclusions .= ' OR ID = ' . intval($incpage) . ' '; } } } } if (!empty($inclusions)) { $inclusions .= ')'; } $exclusions = ''; if (!empty($exclude)) { $expages = wp_parse_id_list($exclude); if (!empty($expages)) { foreach ($expages as $expage) { if (empty($exclusions)) { $exclusions = ' AND ( ID <> ' . intval($expage) . ' '; } else { $exclusions .= ' AND ID <> ' . intval($expage) . ' '; } } } } if (!empty($exclusions)) { $exclusions .= ')'; } $author_query = ''; if (!empty($authors)) { $post_authors = wp_parse_id_list($authors); if (!empty($post_authors)) { foreach ($post_authors as $post_author) { //Do we have an author id or an author login? if (0 == intval($post_author)) { $post_author = get_userdatabylogin($post_author); if (empty($post_author)) { continue; } if (empty($post_author->ID)) { continue; } $post_author = $post_author->ID; } if ('' == $author_query) { $author_query = ' post_author = ' . intval($post_author) . ' '; } else { $author_query .= ' OR post_author = ' . intval($post_author) . ' '; } } if ('' != $author_query) { $author_query = " AND ({$author_query})"; } } } $join = ''; $where = "{$exclusions} {$inclusions} "; if (!empty($meta_key) || !empty($meta_value)) { $join = " INNER JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id"; // Role Scoper modification: was LEFT JOIN in WP 3.0 core (TODO: would that botch uro join results? // meta_key and meta_value might be slashed $meta_key = stripslashes($meta_key); $meta_value = stripslashes($meta_value); if (!empty($meta_key)) { $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_key = %s", $meta_key); } if (!empty($meta_value)) { $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_value = %s", $meta_value); } } if ($parent >= 0) { $where .= $wpdb->prepare(' AND post_parent = %d ', $parent); } // === BEGIN Role Scoper MODIFICATION: // allow pages of multiple statuses to be displayed (requires default status=publish to be ignored) // $where_post_type = $wpdb->prepare("post_type = '%s'", $post_type); $where_status = ''; $is_front = $scoper->is_front(); $is_teaser_active = $scoper->is_front() && scoper_get_otype_option('do_teaser', 'post') && scoper_get_otype_option('use_teaser', 'post', $post_type); $private_teaser = $is_teaser_active && scoper_get_otype_option('use_teaser', 'post', $post_type) && !scoper_get_otype_option('teaser_hide_private', 'post', $post_type); if ($is_front && (!empty($current_rs_user->ID) || $private_teaser)) { $frontend_list_private = scoper_get_otype_option('private_items_listable', 'post', 'page'); } else { $frontend_list_private = false; } // WP core does not include private pages in query. Include private statuses in anticipation of user-specific filtering if ($post_status && ('publish' != $post_status || $is_front && !$frontend_list_private)) { $where_status = $wpdb->prepare("post_status = '%s'", $post_status); } else { // since we will be applying status clauses based on content-specific roles and restrictions, only a sanity check safeguard is needed when post_status is unspecified or defaulted to "publish" $safeguard_statuses = array(); foreach (get_post_stati(array('internal' => false), 'object') as $status_name => $status_obj) { if (!$is_front || $status_obj->private || $status_obj->public) { $safeguard_statuses[] = $status_name; } } $where_status = "post_status IN ('" . implode("','", $safeguard_statuses) . "')"; } $query = "SELECT {$fields} FROM {$wpdb->posts} {$join} WHERE 1=1 AND {$where_post_type} AND ( {$where_status} {$where} {$author_query} ) ORDER BY {$sort_column} {$sort_order}"; if (!empty($number)) { $query .= ' LIMIT ' . $offset . ',' . $number; } if ($is_teaser_active && !defined('SCOPER_TEASER_HIDE_PAGE_LISTING')) { // We are in the front end and the teaser is enabled for pages $query = apply_filters('objects_request_rs', $query, 'post', $post_type, array('force_teaser' => true)); $pages = scoper_get_results($query); // execute unfiltered query // Pass results of unfiltered query through the teaser filter. // If listing private pages is disabled, they will be omitted completely, but restricted published pages // will still be teased. This is a slight design compromise to satisfy potentially conflicting user goals without yet another option $pages = apply_filters('objects_results_rs', $pages, 'post', (array) $post_type, array('request' => $query, 'force_teaser' => true, 'object_type' => $post_type)); // restore buffered titles in case they were filtered previously scoper_restore_property_array($pages, $titles, 'ID', 'post_title'); $pages = apply_filters('objects_teaser_rs', $pages, 'post', $post_type, array('request' => $query, 'force_teaser' => true)); if ($frontend_list_private) { if (!scoper_get_otype_option('teaser_hide_private', 'post', $post_type)) { $tease_all = true; } } } else { $_args = array('skip_teaser' => true); if (in_array($GLOBALS['pagenow'], array('post.php', 'post-new.php'))) { if ($post_type_obj = get_post_type_object($post_type)) { $plural_name = plural_name_from_cap_rs($post_type_obj); $_args['alternate_reqd_caps'][0] = array("create_child_{$plural_name}"); } } // Pass query through the request filter $query = apply_filters('objects_request_rs', $query, 'post', $post_type, $_args); // Execute the filtered query $pages = scoper_get_results($query); // restore buffered titles in case they were filtered previously scoper_restore_property_array($pages, $titles, 'ID', 'post_title'); } if (empty($pages)) { // alternate hook name (WP core already applied get_pages filter) return apply_filters('get_pages_rs', array(), $r); } // // === END Role Scoper MODIFICATION === // ==================================== // Role Scoper note: WP core get_pages has already updated wp_cache and pagecache with unfiltered results. update_page_cache($pages); // === BEGIN Role Scoper MODIFICATION: Support a disjointed pages tree with some parents hidden ======== if ($child_of || empty($tease_all)) { // if we're including all pages with teaser, no need to continue thru tree remapping $ancestors = ScoperAncestry::get_page_ancestors(); // array of all ancestor IDs for keyed page_id, with direct parent first $orderby = $sort_column; if ($parent > 0 || !$hierarchical) { $remap_parents = false; } else { // if these settings were passed into this get_pages call, use them if (-1 === $remap_parents) { $remap_parents = scoper_get_option('remap_page_parents'); } if ($remap_parents) { if (-1 === $enforce_actual_depth) { $enforce_actual_depth = scoper_get_option('enforce_actual_page_depth'); } if (-1 === $remap_thru_excluded_parent) { $remap_thru_excluded_parent = scoper_get_option('remap_thru_excluded_page_parent'); } } } $remap_args = compact('child_of', 'parent', 'exclude', 'depth', 'orderby', 'remap_parents', 'enforce_actual_depth', 'remap_thru_excluded_parent'); // one or more of these args may have been modified after extraction ScoperHardway::remap_tree($pages, $ancestors, 'ID', 'post_parent', $remap_args); } // === END Role Scoper MODIFICATION === // ==================================== if (!empty($exclude_tree)) { $exclude = array(); $exclude = (int) $exclude_tree; $children = get_page_children($exclude, $pages); // RS note: okay to use unfiltered function here since it's only used for excluding $excludes = array(); foreach ($children as $child) { $excludes[] = $child->ID; } $excludes[] = $exclude; $total = count($pages); for ($i = 0; $i < $total; $i++) { if (in_array($pages[$i]->ID, $excludes)) { unset($pages[$i]); } } } if (!empty($append_page) && !empty($pages)) { $found = false; foreach (array_keys($pages) as $key) { if ($post->post_parent == $pages[$key]->ID) { $found = true; break; } } if (empty($found)) { $pages[] = $append_page; } } // re-index the array, just in case anyone cares $pages = array_values($pages); // === BEGIN Role Scoper MODIFICATION: cache key and flag specific to access type and user/groups // if (!$no_cache) { $cache[$ckey] = $pages; $current_rs_user->cache_set($cache, $cache_flag); } // alternate hook name (WP core already applied get_pages filter) $pages = apply_filters('get_pages_rs', $pages, $r); // // === END Role Scoper MODIFICATION === // ==================================== return $pages; }
function flt_objects_results($results, $src_name, $object_types, $args = array()) { if (!$object_types || is_array($object_types) && count($object_types) > 1) { $object_type = cr_find_post_type(); } else { $object_type = strval($object_types); } if ('edit.php' == $GLOBALS['pagenow'] && !is_content_administrator_rs()) { $post_type_obj = get_post_type_object($object_type); if (!empty($post_type_obj->hierarchical)) { // ScoperAncestry class is loaded by hardway_rs.php $ancestors = ScoperAncestry::get_page_ancestors(); // array of all ancestor IDs for keyed page_id, with direct parent first $args = array('remap_parents' => false); ScoperHardway::remap_tree($results, $ancestors, 'ID', 'post_parent', $args); } } if ($this->scoper->is_front() && empty($this->skip_teaser)) { if ($tease_otypes = $this->_get_teaser_object_types($src_name, $object_types, $args)) { require_once dirname(__FILE__) . '/teaser_rs.php'; $args['force_teaser'] = true; return ScoperTeaser::posts_teaser_prep_results($results, $tease_otypes, $args); } // won't do anything unless teaser is enabled for object type(s) //$results = apply_filters('objects_teaser_pre_results_rs', $results, 'post', $object_type, array('force_teaser' => true)); } return $results; }