function scoper_display_rs_roledefs($args = array())
{
    global $scoper;
    echo "<div id='rs-roledefs' style='clear:both;margin:0;' class='rs-options agp_js_hide {$args['bgcolor_class']}'>";
    if (scoper_get_option('display_hints')) {
        echo '<div class="rs-optionhint">';
        echo '<p style="margin-top:0">';
        _e('These roles are defined by Role Scoper (and possibly other plugins) for your use in designating content-specific access or supplemental site-wide access.  Although the default capabilities are ideal for most installations, you may modify them at your discretion.', 'scoper');
        echo '</p>';
        echo '<p>';
        _e('Since Role Scoper role definitions pertain to a particular object type, available capabilities are defined by the provider of that object type. WordPress core or plugins can add or revise default role definitions based on available capabilities.', 'scoper');
        echo '</p>';
        echo '<p>';
        if (awp_ver('3.0-dev')) {
            _e('WordPress Role assignments function as a default which may be supplemented or overriden by site-wide or content-specific assignment of these RS Roles.', 'scoper');
        } else {
            _e('WordPress Role assignments function as a default which may be supplemented or overriden by blog-wide or content-specific assignment of these RS Roles.', 'scoper');
        }
        echo '</p>';
        echo '</div>';
    }
    echo "<input type='hidden' name='rs_role_defs' value='1' />";
    if (empty($args['customize_defaults'])) {
        $rs_role_defs = $scoper->role_defs;
    } else {
        global $scoper_role_types;
        $rs_role_defs = new CR_Roles();
        //$this->load_role_caps();
        $rs_role_defs->role_caps = apply_filters('define_role_caps_rs', cr_role_caps());
        if ($user_role_caps = scoper_get_option('user_role_caps', -1, true)) {
            $rs_role_defs->add_role_caps($user_role_caps);
        }
        if ($disabled_role_caps = scoper_get_option('disabled_role_caps', -1, true)) {
            $rs_role_defs->remove_role_caps($disabled_role_caps);
        }
        $rs_role_defs->add_member_objects(cr_role_defs());
        $rs_role_defs = apply_filters('define_roles_rs', $rs_role_defs);
        $rs_role_defs->remove_invalid();
        // currently don't allow additional custom-defined post, page or link roles
        // To support merging in of WP role assignments, always note actual WP-defined roles
        // regardless of which role type we are scoping with.
        $scoper->log_wp_roles($rs_role_defs);
        $rs_role_defs->lock();
        // prevent inadvertant improper API usage
    }
    // object_type association of roles needs to be based on default role_caps, otherwise roles with all caps disabled will be excluded from UI
    // This also allows the default bolding to be based on custom default settings when role defs are defined per-blog in wp-mu
    global $scoper_role_types;
    $rs_default_role_defs = new CR_Roles();
    $rs_default_role_defs->role_caps = apply_filters('define_role_caps_rs', cr_role_caps());
    $rs_default_role_defs->add_member_objects(cr_role_defs());
    $rs_default_cap_defs = new CR_Capabilities();
    $rs_default_cap_defs->add_member_objects(cr_cap_defs());
    $rs_default_cap_defs = apply_filters('define_capabilities_rs', $rs_default_cap_defs);
    $scoper->log_cap_usage($rs_default_role_defs, $rs_default_cap_defs);
    if (IS_MU_RS && !$args['customize_defaults'] && !$args['sitewide']) {
        if ($user_role_caps = scoper_get_option('user_role_caps', -1, true)) {
            $rs_default_role_defs->add_role_caps($user_role_caps);
        }
        if ($disabled_role_caps = scoper_get_option('disabled_role_caps', -1, true)) {
            $rs_default_role_defs->remove_role_caps($disabled_role_caps);
        }
    }
    $rs_default_role_defs = apply_filters('define_roles_rs', $rs_default_role_defs);
    $rs_default_role_defs->remove_invalid();
    if (has_filter('define_roles_rs')) {
        require_once SCOPER_ABSPATH . '/extension-helper_rs.php';
        scoper_adjust_legacy_extension_cfg($rs_default_role_defs, $rs_default_cap_defs);
    }
    $reviewed_roles = array();
    foreach ($scoper->data_sources->get_all() as $src_name => $src) {
        $object_types = $src->object_types;
        if ('post' == $src_name) {
            global $wp_taxonomies;
            foreach ($wp_taxonomies as $tx) {
                if ($_tx = $scoper->taxonomies->get($tx->name)) {
                    // use RS taxonomy object so we can pull plural_name property
                    $object_types[$tx->name] = $_tx;
                }
            }
            $use_post_types = scoper_get_option('use_post_types');
            $use_taxonomies = scoper_get_option('use_taxonomies');
        }
        foreach ($object_types as $object_type => $otype) {
            if ('post' == $src_name && empty($use_post_types[$object_type]) && empty($use_taxonomies[$object_type])) {
                continue;
            }
            $otype_roles = array();
            $otype_display_names = array();
            if ($obj_roles = $rs_default_role_defs->get_matching('rs', $src_name, $object_type)) {
                $otype_roles[$object_type] = $obj_roles;
            }
            if (!empty($otype->labels->name)) {
                $otype_display_names[$object_type] = $otype->labels->singular_name;
            } else {
                $otype_display_names[$object_type] = $otype->display_name;
            }
            if (!$otype_roles) {
                continue;
            }
            if ('post' == $src_name) {
                $plural_name = plural_name_from_cap_rs(get_post_type_object($object_type));
            } else {
                $plural_name = '';
            }
            foreach ($otype_roles as $object_type => $roles) {
                //display each role which has capabilities for this object type
                echo '<br />';
                echo '<h3>' . sprintf(__('%s Roles'), $otype_display_names[$object_type]) . '</h3>';
                ?>
<table class='widefat rs-backwhite'>
<thead>
<tr class="thead">
	<th width="15%"><?php 
                echo __awp('Role');
                ?>
</th>
	<th><?php 
                _e('Capabilities (abbreviated, defaults are bolded)', 'scoper');
                ?>
</th>
</tr>
</thead>
<tbody>
<?php 
                $wp_role_sync = array('rs_post_contributor' => 'contributor', 'rs_post_revisor' => 'revisor', 'rs_post_author' => 'author', 'rs_post_editor' => 'editor', 'rs_page_editor' => 'editor');
                if (defined('RVY_VERSION')) {
                    $wp_role_sync['rs_page_revisor'] = 'revisor';
                }
                global $wp_roles;
                $style = '';
                foreach ($roles as $rs_role_handle => $role_def) {
                    $reviewed_roles[] = $rs_role_handle;
                    $style = ' class="alternate"' == $style ? '' : ' class="alternate"';
                    echo "\n\t" . "<tr{$style}><td><strong>" . $rs_role_defs->get_display_name($rs_role_handle) . '</strong>';
                    if (isset($wp_role_sync[$rs_role_handle])) {
                        if (isset($wp_roles->role_objects[$wp_role_sync[$rs_role_handle]])) {
                            $wp_role_handle = "wp_" . $wp_role_sync[$rs_role_handle];
                            $wp_display_name = $wp_roles->role_names[$wp_role_sync[$rs_role_handle]];
                            $contained_roles = $rs_role_defs->get_contained_roles($wp_role_handle);
                            if (!isset($contained_roles[$rs_role_handle])) {
                                echo '<br /><br /><span class="rs-warning">';
                                printf(__('Warning: Since the WP %1$s role def lacks some caps selected here, it will be treated as a lesser role if Restrictions are applied.', 'scoper'), $wp_display_name);
                                echo '</span>';
                                $missing_caps = true;
                            } else {
                                $missing_caps = false;
                            }
                            // only display "sync WP role" checkbox if the WP role has missing caps or extra caps
                            $otype_caps = $scoper->cap_defs->get_matching($src_name, $object_type, '', STATUS_ANY_RS);
                            $wp_defined_caps = array_intersect_key($wp_roles->role_objects[$wp_role_sync[$rs_role_handle]]->capabilities, $otype_caps);
                            $wp_extra_caps = array_diff_key($wp_defined_caps, $rs_role_defs->role_caps[$rs_role_handle]);
                            /*
                            if ( $wp_extra_caps )
                            	$sync_caption = sprintf( _ x( 'sync WP %1$s <br />to these selections (currently includes %2$s)', 'role name', 'scoper' ), $wp_display_name, implode( ", ", array_keys($wp_extra_caps) ) );
                            else
                            	$sync_caption = sprintf( _ x( 'sync WP %s <br />to these selections', 'role name', 'scoper' ), $wp_display_name);
                            */
                            if ($wp_extra_caps) {
                                $sync_caption = sprintf(__('sync WP %1$s <br />to these selections (currently includes %2$s)', 'scoper'), $wp_display_name, implode(", ", array_keys($wp_extra_caps)));
                            } else {
                                $sync_caption = sprintf(__('sync WP %s <br />to these selections', 'scoper'), $wp_display_name);
                            }
                            echo '<br /><br />';
                            $title = __('note: only the capabilities listed here will be affected', 'scoper');
                            echo "<input type='checkbox' name='sync_wp_roles[]' id='sync_wp_role_{$rs_role_handle}' value='{$rs_role_handle}:{$wp_role_handle}' title='{$title}' />" . "<label for='sync_wp_role_{$rs_role_handle}' title='{$title}'>" . $sync_caption . '</label>';
                        }
                    }
                    echo "</td><td><ul class='rs-cap_list'>";
                    $active_cap_names = array_keys($rs_role_defs->role_caps[$rs_role_handle]);
                    if (!empty($role_def->anon_user_blogrole) || !empty($role_def->no_custom_caps)) {
                        $disabled_role = 'disabled="disabled"';
                        $available_cap_names = $active_cap_names;
                    } else {
                        $disabled_role = '';
                        $available_caps = $rs_default_cap_defs->get_matching($src_name, $object_type, '', STATUS_ANY_RS);
                        $available_cap_names = array_keys($available_caps);
                        sort($available_cap_names);
                        $available_cap_names = array_merge($available_cap_names, $active_cap_names);
                    }
                    // abbreviate type caps and reorder display
                    $show_cap_names = array();
                    foreach ($available_cap_names as $cap_name) {
                        if ($plural_name && strpos($cap_name, "_{$plural_name}")) {
                            $display = str_replace("_{$plural_name}", '', $cap_name);
                            $display = sprintf(__('%s...', 'scoper'), $display);
                        } else {
                            $display = $cap_name;
                        }
                        $show_cap_names[$display] = $cap_name;
                    }
                    ksort($show_cap_names);
                    foreach ($show_cap_names as $display => $cap_name) {
                        $checked = in_array($cap_name, $active_cap_names) ? 'checked="checked"' : '';
                        $is_default = !empty($rs_default_role_defs->role_caps[$rs_role_handle][$cap_name]);
                        $disabled_cap = $disabled_role || $is_default && !empty($available_caps[$cap_name]->no_custom_remove) || !$is_default && !empty($available_caps[$cap_name]->no_custom_add);
                        $disabled = $disabled_cap ? 'disabled="disabled"' : '';
                        $style = $is_default ? "style='font-weight: bold'" : '';
                        $cap_safename = str_replace(' ', '_', $cap_name);
                        echo "<li><input type='checkbox' name='{$rs_role_handle}_caps[]' id='{$rs_role_handle}_{$cap_safename}' value='{$cap_name}' {$checked} {$disabled} />" . "<label for='{$rs_role_handle}_{$cap_safename}' title='{$cap_name}' {$style}>" . str_replace(' ', '&nbsp;', ucwords(str_replace('_', ' ', $display))) . '</label></li>';
                    }
                    echo '</ul></td></tr>';
                }
                echo '</tbody></table>';
                echo '<br /><br />';
            }
            // foreach otype_role (distinguish object roles from term roles)
        }
        // end foreach object_type
    }
    // end foreach data source
    $reviewed_roles = implode(',', array_unique($reviewed_roles));
    echo "<input type='hidden' name='reviewed_roles' value='{$reviewed_roles}' />";
    echo '<span class="alignright">';
    echo '<label for="rs_role_resync"><input name="rs_role_resync" type="checkbox" id="rs_role_resync" value="1" />';
    echo '&nbsp;';
    _e('Re-sync with WordPress roles on next Update', 'scoper');
    echo '</label></span>';
    echo '<br />';
    ?>
</div>

<?php 
}
 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;
 }
예제 #3
0
 function establish_status_caps()
 {
     global $wp_post_types;
     $use_post_types = scoper_get_option('use_post_types');
     $post_types = array_diff_key(get_post_types(array('public' => true)), array('attachment' => true));
     $stati = get_post_stati(array('internal' => false), 'object');
     foreach ($post_types as $post_type) {
         $plural_name = plural_name_from_cap_rs($wp_post_types[$post_type]);
         // copy existing cap values so we don't overwrite them
         $type_caps = (array) $wp_post_types[$post_type]->cap;
         if ('attachment' == $post_type) {
             $is_attachment_type = true;
             $post_type = 'post';
         } else {
             $is_attachment_type = false;
             if (empty($use_post_types[$post_type])) {
                 continue;
             }
         }
         // force edit_published, edit_private, delete_published, delete_private cap definitions
         foreach ($stati as $status => $status_obj) {
             if (empty($status_obj->moderation) && !$status_obj->public && !$status_obj->private) {
                 // don't mess with draft or future
                 continue;
             }
             foreach (array('read', 'edit', 'delete') as $op) {
                 if ('read' == $op && ($status_obj->public || !empty($status_obj->moderation))) {
                     continue;
                 }
                 $status_string = 'publish' == $status ? 'published' : $status;
                 $posts_cap_name = "{$op}_{$status_string}_posts";
                 // only alter the cap setting if it's not already set
                 if (empty($type_caps[$posts_cap_name])) {
                     if (!empty($status_obj->customize_caps)) {
                         // TODO: RS Options to set this
                         // this status is built in or was marked for full enforcement of custom capabilities
                         $type_caps[$posts_cap_name] = "{$op}_{$status_string}_{$plural_name}";
                     } else {
                         // default to this post type's own equivalent private or published cap
                         if ($status_obj->private) {
                             $type_caps[$posts_cap_name] = "{$op}_private_{$plural_name}";
                         } elseif ($status_obj->public) {
                             $type_caps[$posts_cap_name] = "{$op}_published_{$plural_name}";
                         }
                     }
                 }
             }
             // end foreach op (read/edit/delete)
             // also define a "set_status" cap for custom statuses (to accompany "publish_posts" cap requirement when setting or removing this post status)
             if (!in_array($status, array('publish', 'private'))) {
                 $posts_cap_name = "set_{$status}_posts";
                 if (empty($type_caps[$posts_cap_name])) {
                     if (!empty($status_obj->customize_caps)) {
                         // TODO: RS Options to set this
                         // this status was marked for full enforcement of custom capabilities
                         $type_caps[$posts_cap_name] = "set_{$status}_{$plural_name}";
                     } elseif ($status_obj->public || $status_obj->private) {
                         $type_caps[$posts_cap_name] = "publish_{$plural_name}";
                     }
                 }
             }
         }
         // end foreach front end status
         if (empty($type_caps['delete_posts'])) {
             $type_caps['delete_posts'] = "delete_{$plural_name}";
         }
         if (empty($type_caps['delete_others_posts'])) {
             $type_caps['delete_others_posts'] = "delete_others_{$plural_name}";
         }
         if ($is_attachment_type) {
             $post_type = 'attachment';
         }
         $wp_post_types[$post_type]->cap = (object) $type_caps;
     }
     // end foreach post type
 }
function cr_post_role_caps()
{
    $arr = array();
    $post_types = array_diff_key(get_post_types(array('public' => true), 'object'), array('attachment' => true));
    $use_post_types = scoper_get_option('use_post_types');
    foreach ($post_types as $name => $post_type_obj) {
        if (empty($use_post_types[$name])) {
            continue;
        }
        $cap = $post_type_obj->cap;
        $arr["rs_{$name}_reader"] = array("read" => true);
        $arr["rs_private_{$name}_reader"] = array($cap->read_private_posts => true, "read" => true);
        $arr["rs_{$name}_contributor"] = array($cap->edit_posts => true, $cap->delete_posts => true, "read" => true);
        if (defined('RVY_VERSION')) {
            $arr["rs_{$name}_revisor"] = array($cap->edit_posts => true, $cap->delete_posts => true, "read" => true, $cap->read_private_posts => true, $cap->edit_others_posts => true);
        }
        $arr["rs_{$name}_author"] = array("upload_files" => true, $cap->publish_posts => true, $cap->edit_published_posts => true, $cap->delete_published_posts => true, $cap->edit_posts => true, $cap->delete_posts => true, "read" => true);
        $arr["rs_{$name}_editor"] = array("moderate_comments" => true, $cap->delete_others_posts => true, $cap->edit_others_posts => true, "upload_files" => true, "unfiltered_html" => true, $cap->publish_posts => true, $cap->delete_private_posts => true, $cap->edit_private_posts => true, $cap->delete_published_posts => true, $cap->edit_published_posts => true, $cap->delete_posts => true, $cap->edit_posts => true, $cap->read_private_posts => true, "read" => true);
        // Note: create_child_pages should only be present in associate role, which is used as an object-assigned alternate to blog-wide edit role
        // This way, blog-assignment of author role allows user to create new pages, but only as subpages of pages they can edit (or for which Associate role is object-assigned)
        if ($post_type_obj->hierarchical) {
            $plural_name = plural_name_from_cap_rs($post_type_obj);
            $arr["rs_{$name}_associate"] = array("create_child_{$plural_name}" => true, 'read' => true);
        }
    }
    return $arr;
}
function _cr_get_reqd_caps($src_name, $op, $object_type = '-1', $status = '-1', $base_caps_only = false, $preview_future = false)
{
    if ('admin' == $op) {
        $op = 'delete';
    }
    if ($object_type == -1 && $status == -1 && !$base_caps_only && !$preview_future) {
        // only set / retrieve the static buffer for default Query_Interceptor usage
        static $reqd_caps;
        if (!isset($reqd_caps)) {
            $reqd_caps = array();
        }
    } else {
        $reqd_caps = array();
    }
    if (!isset($reqd_caps[$src_name][$op])) {
        $arr = array();
        switch ($src_name) {
            case 'post':
                $property = "{$op}_posts";
                $others_property = "{$op}_others_posts";
                if (-1 != $object_type && post_type_exists($object_type)) {
                    $post_types = array($object_type => get_post_type_object($object_type));
                } else {
                    $post_types = array_diff_key(get_post_types(array('public' => true), 'object'), array('attachment' => true));
                    $use_post_types = scoper_get_option('use_post_types');
                }
                if (-1 != $status && isset($GLOBALS['wp_post_statuses'][$status])) {
                    $post_statuses = array($status => get_post_status_object($status));
                } else {
                    $post_statuses = get_post_stati(array('internal' => null), 'object');
                    $post_statuses[] = get_post_status_object('trash');
                }
                foreach ($post_types as $_post_type => $post_type_obj) {
                    if (-1 == $object_type && empty($use_post_types[$_post_type])) {
                        continue;
                    }
                    $plural_name = plural_name_from_cap_rs($post_type_obj);
                    $cap = $post_type_obj->cap;
                    if ('read' != $op) {
                        // for "delete" op, select a value from stored cap property in this order of preference, if the proerpty is defined: delete_others_posts, delete_posts, edit_others_posts, edit_posts
                        if (!empty($cap->{$others_property}) && !$base_caps_only) {
                            $main_cap = $cap->{$others_property};
                        } elseif (!empty($cap->{$property})) {
                            $main_cap = $cap->{$property};
                        } elseif (!empty($cap->edit_others_posts) && !$base_caps_only) {
                            $main_cap = $cap->edit_others_posts;
                        } else {
                            $main_cap = $cap->edit_posts;
                        }
                    }
                    $use_statuses = !empty($post_type_obj->statuses) ? $post_type_obj->statuses : $post_statuses;
                    $use_statuses = array_intersect_key($use_statuses, $post_statuses);
                    foreach ($use_statuses as $status_obj) {
                        $_status = $status_obj->name;
                        if ('read' == $op) {
                            if ('trash' == $_status) {
                                continue;
                            }
                            if ('future' == $_status && !$preview_future) {
                                continue;
                            }
                            if (!$status_obj->protected && !$status_obj->internal) {
                                // read
                                $arr['read'][$_post_type][$_status] = array('read');
                                if (!$base_caps_only) {
                                    // read_private_posts
                                    if ($status_obj->private) {
                                        $arr['read'][$_post_type][$_status][] = $cap->read_private_posts;
                                    }
                                    // read_{$_status}_posts (if defined)
                                    if ('publish' != $_status) {
                                        $status_cap = "read_{$_status}_{$plural_name}";
                                        if (!empty($cap->{$status_cap})) {
                                            $arr['read'][$_post_type][$_status][] = $status_cap;
                                        }
                                    }
                                    $arr['read'][$_post_type][$_status] = array_unique($arr['read'][$_post_type][$_status]);
                                }
                            } elseif (('future' == $_status || !empty($_GET['preview'])) && 'trash' != $_status) {
                                // preview supports non-published statuses, but requires edit capability
                                //  array ( 'draft' => array($cap->edit_others_posts), 'pending' => array('edit_others_posts'), 'future' => array('edit_others_posts'), 'publish' => array('read'), 'private' => array('read', 'read_private_posts') );
                                if ($base_caps_only) {
                                    $arr['read'][$_post_type][$_status] = array($cap->edit_posts);
                                } else {
                                    $arr['read'][$_post_type][$_status] = array($cap->edit_others_posts);
                                }
                                $status_cap = "read_published_{$plural_name}";
                                if (!empty($cap->{$status_cap})) {
                                    $arr['read'][$_post_type][$_status][] = $status_cap;
                                }
                            }
                        } else {
                            // op == delete / edit / other
                            // edit_posts / edit_others_posts
                            $arr[$op][$_post_type][$_status][] = $main_cap;
                            // edit_published_posts
                            if ($status_obj->public || $status_obj->private || 'future' == $_status) {
                                $property = "{$op}_published_posts";
                                $arr[$op][$_post_type][$_status][] = $cap->{$property};
                            }
                            if (!$base_caps_only) {
                                // edit private posts
                                if ($status_obj->private) {
                                    $property = "{$op}_private_posts";
                                    $arr[$op][$_post_type][$_status][] = $cap->{$property};
                                }
                                // edit_{$_status}_posts (if defined)
                                $status_string = 'publish' == $_status ? 'published' : $_status;
                                $status_cap = "{$op}_{$status_string}_posts";
                                if (!empty($cap->{$status_cap})) {
                                    $arr[$op][$_post_type][$_status][] = $cap->{$status_cap};
                                }
                            }
                            $arr[$op][$_post_type][$_status] = array_unique($arr[$op][$_post_type][$_status]);
                        }
                    }
                    // end foreach status
                }
                // end foreach post type
                // TODO: re-implement OP_ADMIN distinction with dedicated admin caps
                //$arr['admin'] = $arr['edit'];
                break;
            case 'link':
                $arr['read']['link'][''] = array('read');
                $arr['edit']['link'][''] = array('manage_links');
                // object types with a single status store nullstring status key
                //$arr['admin']['link'][''] = array( 'manage_links' );
                break;
            case 'group':
                $arr['edit']['group'][''] = array('manage_groups');
                //$arr['admin']['group'][''] = array( 'manage_groups' );
                break;
            default:
                global $scoper;
                if ($src = $scoper->data_sources->get($src_name)) {
                    if (isset($src->reqd_caps)) {
                        // legacy API support
                        $arr = $src->reqd_caps;
                    }
                }
        }
        // end src_name switch
        if (empty($arr[$op])) {
            $arr[$op] = array();
        }
        $reqd_caps[$src_name][$op] = apply_filters('define_required_caps_rs', $arr[$op], $src_name, $op);
    }
    // endif pulling from static buffer
    if (-1 != $status && -1 != $object_type) {
        if (isset($reqd_caps[$src_name][$op][$object_type][$status])) {
            return $reqd_caps[$src_name][$op][$object_type][$status];
        } else {
            return array();
        }
    } elseif (-1 != $object_type) {
        if (isset($reqd_caps[$src_name][$op][$object_type])) {
            return $reqd_caps[$src_name][$op][$object_type];
        } else {
            return array();
        }
    } else {
        if (isset($reqd_caps[$src_name][$op])) {
            return $reqd_caps[$src_name][$op];
        } else {
            return array();
        }
    }
}
function scoper_flt_page_parent($parent_id)
{
    if ('no_parent_filter' == scoper_get_option('lock_top_pages')) {
        return (int) $parent_id;
    }
    if (!empty($_REQUEST['post_ID'])) {
        $post_id = $_REQUEST['post_ID'];
    } elseif (!empty($_REQUEST['post_id'])) {
        $post_id = $_REQUEST['post_id'];
    } else {
        return (int) $parent_id;
    }
    if (!empty($post_id)) {
        if ($parent_id == $post_id) {
            // normal revision save
            return (int) $parent_id;
        }
    }
    if (defined('RVY_VERSION')) {
        global $revisionary;
        if (!empty($revisionary->admin->revision_save_in_progress)) {
            return (int) $parent_id;
        }
    }
    if (empty($_POST['post_type'])) {
        return (int) $parent_id;
    }
    // Make sure the selected parent is valid.  Merely an anti-hacking precaution to deal with manually fudged POST data
    global $scoper, $wpdb;
    $post_type = sanitize_key($_POST['post_type']);
    $plural_name = plural_name_from_cap_rs(get_post_type_object($post_type));
    $args = array();
    $args['alternate_reqd_caps'][0] = array("create_child_{$plural_name}");
    if ($descendant_ids = scoper_get_page_descendant_ids($post_id)) {
        $exclusion_clause = "AND ID NOT IN('" . implode("','", $descendant_ids) . "')";
    } else {
        $exclusion_clause = '';
    }
    $qry_parents = "SELECT ID FROM {$wpdb->posts} WHERE post_type = '{$post_type}' AND post_status != 'auto-draft' {$exclusion_clause}";
    $qry_parents = apply_filters('objects_request_rs', $qry_parents, 'post', $post_type, $args);
    $valid_parents = scoper_get_col($qry_parents);
    $post = get_post($post_id);
    if ($parent_id) {
        if ($post && !in_array($parent_id, $valid_parents)) {
            $parent_id = $post->post_parent;
        }
    } else {
        if (!$GLOBALS['scoper_admin_filters']->user_can_associate_main($post_type)) {
            $already_published = false;
            if ($post) {
                if ($saved_status_object = get_post_status_object($post->post_status)) {
                    $already_published = $saved_status_object->public || $saved_status_object->private;
                }
            }
            if ($already_published) {
                // If post was previously published to another parent, revert it
                $parent_id = $post->post_parent;
            } elseif ($valid_parents) {
                // otherwise default to a valid parent
                sort($valid_parents);
                $parent_id = reset($valid_parents);
                $_POST['parent_id'] = (int) $parent_id;
                // for subsequent post_status filter
            }
        }
    }
    return (int) $parent_id;
}