function attachment_access()
 {
     global $post, $wpdb;
     if (empty($post)) {
         global $wp_query;
         if (!empty($wp_query->query_vars['attachment_id'])) {
             $post = scoper_get_row("SELECT * FROM {$wpdb->posts} WHERE post_type = 'attachment' AND ID = '{$wp_query->query_vars['attachment_id']}'");
         } elseif (!empty($wp_query->query_vars['attachment'])) {
             $post = scoper_get_row("SELECT * FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_name = '{$wp_query->query_vars['attachment']}'");
         }
     }
     if (!empty($post)) {
         $object_type = scoper_get_var("SELECT post_type FROM {$wpdb->posts} WHERE ID = '{$post->post_parent}'");
         // default to 'post' object type if retrieval failed for some reason
         if (empty($object_type)) {
             $object_type = 'post';
         }
         if ($post->post_parent) {
             if (!current_user_can("read_{$object_type}", $post->post_parent)) {
                 if (scoper_get_otype_option('do_teaser', 'post')) {
                     if ($use_teaser_type = scoper_get_otype_option('use_teaser', 'post', $object_type)) {
                         AttachmentTemplate_RS::impose_post_teaser($post, $object_type, $use_teaser_type);
                     } else {
                         unset($post);
                     }
                 } else {
                     unset($post);
                 }
                 // WordPress generates 404 if teaser is not enabled
             }
         } elseif (defined('SCOPER_BLOCK_UNATTACHED_UPLOADS') && SCOPER_BLOCK_UNATTACHED_UPLOADS) {
             unset($post);
         }
     }
 }
Example #2
0
 function otype_option_checkboxes($option_name, $caption, $tab_name, $section_name, $hint_text, $trailing_html, $args = array())
 {
     global $scoper, $scoper_admin;
     $defaults = array('caption_header' => true);
     $args = array_merge($defaults, $args);
     extract($args);
     $return = array('in_scope' => false, 'val' => array());
     if (in_array($option_name, $this->form_options[$tab_name][$section_name])) {
         $this->all_otype_options[] = $option_name;
         if (isset($this->def_otype_options[$option_name])) {
             if (!($return['val'] = scoper_get_option($option_name, $this->sitewide, $this->customize_defaults))) {
                 $return['val'] = array();
             }
             $return['val'] = array_merge($this->def_otype_options[$option_name], $return['val']);
             $label_property = isset($args['label_property']) ? $args['label_property'] : 'name';
             $first_pass = true;
             foreach ($return['val'] as $src_otype => $val) {
                 if ($caption_header && $first_pass) {
                     printf($caption, $scoper_admin->interpret_src_otype($src_otype, $label_property));
                     echo '<br /><div style="margin-left: 2em">';
                     $first_pass = false;
                 }
                 $arr_src_otype = explode(':', $src_otype);
                 if (!scoper_get_otype_option('use_object_roles', $arr_src_otype[0], $arr_src_otype[1])) {
                     continue;
                 }
                 $item_label = $scoper_admin->interpret_src_otype($src_otype, $label_property);
                 //arg: use plural display name
                 $id = str_replace(':', '_', $option_name . '-' . $src_otype);
                 echo "<label for='{$id}'>";
                 echo "<input name='{$id}' type='checkbox' id='{$id}' value='1' ";
                 checked('1', $val);
                 echo " /> ";
                 if ($caption_header) {
                     echo $item_label;
                 } else {
                     printf($caption, $item_label);
                 }
                 echo '</label><br />';
             }
             // end foreach src_otype
             if ($caption_header) {
                 echo '</div>';
             }
             if ($hint_text && $this->display_hints) {
                 echo "<span class='rs-subtext'>" . $hint_text . "</span>";
             }
             if ($trailing_html) {
                 echo $trailing_html;
             }
         }
         // endif default option isset
         $return['in_scope'] = true;
     }
     // endif in this option is controlled in this scope
     return $return;
 }
function scoper_admin_init()
{
    global $pagenow;
    if (in_array($pagenow, array('update.php', 'plugin-install.php', 'update-core.php', 'plugins.php'))) {
        require_once dirname(__FILE__) . '/plugin-update-watch_rs.php';
        RS_UpdateWatch::update_watch();
    }
    if (!empty($_POST['rs_submit']) || !empty($_POST['rs_defaults']) || !empty($_POST['rs_flush_cache'])) {
        // For 'options' and 'realm' admin panels, handle updated options right after current_user load (and before scoper init).
        // By then, check_admin_referer is available, but Scoper config and WP admin menu has not been loaded yet.
        require_once SCOPER_ABSPATH . '/submittee_rs.php';
        $handler = new Scoper_Submittee();
        if (isset($_POST['rs_submit'])) {
            $sitewide = isset($_POST['rs_options_doing_sitewide']);
            $customize_defaults = isset($_POST['rs_options_customize_defaults']);
            $handler->handle_submission('update', $sitewide, $customize_defaults);
        } elseif (isset($_POST['rs_defaults'])) {
            $sitewide = isset($_POST['rs_options_doing_sitewide']);
            $customize_defaults = isset($_POST['rs_options_customize_defaults']);
            $handler->handle_submission('default', $sitewide, $customize_defaults);
        } elseif (isset($_POST['rs_flush_cache'])) {
            $handler->handle_submission('flush');
        }
    }
    // work around conflict with Simple Fields plugin uploader
    if (defined('EASY_FIELDS_URL')) {
        if (strpos($_SERVER['SCRIPT_NAME'], '/wp-admin/media-upload.php') || strpos($_SERVER['SCRIPT_NAME'], '/wp-admin/async-upload.php')) {
            define('DISABLE_QUERYFILTERS_RS', true);
        }
    }
    if (defined('SSEO_VERSION')) {
        require_once dirname(__FILE__) . '/eyes-only-admin_rs.php';
    }
    global $pagenow;
    // prevent default_private option from forcing a draft/pending post into private publishing
    if (in_array($pagenow, array('post.php', 'post-new.php'))) {
        if (empty($_POST['publish']) && isset($_POST['post_status']) && isset($_POST['post_type']) && scoper_get_otype_option('default_private', 'post', $_POST['post_type'])) {
            $stati = get_post_stati(array('public' => true, 'private' => true), 'names', 'or');
            if ('private' == $_POST['visibility'] && !in_array($_POST['hidden_post_status'], $stati)) {
                $_POST['post_status'] = $_POST['hidden_post_status'];
                $_REQUEST['post_status'] = $_REQUEST['hidden_post_status'];
                $_POST['visibility'] = 'public';
                $_REQUEST['visibility'] = 'public';
            }
        }
    }
}
 function flt_user_has_cap($wp_blogcaps, $orig_reqd_caps, $args)
 {
     if (empty($args[2])) {
         return $wp_blogcaps;
     }
     // Disregard caps which are not defined in Role Scoper config
     if (!($rs_reqd_caps = array_intersect($orig_reqd_caps, $this->scoper->cap_defs->get_all_keys()))) {
         return $wp_blogcaps;
     }
     $user_id = isset($args[1]) ? $args[1] : 0;
     global $current_rs_user;
     if ($user_id && $user_id != $current_rs_user->ID) {
         $user = rs_get_user($user_id);
     } else {
         $user = $current_rs_user;
     }
     $object_id = (int) $args[2];
     if (!($post_type = get_post_field('post_type', $object_id))) {
         return $wp_blogcaps;
     }
     global $wpdb;
     $use_term_roles = scoper_get_otype_option('use_term_roles', 'post', $post_type);
     $use_object_roles = empty($src->no_object_roles) ? scoper_get_otype_option('use_object_roles', 'post', $post_type) : false;
     $this_args = array('object_type' => $post_type, 'user' => $user, 'otype_use_term_roles' => $use_term_roles, 'otype_use_object_roles' => $use_object_roles, 'skip_teaser' => true);
     $where = $this->query_interceptor->objects_where_role_clauses('post', $rs_reqd_caps, $this_args);
     if ($where) {
         $where = "AND ( {$where} )";
     }
     $id_ok = scoper_get_var("SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} WHERE 1=1 {$where} AND {$wpdb->posts}.ID = '{$object_id}' LIMIT 1");
     $rs_reqd_caps = array_fill_keys($rs_reqd_caps, true);
     if (!$id_ok) {
         //d_echo("object_id $object_id not okay!" );
         //rs_errlog( "object_id $object_id not okay!" );
         return array_diff_key($wp_blogcaps, $rs_reqd_caps);
         // required caps we scrutinized are excluded from this array
     } else {
         if ($restore_caps = array_diff($orig_reqd_caps, array_keys($rs_reqd_caps))) {
             $rs_reqd_caps = $rs_reqd_caps + array_fill_keys($restore_caps, true);
         }
         //rs_errlog( 'RETURNING:' );
         //rs_errlog( serialize(array_merge($wp_blogcaps, $rs_reqd_caps)) );
         return array_merge($wp_blogcaps, $rs_reqd_caps);
     }
 }
 function flt_manage_posts_columns($defaults)
 {
     global $current_user, $scoper, $scoper_role_usage;
     $object_type = cr_find_post_type();
     if ($blogwide_role_requirement = scoper_get_option('role_admin_blogwide_editor_only')) {
         if ('admin' == $blogwide_role_requirement && !is_user_administrator_rs()) {
             return $defaults;
         } elseif ('content_admin' == $blogwide_role_requirement && !is_content_administrator_rs()) {
             return $defaults;
         } elseif ($blogwide_role_requirement) {
             if (!$scoper->user_can_edit_blogwide('post', $object_type, array('require_others_cap' => true))) {
                 return $defaults;
             }
         }
     }
     $use_object_roles = scoper_get_otype_option('use_object_roles', 'post', $object_type);
     $use_term_roles = scoper_get_otype_option('use_term_roles', 'post', $object_type);
     if ($use_term_roles && !empty($scoper_role_usage->any_restricted_terms) || $use_object_roles && !empty($scoper_role_usage->any_restricted_objects)) {
         if (scoper_get_otype_option('restrictions_column', 'post', $object_type)) {
             $defaults['restricted'] = __('Restrict', 'scoper');
         }
     }
     if (!empty($scoper_role_usage->have_termrole_ids['post'])) {
         if (scoper_get_otype_option('term_roles_column', 'post', $object_type)) {
             $defaults['termroles'] = __('Term Roles', 'scoper');
         }
     }
     if ($use_object_roles && !empty($scoper_role_usage->have_objrole_ids['post'])) {
         if (scoper_get_otype_option('object_roles_column', 'post', $object_type)) {
             $otype_display_name = $scoper->data_sources->member_property('post', 'object_types', $object_type, 'display_name');
             //$defaults['objroles'] = sprintf( _ x('%s Roles', 'Post or Page', 'scoper'), $otype_display_name);
             $defaults['objroles'] = sprintf(__('%s Roles', 'scoper'), $otype_display_name);
         }
     }
     return $defaults;
 }
function scoper_get_taxonomy_usage($src_name, $object_types = '')
{
    $taxonomies = array();
    $object_types = (array) $object_types;
    foreach ($object_types as $object_type) {
        if (taxonomy_exists($object_type)) {
            $use_taxonomies = array($object_type => 1);
        } else {
            $use_taxonomies = scoper_get_otype_option('use_term_roles', $src_name, $object_type);
        }
        $taxonomies = array_merge($taxonomies, array_intersect((array) $use_taxonomies, array(1)));
        // array cast prevents PHP warning on first-time execution following update to RS 1.2
    }
    if ($taxonomies) {
        // make sure we indicate non-usage of term roles for taxonomies that are completely disabled for RS
        if ('post' == $src_name) {
            $use_taxonomies = scoper_get_option('use_taxonomies');
            $taxonomies = array_intersect_key($taxonomies, array_intersect($use_taxonomies, array(1)));
        }
        return array_keys($taxonomies);
    } else {
        return array();
    }
}
 function get_terms_reqd_caps($taxonomy, $operation = '', $is_term_admin = false)
 {
     global $pagenow;
     if (!($src_name = $this->taxonomies->member_property($taxonomy, 'object_source'))) {
         if (taxonomy_exists($taxonomy)) {
             $src_name = 'post';
         }
     }
     $return_caps = array();
     $is_term_admin = $is_term_admin || in_array($pagenow, array('edit-tags.php')) || ('nav_menu' == $taxonomy && 'nav-menus.php' == $pagenow || 'admin-ajax.php' == $pagenow && (!empty($_REQUEST['action']) && in_array($_REQUEST['action'], array('add-menu-item', 'menu-locations-save'))));
     // possible TODO: abstract for non-WP taxonomies
     if ($is_term_admin) {
         // query pertains to the management of terms
         if ('post' == $src_name) {
             $taxonomy_obj = get_taxonomy($taxonomy);
             $return_caps[$taxonomy] = array($taxonomy_obj->cap->manage_terms);
         } elseif ('link_category' == $taxonomy) {
             $return_caps[$taxonomy] = array('manage_categories');
         } else {
             global $scoper;
             $cap_defs = $scoper->cap_defs->get_matching($src_name, $taxonomy, OP_ADMIN_RS);
             $return_caps[$taxonomy] = $cap_defs ? array_keys($cap_defs) : array();
         }
     } else {
         // query pertains to reading or editing content within certain terms, or adding terms to content
         $base_caps_only = true;
         if ('post' == $src_name) {
             if (!$operation) {
                 $operation = $this->is_front() || 'profile.php' == $pagenow || is_admin() && 's2' == $GLOBALS['plugin_page'] ? 'read' : 'edit';
             }
             // hack to support subscribe2 categories checklist
             $status = 'read' == $operation ? 'publish' : 'draft';
             // terms query should be limited to a single object type for post.php, post-new.php, so only return caps for that object type (TODO: do this in wp-admin regardless of URI ?)
             if (in_array($pagenow, array('post.php', 'post-new.php'))) {
                 $object_type = cr_find_post_type();
             }
         } else {
             if (!$operation) {
                 $operation = $this->is_front() ? 'read' : 'edit';
             }
             $status = '';
         }
         // The return array will indicate term role enable / disable, as well as associated capabilities
         if (!empty($object_type)) {
             $check_object_types = array($object_type);
         } else {
             if ($check_object_types = (array) $this->data_sources->member_property($src_name, 'object_types')) {
                 $check_object_types = array_keys($check_object_types);
             }
         }
         if ('post' == $src_name) {
             $use_post_types = scoper_get_option('use_post_types');
         }
         $enabled_object_types = array();
         foreach ($check_object_types as $_object_type) {
             if ($use_term_roles = scoper_get_otype_option('use_term_roles', $src_name, $_object_type)) {
                 if (!empty($use_term_roles[$taxonomy])) {
                     if ('post' != $src_name || !empty($use_post_types[$_object_type])) {
                         $enabled_object_types[] = $_object_type;
                     }
                 }
             }
         }
         foreach ($enabled_object_types as $object_type) {
             $return_caps[$object_type] = cr_get_reqd_caps($src_name, $operation, $object_type, $status, $base_caps_only);
         }
     }
     return $return_caps;
 }
 function display_ui_user_roles($user, $groups_only = false)
 {
     global $scoper;
     $blog_roles = array();
     $term_roles = array();
     $blog_roles = $user->get_blog_roles_daterange('rs', array('include_role_duration_key' => true, 'enforce_duration_limits' => false));
     // arg: return array with additional key dimension for role duration
     // for Administrators, display any custom post General Roles which were auto-assigned to maintain default editing rights
     global $current_rs_user;
     if ($current_rs_user->ID == $user->ID) {
         if (is_content_administrator_rs()) {
             $blog_roles[''][''] = isset($blog_roles['']['']) ? array_merge($current_rs_user->assigned_blog_roles['']) : $current_rs_user->assigned_blog_roles[''];
         }
     }
     foreach ($this->scoper->taxonomies->get_all() as $taxonomy => $tx) {
         $term_roles[$taxonomy] = $user->get_term_roles_daterange($taxonomy, 'rs', array('include_role_duration_key' => true, 'enforce_duration_limits' => false));
     }
     // arg: return array with additional key dimension for role duration
     $duration_limits_enabled = scoper_get_option('role_duration_limits');
     $content_date_limits_enabled = scoper_get_option('role_content_date_limits');
     $html = '';
     if ($groups_only) {
         if (IS_MU_RS && scoper_get_option('mu_sitewide_groups', true)) {
             global $blog_id;
             $list = scoper_get_blog_list(0, 'all');
             $blog_path = '';
             foreach ($list as $blog) {
                 if ($blog['blog_id'] == $blog_id) {
                     $blog_path = $blog['path'];
                     break;
                 }
             }
             $group_caption = sprintf(__('Group Roles %1$s(for %2$s)%3$s', 'scoper'), '<span style="font-weight: normal">', rtrim($blog_path, '/'), '</span>');
         } else {
             $group_caption = __('Group Roles', 'scoper');
         }
     } else {
         $html .= "<div id='userprofile_rolesdiv_rs' class='rs-scoped_role_profile'>";
         $html .= "<h3>" . __('Scoped Roles', 'scoper') . "</h3>";
         $wp_blog_roles = array_intersect_key($user->assigned_blog_roles[''], $scoper->role_defs->get_matching('wp'));
         if (!empty($wp_blog_roles)) {
             $display_names = array();
             foreach (array_keys($wp_blog_roles) as $role_handle) {
                 $display_names[] = $scoper->role_defs->get_display_name($role_handle);
             }
             $html .= sprintf(__("<strong>Assigned WordPress Role:</strong> %s", 'scoper'), implode(", ", $display_names));
             if ($contained_roles = $this->scoper->role_defs->get_contained_roles(array_keys($wp_blog_roles), false, 'rs')) {
                 $display_names = array();
                 foreach (array_keys($contained_roles) as $role_handle) {
                     $display_names[] = $this->scoper->role_defs->get_display_name($role_handle);
                 }
                 $html .= '<br /><span class="rs-gray">';
                 $html .= sprintf(__("(contains %s)", 'scoper'), implode(", ", $display_names));
                 $html .= '</span>';
             }
         }
         $html .= '<br /><br />';
     }
     $display_names = array();
     foreach (array_keys($blog_roles) as $duration_key) {
         if (is_serialized($duration_key)) {
             $role_date_limits = unserialize($duration_key);
             $role_date_limits->date_limited = true;
         } else {
             $role_date_limits = array();
         }
         foreach (array_keys($blog_roles[$duration_key]) as $date_key) {
             $display_names = array();
             if (is_serialized($date_key)) {
                 $content_date_limits = unserialize($date_key);
                 $content_date_limits->content_date_limited = true;
             } else {
                 $content_date_limits = array();
             }
             $date_caption = '';
             if ($role_date_limits || $content_date_limits) {
                 $limit_class = '';
                 // unused byref arg
                 $limit_style = '';
                 // unused byref arg
                 $link_class = '';
                 // unused byref arg
                 ScoperAdminUI::set_agent_formatting(array_merge((array) $role_date_limits, (array) $content_date_limits), $date_caption, $limit_class, $link_class, $limit_style, false);
                 // arg: no title='' wrapper around date_caption
                 $date_caption = '<span class="rs-gray"> ' . trim($date_caption) . '</span>';
             }
             if ($rs_blog_roles = $this->scoper->role_defs->filter($blog_roles[$duration_key][$date_key], array('role_type' => 'rs'))) {
                 foreach (array_keys($rs_blog_roles) as $role_handle) {
                     $display_names[] = $this->scoper->role_defs->get_display_name($role_handle);
                 }
                 $url = "admin.php?page=rs-general_roles";
                 $linkopen = "<strong><a href='{$url}'>";
                 $linkclose = "</a></strong>";
                 $list = implode(", ", $display_names);
                 if ($groups_only) {
                     $html .= sprintf(_n('<strong>%1$sGeneral Role%2$s</strong>%4$s: %3$s', '<strong>%1$sGeneral Roles%2$s</strong>%4$s: %3$s', count($display_names), 'scoper'), $linkopen, $linkclose, $list, $date_caption);
                 } else {
                     $html .= sprintf(_n('<strong>Additional %1$sGeneral Role%2$s</strong>%4$s: %3$s', '<strong>Additional %1$sGeneral Roles%2$s</strong>%4$s: %3$s', count($display_names), 'scoper'), $linkopen, $linkclose, $list, $date_caption);
                 }
                 if ($contained_roles = $this->scoper->role_defs->get_contained_roles(array_keys($rs_blog_roles), false, 'rs')) {
                     $display_names = array();
                     foreach (array_keys($contained_roles) as $role_handle) {
                         $display_names[] = $this->scoper->role_defs->get_display_name($role_handle);
                     }
                     $html .= '<br /><span class="rs-gray">';
                     $html .= sprintf(__("(contains %s)", 'scoper'), implode(", ", $display_names));
                     $html .= '</span>';
                 }
                 $html .= '<br /><br />';
             }
         }
         // end foreach content date range
     }
     // end foreach role duration date range
     $disable_role_admin = false;
     global $profileuser;
     $viewing_own_profile = !empty($profileuser) && $profileuser->ID == $current_rs_user->ID;
     if (!$viewing_own_profile) {
         if ($require_blogwide_editor = scoper_get_option('role_admin_blogwide_editor_only')) {
             if ('admin' == $require_blogwide_editor && !is_user_administrator_rs()) {
                 return false;
             }
             if ('admin_content' == $require_blogwide_editor && !is_content_administrator_rs()) {
                 return false;
             }
             $disable_role_admin = !$scoper->user_can_edit_blogwide('post', '', array('require_others_cap' => true, 'status' => 'publish'));
         }
     }
     foreach ($this->scoper->taxonomies->get_all() as $taxonomy => $tx) {
         if (empty($term_roles[$taxonomy])) {
             continue;
         }
         $val = ORDERBY_HIERARCHY_RS;
         $args = array('order_by' => $val);
         if (!($terms = $this->scoper->get_terms($taxonomy, UNFILTERED_RS, COLS_ALL_RS, 0, $args))) {
             continue;
         }
         $object_types = array();
         $obj_src = $this->scoper->data_sources->get($tx->object_source);
         if (!$obj_src || !is_array($obj_src->object_types)) {
             continue;
         }
         foreach (array_keys($obj_src->object_types) as $object_type) {
             if (scoper_get_otype_option('use_term_roles', $tx->object_source, $object_type)) {
                 $object_types[] = $object_type;
             }
         }
         if (!$object_types) {
             continue;
         }
         $object_types[] = $taxonomy;
         $admin_terms = $disable_role_admin ? array() : $this->scoper->get_terms($taxonomy, ADMIN_TERMS_FILTER_RS, COL_ID_RS);
         $strict_terms = $this->scoper->get_restrictions(TERM_SCOPE_RS, $taxonomy);
         $role_defs = $this->scoper->role_defs->get_matching('rs', $tx->object_source, $object_types);
         $tx_src = $this->scoper->data_sources->get($tx->source);
         $col_id = $tx_src->cols->id;
         $col_name = $tx_src->cols->name;
         $term_names = array();
         foreach ($terms as $term) {
             $term_names[$term->{$col_id}] = $term->{$col_name};
         }
         foreach (array_keys($term_roles[$taxonomy]) as $duration_key) {
             if (is_serialized($duration_key)) {
                 $role_date_limits = unserialize($duration_key);
                 $role_date_limits->date_limited = true;
             } else {
                 $role_date_limits = array();
             }
             foreach (array_keys($term_roles[$taxonomy][$duration_key]) as $date_key) {
                 if (is_serialized($date_key)) {
                     $content_date_limits = unserialize($date_key);
                     $content_date_limits->content_date_limited = true;
                 } else {
                     $content_date_limits = array();
                 }
                 $title = '';
                 $date_caption = '';
                 $limit_class = '';
                 $limit_style = '';
                 $link_class = '';
                 $style = '';
                 if ($role_date_limits || $content_date_limits) {
                     ScoperAdminUI::set_agent_formatting(array_merge((array) $role_date_limits, (array) $content_date_limits), $date_caption, $limit_class, $link_class, $limit_style);
                     $title = "title='{$date_caption}'";
                     $date_caption = '<span class="rs-gray"> ' . trim($date_caption) . '</span>';
                 }
                 if ($admin_terms) {
                     $url = "admin.php?page=rs-{$taxonomy}-roles_t";
                     //$html .= ("\n<h4><a href='$url'>" . sprintf(_ x('%1$s Roles%2$s:', 'Category Roles, content date range', 'scoper'), $tx->display_name, '</a><span style="font-weight:normal">' . $date_caption) . '</span></h4>' );
                     $html .= "\n<h4><a href='{$url}'>" . sprintf(__('%1$s Roles%2$s:', 'scoper'), $tx->labels->singular_name, '</a><span style="font-weight:normal">' . $date_caption) . '</span></h4>';
                 } else {
                     $html .= "\n<h4>" . sprintf(__('%1$s Roles%2$s:', 'scoper'), $tx->labels->singular_name, $date_caption) . '</h4>';
                 }
                 //$html .= ("\n<h4>" . sprintf(_ x('%1$s Roles%2$s:', 'Category Roles, content date range', 'scoper'), $tx->display_name, $date_caption) . '</h4>' );
                 $html .= '<ul class="rs-termlist" style="padding-left:0.1em;">';
                 $html .= '<li>';
                 $html .= '<table class="widefat"><thead><tr class="thead">';
                 $html .= '<th class="rs-tightcol">' . __awp('Role') . '</th>';
                 $html .= '<th>' . $tx->labels->name . '</th>';
                 $html .= '</tr></thead><tbody>';
                 foreach (array_keys($role_defs) as $role_handle) {
                     if (isset($term_roles[$taxonomy][$duration_key][$date_key][$role_handle])) {
                         $role_terms = $term_roles[$taxonomy][$duration_key][$date_key][$role_handle];
                         $role_display = $this->scoper->role_defs->get_display_name($role_handle);
                         $term_role_list = array();
                         foreach ($role_terms as $term_id) {
                             if (!in_array($term_id, $admin_terms)) {
                                 $term_role_list[] = $term_names[$term_id];
                             } elseif (isset($strict_terms['restrictions'][$role_handle][$term_id]) || isset($strict_terms['unrestrictions'][$role_handle]) && is_array($strict_terms['unrestrictions'][$role_handle]) && !isset($strict_terms['unrestrictions'][$role_handle][$term_id])) {
                                 $term_role_list[] = "<span class='rs-backylw'><a {$title}{$limit_style}class='{$link_class}{$limit_class}' href='{$url}#item-{$term_id}'>" . $term_names[$term_id] . '</a></span>';
                             } else {
                                 $term_role_list[] = "<a {$title}{$limit_style}class='{$link_class}{$limit_class}' href='{$url}#item-{$term_id}'>" . $term_names[$term_id] . '</a>';
                             }
                         }
                         $html .= "\r\n" . "<tr{$style}>" . "<td>" . str_replace(' ', '&nbsp;', $role_display) . "</td>" . '<td>' . implode(', ', $term_role_list) . '</td>' . "</tr>";
                         $style = ' class="alternate"' == $style ? ' class="rs-backwhite"' : ' class="alternate"';
                     }
                 }
                 $html .= '</tbody></table>';
                 $html .= '</li></ul><br />';
             }
             // end foreach content date range
         }
         // end foreach role duration date range
     }
     // end foreach taxonomy
     require_once dirname(__FILE__) . '/object_roles_list.php';
     $html .= scoper_object_roles_list($user, array('enforce_duration_limits' => false, 'is_user_profile' => $viewing_own_profile, 'echo' => false));
     if ($groups_only) {
         //if ( empty($rs_blog_roles) && empty($term_role_list) && empty($got_obj_roles) )
         if ($html) {
             echo '<div>';
             echo "<h3>{$group_caption}</h3>";
             echo $html;
             echo '</div>';
             if (IS_MU_RS) {
                 echo '<br /><hr /><br />';
             }
         }
         //echo '<p>' . __('No roles are assigned to this group.', 'scoper'), '</p>';
     } else {
         echo $html;
         echo '</div>';
     }
 }
 function flt_objects_listing($results, $src_name, $object_types, $args = array())
 {
     global $wpdb;
     // it's not currently necessary or possible to log listed revisions from here
     //if ( isset($wpdb->last_query) && strpos( $wpdb->last_query, "post_type = 'revision'") )
     //	return $results;
     // if currently listed IDs are not already in post_cache, make our own equivalent memcache
     // ( create this cache for any data source, front end or admin )
     if ('post' == $src_name) {
         global $wp_object_cache;
     }
     $listed_ids = array();
     //if ( ('post' != $src_name) || empty($wp_object_cache->cache['posts']) ) {
     if (empty($this->scoper->listed_ids[$src_name])) {
         if ($col_id = $this->scoper->data_sources->member_property($src_name, 'cols', 'id')) {
             $listed_ids = array();
             // In edit.php, WP forces all objects into recordset for hierarchical post types.  But for perf enchancement, we need to know IDs of items which are actually listed
             if ('edit.php' == $GLOBALS['pagenow']) {
                 $post_type = !empty($_GET['post_type']) ? sanitize_key($_GET['post_type']) : 'post';
                 $determine_listed_ids = !is_content_administrator_rs() && is_post_type_hierarchical($post_type) && !empty($GLOBALS['query_interceptor']->last_request[$src_name]) && !strpos($GLOBALS['query_interceptor']->last_request[$src_name], 'LIMIT ');
                 if ($determine_listed_ids) {
                     // mimic recordset paging used in edit.php
                     $pagenum = isset($_GET['paged']) ? absint($_GET['paged']) : 0;
                     if (empty($pagenum)) {
                         $pagenum = 1;
                     }
                     $edit_per_page = 'edit_' . $post_type . '_per_page';
                     $per_page = (int) get_user_option($edit_per_page);
                     if (empty($per_page) || $per_page < 1) {
                         $per_page = 20;
                     }
                     $per_page = apply_filters($edit_per_page, $per_page);
                     $per_page = apply_filters('edit_posts_per_page', $per_page, $post_type);
                     if (count($results) <= $per_page) {
                         $determine_listed_ids = false;
                     }
                 }
             } else {
                 $determine_listed_ids = false;
             }
             if ($determine_listed_ids) {
                 // Construct and execute a secondary query (for IDs only) which includes the paging clause that would be used if edit.php did not defeat it
                 $pgstrt = ($pagenum - 1) * $per_page . ', ';
                 $limits = ' LIMIT ' . $pgstrt . $per_page;
                 global $wpdb;
                 $qry = $GLOBALS['query_interceptor']->last_request[$src_name] . $limits;
                 $qry = str_replace("{$wpdb->posts}.*", "{$wpdb->posts}.ID", $qry);
                 $_results = scoper_get_results($qry);
                 foreach ($_results as $row) {
                     if (isset($row->{$col_id})) {
                         $listed_ids[$row->{$col_id}] = true;
                     }
                 }
             } else {
                 // No secondary query, just buffer all IDs in the results set
                 foreach ($results as $row) {
                     if (isset($row->{$col_id})) {
                         $listed_ids[$row->{$col_id}] = true;
                     }
                 }
             }
             if (empty($this->scoper->listed_ids)) {
                 $this->scoper->listed_ids = array();
             }
             $this->scoper->listed_ids[$src_name] = $listed_ids;
         }
     } else {
         return $results;
     }
     //}
     // now determine what restrictions were in place on these results
     // (currently only for post data source, front end or manage posts/pages)
     //
     // possible todo: support other data sources, WP role type
     if ('edit.php' == $GLOBALS['pagenow']) {
         if (scoper_get_otype_option('restrictions_column', 'post') || scoper_get_otype_option('term_roles_column', 'post') || scoper_get_otype_option('object_roles_column', 'post')) {
             global $scoper_role_usage;
             require_once dirname(__FILE__) . '/role_usage_rs.php';
             $scoper_role_usage = new Role_Usage_RS();
             $scoper_role_usage->determine_role_usage_rs('post', $listed_ids);
         }
     }
     return $results;
 }
 function flt_objects_where($where, $src_name, $object_types = '', $args = array())
 {
     $defaults = array('user' => '', 'use_object_roles' => -1, 'use_term_roles' => -1, 'taxonomies' => array(), 'request' => '', 'terms_query' => 0, 'force_reqd_caps' => '', 'alternate_reqd_caps' => '', 'source_alias' => '', 'required_operation' => '', 'terms_reqd_caps' => '', 'skip_teaser' => false);
     $args = array_merge($defaults, (array) $args);
     extract($args);
     // filtering in user_has_cap sufficiently controls revision access; a match here should be for internal, pre-validation purposes
     if (strpos($where, "post_type = 'revision'")) {
         return $where;
     }
     $where_prepend = '';
     //rs_errlog ("object_where input: $where");
     //rs_errlog ('');
     //d_echo ("<br /><strong>object_where input:</strong> $where<br />");
     //echo "<br />$where<br />";
     if (!is_object($user)) {
         $user = $GLOBALS['current_rs_user'];
         $args['user'] = $user;
     }
     if (!($src = $this->scoper->data_sources->get($src_name))) {
         return $where;
     }
     // the specified data source is not know to Role Scoper
     $src_table = !empty($source_alias) ? $source_alias : $src->table;
     // verify table name and id col definition (the actual existance checked at time of admin entry)
     if (!($src->table && $src->cols->id)) {
         rs_notice(sprintf('Role Scoper Configuration Error: table_basename or col_id are undefined for the %s data source.', $src_name));
         return $where;
     }
     // need to allow ambiguous object type for special cap requirements like comment filtering
     $object_types = $this->_get_object_types($src, $object_types);
     $tease_otypes = array_intersect($object_types, $this->_get_teaser_object_types($src_name, $object_types, $args));
     if (!empty($src->no_object_roles)) {
         $use_object_roles = false;
     }
     if ($terms_query && $terms_reqd_caps) {
         foreach (array_keys($terms_reqd_caps) as $_object_type) {
             $otype_status_reqd_caps[$_object_type][''] = $terms_reqd_caps[$_object_type];
         }
         // terms request does not support multiple statuses
     } else {
         if ($force_reqd_caps && is_array($force_reqd_caps)) {
             $otype_status_reqd_caps = $force_reqd_caps;
         } else {
             global $wpdb;
             if (!$required_operation) {
                 $required_operation = 'front' == CURRENT_ACCESS_NAME_RS ? OP_READ_RS : OP_EDIT_RS;
             }
             $preview_future = strpos($where, "{$wpdb->posts}.post_name =") || strpos($where, "{$wpdb->posts}.ID =");
             if (!($otype_status_reqd_caps = cr_get_reqd_caps($src_name, $required_operation, -1, -1, false, $preview_future))) {
                 return $where;
             }
         }
         $otype_status_reqd_caps = array_intersect_key($otype_status_reqd_caps, array_flip($object_types));
     }
     // Since Role Scoper can restrict or expand access regardless of post_status, query must be modified such that
     //  * the default owner inclusion clause "OR post_author = [user_id] AND post_status = 'private'" is removed
     //  * all statuses are listed apart from owner inclusion clause (and each of these status clauses is subsequently replaced with a scoped equivalent which imposes any necessary access limits)
     //  * a new scoped owner clause is constructed where appropriate (see $where[$cap_name]['owner'] in function objects_where_role_clauses()
     //
     if ($src->cols->owner && $user->ID) {
         // force standard query padding
         $where = preg_replace("/{$src->cols->owner}\\s*=\\s*/", "{$src->cols->owner} = ", $where);
         $where = str_replace(" {$src->cols->owner} =", " {$src_table}.{$src->cols->owner} =", $where);
         $where = str_replace(" {$src->cols->owner} IN", " {$src_table}.{$src->cols->owner} IN", $where);
     }
     if (!empty($src->query_replacements)) {
         foreach ($src->query_replacements as $find => $replace) {
             // for posts_request, remove the owner inclusion clause "OR post_author = [user_id] AND post_status = 'private'" because we'll account for each status based on properties of required caps
             $find_ = str_replace('[user_id]', $user->ID, $find);
             if (false !== strpos($find_, '[') || false !== strpos($find_, ']')) {
                 rs_notice(sprintf('Role Scoper Config Error: invalid query clause search criteria for %1$s (%2$s).<br /><br />Valid placeholders are:<br />', $src_name, $find) . print_r(array_keys($map)));
                 return ' AND 1=2 ';
             }
             $replace_ = str_replace('[user_id]', $user->ID, $replace);
             if (false !== strpos($replace_, '[') || false !== strpos($replace_, ']')) {
                 rs_notice(sprintf('Role Scoper Config Error: invalid query clause replacement criteria for %1$s (%2$s).<br /><br />Valid placeholders are:<br />', $src_name, $replace) . print_r(array_keys($map)));
                 return ' AND 1=2 ';
             }
             $where = str_replace($find_, $replace_, $where);
         }
     }
     $force_single_type = false;
     $col_type = !empty($src->cols->type) ? $src->cols->type : '';
     if ($col_type) {
         // If the passed request contains a single object type criteria, maintain that status exclusively (otherwise include type-specific conditions for each available type)
         $matches = array();
         $num_matches = preg_match_all("/{$col_type}\\s*=\\s*'([^']+)'/", $where, $matches);
         if (1 == $num_matches) {
             $force_single_type = true;
             $object_types = array($matches[1][0]);
             if ($matched_reqd_caps = array_intersect_key($otype_status_reqd_caps, array_flip($object_types))) {
                 // sanity check prevents running with an empty reqd_caps array if something goes wrong with otype detection
                 $otype_status_reqd_caps = $matched_reqd_caps;
             }
         }
     }
     if ('post' == $src_name && !array_intersect($object_types, array_keys(array_intersect(scoper_get_option('use_post_types'), array(true))))) {
         return $where;
     } elseif (empty($otype_status_reqd_caps)) {
         return ' AND 1=2 ';
     }
     $basic_status_clause = array();
     $force_single_status = false;
     $status_clause_pos = 0;
     $col_status = !empty($src->cols->status) ? $src->cols->status : '';
     if ($col_status) {
         // force standard query padding
         $where = preg_replace("/{$col_status}\\s*=\\s*'/", "{$col_status} = '", $where);
         $where = str_replace(" {$col_status} =", " {$src_table}.{$col_status} =", $where);
         $where = str_replace(" {$col_status} IN", " {$src_table}.{$col_status} IN", $where);
         foreach (array_keys($otype_status_reqd_caps) as $listing_otype) {
             foreach (array_keys($otype_status_reqd_caps[$listing_otype]) as $status) {
                 $basic_status_clause[$status] = "{$src_table}.{$col_status} = '{$status}'";
             }
         }
         // If the passed request contains a single status criteria, maintain that status exclusively (otherwise include status-specific conditions for each available status)
         // (But not if user is anon and hidden content teaser is enabled.  In that case, we need to replace the default "status=publish" clause)
         $matches = array();
         if ($num_matches = preg_match_all("/{$src_table}.{$col_status}\\s*=\\s*'([^']+)'/", $where, $matches)) {
             $status_clause_pos = strpos($where, $matches[0][0]);
         }
         // note the match position for use downstream
         if (1 == $num_matches) {
             $use_status = $matches[1][0];
             // Eliminate a primary plugin incompatibility by skipping this preservation of existing single status requirements if we're on the front end and the requirement is 'publish'.
             // (i.e. include private posts that this user has access to via RS role assignment).
             if (!$this->scoper->is_front() || 'publish' != $use_status || empty($args['user']->ID) && empty($tease_otypes) || defined('SCOPER_RETAIN_PUBLISH_FILTER')) {
                 $force_single_status = true;
                 foreach (array_keys($otype_status_reqd_caps) as $_object_type) {
                     $otype_status_reqd_caps[$_object_type] = array_intersect_key($otype_status_reqd_caps[$_object_type], array($use_status => true));
                 }
             }
         }
     } else {
         // this source doesn't define statuses
         $basic_status_clause = array('' => '');
     }
     if (empty($skip_teaser) && !array_diff($object_types, $tease_otypes)) {
         if ($status_clause_pos && $force_single_type) {
             // All object types potentially returned by this query will have a teaser filter applied to results, so we don't need to filter the query
             // override our sanity safeguard against exposing private posts to anonymous readers
             if (empty($user->ID)) {
                 // Since we're dropping out of this function early in advance of teaser filtering,
                 // must take this opportunity to add private status to the query (otherwise WP excludes private for anon user)
                 // (But don't do this if teaser is configured to hide private content)
                 $check_otype = count($tease_otypes) && in_array('post', $tease_otypes) ? 'post' : $tease_otypes[0];
                 $post_type_obj = get_post_type_object($check_otype);
                 if (!scoper_get_otype_option('teaser_hide_private', $src_name, $check_otype) && (!$post_type_obj->hierarchical || scoper_get_otype_option('private_items_listable', 'post', 'page'))) {
                     if ($col_status && isset($otype_status_reqd_caps[$check_otype])) {
                         $status_or = "{$src_table}.{$col_status} = '" . implode("' OR {$src_table}.{$col_status} = '", array_keys($otype_status_reqd_caps[$check_otype])) . "'";
                         $where = str_replace($basic_status_clause['publish'], "( {$status_or} )", $where);
                     } else {
                         $where = str_replace($basic_status_clause['publish'], "1=1", $where);
                     }
                 }
             }
         }
         return $where;
     }
     $is_administrator = is_content_administrator_rs();
     // make sure administrators never have content limited
     $status_or = '';
     $status_where = array();
     foreach ($otype_status_reqd_caps as $object_type => $status_reqd_caps) {
         if (!is_array($status_reqd_caps)) {
             rs_notice(sprintf('Role Scoper Configuration Error: reqd_caps for the %s data source must be array[operation][object_type][status] where operation is "read", "edit" or "admin".', $src_name));
             return $where;
         }
         // don't bother generating these parameters if we're just going to pass the object type through for teaser filtering
         if (!in_array($object_type, $tease_otypes)) {
             if (true === $use_term_roles) {
                 // if boolean true was passed in, force usage of all term roles
                 if ('post' == $src_name) {
                     //$otype_use_term_roles = array_fill_keys( get_taxonomies( array( 'public' => true, 'object_type' => $object_type ) ), 1 );
                     $otype_use_term_roles = array();
                     foreach (get_taxonomies(array('public' => true), 'object') as $taxonomy => $taxonomy_obj) {
                         if (in_array($object_type, $taxonomy_obj->object_type)) {
                             $otype_use_term_roles[$taxonomy] = 1;
                         }
                     }
                 } else {
                     $otype_use_term_roles = !empty($src->uses_taxonomies) ? array_fill_keys($src->uses_taxonomies, true) : array();
                 }
             } else {
                 $check_object_type = 'link_category' == $object_type ? 'link' : $object_type;
                 $otype_use_term_roles = -1 == $use_term_roles ? scoper_get_otype_option('use_term_roles', $src_name, $check_object_type) : false;
             }
             if (!$otype_use_term_roles && $terms_query) {
                 continue;
             }
             // if a boolean was passed in, override the stored option
             $otype_use_object_roles = -1 == $use_object_roles ? scoper_get_otype_option('use_object_roles', $src_name, $object_type) : $use_object_roles;
         } else {
             $otype_use_term_roles = false;
             $otype_use_object_roles = false;
         }
         //now step through all statuses and corresponding cap requirements for this otype and access type
         // (will replace "col_status = status_name" with "col_status = status_name AND ( [scoper requirements] )
         foreach ($status_reqd_caps as $status_name => $reqd_caps) {
             if ('trash' == $status_name) {
                 // in wp-admin, we need to include trash posts for the count query, but not for the listing query unless trash status is requested
                 if ((empty($this->last_request[$src_name]) || !strpos($this->last_request[$src_name], 'COUNT')) && (empty($_GET['post_status']) || 'trash' != $_GET['post_status'])) {
                     continue;
                 }
             }
             if ($is_administrator) {
                 $status_where[$status_name][$object_type] = '1=1';
             } elseif (empty($skip_teaser) && in_array($object_type, $tease_otypes)) {
                 if ($terms_query && !$otype_use_object_roles) {
                     $status_where[$status_name][$object_type] = '1=1';
                 } else {
                     $status_where[$status_name][$object_type] = "{$src_table}.{$src->cols->type} = '{$object_type}'";
                 }
             } else {
                 // filter defs for otypes which don't define a status will still have a single status element with value ''
                 $args = array_merge($args, array('object_type' => $object_type, 'otype_use_term_roles' => $otype_use_term_roles, 'otype_use_object_roles' => $otype_use_object_roles));
                 $clause = $this->objects_where_role_clauses($src_name, $reqd_caps, $args);
                 if (empty($clause) || '1=2' == $clause) {
                     // this means no qualifying roles are available
                     $status_where[$status_name][$object_type] = '1=2';
                 } elseif (count($otype_status_reqd_caps) > 1 && (!$terms_query || $otype_use_object_roles)) {
                     // more than 1 object type
                     $status_where[$status_name][$object_type] = "( {$src_table}.{$src->cols->type} = '{$object_type}' AND ( {$clause} ) )";
                 } else {
                     $status_where[$status_name][$object_type] = $clause;
                 }
             }
         }
     }
     // all otype clauses concat: object_type1 clause [OR] [object_type2 clause] [OR] ...
     foreach (array_keys($status_where) as $status_name) {
         if (isset($preserve_or_clause[$status_name])) {
             $status_where[$status_name][] = $preserve_or_clause[$status_name];
         }
         if ($tease_otypes) {
             $check_otype = count($tease_otypes) && in_array('post', $tease_otypes) ? 'post' : $tease_otypes[0];
         }
         // extra line of defense: even if upstream logic goes wrong, never disclose a private item to anon user (but if the where clause was passed in with explicit status=private, must include our condition)
         if ('private' == $status_name && !$force_single_status && empty($GLOBALS['current_user']->ID) && (!$tease_otypes || scoper_get_otype_option('teaser_hide_private', $src_name, $check_otype))) {
             unset($status_where[$status_name]);
         } else {
             $status_where[$status_name] = agp_implode(' ) OR ( ', $status_where[$status_name], ' ( ', ' ) ');
         }
     }
     // combine identical status clauses
     $duplicate_clause = array();
     $replace_clause = array();
     if ($col_status && count($status_where) > 1) {
         // more than one status clause
         foreach ($status_where as $status_name => $status_clause) {
             if (isset($duplicate_clause[$status_name])) {
                 continue;
             }
             reset($status_where);
             if ($other_status_name = array_search($status_clause, $status_where)) {
                 if ($other_status_name == $status_name) {
                     $other_status_name = array_search($status_clause, $status_where);
                 }
                 if ($other_status_name && $other_status_name != $status_name) {
                     $duplicate_clause[$other_status_name][$status_name] = true;
                     $replace_clause[$status_name] = true;
                 }
             }
         }
     }
     $status_where = array_diff_key($status_where, $replace_clause);
     foreach ($status_where as $status_name => $this_status_where) {
         if ($status_clause_pos && $force_single_status) {
             //We are maintaining the single status which was specified in original query
             if (!$this_status_where || $this_status_where == '1=2') {
                 $where_prepend = '1=2';
             } elseif ($this_status_where == '1=1') {
                 $where_prepend = '';
             } else {
                 //insert at original status clause position
                 $where_prepend = '';
                 $where = substr($where, 0, $status_clause_pos) . "( {$this_status_where} ) AND " . substr($where, $status_clause_pos);
             }
             break;
         }
         // We may be replacing or inserting status clauses
         if (!empty($duplicate_clause[$status_name])) {
             // We generated duplicate clauses for some statuses
             foreach (array_keys($duplicate_clause[$status_name]) as $other_status_name) {
                 $where = str_replace($basic_status_clause[$other_status_name], '1=2', $where);
             }
             $duplicate_clause[$status_name] = array_merge($duplicate_clause[$status_name], array($status_name => 1));
             if ($col_status) {
                 $name_in = "'" . implode("', '", array_keys($duplicate_clause[$status_name])) . "'";
                 $status_prefix = "{$src_table}.{$col_status} IN ({$name_in})";
             } else {
                 $status_prefix = "1=1";
             }
         } elseif ($col_status && $status_name) {
             $status_prefix = $basic_status_clause[$status_name];
         } else {
             $status_prefix = '';
         }
         if ($this_status_where && ($this_status_where != '1=2' || count($status_where) > 1)) {
             //todo: confirm we can OR the 1=2 even if only one status clause
             if ('1=1' == $this_status_where) {
                 $status_clause = $status_prefix ? "{$status_prefix} " : '';
             } else {
                 $status_clause = $col_status && $status_prefix ? "{$status_prefix} AND " : '';
                 $status_clause .= "( {$this_status_where} )";
                 // TODO: reduce number of parentheses
                 $status_clause = " ( {$status_clause} )";
             }
         } else {
             $status_clause = '1=2';
         }
         if ($status_clause) {
             if ($col_status && $status_name && strpos($where, $basic_status_clause[$status_name])) {
                 // Replace existing status clause with our scoped equivalent
                 $where = str_replace($basic_status_clause[$status_name], "{$status_clause}", $where);
             } elseif ($status_clause_pos && $status_clause != '1=2') {
                 // This status was not in the original query, but we now insert it with scoping clause at the position of another existing status clause
                 $where = substr($where, 0, $status_clause_pos) . "{$status_clause} OR " . substr($where, $status_clause_pos);
             } else {
                 // Default query makes no mention of status (perhaps because this data source doesn't define statuses),
                 // so prepend this clause to front of where clause
                 $where_prepend .= "{$status_or} {$status_clause}";
                 $status_or = ' OR';
             }
         }
     }
     // Existance of this variable means no status clause exists in default WHERE.  AND away we go.
     // Prepend so we don't disturb any orderby/groupby/limit clauses which are along for the ride
     if ($where_prepend) {
         if ($where) {
             $where = " AND ( {$where_prepend} ) {$where}";
         } else {
             $where = " AND ( {$where_prepend} )";
         }
     }
     //d_echo ("<br /><br /><strong>objects_where output:</strong> $where<br /><br />");
     //echo "<br />$where<br />";
     //rs_errlog ("object_where output: $where");
     //rs_errlog ('');
     //rs_errlog ('');
     return $where;
 }
 function determine_role_usage_rs($src_name = 'post', $listed_ids = '')
 {
     global $scoper, $wpdb;
     if ('post' != $src_name) {
         return;
     }
     if (empty($listed_ids)) {
         if (!empty($scoper->listed_ids[$src_name])) {
             $listed_ids = $scoper->listed_ids[$src_name];
         } else {
             return;
         }
     }
     if (empty($this->checked_ids[$src_name])) {
         $this->checked_ids[$src_name] = array();
     } else {
         if (!array_diff_key($this->checked_ids[$src_name], $listed_ids)) {
             return;
         }
     }
     $this->checked_ids[$src_name] = $this->checked_ids[$src_name] + $listed_ids;
     $src = $scoper->data_sources->get($src_name);
     $col_id = $src->cols->id;
     $col_type = isset($src->cols->type) ? $src->cols->type : '';
     if ($viewing_object_type = cr_find_post_type()) {
         $object_types = (array) $viewing_object_type;
     } else {
         $object_types = array_diff_key(get_post_types(array('public' => true)), array('attachment'));
     }
     // For now, only determine restricted posts if using RS role type.
     // Backing this out will be more convoluted for WP role type; may need to just list which roles are restricted rather than trying to give an Restricted Read/Edit summary
     $roles = array();
     if (is_admin()) {
         foreach ($object_types as $_post_type) {
             $roles["edit"][$_post_type] = array("publish" => "rs_{$_post_type}_editor", "private" => "rs_{$_post_type}_editor", "draft" => "rs_{$_post_type}_contributor", "pending" => "rs_{$_post_type}_contributor", "future" => "rs_{$_post_type}_editor", "trash" => "rs_{$_post_type}_editor");
             $roles["read"][$_post_type] = array("publish" => "rs_{$_post_type}_reader", "private" => "rs_private_{$_post_type}_reader", "draft" => "rs_{$_post_type}_reader", "pending" => "rs_{$_post_type}_reader", "future" => "rs_{$_post_type}_reader", "trash" => "rs_{$_post_type}_editor");
         }
     } else {
         foreach ($object_types as $_post_type) {
             $roles["read"][$_post_type] = array("publish" => "rs_{$_post_type}_reader", "private" => "rs_private_{$_post_type}_reader");
         }
     }
     // which of these results ignore blog role assignments?
     $uses_taxonomies = scoper_get_taxonomy_usage($src_name, $object_types);
     if (!empty($uses_taxonomies)) {
         foreach ($uses_taxonomies as $taxonomy) {
             $tx_object_types = $object_types;
             foreach ($tx_object_types as $key => $object_type) {
                 // ignore term restrictions / roles for object types which have them disabled
                 $_use_term_roles = scoper_get_otype_option('use_term_roles', $src_name, $object_type);
                 if (empty($_use_term_roles[$taxonomy])) {
                     unset($tx_object_types[$key]);
                 }
             }
             if (!$tx_object_types) {
                 continue;
             }
             if (!$scoper->taxonomies->is_member($taxonomy)) {
                 continue;
             }
             $qvars = $scoper->taxonomies->get_terms_query_vars($taxonomy);
             $term_join = " INNER JOIN {$qvars->term->table} {$qvars->term->as} ON {$src->table}.{$src->cols->id} = {$qvars->term->alias}.{$qvars->term->col_obj_id} ";
             // ======== Log term restrictions ========
             //
             if ($scoper->taxonomies->member_property($taxonomy, 'requires_term')) {
                 if ($strict_terms = $scoper->get_restrictions(TERM_SCOPE_RS, $taxonomy)) {
                     $this->any_restricted_terms = true;
                 }
                 $all_terms = $scoper->get_terms($taxonomy, UNFILTERED_RS, COL_ID_RS);
                 foreach (array_keys($roles) as $op_type) {
                     $status_where = array();
                     foreach ($tx_object_types as $object_type) {
                         $term_clauses = array();
                         foreach ($roles[$op_type][$object_type] as $status => $check_role) {
                             if (isset($strict_terms['restrictions'][$check_role]) && is_array($strict_terms['restrictions'][$check_role])) {
                                 $this_strict_terms = array_keys($strict_terms['restrictions'][$check_role]);
                             } elseif (isset($strict_terms['unrestrictions'][$check_role]) && is_array($strict_terms['unrestrictions'][$check_role])) {
                                 $this_strict_terms = array_diff($all_terms, array_keys($strict_terms['unrestrictions'][$check_role]));
                             } else {
                                 $this_strict_terms = array();
                             }
                             if (!$this_strict_terms) {
                                 // no terms in this taxonomy have restricted roles
                                 $term_clauses[$status] = '1=2';
                             } elseif (count($this_strict_terms) < count($all_terms)) {
                                 // some (but not all) terms in this taxonomy honor blog-wide assignment of the pertinent role
                                 $term_clauses[$status] = " {$qvars->term->alias}.{$qvars->term->col_id} IN ('" . implode("', '", $this_strict_terms) . "')";
                             } else {
                                 $term_clauses[$status] = '1=1';
                             }
                             if (isset($term_clauses[$status])) {
                                 $status_where[$object_type][$status] = " {$src->cols->status} = '{$status}' AND ( {$term_clauses[$status]} ) ";
                             }
                         }
                         // end foreach statuses
                         if (isset($status_where[$object_type])) {
                             // object_type='type_val' AND ( (status 1 clause) OR (status 2 clause) ...
                             $status_where[$object_type] = " {$src->cols->type} = '{$object_type}' AND ( " . agp_implode(' ) OR ( ', $status_where[$object_type], ' ( ', ' ) ') . " )";
                         }
                     }
                     // end foreach tx_object_types
                     // NOTE: we are querying for posts/pages which HAVE restrictions that apply to their current post_status
                     //
                     if ($status_where) {
                         // (object type 1 clause) OR (object type 2 clause) ...
                         $where = ' AND (' . agp_implode(' ) OR ( ', $status_where, ' ( ', ' ) ') . ' )';
                         $where .= " AND {$src->table}.{$col_id} IN ('" . implode("', '", array_keys($listed_ids)) . "')";
                         $query = "SELECT DISTINCT {$col_id} FROM {$src->table} {$term_join} WHERE 1=1 {$where}";
                         if (isset($query_results[$query])) {
                             $restricted_ids = $query_results[$query];
                         } else {
                             $restricted_ids = scoper_get_col($query);
                             $query_results[$query] = $restricted_ids;
                         }
                         foreach ($restricted_ids as $id) {
                             $this->termscoped_ids[$src_name][$id][$op_type] = true;
                             $this->restricted_ids[$src_name][$id][$op_type] = true;
                         }
                     }
                 }
                 // end foreach op_type (read/edit)
             }
             // end term restrictions logging
             // ======== Log term roles ========
             //
             if (is_admin() && !empty($qvars)) {
                 if ($src_roles = $scoper->role_defs->get_matching('rs', 'post', $tx_object_types)) {
                     $otype_role_names = array();
                     foreach (array_keys($src_roles) as $role_handle) {
                         $otype_role_names[] = $src_roles[$role_handle]->name;
                     }
                     $role_clause = "AND uro.role_name IN ('" . implode("', '", $otype_role_names) . "')";
                     $join_assigned = $term_join . " INNER JOIN {$wpdb->user2role2object_rs} AS uro ON uro.obj_or_term_id = {$qvars->term->alias}.{$qvars->term->col_id}" . " AND uro.scope = 'term' AND uro.role_type = 'rs' {$role_clause} AND uro.src_or_tx_name = '{$taxonomy}'";
                     $where = " AND {$src->table}.{$col_id} IN ('" . implode("', '", array_keys($listed_ids)) . "')";
                     $query = "SELECT DISTINCT {$col_id}, uro.role_name FROM {$src->table} {$join_assigned} WHERE 1=1 {$where}";
                     $role_results = scoper_get_results($query);
                     foreach ($role_results as $row) {
                         $role_handle = scoper_get_role_handle($row->role_name, 'rs');
                         $this->have_termrole_ids[$src_name][$row->{$col_id}][$role_handle] = true;
                     }
                 }
             }
             // end term roles logging
         }
         // end foreach of this data source's taxonomies
     }
     // endif this data source uses taxonomies
     // which of these results ignore blog AND term role assignments?
     if ($objscope_objects = $scoper->get_restrictions(OBJECT_SCOPE_RS, $src_name)) {
         $this->any_restricted_objects = true;
     }
     foreach (array_keys($roles) as $op_type) {
         foreach ($object_types as $object_type) {
             if (!scoper_get_otype_option('use_object_roles', $src_name, $object_type)) {
                 continue;
             }
             if (is_array($roles[$op_type][$object_type])) {
                 foreach (array_keys($listed_ids) as $id) {
                     foreach ($roles[$op_type][$object_type] as $check_role) {
                         // If a restriction is set for this object and role,
                         // OR if the role is default-restricted with no unrestriction for this object...
                         if (isset($objscope_objects['restrictions'][$check_role][$id]) || isset($objscope_objects['unrestrictions'][$check_role]) && is_array($objscope_objects['unrestrictions'][$check_role]) && !isset($objscope_objects['unrestrictions'][$check_role][$id])) {
                             $this->objscoped_ids[$src_name][$id][$op_type] = true;
                             $this->restricted_ids[$src_name][$id][$op_type] = true;
                         }
                     }
                 }
                 //end foreach listed ids
             }
             // endif any applicable roles defined
         }
         // end forach object type
     }
     // end foreach op_type (read/edit)
     // query for object role assignments
     if (is_admin()) {
         if ($scoper->get_applied_object_roles()) {
             //$this->any_object_roles = true;
             $join_assigned = " INNER JOIN {$wpdb->user2role2object_rs} AS uro ON uro.obj_or_term_id = {$src->table}.{$col_id}" . " AND uro.src_or_tx_name = '{$src_name}' AND uro.scope = 'object' AND uro.role_type = 'rs'";
             $where = " AND {$src->table}.{$col_id} IN ('" . implode("', '", array_keys($listed_ids)) . "')";
             $query = "SELECT DISTINCT {$col_id}, uro.role_name FROM {$src->table} {$join_assigned} WHERE 1=1 {$where}";
             $role_results = scoper_get_results($query);
             foreach ($role_results as $row) {
                 $role_handle = scoper_get_role_handle($row->role_name, 'rs');
                 $this->have_objrole_ids[$src_name][$row->{$col_id}][$role_handle] = true;
                 //$this->any_object_roles = true;
             }
         }
     }
 }
 function _flt_user_has_cap($wp_blogcaps, $orig_reqd_caps, $args)
 {
     // =============================== STATIC VARIABLE DECLARATION AND INITIALIZATION (to memcache filtering results) =====
     static $cache_tested_ids;
     static $cache_okay_ids;
     static $cache_where_clause;
     if (empty($cache_tested_ids)) {
         $cache_where_clause = array();
         $cache_tested_ids = array();
         $cache_okay_ids = array();
     }
     // ====================================================================================================================
     // =============================================== TEMPORARY DEBUG CODE ================================================
     //dump($orig_reqd_caps);
     //dump($args);
     //if ( strpos( $_SERVER['REQUEST_URI'], 'ajax' ) ) {
     //if ( ! empty($_REQUEST) )
     //	rs_errlog( serialize($_REQUEST) );
     //rs_errlog( '' );
     //rs_errlog('flt_user_has_cap');
     //rs_errlog(serialize($orig_reqd_caps));
     //rs_errlog(serialize($args));
     //rs_errlog('');
     //}
     // ============================================= (end temporary debug code) ==============================================
     // convert 'rs_role_name' to corresponding caps (and also make a tinkerable copy of orig_reqd_caps)
     $orig_reqd_caps = $this->scoper->role_defs->role_handles_to_caps($orig_reqd_caps);
     // ================= EARLY EXIT CHECKS (if the provided reqd_caps do not need filtering or need special case filtering ==================
     global $pagenow;
     // Disregard caps which are not defined in Role Scoper config
     if (!($rs_reqd_caps = array_intersect($orig_reqd_caps, $this->scoper->cap_defs->get_all_keys()))) {
         return $wp_blogcaps;
     }
     // log initial set of RS-filtered caps (in case we swap in equivalent caps for intermediate processing)
     $orig_reqd_caps = $rs_reqd_caps;
     // permitting this filter to execute early in an attachment request resets the found_posts record, preventing display in the template
     if (is_attachment() && !is_admin() && !did_action('template_redirect')) {
         if (empty($GLOBALS['scoper_checking_attachment_access'])) {
             return $wp_blogcaps;
         }
     }
     // work around bug in mw_EditPost method (requires publish_pages AND publish_posts cap)
     if (defined('XMLRPC_REQUEST') && 'publish_posts' == $orig_reqd_caps[0]) {
         if (!empty($GLOBALS['xmlrpc_post_type_rs']) && 'page' == $GLOBALS['xmlrpc_post_type_rs']) {
             return array('publish_posts' => true);
         }
     }
     // backdoor to deal with rare cases where one of the caps included in RS role defs cannot be filtered properly
     if (defined('UNSCOPED_CAPS_RS') && !array_diff($orig_reqd_caps, explode(',', UNSCOPED_CAPS_RS))) {
         return $wp_blogcaps;
     }
     // custom workaround to reveal all private / restricted content in all blogs if logged into main blog
     if (defined('SCOPER_MU_MAIN_BLOG_RULES')) {
         include_once dirname(__FILE__) . '/mu-custom.php';
         if (!array_diff($orig_reqd_caps, array('read', 'read_private_pages', 'read_private_posts'))) {
             if ($return_caps = ScoperMU_Custom::current_user_logged_into_main($wp_blogcaps, $orig_reqd_caps)) {
                 return $return_caps;
             }
         }
     }
     //define( 'SCOPER_NO_COMMENT_FILTERING', true );
     if (defined('SCOPER_NO_COMMENT_FILTERING') && 'moderate_comments' == $orig_reqd_caps[0] && empty($GLOBALS['current_rs_user']->allcaps['moderate_comments'])) {
         return $wp_blogcaps;
     }
     if (defined('SCOPER_ALL_UPLOADS_EDITABLE') && $pagenow == 'upload.php' && in_array($orig_reqd_caps[0], array('upload_files', 'edit_others_posts', 'delete_others_posts'))) {
         return $wp_blogcaps;
     }
     // =================================================== (end early exit checks) ======================================================
     // ============================ GLOBAL VARIABLE DECLARATIONS, ARGUMENT TRANSLATION AND STATUS DETECTION =============================
     global $current_rs_user;
     $user_id = isset($args[1]) ? $args[1] : 0;
     if ($user_id && $user_id != $current_rs_user->ID) {
         $user = rs_get_user($user_id);
     } else {
         $user = $current_rs_user;
     }
     // currently needed for filtering async-upload.php
     if (empty($user->blog_roles) || empty($user->blog_roles[''])) {
         $this->scoper->refresh_blogroles();
     }
     $object_id = isset($args[2]) ? (int) $args[2] : 0;
     // WP passes comment ID with 'edit_comment' metacap
     if ($object_id && 'edit_comment' == $args[0]) {
         if (!in_array('moderate_comments', $rs_reqd_caps)) {
             // as of WP 3.2.1, 'edit_comment' maps to related post's 'edit_post' caps without requiring moderate_comments
             if (scoper_get_option('require_moderate_comments_cap')) {
                 $rs_reqd_caps[] = 'moderate_comments';
                 $modified_caps = true;
             }
         }
         if ($comment = get_comment($object_id)) {
             $object_id = $comment->comment_post_ID;
         } else {
             $object_id = 0;
         }
     }
     // note the data source and object type(s) which are associated with the required caps (based on inclusion in RS Role Definitions)
     $is_taxonomy_cap = false;
     $src_name = '';
     $cap_types = $this->scoper->cap_defs->src_otypes_from_caps($rs_reqd_caps, $src_name);
     // note: currently only needed for src_name determination
     $doing_admin_menus = is_admin() && (did_action('_admin_menu') && !did_action('admin_menu') || did_action('admin_head') && !did_action('adminmenu'));
     // for scoped menu management roles, satisfy edit_theme_options cap requirement
     if (array_key_exists(0, $orig_reqd_caps) && 'edit_theme_options' == $orig_reqd_caps[0] && empty($wp_blogcaps['edit_theme_options'])) {
         if (in_array($GLOBALS['pagenow'], array('nav-menus.php', 'admin-ajax.php')) || $doing_admin_menus) {
             $key = array_search('edit_theme_options', $rs_reqd_caps);
             if (false !== $key) {
                 $tx = get_taxonomy('nav_menu');
                 $rs_reqd_caps[$key] = $tx->cap->manage_terms;
                 $src_name = 'nav_menu';
                 // menu-specific manager assignment does not permit deletion of the menu
                 if (!empty($_REQUEST['action']) && 'delete' == $_REQUEST['action']) {
                     $this->skip_any_term_check = true;
                 }
             }
         }
     }
     if (!$src_name) {
         // required capabilities correspond to multiple data sources
         return $wp_blogcaps;
     }
     // slight simplification: assume a single cap object type for a few cap substitution checks
     $is_taxonomy_cap = $this->scoper->cap_defs->member_property(reset($rs_reqd_caps), 'is_taxonomy_cap');
     // Establish some context by detecting object type - based on object ID if provided, or otherwise based on http variables.
     if (in_array($pagenow, array('media-upload.php', 'async-upload.php'))) {
         if (!empty($GLOBALS['post'])) {
             $object_type = $GLOBALS['post']->post_type;
         }
     } elseif (is_admin() && 'edit-tags.php' == $GLOBALS['pagenow'] && 'link_category' == $_REQUEST['taxonomy']) {
         $src_name = 'link';
         $object_type = 'link_category';
     } elseif (array_key_exists(0, $orig_reqd_caps) && in_array($orig_reqd_caps[0], array('manage_nav_menus', 'edit_theme_options'))) {
         $src_name = 'nav_menu';
     }
     if (empty($object_type)) {
         $object_type = cr_find_object_type($src_name, $object_id);
     }
     $object_type_obj = cr_get_type_object($src_name, $object_type);
     $is_att_rev = false;
     if ('post' == $src_name) {
         if (in_array($object_type, array('attachment', 'revision'))) {
             $is_att_rev = true;
             if ($object_id) {
                 if ($_post = get_post($object_id)) {
                     if ($_parent = get_post($_post->post_parent)) {
                         $object_type = $_parent->post_type;
                         $object_id = $_parent->ID;
                         // deal with case of edit_posts cap check on attachments to revision (with Revisionary)
                         if ('revision' == $object_type) {
                             if ($_orig_post = get_post($_parent->post_parent)) {
                                 $object_type = $_orig_post->post_type;
                                 $object_id = $_orig_post->ID;
                             }
                         }
                         $object_type_obj = get_post_type_object($object_type);
                     }
                 }
             }
         } elseif (!$is_taxonomy_cap) {
             $use_post_types = scoper_get_option('use_post_types');
             if (empty($use_post_types[$object_type])) {
                 return $wp_blogcaps;
             }
         }
     }
     // =====================================================================================================================================
     // ======================================== SUBVERT MISGUIDED CAPABILITY REQUIREMENTS ==================================================
     if ('post' == $src_name) {
         if (!$is_taxonomy_cap) {
             $modified_caps = false;
             if ('post' != $object_type) {
                 $replace_post_caps = array('publish_posts', 'edit_others_posts', 'edit_published_posts');
                 // Replace edit_posts requirement with corresponding type-specific requirement, but only after admin menu is drawn, or on a submission before the menu is drawn
                 if (did_action('admin_init')) {
                     // otherwise extra padding between menu items due to some items populated but unpermitted
                     $replace_post_caps[] = 'edit_posts';
                 }
                 if (in_array($pagenow, array('upload.php', 'media.php'))) {
                     $replace_post_caps = array_merge($replace_post_caps, array('delete_posts', 'delete_others_posts'));
                 }
                 foreach ($replace_post_caps as $post_cap_name) {
                     $key = array_search($post_cap_name, $rs_reqd_caps);
                     if (false !== $key && !$doing_admin_menus && in_array($pagenow, array('edit.php', 'post.php', 'post-new.php', 'press-this.php', 'admin-ajax.php', 'upload.php', 'media.php'))) {
                         $rs_reqd_caps[$key] = $object_type_obj->cap->{$post_cap_name};
                         $modified_caps = true;
                     }
                 }
             }
             // WP core quirk workaround: edit_others_posts is required as preliminary check for populating authors dropdown for any post type.  Instead, we need to do our own validation based on scoped roles.
             // (but don't mess if this cap requirement is part of an edit_post metacap check for a specific post)
             if (!$object_id && count($rs_reqd_caps) == 1) {
                 if (in_array(reset($rs_reqd_caps), array('edit_others_posts'))) {
                     require_once dirname(__FILE__) . '/lib/agapetry_wp_admin_lib.php';
                     // function awp_metaboxes_started()
                     if (!awp_metaboxes_started($object_type) && 'revision.php' != $pagenow && 'revisions' != $GLOBALS['plugin_page_cr']) {
                         // don't enable contributors to view/restore revisions
                         $rs_reqd_caps[0] = $object_type_obj->cap->edit_posts;
                     } else {
                         $rs_reqd_caps[0] = $object_type_obj->cap->edit_published_posts;
                     }
                     // we will filter / suppress the author dropdown downstream from here
                     $modified_caps = true;
                 }
             }
             // as of WP 3.1, addition of new nav menu items requires edit_posts capability (otherwise nav menu item is orphaned with no menu relationship)
             if (is_admin() && strpos($_SERVER['SCRIPT_NAME'], 'nav-menus.php')) {
                 if ('edit_posts' == $orig_reqd_caps[0]) {
                     $type_obj = get_taxonomy('nav_menu');
                     $rs_reqd_caps[0] = $type_obj->cap->manage_terms;
                     $modified_caps = true;
                 }
             }
         }
         // endif not taxonomy cap
     }
     // endif caps correspond to 'post' data source
     //====================================== (end subvert misguided capability requirements) =============================================
     if (defined('RVY_VERSION')) {
         require_once dirname(__FILE__) . '/revisionary-helper_rs.php';
         $rs_reqd_caps = Rvy_Helper::convert_post_edit_caps($rs_reqd_caps, $object_type);
     }
     //rs_errlog( "matched context for $object_id : $matched_context" );
     // don't apply object-specific filtering for auto-drafts
     if ('post' == $src_name) {
         if ($object_id) {
             if ($_post = get_post($object_id)) {
                 if ('auto-draft' == $_post->post_status) {
                     // && ! empty($_POST['action']) )
                     $object_id = 0;
                     if (!$doing_admin_menus) {
                         $this->skip_id_generation = true;
                     }
                 }
             }
         } else {
             if (!empty($GLOBALS['post']) && !is_object($GLOBALS['post'])) {
                 $GLOBALS['post'] = get_post($GLOBALS['post']);
             }
             if (!empty($GLOBALS['post']) && 'auto-draft' == $GLOBALS['post']->post_status && !$doing_admin_menus) {
                 $this->skip_id_generation = true;
             }
         }
     }
     //dump($object_id);
     // If no object id was passed in...
     if (!$object_id) {
         // || ! $matched_context ) {
         //if ( $missing_caps = array_diff($rs_reqd_caps, array_keys($wp_blogcaps) ) ) {
         if (!$doing_admin_menus) {
             if (!empty($_REQUEST['action']) && in_array($pagenow, array('edit.php', 'edit-tags.php'))) {
                 $this->skip_id_generation = true;
             }
             // ============================================ OBJECT ID DETERMINATION ========================================
             if (!$this->skip_id_generation && !defined('XMLRPC_REQUEST') && !in_array($pagenow, array('media-upload.php', 'async-upload.php'))) {
                 // lots of superfluous queries in media upload popup otherwise
                 // Try to generate missing object_id argument for problematic current_user_can calls
                 static $generated_id;
                 if (!isset($generated_id)) {
                     $generated_id = array();
                 }
                 // if the id was not already detected and stored to the static variable...
                 $caps_key = serialize($rs_reqd_caps);
                 if (!isset($generated_id[$object_type][$caps_key])) {
                     $gen_id = 0;
                     foreach ($rs_reqd_caps as $cap_name) {
                         if ($gen_id = (int) $this->_detect_object_id($cap_name)) {
                             break;
                             // means we are accepting the generated id
                         }
                     }
                     $generated_id[$object_type][$caps_key] = $gen_id;
                     $object_id = $gen_id;
                 } else {
                     $object_id = $generated_id[$object_type][$caps_key];
                 }
                 //rs_errlog( "detected ID: $object_id" );
             } else {
                 $this->skip_id_generation = false;
             }
             // this is a one-time flag
             // ========================================= (end object id determination) =======================================
         }
         // If we still have no object id (detection was skipped or failed to identify it)...
         if (!$object_id) {
             // || ! $matched_context ) {
             // ============================================ "CAN FOR ANY" CHECKS ===========================================
             if ($missing_caps = array_diff($rs_reqd_caps, array_keys($wp_blogcaps))) {
                 // These checks are only relevant since no object_id was provided.  Otherwise (in the main body of this function), taxonomy and object caps will be credited via scoped query.
                 // If we are about to fail the blogcap requirement, credit a missing cap if the user has it by term role for ANY term.
                 // This prevents failing initial UI entrance exams that only consider blog-wide roles.
                 if (!$this->skip_any_term_check) {
                     if ($tax_caps = $this->user_can_for_any_term($missing_caps)) {
                         $wp_blogcaps = array_merge($wp_blogcaps, $tax_caps);
                     }
                     //rs_errlog( "can for any term: " . serialize($tax_caps) );
                 } else {
                     $this->skip_any_term_check = false;
                 }
                 // this is a one-time flag
                 // If we are still missing required caps, credit a missing scoper-defined cap if the user has it by object role for ANY object.
                 // (i.e. don't bar user from "Edit Pages" if they have edit_pages cap for at least one page)
                 if ($missing_caps = array_diff($rs_reqd_caps, array_keys($wp_blogcaps))) {
                     // prevent object-specific editing roles from allowing new object creation w/o sitewide capability
                     $add_new_check = strpos($_SERVER['SCRIPT_NAME'], 'post-new.php') && 'post' == $src_name && reset($rs_reqd_caps) == $object_type_obj->cap->edit_posts;
                     if (!$this->skip_any_object_check && !$add_new_check) {
                         //if ( ! $this->skip_any_object_check ) {
                         if ($object_caps = $this->user_can_for_any_object($missing_caps)) {
                             $wp_blogcaps = array_merge($wp_blogcaps, $object_caps);
                         }
                         //rs_errlog( "can for any object: " . serialize($object_caps) );
                     } else {
                         $this->skip_any_object_check = false;
                     }
                     // this is a one-time flag
                 }
             }
             // ========================================== (end "can for any" checks ) =========================================
             //rs_errlog( serialize( $wp_blogcaps) );
             if ($missing_caps = array_diff($rs_reqd_caps, array_keys($wp_blogcaps))) {
                 // normal exit point when no object ID is passed or detected, or when detected object type does not match required capabilities
                 return $wp_blogcaps;
             } else {
                 if ($restore_caps = array_diff($orig_reqd_caps, $rs_reqd_caps)) {
                     // restore original reqd_caps which we substituted for the type-specific scoped query
                     $wp_blogcaps = array_merge($wp_blogcaps, array_fill_keys($restore_caps, true));
                 }
                 return $wp_blogcaps;
             }
         }
         //} else
         //return $wp_blogcaps;
     }
     if ($object_id && 'post' == $src_name) {
         $_post = get_post($object_id);
         $object_type = $_post->post_type;
         $object_type_obj = cr_get_type_object($src_name, $object_type);
         if (defined('RVY_VERSION') && in_array($pagenow, array('edit.php', 'edit-tags.php', 'admin-ajax.php')) && (!empty($_REQUEST['action']) && -1 != $_REQUEST['action'])) {
             $rs_reqd_caps = Rvy_Helper::fix_table_edit_reqd_caps($rs_reqd_caps, $args[0], $_post, $object_type_obj);
         }
         // if the top level page structure is locked, don't allow non-administrator to delete a top level page either
         if ('page' == $object_type || defined('SCOPER_LOCK_OPTION_ALL_TYPES') && !is_content_administrator_rs()) {
             $delete_metacap = !empty($object_type_obj->hierarchical) ? $object_type_obj->cap->delete_post : 'delete_page';
             // if the top level page structure is locked, don't allow non-administrator to delete a top level page either
             if ($delete_metacap == $args[0]) {
                 if ('1' === scoper_get_option('lock_top_pages')) {
                     // stored value of 1 means only Administrators are allowed to modify top-level page structure
                     if ($page = get_post($args[2])) {
                         if (empty($page->post_parent)) {
                             $in_process = false;
                             return false;
                         }
                     }
                 }
             }
         }
     }
     // Note: At this point, we have a nonzero object_id...
     // if this is a term administration request, route to user_can_admin_terms()
     if ($is_taxonomy_cap) {
         if ('post' == $src_name) {
             $cap_otype_obj = get_taxonomy($object_type);
         }
         if (('post' != $src_name || $cap_otype_obj && $rs_reqd_caps[0] == $cap_otype_obj->cap->manage_terms) && count($rs_reqd_caps) == 1) {
             // don't re-route if multiple caps are being required
             // always pass through any assigned blog caps which will not be involved in this filtering
             $rs_reqd_caps = array_fill_keys($rs_reqd_caps, 1);
             $undefined_reqd_caps = array_diff_key($wp_blogcaps, $rs_reqd_caps);
             require_once dirname(__FILE__) . '/admin/permission_lib_rs.php';
             if (user_can_admin_terms_rs($object_type, $object_id, $user)) {
                 return array_merge($undefined_reqd_caps, $rs_reqd_caps);
             } else {
                 return $undefined_reqd_caps;
                 // required caps we scrutinized are excluded from this array
             }
         }
     }
     // Workaround to deal with WP core's checking of publish cap prior to storing categories
     // Store terms to DB in advance of any cap-checking query which may use those terms to qualify an operation
     if (!empty($_REQUEST['action']) && (in_array($_REQUEST['action'], array('editpost', 'post')) || 'autosave' == $_REQUEST['action'])) {
         if (array_intersect(array('publish_posts', 'edit_posts', $object_type_obj->cap->publish_posts, $object_type_obj->cap->edit_posts), $rs_reqd_caps)) {
             $uses_taxonomies = scoper_get_taxonomy_usage($src_name, $object_type);
             static $inserted_terms;
             if (!isset($inserted_terms)) {
                 $inserted_terms = array();
             }
             foreach ($uses_taxonomies as $taxonomy) {
                 // TODO: only if tx->requires_term is true?
                 if (isset($inserted_terms[$taxonomy][$object_id])) {
                     continue;
                 }
                 $inserted_terms[$taxonomy][$object_id] = true;
                 //if ( $stored_terms = wp_get_object_terms( $object_id, $taxonomy ) ) // note: this will cause trouble if WP core ever auto-stores object terms on post creation
                 //	continue;
                 $stored_terms = $this->scoper->get_terms($taxonomy, UNFILTERED_RS, COL_ID_RS, $object_id);
                 require_once dirname(__FILE__) . '/admin/filters-admin-save_rs.php';
                 $selected_terms = cr_get_posted_object_terms($taxonomy);
                 if (is_array($selected_terms)) {
                     // non-hierarchical terms do not need to be pre-inserted
                     if ($set_terms = $GLOBALS['scoper_admin_filters']->flt_pre_object_terms($selected_terms, $taxonomy)) {
                         $set_terms = array_unique(array_map('intval', $set_terms));
                         if ($set_terms != $stored_terms && $set_terms && $set_terms != array(1)) {
                             // safeguard against unintended clearing of stored categories
                             wp_set_object_terms($object_id, $set_terms, $taxonomy);
                             // delete any buffered cap check results which were queried prior to storage of these object terms
                             unset($cache_tested_ids);
                             unset($cache_where_clause);
                             unset($cache_okay_ids);
                         }
                     }
                 }
             }
             // also avoid chicken-egg situation when publish cap is granted by a propagating page role
             if ($object_type_obj->hierarchical && isset($_POST['parent_id'])) {
                 if ($_POST['parent_id'] != get_post_field('post_parent', $object_id)) {
                     global $wpdb;
                     $set_parent = $GLOBALS['scoper_admin_filters']->flt_page_parent($_POST['parent_id']);
                     $GLOBALS['wpdb']->query("UPDATE {$wpdb->posts} SET post_parent = '{$set_parent}' WHERE ID = '{$object_id}'");
                     require_once dirname(__FILE__) . '/admin/filters-admin-save_rs.php';
                     scoper_inherit_parent_roles($object_id, OBJECT_SCOPE_RS, $src_name, $set_parent, $object_type);
                     scoper_inherit_parent_restrictions($object_id, OBJECT_SCOPE_RS, $src_name, $set_parent, $object_type);
                 }
             }
         }
     }
     // generate a string key for this set of required caps, for use below in checking, caching the scoped results
     $arg_append = '';
     $arg_append .= !empty($this->require_full_object_role) ? '-require_full_object_role-' : '';
     $arg_append .= !empty($GLOBALS['revisionary']->skip_revision_allowance) ? '-skip_revision_allowance-' : '';
     sort($rs_reqd_caps);
     $capreqs_key = implode($rs_reqd_caps) . $arg_append;
     // see ScoperAdmin::user_can_admin_object
     // ================================ SPECIAL HANDLING FOR ATTACHMENTS AND REVISIONS ==========================================
     $maybe_revision = 'post' == $src_name && !isset($cache_tested_ids[$src_name][$object_type][$capreqs_key][$object_id]);
     $maybe_attachment = in_array($pagenow, array('upload.php', 'media.php'));
     if ($maybe_revision || $maybe_attachment) {
         global $wpdb;
         if ($_post = get_post($object_id)) {
             if ('revision' == $_post->post_type) {
                 require_once dirname(__FILE__) . '/lib/revisions_lib_rs.php';
                 $rev_where = defined('RVY_VERSION') && rvy_get_option('revisor_lock_others_revisions') ? " AND post_author = '{$current_rs_user->ID}'" : '';
                 // might need to apply different cap requirement for other users' revisions. todo: skip this clause for sitewide editors
                 $revisions = rs_get_post_revisions($_post->post_parent, 'inherit', array('fields' => constant('COL_ID_RS'), 'return_flipped' => true, 'where' => $rev_where));
             }
             if ('revision' == $_post->post_type || 'attachment' == $_post->post_type) {
                 $is_att_rev = true;
                 if ($_post->post_parent) {
                     $object_id = $_post->post_parent;
                     if ($_parent = get_post($_post->post_parent)) {
                         $object_type = $_parent->post_type;
                         $object_type_obj = get_post_type_object($object_type);
                     }
                 } elseif ('attachment' == $_post->post_type) {
                     // special case for unattached uploads: uploading user should have their way with them
                     if ($_post->post_author == $current_rs_user->ID) {
                         $rs_reqd_caps[0] = 'read';
                         if ($restore_caps = array_diff($orig_reqd_caps, array_keys($rs_reqd_caps))) {
                             // restore original reqd_caps which we substituted for the type-specific scoped query
                             $wp_blogcaps = array_merge($wp_blogcaps, array_fill_keys($restore_caps, true));
                         }
                     }
                     return $wp_blogcaps;
                 }
             }
             //endif retrieved post is a revision or attachment
         }
         // endif post retrieved
     }
     // endif specified id might be a revision or attachment
     if ($is_att_rev) {
         if ('post' != $object_type_obj->name) {
             // Compensate for WP's requirement of posts cap for attachment editing, regardless of whether it's attached to a post or page
             if ('edit_others_posts' == $rs_reqd_caps[0]) {
                 $rs_reqd_caps[0] = $object_type_obj->cap->edit_others_posts;
             } elseif ('delete_others_posts' == $rs_reqd_caps[0]) {
                 $rs_reqd_caps[0] = $object_type_obj->cap->delete_others_posts;
             } elseif ('edit_posts' == $rs_reqd_caps[0]) {
                 $rs_reqd_caps[0] = $object_type_obj->cap->edit_posts;
             } elseif ('delete_posts' == $rs_reqd_caps[0]) {
                 $rs_reqd_caps[0] = $object_type_obj->cap->delete_posts;
             }
         }
     }
     //endif retrieved post is a revision or attachment
     // ============================== (end special handling for attachments and revisions) ==========================================
     // ============ SCOPED QUERY for required caps on object id (if other listed ids are known, query for them also).  Cache results to static var. ===============
     // $force_refresh = 'async-upload.php' == $pagenow;
     // Page refresh following publishing of new page by users who can edit by way of Term Role fails without this workaround
     if (!empty($_POST) && (defined('SCOPER_CACHE_SAFE_MODE') || in_array($pagenow, array('post.php', 'press-this.php')) && $args[0] == $object_type_obj->cap->edit_post)) {
         $force_refresh = true;
         $cache_tested_ids = array();
         $cache_okay_ids = array();
         $cache_where_clause = array();
     } else {
         $force_refresh = false;
     }
     // Check whether this object id was already tested for the same reqd_caps in a previous execution of this function within the same http request
     if ($force_refresh || !isset($cache_tested_ids[$src_name][$object_type][$capreqs_key][$object_id])) {
         //if ( ! isset($cache_tested_ids[$src_name][$object_type][$capreqs_key][$object_id]) ) {
         // retrieve CR_Data_Source object, which contains database column names
         $src_table = $this->scoper->data_sources->member_property($src_name, 'table');
         $cols = $this->scoper->data_sources->member_property($src_name, 'cols');
         // Before querying for caps on this object, check whether we have a record of other posts listed alongside it.
         // If so, run the scoped query for ALL listed objects in that buffer, and buffer the results to static variable hascap_object_ids.
         //
         // (This is useful when front end code must check caps for each post
         //  to determine whether to display 'edit' link, etc.)
         if (is_admin() && 'index.php' == $pagenow) {
             // there's too much happening on the dashboard (and too much low-level query filtering) to buffer listed IDs reliably.
             $listed_ids = array();
         } else {
             if (isset($this->scoper->listed_ids[$src_name])) {
                 $listed_ids = array_keys($this->scoper->listed_ids[$src_name]);
             } else {
                 // note: don't use wp_object_cache because it includes posts not present in currently displayed resultset listing page
                 $listed_ids = array();
             }
         }
         // make sure our current object_id is in the list
         $listed_ids[] = $object_id;
         // since the objects_where_role_clauses() output itself is not id-specific, also statically buffer it per reqd_caps
         if ($force_refresh || !isset($cache_where_clause[$src_name][$object_type][$capreqs_key])) {
             $check_otype = 'link_category' == $object_type ? 'link' : $object_type;
             $use_term_roles = scoper_get_otype_option('use_term_roles', $src_name, $check_otype);
             $no_object_roles = $this->scoper->data_sources->member_property($src_name, 'no_object_roles');
             $use_object_roles = $no_object_roles ? false : scoper_get_otype_option('use_object_roles', $src_name, $object_type);
             $this_args = array('object_type' => $object_type, 'user' => $user, 'otype_use_term_roles' => $use_term_roles, 'otype_use_object_roles' => $use_object_roles, 'skip_teaser' => true, 'require_full_object_role' => !empty($this->require_full_object_role));
             //rs_errlog( serialize($rs_reqd_caps) );
             //rs_errlog( serialize($this_args) );
             $where = $this->query_interceptor->objects_where_role_clauses($src_name, $rs_reqd_caps, $this_args);
             if ($where) {
                 $where = "AND ( {$where} )";
             }
             // update static variable
             $cache_where_clause[$src_name][$object_type][$capreqs_key] = $where;
         } else {
             $where = $cache_where_clause[$src_name][$object_type][$capreqs_key];
         }
         // run the query
         $query = "SELECT {$src_table}.{$cols->id} FROM {$src_table} WHERE 1=1 {$where} AND {$src_table}.{$cols->id} IN ('" . implode("', '", array_unique($listed_ids)) . "')";
         if (isset($cache_okay_ids[$query])) {
             $okay_ids = $cache_okay_ids[$query];
         } else {
             if ($okay_ids = scoper_get_col($query)) {
                 $okay_ids = array_fill_keys($okay_ids, true);
             }
         }
         //dump($rs_reqd_caps);
         //dump($query);
         //dump($okay_ids);
         //rs_errlog( $query );
         //rs_errlog( 'results: ' . serialize( $okay_ids ) );
         // update static cache_tested_ids to log scoped results for this object id, and possibly also for other listed IDs
         if (empty($_GET['doaction']) || 'delete_post' != $args[0] && $object_type_obj->cap->delete_post != $args[0]) {
             // bulk post/page deletion is broken by hascap buffering
             foreach ($listed_ids as $_id) {
                 $cache_tested_ids[$src_name][$object_type][$capreqs_key][$_id] = isset($okay_ids[$_id]);
             }
             $cache_okay_ids[$query] = $okay_ids;
         }
         $this_id_okay = isset($okay_ids[$object_id]);
     } else {
         // results of this same has_cap inquiry are already stored (from another call within current http request)
         $this_id_okay = $cache_tested_ids[$src_name][$object_type][$capreqs_key][$object_id];
     }
     //rs_errlog( "okay ids: " . serialize( $okay_ids ) );
     // if we redirected the cap check to revision parent, also credit all the revisions for passing results
     if ($this_id_okay && !empty($revisions)) {
         if (empty($_GET['doaction']) || 'delete_post' != $args[0] && $object_type_obj->cap->delete_post != $args[0]) {
             // bulk post/page deletion is broken by hascap buffering
             $cache_tested_ids[$src_name][$object_type][$capreqs_key] = $cache_tested_ids[$src_name][$object_type][$capreqs_key] + array_fill_keys($revisions, true);
         }
     }
     $rs_reqd_caps = array_fill_keys($rs_reqd_caps, true);
     if (!$this_id_okay) {
         if (array_key_exists(0, $orig_reqd_caps) && 'edit_posts' == $orig_reqd_caps[0] && strpos($_SERVER['REQUEST_URI'], 'async-upload.php')) {
             // temp workaround for ACF with Revisionary
             return $wp_blogcaps;
         }
         // ================= TEMPORARY DEBUG CODE ===================
         //d_echo("object_id $object_id FAILED !!!!!!!!!!!!!!!!!" );
         //rs_errlog( "object_id $object_id FAILED !!!!!!!!!!!!!!!!!"  );
         //rs_errlog(serialize($orig_reqd_caps));
         //rs_errlog(serialize($rs_reqd_caps));
         //rs_errlog('');
         /*
         $log .= "checked caps: " . serialize($rs_reqd_caps) . "\r\n";
         $log .= "object_id $object_id FAILED !!!!!!!!!!!!!!!!!\r\n";
         $log .= $query;
         rs_errlog( "\r\n{$log}\r\n" );
         */
         //d_echo( "FAILED for " . serialize($rs_reqd_caps) );
         // ============== (end temporary debug code ==================
         return array_diff_key($wp_blogcaps, $rs_reqd_caps);
         // required caps we scrutinized are excluded from this array
     } else {
         if ($restore_caps = array_diff($orig_reqd_caps, array_keys($rs_reqd_caps))) {
             // restore original reqd_caps which we substituted for the type-specific scoped query
             $rs_reqd_caps = $rs_reqd_caps + array_fill_keys($restore_caps, true);
         }
         //d_echo( 'OKAY:' );
         //dump($args);
         //dump($rs_reqd_caps);
         //d_echo( '<br />' );
         return array_merge($wp_blogcaps, $rs_reqd_caps);
     }
 }
Example #13
0
 function build_menu()
 {
     if (strpos($_SERVER['REQUEST_URI'], 'wp-admin/network/')) {
         return;
     }
     global $plugin_page_cr;
     if (!defined('USER_ROLES_RS') && isset($_POST['enable_group_roles'])) {
         scoper_use_posted_init_options();
     }
     global $current_user;
     $is_option_administrator = is_option_administrator_rs();
     $is_user_administrator = is_user_administrator_rs();
     $is_content_administrator = is_content_administrator_rs();
     /*
     // optional hack to prevent roles / restrictions menu for non-Administrators
     //
     // This is now handled as a Role Scoper Option.
     // In Roles > Options > Features > Content Maintenance, set "Roles and Restrictions can be set" to "Administrators only" 
     //
     // To prevent Role Scoper from filtering the backend at all, go to Roles > Options > Realm > Access Types and deselect "editing and administering content"
     //
     // end optional hack
     */
     $require_blogwide_editor = scoper_get_option('role_admin_blogwide_editor_only');
     if (!$is_content_administrator && 'admin_content' == $require_blogwide_editor) {
         if (!$is_option_administrator) {
             return;
         }
     }
     if (!$is_user_administrator && 'admin' == $require_blogwide_editor) {
         if (!$is_option_administrator) {
             return;
         }
     }
     $can_admin_objects = array();
     $can_admin_terms = array();
     $use_post_types = scoper_get_option('use_post_types');
     $use_taxonomies = scoper_get_option('use_taxonomies');
     // which object types does this user have any administration over?
     foreach ($this->scoper->data_sources->get_all() as $src_name => $src) {
         if (!empty($src->no_object_roles) || !empty($src->taxonomy_only) || 'group' == $src_name) {
             continue;
         }
         $object_types = isset($src->object_types) ? $src->object_types : array($src_name => true);
         foreach (array_keys($object_types) as $object_type) {
             if ('post' == $src_name && empty($use_post_types[$object_type])) {
                 continue;
             }
             if (is_administrator_rs($src, 'user') || $this->user_can_admin_object($src_name, $object_type, 0, true)) {
                 if (scoper_get_otype_option('use_object_roles', "{$src_name}:{$object_type}")) {
                     $can_admin_objects[$src_name][$object_type] = true;
                 }
             }
         }
     }
     // which taxonomies does this user have any administration over?
     foreach ($this->scoper->taxonomies->get_all() as $taxonomy => $tx) {
         if (taxonomy_exists($taxonomy) && empty($use_taxonomies[$taxonomy]) && 'post' == $tx->object_source) {
             continue;
         }
         if (is_taxonomy_used_rs($taxonomy) && (is_administrator_rs($tx->source, 'user') || $this->user_can_admin_terms($taxonomy))) {
             $can_admin_terms[$taxonomy] = true;
         }
     }
     // Users Tab
     if (DEFINE_GROUPS_RS) {
         $can_manage_groups = DEFINE_GROUPS_RS && ($is_user_administrator || current_user_can('recommend_group_membership'));
         $cap_req = $can_manage_groups ? 'read' : 'manage_groups';
         $groups_caption = defined('GROUPS_CAPTION_RS') ? GROUPS_CAPTION_RS : __('Role Groups', 'scoper');
         if (!IS_MU_RS || !scoper_get_site_option('mu_sitewide_groups')) {
             add_submenu_page('users.php', $groups_caption, $groups_caption, $cap_req, 'rs-groups', array(&$this, 'menu_handler'));
         } elseif (IS_MU_RS && !awp_ver('3.1')) {
             add_submenu_page("ms-admin.php", $groups_caption, $groups_caption, $cap_req, 'rs-groups', array(&$this, 'menu_handler'));
         }
         // satisfy WordPress' demand that all admin links be properly defined in menu
         if ('rs-default_groups' == $plugin_page_cr) {
             add_submenu_page('users.php', __('User Groups', 'scoper'), __('Default Groups', 'scoper'), $cap_req, 'rs-default_groups', array(&$this, 'menu_handler'));
         }
         if ('rs-group_members' == $plugin_page_cr) {
             add_submenu_page('users.php', __('User Groups', 'scoper'), __('Group Members', 'scoper'), $cap_req, 'rs-group_members', array(&$this, 'menu_handler'));
         }
     }
     // the rest of this function pertains to Roles and Restrictions menus
     if (!$is_user_administrator && !$can_admin_terms && !$is_user_administrator && !$can_admin_objects) {
         return;
     }
     $general_roles = $is_user_administrator;
     // && scoper_get_option('rs_blog_roles');  // rs_blog_roles option has never been active in any RS release; leave commented here in case need arises
     // determine the official WP-registered URL for roles and restrictions menus
     $object_submenus_first = false;
     $use_users_menu = defined('OZH_MENU_VER') && !defined('SCOPER_FORCE_ROLES_MENU') || defined('SCOPER_FORCE_USERS_MENU');
     $tweak_menu = false;
     if ($use_users_menu) {
         $roles_menu = 'users.php';
         $restrictions_menu = 'users.php';
         if ($is_option_administrator) {
             add_submenu_page($roles_menu, __('Role Options', 'scoper'), __('Role Options', 'scoper'), 'read', 'rs-options', array(&$this, 'menu_handler'));
         }
     } else {
         if (!empty($can_admin_terms['category'])) {
             $roles_menu = 'rs-category-roles_t';
             $restrictions_menu = 'rs-category-restrictions_t';
         } elseif (!empty($can_admin_objects['post']['post'])) {
             $roles_menu = 'rs-post-roles';
             $restrictions_menu = 'rs-post-restrictions';
             $object_submenus_first = true;
         } elseif (!empty($can_admin_objects['post']['page'])) {
             // TODO: handle custom types here?
             $roles_menu = 'rs-page-roles';
             $restrictions_menu = 'rs-page-restrictions';
             $object_submenus_first = true;
         } elseif ($can_admin_terms && $this->scoper->taxonomies->member_property(key($can_admin_terms), 'requires_term')) {
             $taxonomy = key($can_admin_terms);
             $roles_menu = "rs-{$taxonomy}-roles_t";
             $restrictions_menu = "rs-{$taxonomy}-restrictions_t";
         } elseif ($can_admin_objects) {
             $src_name = key($can_admin_objects);
             $object_type = key($can_admin_objects[$src_name]);
             if ($src_name != $object_type && 'post' != $src_name) {
                 $roles_menu = "rs-{$object_type}-roles_{$src_name}";
                 $restrictions_menu = "rs-{$object_type}-restrictions_{$src_name}";
             } else {
                 $roles_menu = "rs-{$object_type}-roles";
                 $restrictions_menu = "rs-{$object_type}-restrictions";
             }
             $object_submenus_first = true;
         } else {
             // shouldn't ever need this
             $roles_menu = 'rs-roles-post';
             $restrictions_menu = 'rs-restrictions-post';
             $object_submenus_first = true;
         }
         if ($general_roles) {
             $roles_menu = 'rs-general_roles';
         }
         if ($is_option_administrator) {
             $roles_menu = 'rs-options';
         }
         // option administrators always have RS Options as top level roles submenu
         if ($is_user_administrator) {
             if (empty($restrictions_menu)) {
                 $restrictions_menu = 'rs-category-restrictions_t';
             }
             // If RS Realms are customized, the can_admin_terms / can_admin_objects result can override this default, even for user administrators
         }
         // Register the menus with WP using URI and links determined above
         global $menu;
         //  Manually set menu indexes for positioning below Users menu,
         //  but not if Flutter (a.k.a. Fresh Page) plugin is active.  It re-indexes menu items
         if (!defined('SCOPER_DISABLE_MENU_TWEAK')) {
             //if ( awp_ver('2.9') ) {
             // review each WP version for menu indexes until there's a clean way to force menu proximity to 'Users'
             if (isset($menu[70]) && $menu[70][2] == 'users.php') {
                 // WP 2.9 and 3.0
                 $tweak_menu = true;
                 $restrictions_menu_key = 71;
                 $roles_menu_key = 72;
             }
             //}
         }
         $roles_cap = 'read';
         // we apply other checks within this function to confirm the menu is valid for current user
         $restrictions_caption = __('Restrictions', 'scoper');
         $roles_caption = __('Roles', 'scoper');
         if ($tweak_menu) {
             add_menu_page($restrictions_caption, __('Restrictions', 'scoper'), 'read', $restrictions_menu, array(&$this, 'menu_handler'), SCOPER_URLPATH . '/admin/images/menu/restrictions.png', $restrictions_menu_key);
             add_menu_page($roles_caption, __('Roles', 'scoper'), $roles_cap, $roles_menu, array(&$this, 'menu_handler'), SCOPER_URLPATH . '/admin/images/menu/roles.png', $roles_menu_key);
         } else {
             add_menu_page($restrictions_caption, __('Restrictions', 'scoper'), 'read', $restrictions_menu, array(&$this, 'menu_handler'), SCOPER_URLPATH . '/admin/images/menu/restrictions.png');
             add_menu_page($roles_caption, __('Roles', 'scoper'), $roles_cap, $roles_menu, array(&$this, 'menu_handler'), SCOPER_URLPATH . '/admin/images/menu/roles.png');
         }
     }
     // endif putting roles and restrictions links in Users menu
     if ($general_roles) {
         $menu_label = $use_users_menu ? __('General Roles', 'scoper') : __('General', 'scoper');
         add_submenu_page($roles_menu, __('General Roles', 'scoper'), $menu_label, 'read', 'rs-general_roles', array(&$this, 'menu_handler'));
     }
     $first_pass = true;
     $submenu_types = $object_submenus_first ? array('object', 'term') : array('term', 'object');
     foreach ($submenu_types as $scope) {
         if ('term' == $scope) {
             // Term Roles and Restrictions (will only display objects user can edit)
             if ($can_admin_terms) {
                 // Will only allow assignment to terms for which current user has admin cap
                 // Term Roles page also prevents assignment or removal of roles current user doesn't have
                 foreach ($this->scoper->taxonomies->get_all() as $taxonomy => $tx) {
                     if (empty($can_admin_terms[$taxonomy])) {
                         continue;
                     }
                     $show_roles_menu = true;
                     $menu_label = $use_users_menu ? sprintf(__('%s Roles', 'scoper'), $tx->labels->singular_name) : $tx->labels->name;
                     add_submenu_page($roles_menu, sprintf(__('%s Roles', 'scoper'), $tx->labels->singular_name), $menu_label, 'read', "rs-{$taxonomy}-roles_t", array(&$this, 'menu_handler'));
                     if (!empty($tx->requires_term)) {
                         $show_restrictions_menu = true;
                         $menu_label = $use_users_menu ? sprintf(__('%s Restrictions', 'scoper'), $tx->labels->singular_name) : $tx->labels->name;
                         add_submenu_page($restrictions_menu, sprintf(__('%s Restrictions', 'scoper'), $tx->labels->singular_name), $menu_label, 'read', "rs-{$taxonomy}-restrictions_t", array(&$this, 'menu_handler'));
                     }
                 }
                 // end foreach taxonomy
             }
             // endif can admin terms
         } else {
             // Object Roles (will only display objects user can edit)
             if ($can_admin_objects) {
                 foreach ($this->scoper->data_sources->get_all() as $src_name => $src) {
                     if (!empty($src->no_object_roles) || !empty($src->taxonomy_only) || 'group' == $src_name) {
                         continue;
                     }
                     $object_types = isset($src->object_types) ? $src->object_types : array($src_name => true);
                     foreach (array_keys($object_types) as $object_type) {
                         if (empty($can_admin_objects[$src_name][$object_type])) {
                             continue;
                         }
                         if ($require_blogwide_editor) {
                             if (!$this->scoper->user_can_edit_blogwide($src_name, $object_type, array('require_others_cap' => true))) {
                                 continue;
                             }
                         }
                         $show_roles_menu = true;
                         $show_restrictions_menu = true;
                         if ($src_name != $object_type && 'post' != $src_name) {
                             $roles_page = "rs-{$object_type}-roles_{$src_name}";
                             $restrictions_page = "rs-{$object_type}-restrictions_{$src_name}";
                         } else {
                             $roles_page = "rs-{$object_type}-roles";
                             $restrictions_page = "rs-{$object_type}-restrictions";
                         }
                         $src_otype = isset($src->object_types) ? "{$src_name}:{$object_type}" : $src_name;
                         $item_label_singular = $this->interpret_src_otype($src_otype, 'singular_name');
                         $item_label = $this->interpret_src_otype($src_otype);
                         $menu_label = $use_users_menu ? sprintf(__('%s Roles', 'scoper'), $item_label_singular) : $item_label;
                         add_submenu_page($roles_menu, sprintf(__('%s Roles', 'scoper'), $item_label_singular), $menu_label, 'read', $roles_page, array(&$this, 'menu_handler'));
                         $menu_label = $use_users_menu ? sprintf(__('%s Restrictions', 'scoper'), $item_label_singular) : $item_label;
                         add_submenu_page($restrictions_menu, sprintf(__('%s Restrictions', 'scoper'), $item_label_singular), $menu_label, 'read', $restrictions_page, array(&$this, 'menu_handler'));
                     }
                     // end foreach obj type
                 }
                 // end foreach data source
             }
             // endif can admin objects
         }
         // endif drawing object scope submenus
     }
     // end foreach submenu scope
     if ($is_user_administrator) {
         add_submenu_page($roles_menu, __('About Role Scoper', 'scoper'), __('About', 'scoper'), 'read', 'rs-about', array(&$this, 'menu_handler'));
     }
     global $submenu;
     // Change Role Scoper Options submenu title from default "Roles" to "Options"
     if ($is_option_administrator) {
         if (isset($submenu[$roles_menu][0][2]) && $roles_menu == $submenu[$roles_menu][0][2]) {
             $submenu[$roles_menu][0][0] = __awp('Options');
         }
         // satisfy WordPress' demand that all admin links be properly defined in menu
         if ('rs-attachments_utility' == $plugin_page_cr) {
             add_submenu_page($roles_menu, __('Attachment Utility', 'scoper'), __('Attachment Utility', 'scoper'), 'read', 'rs-attachments_utility', array(&$this, 'menu_handler'));
         }
     } elseif (empty($show_restrictions_menu) || empty($show_roles_menu)) {
         // Remove Roles or Restrictions menu if it has no submenu
         if ($tweak_menu) {
             // since we forced the menu keys, no need to loop through menu looking for them
             if (empty($show_restrictions_menu) && isset($menu[$restrictions_menu_key])) {
                 unset($menu[$restrictions_menu_key]);
             }
             if (empty($show_roles_menu) && isset($menu[$roles_menu_key])) {
                 unset($menu[$roles_menu_key]);
             }
         } else {
             global $menu;
             foreach (array_keys($menu) as $key) {
                 if (isset($menu[$key][0])) {
                     if (empty($show_roles_menu) && $roles_caption == $menu[$key][0]) {
                         unset($menu[$key]);
                     } elseif (empty($show_restrictions_menu) && $restrictions_caption == $menu[$key][0]) {
                         unset($menu[$key]);
                     }
                 }
             }
         }
     }
     // WP MU site options
     if (!awp_ver('3.1') && $is_option_administrator && IS_MU_RS) {
         scoper_mu_site_menu();
     }
     // satisfy WordPress' demand that all admin links be properly defined in menu
     if ('rs-object_role_edit' == $plugin_page_cr) {
         add_submenu_page($roles_menu, __('Object Role Edit', 'scoper'), __('Object Role Edit', 'scoper'), 'read', 'rs-object_role_edit', array(&$this, 'menu_handler'));
     }
 }
 function flt_users_where($where, $reqd_caps = '', $object_src_name = '', $object_id = '', $args = array())
 {
     if (!USER_ROLES_RS && !GROUP_ROLES_RS) {
         return $where;
     }
     global $wpdb;
     static $stored_owner_id;
     if (!isset($stored_owner_id)) {
         $stored_owner_id = array();
     }
     $defaults = array('use_term_roles' => 1, 'use_blog_roles' => 1, 'skip_object_roles' => 0, 'querying_groups' => 0, 'ignore_group_roles' => false, 'ignore_user_roles' => false, 'object_type' => '', 'objscope_roles' => '', 'preserve_or_clause' => '', 'enforce_duration_limits' => true, 'enforce_content_date_limits' => true);
     $args = array_merge($defaults, (array) $args);
     extract($args);
     // Default to not honoring custom user caps, but support option
     $custom_user_blogcaps = SCOPER_CUSTOM_USER_BLOGCAPS;
     // if reqd_caps are missing, try to determine context from URI
     if (!$reqd_caps) {
         return $where;
     }
     // no basis for filtering without required caps
     $reqd_caps = (array) $reqd_caps;
     // if rolenames are intermingled with caps in reqd_caps array, convert them to caps
     $reqd_caps = $this->scoper->role_defs->role_handles_to_caps($reqd_caps, true);
     //arg: also check for unprefixed WP rolenames
     if ($object_id && !$object_src_name) {
         $object_id = 0;
     }
     if ($object_id) {
         foreach ($reqd_caps as $cap_name) {
             if ($meta_caps = apply_filters('map_meta_cap_rs', (array) $cap_name, $cap_name, -1, $object_id)) {
                 $reqd_caps = array_diff($reqd_caps, array($cap_name));
                 $reqd_caps = array_unique(array_merge($reqd_caps, $meta_caps));
             }
         }
         if ('post' == $object_src_name && ($use_term_roles || $use_blog_roles)) {
             if ($post = get_post($object_id)) {
                 $object_date_gmt = $post->post_date_gmt;
             }
         } else {
             $object_date_gmt = '';
         }
     }
     $owner_has_all_caps = true;
     // IMPORTANT: set this false downstream as appropriate
     $rs_where = array();
     // Group the required caps by object type (as defined by $scoper->cap_defs).
     // The 2nd arg causes caps without an otype association to be included with a nullstring src_name key
     // The 3rd arg forces caps with a data source other than $object_src to be also lumped in with sourceless caps
     // $caps_by_otype[src_name][object_type] = array of cap names
     $caps_by_otype = $this->scoper->cap_defs->organize_caps_by_otype($reqd_caps, true, $object_src_name, $object_type);
     foreach ($caps_by_otype as $src_name => $otypes) {
         if ($object_type) {
             $otypes = array_intersect_key($otypes, array($object_type => 1));
         }
         // Cap reqs that pertain to other data sources or have no data source association
         // will only be satisfied by blog roles.
         $args['use_term_roles'] = $use_term_roles && $src_name == $object_src_name;
         $args['skip_object_roles'] = $skip_object_roles || $src_name != $object_src_name;
         $this_src_object_id = $src_name == $object_src_name ? $object_id : 0;
         if ($src_name) {
             if (!($src = $this->scoper->data_sources->get($src_name))) {
                 continue;
             }
             $uses_taxonomies = scoper_get_taxonomy_usage($src_name, array_keys($otypes));
             if ($this_src_object_id && $args['use_term_roles'] && !empty($uses_taxonomies)) {
                 $args['object_terms'] = array();
                 foreach ($uses_taxonomies as $taxonomy) {
                     $args['object_terms'][$taxonomy] = $this->scoper->get_terms($taxonomy, UNFILTERED_RS, COL_ID_RS, $this_src_object_id);
                 }
             }
         }
         foreach ($otypes as $object_type => $this_otype_caps) {
             $qry_roles = array();
             $args['use_term_roles'] = $args['use_term_roles'] && scoper_get_otype_option('use_term_roles', $src_name, $object_type);
             //$caps_by_op = $this->scoper->cap_defs->organize_caps_by_op($this_otype_caps, true); //arg: retain caps which are not scoper-defined
             //foreach ( $caps_by_op as $op => $this_op_caps ) {
             foreach ($this_otype_caps as $cap_name) {
                 // If supporting custom user blogcaps, a separate role clause for each cap
                 // Otherwise (default) all reqd_caps from one role assignment (whatever scope it may be)
                 if ($custom_user_blogcaps) {
                     $reqd_caps_arg = array($cap_name);
                 } else {
                     $reqd_caps_arg = $this_otype_caps;
                     $cap_name = '';
                 }
                 // 'blog' argument forces inclusion of qualifying WP roles even if scoping with RS roles
                 // (will later strip out non-scopable roles for term role / object role clauses)
                 $args['roles'] = $this->scoper->role_defs->qualify_roles($reqd_caps_arg, '', '', array('all_wp_caps' => true));
                 if ($args['roles'] || !$src_name) {
                     if (USER_ROLES_RS && !$ignore_user_roles) {
                         $qry_roles[$cap_name]['general'][ROLE_BASIS_USER] = $this->users_queryroles($reqd_caps_arg, $src_name, $this_src_object_id, $args);
                     }
                     if (GROUP_ROLES_RS && !$ignore_group_roles) {
                         $qry_roles[$cap_name]['general'][ROLE_BASIS_GROUPS] = $this->users_queryroles($reqd_caps_arg, $src_name, $this_src_object_id, $args);
                     }
                 }
                 // potentially, a separate set of role clauses for object owner
                 if ($this_src_object_id && $src->cols->owner) {
                     $owner_needs_caps = $this->scoper->cap_defs->get_base_caps($reqd_caps_arg);
                     //returns array of caps the owner needs, after removing those which are credited to owners automatically
                     if ($owner_needs_caps) {
                         $owner_has_all_caps = false;
                     }
                     if ($owner_needs_caps != $reqd_caps_arg) {
                         if (!isset($stored_owner_id[$src_name][$this_src_object_id])) {
                             // DON'T initialize this at top of function
                             $stored_owner_id[$src_name][$this_src_object_id] = scoper_get_var("SELECT {$src->cols->owner} FROM {$src->table} WHERE {$src->cols->id} = '{$object_id}' LIMIT 1");
                         }
                         if ($stored_owner_id[$src_name][$this_src_object_id]) {
                             $owner_roles = $this->scoper->role_defs->qualify_roles($owner_needs_caps);
                             if ($args['roles'] = array_diff_key($owner_roles, $args['roles'])) {
                                 // if owners (needing fewer caps) qualify under different roles than other users:
                                 if (GROUP_ROLES_RS && !$ignore_group_roles) {
                                     if (!isset($owner_groups)) {
                                         $owner_groups = WP_Scoped_User::get_groups_for_user($stored_owner_id[$src_name][$this_src_object_id]);
                                     }
                                     //$owner_groups = scoper_get_col("SELECT $wpdb->user2group_gid_col FROM $wpdb->user2group_rs WHERE $wpdb->user2group_uid_col = '{$stored_owner_id[$src_name][$this_src_object_id]}'");
                                     if ($owner_groups) {
                                         $qry_roles[$cap_name]['owner'][ROLE_BASIS_GROUPS] = $this->users_queryroles($owner_needs_caps, $src_name, $this_src_object_id, $args);
                                     }
                                 }
                                 if (USER_ROLES_RS && !$ignore_user_roles) {
                                     $qry_roles[$cap_name]['owner'][ROLE_BASIS_USER] = $this->users_queryroles($owner_needs_caps, $src_name, $this_src_object_id, $args);
                                 }
                             }
                             // endif owner needs any caps assigned by role
                         }
                         //endif stored owner_id found
                     }
                     // endif any required caps are automatically granted to owner
                 }
                 // endif request is for a specific object from a data source which stores owner_id
                 // If not supporting custom blogcaps, we actually passed all of this object type's caps together
                 if (!$custom_user_blogcaps) {
                     break;
                 }
             }
             // end foreach this_otype_caps
             //d_echo ('scope data');
             //dump($qry_roles);
             // ------------ Construct this object type's where clause from $qry_roles: -----------------
             // ( note: if custom user blogcaps are not enabled, all roles stored into one cap_name dimension )
             // $qry_roles[cap_name][general/owner][user/groups]['object'][''] = array of role handles
             // $qry_roles[cap_name][general/owner][user/groups]['term'][taxonomy] = array of role handles
             // $qry_roles[cap_name][general/owner][user/groups]['blog'][role_type] = array of role handles
             // now construct the query for this iteration's operation type
             $table_aliases = array(ROLE_BASIS_USER => 'uro', ROLE_BASIS_GROUPS => 'gro');
             foreach ($qry_roles as $cap_name => $user_types) {
                 // note: default is to put qualifying roles from all reqd_caps into a single "cap_name" element
                 $ot_where = array();
                 if (!empty($stored_owner_id) && $owner_has_all_caps && USER_ROLES_RS && !$ignore_user_roles) {
                     $ot_where['owner'][ROLE_BASIS_USER] = "uro.user_id = '{$stored_owner_id[$src_name][$this_src_object_id]}'";
                 }
                 foreach ($user_types as $user_type => $role_bases) {
                     foreach ($role_bases as $role_basis => $scopes) {
                         $alias = $table_aliases[$role_basis];
                         $content_date_comparison = $enforce_content_date_limits && !empty($object_date_gmt) ? "'{$object_date_gmt}'" : '';
                         $duration_clause = scoper_get_duration_clause($content_date_comparison, $alias, $enforce_duration_limits);
                         // arg: skip duration clause
                         foreach ($scopes as $scope => $keys) {
                             foreach ($keys as $key => $role_names) {
                                 if (empty($role_names)) {
                                     continue;
                                 }
                                 $role_in = "'" . implode("','", $role_names) . "'";
                                 switch ($scope) {
                                     case OBJECT_SCOPE_RS:
                                         $id_clause = $object_id ? "AND {$alias}.obj_or_term_id = '{$object_id}'" : '';
                                         $ot_where[$user_type][$role_basis][$scope][$key] = "{$alias}.scope = 'object' AND {$alias}.assign_for IN ('entity', 'both') AND {$alias}.src_or_tx_name = '{$src_name}' AND {$alias}.role_type = 'rs' AND {$alias}.role_name IN ({$role_in}) {$duration_clause} {$id_clause}";
                                         break;
                                     case TERM_SCOPE_RS:
                                         $terms_clause = $object_id && $args['object_terms'][$key] ? "AND {$alias}.obj_or_term_id IN ('" . implode("', '", $args['object_terms'][$key]) . "')" : '';
                                         $ot_where[$user_type][$role_basis][$scope][$key] = "{$alias}.scope = 'term' AND {$alias}.assign_for IN ('entity', 'both') AND {$alias}.src_or_tx_name = '{$key}' {$terms_clause} AND {$alias}.role_type = 'rs' AND {$alias}.role_name IN ({$role_in}) {$duration_clause}";
                                         break;
                                     case BLOG_SCOPE_RS:
                                         $ot_where[$user_type][$role_basis][$scope][$key] = "{$alias}.scope = 'blog' AND {$alias}.role_type = '{$key}' AND {$alias}.role_name IN ({$role_in}) {$duration_clause}";
                                         break;
                                 }
                                 // end scope switch
                             }
                             // end foreach key
                             if (!empty($ot_where[$user_type][$role_basis][$scope])) {
                                 // [key 1 clause] [OR] [key 2 clause] [OR] ...
                                 $ot_where[$user_type][$role_basis][$scope] = agp_implode(' ) OR ( ', $ot_where[$user_type][$role_basis][$scope], ' ( ', ' ) ');
                             }
                         }
                         // end foreach scope
                         if (!empty($ot_where[$user_type][$role_basis])) {
                             // [object scope clauses] [OR] [taxonomy scope clauses] [OR] [blog scope clauses]
                             $ot_where[$user_type][$role_basis] = agp_implode(' ) OR ( ', $ot_where[$user_type][$role_basis], ' ( ', ' ) ');
                             if ('owner' == $user_type) {
                                 switch ($role_basis) {
                                     case ROLE_BASIS_GROUPS:
                                         $ot_where[$user_type][$role_basis] .= "AND gro.group_id IN ('" . implode("', '", $owner_groups) . "')";
                                         break;
                                     case ROLE_BASIS_USER:
                                         $ot_where[$user_type][$role_basis] .= "AND uro.user_id = '{$stored_owner_id[$src_name][$this_src_object_id]}'";
                                 }
                                 // end role basis switch
                             }
                             // endif owner
                         }
                         // endif any role clauses for this user_type/role_basis
                     }
                     // end foreach role basis (user or groups)
                 }
                 // end foreach user type (general or owner)
                 foreach ($ot_where as $user_type => $arr) {
                     foreach ($arr as $role_basis => $val) {
                         if (!empty($ot_where[$user_type])) {
                             // [group role clauses] [OR] [user role clauses]
                             $ot_where[$user_type] = agp_implode(' ) OR ( ', $ot_where[$user_type], ' ( ', ' ) ');
                         }
                     }
                 }
                 if (!empty($ot_where)) {
                     // [general user clauses] [OR] [owner clauses]
                     $rs_where[$src_name][$object_type][$cap_name] = agp_implode(' ) OR ( ', $ot_where, ' ( ', ' ) ');
                 }
             }
             // end foreach cap name (for optional support of custom user blogcaps)
             if (!empty($rs_where[$src_name][$object_type])) {
                 // [cap1 clauses] [AND] [cap2 clauses]
                 $rs_where[$src_name][$object_type] = agp_implode(' ) AND ( ', $rs_where[$src_name][$object_type], ' ( ', ' ) ');
             }
         }
         // end foreach otypes
         if (isset($rs_where[$src_name])) {
             // object_type1 clauses [AND] [object_type2 clauses] [AND] ...
             $rs_where[$src_name] = agp_implode(' ) AND ( ', $rs_where[$src_name], ' ( ', ' ) ');
         }
     }
     // end foreach data source
     // data_source 1 clauses [AND] [data_source 2 clauses] [AND] ...
     $rs_where = agp_implode(' ) AND ( ', $rs_where, ' ( ', ' ) ');
     if ($rs_where) {
         if (false !== strpos($where, $rs_where)) {
             return $where;
         }
         if (!empty($preserve_or_clause)) {
             $rs_where = "( ( {$rs_where} ) OR ( {$preserve_or_clause} ) )";
         }
         if ($where) {
             $where = " AND ( {$rs_where} ) {$where}";
         } else {
             $where = " AND {$rs_where}";
         }
     } else {
         // if no valid role clauses were constructed, required caps are invalid; no users can do it
         $where = ' AND 1=2';
     }
     return $where;
 }
function rs_tally_term_counts(&$terms, $taxonomy, $args = array())
{
    global $wpdb, $scoper;
    $defaults = array('pad_counts' => true, 'skip_teaser' => false, 'post_type' => '');
    $args = array_merge($defaults, (array) $args);
    extract($args);
    if (!$terms) {
        return;
    }
    $term_items = array();
    $terms_by_id = array();
    foreach ($terms as $key => $term) {
        $terms_by_id[$term->term_id] =& $terms[$key];
        $term_ids[$term->term_taxonomy_id] = $term->term_id;
        // key and value will match for non-taxonomy category types
    }
    $tx_obj = get_taxonomy($taxonomy);
    $post_types = array_unique((array) $tx_obj->object_type);
    $enabled_types = array();
    foreach ($post_types as $_post_type) {
        if (scoper_get_otype_option('use_term_roles', 'post', $_post_type)) {
            $enabled_types[] = $_post_type;
        }
    }
    if (!$enabled_types) {
        return;
    }
    if ($post_type) {
        $post_type = (array) $post_type;
        $enabled_types = array_intersect($enabled_types, $post_type);
    }
    // Get the object and term ids and stick them in a lookup table
    $request = "SELECT DISTINCT {$wpdb->posts}.ID, tt.term_taxonomy_id, tt.term_id, tr.object_id" . " FROM {$wpdb->posts}" . " INNER JOIN {$wpdb->term_relationships} AS tr ON {$wpdb->posts}.ID = tr.object_id " . " INNER JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id " . " WHERE tt.taxonomy = '{$taxonomy}' AND tt.term_id IN ('" . implode("','", $term_ids) . "') " . " AND {$wpdb->posts}.post_type IN ('" . implode("','", $enabled_types) . "')";
    // no need to pass any parameters which do not pertain to the objects_request filter
    $args = array_intersect_key($args, array_flip(array('skip_teaser')));
    //$post_type = reset($enabled_types);
    $post_type = $enabled_types;
    // note: don't pass in a taxonomies arg because we need to consider restrictions associated with any taxonomy to determine readable objects for terms of this taxonomy
    $request = apply_filters('objects_request_rs', $request, 'post', $post_type, $args);
    $results = scoper_get_results($request);
    foreach ($results as $row) {
        $id = $term_ids[$row->term_taxonomy_id];
        if (isset($term_items[$id][$row->object_id])) {
            ++$term_items[$id][$row->object_id];
        } else {
            $term_items[$id][$row->object_id] = 1;
        }
    }
    // credit each term for every object contained in any of its descendant terms
    if ($pad_counts && ScoperAncestry::get_terms_children($taxonomy)) {
        foreach ($term_ids as $term_id) {
            $child_term_id = $term_id;
            while (isset($terms_by_id[$child_term_id]->parent)) {
                if (!($parent_term_id = $terms_by_id[$child_term_id]->parent)) {
                    break;
                }
                if (!empty($term_items[$term_id])) {
                    foreach (array_keys($term_items[$term_id]) as $item_id) {
                        $term_items[$parent_term_id][$item_id] = 1;
                    }
                }
                $child_term_id = $parent_term_id;
            }
        }
    }
    // Tally and apply the item credits
    foreach ($term_items as $term_id => $items) {
        if (isset($terms_by_id[$term_id])) {
            $terms_by_id[$term_id]->count = count($items);
        }
    }
    // update count property for zero-item terms too
    foreach (array_keys($terms_by_id) as $term_id) {
        if (!isset($term_items[$term_id])) {
            if (is_object($terms_by_id[$term_id])) {
                $terms_by_id[$term_id]->count = 0;
            }
        }
    }
}
 function doing_teaser($args)
 {
     $fields = isset($args['actual_args']['fields']) ? $args['actual_args']['fields'] : $args['fields'];
     return 'all' == $fields && $GLOBALS['scoper']->is_front() && empty($args['skip_teaser']) && scoper_get_otype_option('do_teaser', 'post');
 }
 function flt_nav_menu_items($items, $menu_name, $args)
 {
     global $wpdb;
     $item_types = array();
     foreach ($items as $key => $item) {
         if (!isset($item_types[$item->type])) {
             $item_types["{$item->type}"] = array();
         }
         if (!isset($item_types[$item->type][$item->object])) {
             $item_types[$item->type][$item->object] = array($key => $item->object_id);
         } else {
             $item_types[$item->type][$item->object][$key] = $item->object_id;
         }
     }
     $teaser_enabled = scoper_get_otype_option('do_teaser', 'post');
     // remove unreadable terms
     if (isset($item_types['taxonomy'])) {
         foreach ($item_types['taxonomy'] as $taxonomy => $item_ids) {
             if ($teaser_enabled) {
                 if ($taxonomy_obj = get_taxonomy($taxonomy)) {
                     foreach ($taxonomy_obj->object_type as $post_type) {
                         // don't remove a term if it is associated with a post type that's being teased
                         if (scoper_get_otype_option('use_teaser', 'post', $post_type)) {
                             continue 2;
                         }
                     }
                 }
             }
             /*
             $query_base = "SELECT t.term_id FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id WHERE 1=1 AND tt.taxonomy = '$taxonomy'";
             $query = apply_filters( 'terms_request_rs', $query_base, $taxonomy ); //, array( 'skip_teaser' => true ) );
             $okay_ids = scoper_get_col($query);
             */
             $hide_empty = isset($args['hide_empty']) ? $args['hide_empty'] : 0;
             $okay_ids = get_terms($taxonomy, "fields=ids&hierarchical=0&hide_empty={$hide_empty}");
             if ($remove_ids = array_diff($item_ids, $okay_ids)) {
                 $items = array_diff_key($items, $remove_ids);
             }
         }
     }
     // remove unreadable posts
     if (isset($item_types['post_type'])) {
         foreach ($item_types['post_type'] as $post_type => $item_ids) {
             $where = apply_filters('objects_where_rs', '', 'post', $post_type, array('skip_teaser' => true));
             $okay_ids = scoper_get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type = '{$post_type}' {$where} AND ID IN ('" . implode("','", $item_ids) . "')");
             if ($remove_ids = array_diff($item_ids, $okay_ids)) {
                 if ($teaser_enabled && scoper_get_otype_option('use_teaser', 'post', $post_type)) {
                     require_once dirname(__FILE__) . '/teaser_rs.php';
                     $teaser_prepend = ScoperTeaser::get_teaser_text('prepend', 'name', 'post', $post_type);
                     $teaser_append = ScoperTeaser::get_teaser_text('append', 'name', 'post', $post_type);
                     foreach (array_keys($remove_ids) as $key) {
                         $items[$key]->title = $teaser_prepend . $items[$key]->title . $teaser_append;
                     }
                 } else {
                     $items = array_diff_key($items, $remove_ids);
                 }
             }
         }
     }
     return $items;
 }
function scoper_admin_section_restrictions($taxonomy)
{
    global $scoper, $scoper_admin;
    $tx = $scoper->taxonomies->get($taxonomy);
    if (empty($tx) || empty($tx->requires_term)) {
        wp_die(__('Invalid taxonomy', 'scoper'));
    }
    $is_administrator = is_administrator_rs($tx, 'user');
    if (!$scoper_admin->user_can_admin_terms($taxonomy)) {
        wp_die(__awp('Cheatin&#8217; uh?'));
    }
    require_once dirname(__FILE__) . '/admin-bulk_rs.php';
    $role_assigner = init_role_assigner();
    $nonce_id = 'scoper-assign-roles';
    $role_codes = ScoperAdminBulk::get_role_codes();
    echo '<a name="scoper_top"></a>';
    // retrieve all terms to track hierarchical relationship, even though some may not be adminable by current user
    $val = ORDERBY_HIERARCHY_RS;
    $args = array('order_by' => $val);
    $all_terms = $scoper->get_terms($taxonomy, UNFILTERED_RS, COLS_ALL_RS, 0, $args);
    // =========================== Submission Handling =========================
    if (isset($_POST['rs_submit'])) {
        $err = ScoperAdminBulk::role_submission(TERM_SCOPE_RS, ROLE_RESTRICTION_RS, '', $taxonomy, $role_codes, '', $nonce_id);
        if (scoper_get_option('file_filtering')) {
            scoper_flush_file_rules();
        }
    } else {
        $err = 0;
    }
    // =========================== Prepare Data ===============================
    $tx_src = $scoper->data_sources->get($tx->source);
    if ($col_id = $tx_src->cols->id) {
        // determine which terms current user can admin
        if ($admin_terms = $scoper->get_terms($taxonomy, ADMIN_TERMS_FILTER_RS, COL_ID_RS)) {
            $admin_terms = array_fill_keys($admin_terms, true);
        }
    } else {
        $admin_terms = array();
    }
    // =========================== Display UI ===============================
    ?>


<div class="wrap agp-width97">
<?php 
    $tx_label = $tx->labels->singular_name;
    $src_label = $scoper->data_sources->member_property($tx->object_source, 'labels', 'singular_name');
    echo '<h2>' . sprintf(__('%s Restrictions', 'scoper'), $tx_label);
    echo '&nbsp;&nbsp;<span style="font-size: 0.6em; font-style: normal">(<a href="#scoper_notes">' . __('see notes', 'scoper') . '</a>)</span></h2>';
    if (scoper_get_option('display_hints')) {
        echo '<div class="rs-hint">';
        if ('category' == $taxonomy && scoper_get_otype_option('use_object_roles', 'post', 'post')) {
            printf(__('Reduce access by requiring some role(s) to be %1$s%2$s-assigned%3$s (or %4$s-assigned). Corresponding General Roles (whether assigned by WordPress or Role Scoper) are ignored.', 'scoper'), "<a href='admin.php?page=rs-{$taxonomy}-roles_t'>", $tx_label, '</a>', $src_label);
        } else {
            printf(__('Reduce access by requiring some role(s) to be %1$s%2$s-assigned%3$s. Corresponding General Role assignments are ignored.', 'scoper'), "<a href='admin.php?page=rs-{$taxonomy}-roles_t'>", $tx_label, '</a>');
        }
        echo '</div>';
    }
    if (!($role_defs_by_otype = $scoper->role_defs->get_for_taxonomy($tx->object_source, $taxonomy))) {
        echo '<br />' . sprintf(__('Role definition error (taxonomy: %s).', 'scoper'), $taxonomy);
        echo '</div>';
        return;
    }
    if (empty($admin_terms)) {
        echo '<br />' . sprintf(__('Either you do not have permission to administer any %s, or none exist.', 'scoper'), $tx->labels->name);
        echo '</div>';
        return;
    }
    ?>

<form action="" method="post" name="role_scope" id="role_assign">
<?php 
    wp_nonce_field($nonce_id);
    echo '<br /><div id="rs-term-scroll-links">';
    echo ScoperAdminBulkLib::taxonomy_scroll_links($tx, $all_terms, $admin_terms);
    echo '</div><hr />';
    // ============ Assignment Mode Selection Display ================
    // TODO: is Link Category label handled without workaround now?
    $tx_label = agp_strtolower($tx->labels->name);
    $tx_label_singular = agp_strtolower($tx->labels->singular_name);
    $parent_col = $tx_src->cols->parent;
    if (!$parent_col || !empty($tx->uses_standard_schema) && empty($tx->hierarchical)) {
        $assignment_modes = array(ASSIGN_FOR_ENTITY_RS => sprintf(__('for selected %s', 'scoper'), $tx_label));
    } else {
        $assignment_modes = array(ASSIGN_FOR_ENTITY_RS => sprintf(__('for selected %s', 'scoper'), $tx_label), ASSIGN_FOR_CHILDREN_RS => sprintf(__('for sub-%s of selected', 'scoper'), $tx_label), ASSIGN_FOR_BOTH_RS => sprintf(__('for selected and sub-%s', 'scoper'), $tx_label));
    }
    $max_scopes = array('term' => __('Restrict selected roles', 'scoper'), 'blog' => __('Unrestrict selected roles', 'scoper'));
    $args = array('max_scopes' => $max_scopes, 'scope' => TERM_SCOPE_RS);
    ScoperAdminBulk::display_inputs(ROLE_RESTRICTION_RS, $assignment_modes, $args);
    ScoperAdminBulk::item_tree_jslinks(ROLE_RESTRICTION_RS);
    // IE (6 at least) won't obey link color directive in a.classname CSS
    $ie_link_style = strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') !== false ? ' style="color:white;"' : '';
    $args = array('include_child_restrictions' => true, 'return_array' => true, 'role_type' => 'rs', 'force_refresh' => true);
    $strict_terms = $scoper->get_restrictions(TERM_SCOPE_RS, $taxonomy, $args);
    //strict_terms[taxonomy][role name][term_id] = array: terms which require Role Scoper assignment for specified role (user blog roles ignored, required caps may be supplied by scoper term role or object-specific assignment)
    // (for other terms, Role Scoper role assignment is optional (term role assignments will supplement blog caps)
    $editable_roles = array();
    foreach ($all_terms as $term) {
        $id = $term->{$col_id};
        foreach ($role_defs_by_otype as $object_type => $role_defs) {
            foreach (array_keys($role_defs) as $role_handle) {
                if ($role_assigner->user_has_role_in_term($role_handle, $taxonomy, $id, '', array('src_name' => $tx->object_source, 'object_type' => $object_type))) {
                    $editable_roles[$id][$role_handle] = true;
                }
            }
        }
    }
    $default_restrictions = $scoper->get_default_restrictions(TERM_SCOPE_RS);
    $default_strict_roles = !empty($default_restrictions[$taxonomy]) ? array_flip(array_keys($default_restrictions[$taxonomy])) : array();
    $table_captions = ScoperAdminUI::restriction_captions(TERM_SCOPE_RS, $tx, $tx_label_singular, $tx_label);
    $args = array('admin_items' => $admin_terms, 'editable_roles' => $editable_roles, 'default_strict_roles' => $default_strict_roles, 'ul_class' => 'rs-termlist', 'ie_link_style' => $ie_link_style, 'err' => $err, 'table_captions' => $table_captions);
    ScoperAdminBulk::item_tree(TERM_SCOPE_RS, ROLE_RESTRICTION_RS, $tx_src, $tx, $all_terms, '', $strict_terms, $role_defs_by_otype, $role_codes, $args);
    echo '<a href="#scoper_top">' . __('top', 'scoper') . '</a>';
    echo '<hr />';
    echo '<h4 style="margin-bottom:0.1em"><a name="scoper_notes"></a>' . __("Notes", 'scoper') . ':</h4><ul class="rs-notes">';
    $osrc = $scoper->data_sources->get($tx->object_source);
    if (empty($osrc->no_object_roles)) {
        echo '<li>';
        printf(__('Any %1$s Restriction causes the specified role to be granted only via %1$s Role assignment, regardless of these %2$s settings.', 'scoper'), $osrc->labels->singular_name, $tx->labels->singular_name);
        echo '</li></ul>';
    }
    ?>

</form>
</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;
 }
 function flt_get_terms($results, $taxonomies, $args)
 {
     global $wpdb;
     $empty_array = array();
     //d_echo( 'flt_get_terms input:' );
     $single_taxonomy = false;
     if (!is_array($taxonomies)) {
         $single_taxonomy = true;
         $taxonomies = array($taxonomies);
     } elseif (count($taxonomies) < 2) {
         $single_taxonomy = true;
     }
     // === END Role Scoper MODIFICATION ===
     foreach ((array) $taxonomies as $taxonomy) {
         if (!taxonomy_exists($taxonomy)) {
             // === BEGIN Role Scoper MODIFICATION: this caused plugin activation error in some situations (though at that time, the error object was created and return on a single line, not byRef as now) ===
             //
             //$error = & new WP_Error('invalid_taxonomy', __awp('Invalid Taxonomy'));
             //return $error;
             return array();
             //
             // === END Role Scoper MODIFICATION ===
         }
     }
     // === BEGIN Role Scoper ADDITION: global var; various special case exemption checks ===
     //
     global $scoper;
     if ($tx_obj = get_taxonomy($taxonomies[0])) {
         // don't require use_taxonomies setting for link_categories or other non-post taxonomies
         if (array_intersect($tx_obj->object_type, get_post_types(array('public' => true)))) {
             $use_taxonomies = scoper_get_option('use_taxonomies');
             if (empty($use_taxonomies[$taxonomy])) {
                 return $results;
             }
         }
     }
     // no backend filter for administrators
     $parent_or = '';
     if (is_admin() || defined('XMLRPC_REQUEST')) {
         if (is_content_administrator_rs()) {
             return $results;
         } else {
             if ($tx = $scoper->taxonomies->get($taxonomies[0])) {
                 // is a Category Edit form being displayed?
                 if (!empty($tx->uri_vars)) {
                     $term_id = $scoper->data_sources->detect('id', $tx);
                 } else {
                     $term_id = $scoper->data_sources->detect('id', $tx->source);
                 }
                 if ($term_id) {
                     // don't filter current parent category out of selection UI even if current user can't manage it
                     $parent_or = " OR t.term_id = (SELECT parent FROM {$wpdb->term_taxonomy} WHERE term_id = '{$term_id}') ";
                 }
             }
         }
     }
     // need to skip cache retrieval if QTranslate is filtering get_terms with a priority of 1 or less
     static $no_cache;
     if (!isset($no_cache)) {
         $no_cache = defined('SCOPER_NO_TERMS_CACHE') || !defined('SCOPER_QTRANSLATE_COMPAT') && awp_is_plugin_active('qtranslate');
     }
     // this filter currently only supports a single taxonomy for each get_terms call
     // (although the terms_where filter does support multiple taxonomies and this function could be made to do so)
     if (!$single_taxonomy) {
         return $results;
     }
     // link category roles / restrictions are only scoped for management (TODO: abstract this)
     if ($single_taxonomy && 'link_category' == $taxonomies[0] && $scoper->is_front()) {
         return $results;
     }
     // depth is not really a get_terms 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']) {
         $args['exclude_tree'] = $args['exclude'];
     }
     // don't offer to set a category as its own parent
     if ('edit-tags.php' == $GLOBALS['pagenow']) {
         if ($tx_obj->hierarchical) {
             if ($editing_cat_id = $scoper->data_sources->get_from_uri('id', 'term')) {
                 if (!empty($args['exclude'])) {
                     $args['exclude'] .= ',';
                 }
                 $args['exclude'] .= $editing_cat_id;
             }
         }
     }
     // we'll need this array in most cases, to support a disjointed tree with some parents missing (note alternate function call - was _get_term_hierarchy)
     $children = ScoperAncestry::get_terms_children($taxonomies[0]);
     //
     // === END Role Scoper ADDITION ===
     // =================================
     $in_taxonomies = "'" . implode("', '", $taxonomies) . "'";
     $defaults = array('orderby' => 'name', 'order' => 'ASC', 'hide_empty' => true, 'exclude' => '', 'exclude_tree' => '', 'include' => '', 'number' => '', 'fields' => 'all', 'slug' => '', 'parent' => '', 'hierarchical' => true, 'child_of' => 0, 'get' => '', 'name__like' => '', 'pad_counts' => false, 'offset' => '', 'search' => '', 'skip_teaser' => false, 'depth' => 0, 'remap_parents' => -1, 'enforce_actual_depth' => -1, 'remap_thru_excluded_parent' => -1, 'post_type' => '');
     // Role Scoper arguments added above
     $args = wp_parse_args($args, $defaults);
     $args['number'] = (int) $args['number'];
     $args['offset'] = absint($args['offset']);
     $args['child_of'] = (int) $args['child_of'];
     // Role Scoper modification: null value will confuse children array check
     if (!$single_taxonomy || !is_taxonomy_hierarchical($taxonomies[0]) || '' !== $args['parent']) {
         $args['child_of'] = 0;
         $args['hierarchical'] = false;
         $args['pad_counts'] = false;
     }
     if ('all' == $args['get']) {
         $args['child_of'] = 0;
         $args['hide_empty'] = 0;
         $args['hierarchical'] = false;
         $args['pad_counts'] = false;
     }
     extract($args, EXTR_SKIP);
     // === BEGIN Role Scoper MODIFICATION: use the $children array we already have ===
     //
     if ('nav-menus.php' == $GLOBALS['pagenow']) {
         if ('nav_menu' != $taxonomies[0]) {
             if (!scoper_get_option('admin_nav_menu_filter_items')) {
                 return $results;
             } else {
                 $hide_empty = 1;
             }
         }
     }
     if ($child_of && !isset($children[$child_of])) {
         return array();
     }
     if ($parent && !isset($children[$parent])) {
         return array();
     }
     if ($post_type && is_string($post_type)) {
         $post_type = explode(',', $post_type);
     }
     //
     // === END Role Scoper MODIFICATION ===
     // ====================================
     $is_term_admin = in_array($GLOBALS['pagenow'], array('edit-tags.php', 'edit-link-categories.php'));
     $filter_key = has_filter('list_terms_exclusions') ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : '';
     $key = md5(serialize(compact(array_keys($defaults))) . serialize($taxonomies) . $filter_key);
     // === BEGIN Role Scoper MODIFICATION: cache key specific to access type and user/groups ===
     // support Quick Post Widget plugin
     if (isset($name) && 'quick_post_cat' == $name) {
         $required_operation = 'edit';
         $post_type = 'post';
         $remap_parents = true;
     } elseif (isset($name) && 'quick_post_new_cat_parent' == $name) {
         $is_term_admin = true;
         $required_operation = '';
         $remap_parents = true;
     } else {
         $required_operation = '';
     }
     $object_src_name = $scoper->taxonomies->member_property($taxonomies[0], 'object_source', 'name');
     $ckey = md5($key . serialize($scoper->get_terms_reqd_caps($taxonomies[0], $required_operation, $is_term_admin)));
     global $current_rs_user;
     $cache_flag = 'rs_get_terms';
     $cache = $current_rs_user->cache_get($cache_flag);
     if (false !== $cache) {
         if (!is_array($cache)) {
             $cache = array();
         }
         if (!$no_cache && isset($cache[$ckey])) {
             // RS Modification: alternate filter name (get_terms filter is already applied by WP)
             remove_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
             $terms = apply_filters('get_terms', $cache[$ckey], $taxonomies, $args);
             $terms = apply_filters('get_terms_rs', $terms, $taxonomies, $args);
             add_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
             return $terms;
         }
     }
     // buffer term names in case they were filtered previously
     if ('all' == $fields) {
         $term_names = scoper_get_property_array($results, 'term_id', 'name');
     }
     //
     // === END Role Scoper MODIFICATION ===
     // =====================================
     $_orderby = strtolower($orderby);
     if ('count' == $_orderby) {
         $orderby = 'tt.count';
     } else {
         if ('name' == $_orderby) {
             $orderby = 't.name';
         } else {
             if ('slug' == $_orderby) {
                 $orderby = 't.slug';
             } else {
                 if ('term_group' == $_orderby) {
                     $orderby = 't.term_group';
                 } else {
                     if ('none' == $_orderby) {
                         $orderby = '';
                         $order = '';
                     } else {
                         if (empty($_orderby) || 'id' == $_orderby) {
                             $orderby = 't.term_id';
                         } elseif ('order' == $_orderby) {
                             $orderby = 't.term_order';
                         } else {
                             $orderby = 't.name';
                         }
                     }
                 }
             }
         }
     }
     $orderby = apply_filters('get_terms_orderby', $orderby, $args);
     if (!empty($orderby)) {
         $orderby = "ORDER BY {$orderby}";
     }
     $where = '';
     // === Role Scoper MODIFICATION: if an include argument is provided, strip out non-matching terms after filtering is done. ===
     /*
     $inclusions = '';
     if ( !empty($include) ) {
     	$exclude = '';
     	$exclude_tree = '';
     	$interms = wp_parse_id_list($include);
     	if ( count($interms) ) {
     		foreach ( $interms as $interm ) {
     			if (empty($inclusions))
     				$inclusions = ' AND ( t.term_id = ' . intval($interm) . ' ';
     			else
     				$inclusions .= ' OR t.term_id = ' . intval($interm) . ' ';
     		}
     	}
     }
     	
     if ( !empty($inclusions) )
     	$inclusions .= ')';
     $where .= $inclusions;
     */
     // === END Role Scoper MODIFICATION ===
     $exclusions = '';
     if (!empty($exclude_tree)) {
         // === BEGIN Role Scoper MODIFICATION: temporarily unhook this filter for unfiltered get_terms calls ===
         remove_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
         // === END Role Scoper MODIFICATION ===
         $excluded_trunks = wp_parse_id_list($exclude_tree);
         foreach ((array) $excluded_trunks as $extrunk) {
             $excluded_children = (array) get_terms($taxonomies[0], array('child_of' => intval($extrunk), 'fields' => 'ids'));
             $excluded_children[] = $extrunk;
             foreach ($excluded_children as $exterm) {
                 if (empty($exclusions)) {
                     $exclusions = ' AND ( t.term_id <> ' . intval($exterm) . ' ';
                 } else {
                     $exclusions .= ' AND t.term_id <> ' . intval($exterm) . ' ';
                 }
             }
         }
         // === BEGIN Role Scoper MODIFICATION: re-hook this filter
         add_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
         // === END Role Scoper MODIFICATION ===
     }
     if (!empty($exclude)) {
         $exterms = wp_parse_id_list($exclude);
         foreach ($exterms as $exterm) {
             if (empty($exclusions)) {
                 $exclusions = ' AND ( t.term_id <> "' . intval($exterm) . '" ';
             } else {
                 $exclusions .= ' AND t.term_id <> "' . intval($exterm) . '" ';
             }
         }
     }
     if (!empty($exclusions)) {
         $exclusions .= ')';
     }
     // WPML attempts to pull taxonomy out of debug_backtrace() unless set in $_GET or $_POST; previous filter execution throws it off
     if (defined('ICL_SITEPRESS_VERSION') && !isset($_GET['taxonomy'])) {
         $_GET['taxonomy'] = current($taxonomies);
     }
     $exclusions = apply_filters('list_terms_exclusions', $exclusions, $args);
     $where .= $exclusions;
     if (!empty($slug)) {
         $slug = sanitize_title($slug);
         $where .= " AND t.slug = '{$slug}'";
     }
     if (!empty($name__like)) {
         $where .= " AND t.name LIKE '{$name__like}%'";
     }
     if ('' !== $parent) {
         $parent = (int) $parent;
         // === BEGIN Role Scoper MODIFICATION: otherwise termroles only work if parent terms also have role
         if ($parent || 'ids' != $fields) {
             $where .= " AND tt.parent = '{$parent}'";
         }
         // === END Role Scoper MODIFICATION ===
     }
     // === BEGIN Role Scoper MODIFICATION: instead, manually remove truly empty cats at the bottom of this function, so we don't exclude cats with private but readable posts
     //if ( $hide_empty && !$hierarchical )
     //	$where .= ' AND tt.count > 0';
     // === END Role Scoper MODIFICATION ===
     // don't limit the query results when we have to descend the family tree
     if (!empty($number) && !$hierarchical && empty($child_of) && '' == $parent) {
         if ($offset) {
             $limit = 'LIMIT ' . $offset . ',' . $number;
         } else {
             $limit = 'LIMIT ' . $number;
         }
     } else {
         $limit = '';
     }
     if (!empty($search)) {
         $search = like_escape($search);
         $where .= " AND (t.name LIKE '%{$search}%')";
     }
     $selects = array();
     switch ($fields) {
         case 'all':
             $selects = array('t.*', 'tt.*');
             break;
         case 'ids':
         case 'id=>parent':
             $selects = array('t.term_id', 'tt.term_taxonomy_id', 'tt.parent', 'tt.count');
             break;
         case 'names':
             $selects = array('t.term_id', 'tt.term_taxonomy_id', 'tt.parent', 'tt.count', 't.name');
             break;
         case 'count':
             $orderby = '';
             $order = '';
             $selects = array('COUNT(*)');
     }
     $select_this = implode(', ', apply_filters('get_terms_fields', $selects, $args));
     // === BEGIN Role Scoper MODIFICATION: run the query through scoping filter
     //
     $query_base = "SELECT DISTINCT {$select_this} FROM {$wpdb->terms} AS t INNER JOIN {$wpdb->term_taxonomy} AS tt ON t.term_id = tt.term_id WHERE 1=1 AND tt.taxonomy IN ({$in_taxonomies}) {$where} {$parent_or} {$orderby} {$order} {$limit}";
     // only force application of scoped query filter if we're NOT doing a teaser
     if ('all' == $fields) {
         $do_teaser = $scoper->is_front() && empty($skip_teaser) && scoper_get_otype_option('do_teaser', 'post');
     } else {
         $do_teaser = false;
     }
     $query = apply_filters('terms_request_rs', $query_base, $taxonomies[0], array('skip_teaser' => !$do_teaser, 'is_term_admin' => $is_term_admin, 'required_operation' => $required_operation, 'post_type' => $post_type));
     // if no filering was applied because the teaser is enabled, prevent a redundant query
     if (!empty($exclude_tree) || $query_base != $query || $parent || 'all' != $fields) {
         $terms = scoper_get_results($query);
     } else {
         $terms = $results;
     }
     if ('count' == $fields) {
         $term_count = $wpdb->get_var($query);
         return $term_count;
     }
     if ('all' == $fields && empty($include)) {
         update_term_cache($terms);
     }
     // RS: don't cache an empty array, just in case something went wrong
     if (empty($terms)) {
         return array();
     }
     //
     // === END Role Scoper MODIFICATION ===
     // ====================================
     // === BEGIN Role Scoper ADDITION: Support a disjointed terms tree with some parents hidden
     //
     if ('all' == $fields) {
         $ancestors = ScoperAncestry::get_term_ancestors($taxonomy);
         // array of all ancestor IDs for keyed term_id, with direct parent first
         if ($parent > 0 || !$hierarchical) {
             // in Category Edit form, need to list all editable cats even if parent is not editable
             $remap_parents = false;
             $enforce_actual_depth = true;
             $remap_thru_excluded_parent = false;
         } else {
             // if these settings were passed into this get_terms call, use them
             if (is_admin()) {
                 $remap_parents = true;
             } else {
                 if (-1 === $remap_parents) {
                     $remap_parents = scoper_get_option('remap_term_parents');
                 }
                 if ($remap_parents) {
                     if (-1 === $enforce_actual_depth) {
                         $enforce_actual_depth = scoper_get_option('enforce_actual_term_depth');
                     }
                     if (-1 === $remap_thru_excluded_parent) {
                         $remap_thru_excluded_parent = scoper_get_option('remap_thru_excluded_term_parent');
                     }
                 }
             }
         }
         $remap_args = compact('child_of', 'parent', '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($terms, $ancestors, 'term_id', 'parent', $remap_args);
     }
     //
     // === END Role Scoper ADDITION ===
     // ================================
     // === BEGIN Role Scoper MODIFICATION: call alternate functions
     // rs_tally_term_counts() replaces _pad_term_counts()
     // rs_get_term_descendants replaces _get_term_children()
     //
     if (($child_of || $hierarchical) && !empty($children)) {
         $terms = rs_get_term_descendants($child_of, $terms, $taxonomies[0]);
     }
     if (!$terms) {
         return array();
     }
     // Replace DB-stored term counts with actual number of posts this user can read.
     // In addition, without the rs_tally_term_counts call, WP will hide categories that have no public posts (even if this user can read some of the pvt posts).
     // Post counts will be incremented to include child categories only if $pad_counts is true
     if (!defined('XMLRPC_REQUEST') && in_array($fields, array('all', 'ids', 'names')) && !$is_term_admin) {
         if (!is_admin() || !in_array($GLOBALS['pagenow'], array('post.php', 'post-new.php'))) {
             //-- RoleScoper Modification - alternate function call (was _pad_term_counts) --//
             rs_tally_term_counts($terms, $taxonomies[0], array('pad_counts' => $pad_counts, 'skip_teaser' => !$do_teaser, 'post_type' => $post_type));
         }
     }
     // Make sure we show empty categories that have children.
     if ($hierarchical && $hide_empty) {
         foreach ($terms as $k => $term) {
             if (!$term->count) {
                 //-- RoleScoper Modification - call alternate function (was _get_term_children) --//
                 if ($children = rs_get_term_descendants($term->term_id, $terms, $taxonomies[0])) {
                     foreach ($children as $child) {
                         if ($child->count) {
                             continue 2;
                         }
                     }
                 }
                 // It really is empty
                 unset($terms[$k]);
             }
         }
     }
     reset($terms);
     //
     // === END Role Scoper MODIFICATION ===
     // ====================================
     // === BEGIN Role Scoper ADDITION: hide empty cats based on actual query result instead of 'count > 0' clause, so we don't exclude cats with private but readable posts
     if ($terms && empty($hierarchical) && !empty($hide_empty)) {
         foreach ($terms as $key => $term) {
             if (!$term->count) {
                 unset($terms[$key]);
             }
         }
     }
     //
     // === END Role Scoper ADDITION ===
     // ================================
     if (!empty($include)) {
         $interms = wp_parse_id_list($include);
         foreach ($terms as $key => $term) {
             if (!in_array($term->term_id, $interms)) {
                 unset($terms[$key]);
             }
         }
     }
     $_terms = array();
     if ('id=>parent' == $fields) {
         while ($term = array_shift($terms)) {
             $_terms[$term->term_id] = $term->parent;
         }
         $terms = $_terms;
     } elseif ('ids' == $fields) {
         while ($term = array_shift($terms)) {
             $_terms[] = $term->term_id;
         }
         $terms = $_terms;
     } elseif ('names' == $fields) {
         while ($term = array_shift($terms)) {
             $_terms[] = $term->name;
         }
         $terms = $_terms;
     }
     if (0 < $number && intval(@count($terms)) > $number) {
         $terms = array_slice($terms, $offset, $number);
     }
     // === BEGIN Role Scoper MODIFICATION: cache key is specific to user/group
     //
     if (!$no_cache) {
         $cache[$ckey] = $terms;
         $current_rs_user->cache_set($cache, $cache_flag);
     }
     // RS Modification: alternate filter name (get_terms filter is already applied by WP)
     remove_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
     $terms = apply_filters('get_terms', $terms, $taxonomies, $args);
     $terms = apply_filters('get_terms_rs', $terms, $taxonomies, $args);
     add_filter('get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 0, 3);
     // restore buffered term names in case they were filtered previously
     if ('all' == $fields) {
         scoper_restore_property_array($terms, $term_names, 'term_id', 'name');
     }
     //
     // === END Role Scoper MODIFICATION ===
     // ====================================
     //dump($terms);
     return $terms;
 }
 function parse_query_for_direct_access(&$query)
 {
     if (empty($query->query_vars['attachment']) || false === strpos($_SERVER['QUERY_STRING'], 'rs_rewrite')) {
         return;
     }
     $file = $query->query_vars['attachment'];
     require_once dirname(__FILE__) . '/uploads_rs.php';
     $uploads = scoper_get_upload_info();
     $return_attachment_id = 0;
     $matched_published_post = array();
     if (AttachmentFilters_RS::_user_can_read_file($file, $return_attachment_id, $matched_published_post, $uploads)) {
         agp_return_file($file, $return_attachment_id);
         return;
     }
     // File access was not granted.  Since a 404 page will now be displayed, add filters which (for performance) were suppressed on the direct file access request
     global $scoper;
     $scoper->direct_file_access = false;
     $scoper->add_main_filters();
     $scoper->add_hardway_filters();
     //Determine if teaser message should be triggered
     if (file_exists($uploads['basedir'] . "/{$file}")) {
         if ($matched_published_post && scoper_get_otype_option('do_teaser', 'post')) {
             foreach (array_keys($matched_published_post) as $object_type) {
                 if ($use_teaser_type = scoper_get_otype_option('use_teaser', 'post', $object_type)) {
                     if ($matched_published_post[$object_type]) {
                         if (!defined('SCOPER_QUIET_FILE_404')) {
                             // note: subsequent act_attachment_access will call impose_post_teaser()
                             $will_tease = true;
                             // will_tease flag only used within this function
                             $wp_query->query_vars['attachment'] = $matched_published_post[$object_type];
                             break;
                         }
                     }
                 }
             }
         }
         status_header(401);
         // Unauthorized
         if (empty($will_tease)) {
             // User is not qualified to access the requested attachment, and no teaser will apply
             // Normally, allow the function to return for WordPress 404 handling
             // But end script execution here if requested attachment is a media type (or if definition set)
             // Linking pages won't want WP html returned in place of inaccessable image / video
             if (defined('SCOPER_QUIET_FILE_404')) {
                 exit;
             }
             // this may not be necessary
             $wp_query->is_404 = true;
             $wp_query->is_single = true;
             $wp_query->is_singular = true;
             $wp_query->query_vars['is_single'] = true;
         }
     }
 }
 function add_meta_boxes()
 {
     /*
     // optional hack to prevent role assignment boxes for non-Editors
     //
     //	This is now handled as a Role Scoper Option. 
     //	On the Advanced tab, Hidden Editing Elements section: select "Role administration requires a blog-wide Editor role"
     //
     // end optional hack
     */
     // ========= register WP-rendered metaboxes ============
     $src_name = 'post';
     // TODO: different handling for edit-tags.php
     $object_type = cr_find_post_type();
     $require_blogwide_editor = scoper_get_option('role_admin_blogwide_editor_only');
     if ('admin' == $require_blogwide_editor && !is_user_administrator_rs()) {
         return;
     }
     if ('admin_content' == $require_blogwide_editor && !is_content_administrator_rs()) {
         return;
     }
     if (!scoper_get_otype_option('use_object_roles', $src_name, $object_type)) {
         return;
     }
     if ($require_blogwide_editor) {
         if (!$this->scoper->user_can_edit_blogwide($src_name, $object_type, array('require_others_cap' => true))) {
             return;
         }
     }
     $role_defs = $this->scoper->role_defs->get_matching('rs', $src_name, $object_type);
     foreach ($role_defs as $role_handle => $role_def) {
         if (!isset($role_def->valid_scopes[OBJECT_SCOPE_RS])) {
             continue;
         }
         $box_id = $role_handle;
         add_meta_box($box_id, $this->scoper->role_defs->get_abbrev($role_handle, OBJECT_UI_RS), array(&$this, 'draw_object_roles_content'), $object_type);
         $this->meta_box_ids[$role_handle] = $box_id;
     }
 }
 function single_object_roles_ui($src_name, $object_type, $object_id, $args = array())
 {
     $defaults = array('html_inserts' => '');
     $args = array_merge($defaults, (array) $args);
     extract($args);
     if (!scoper_get_otype_option('use_object_roles', $src_name, $object_type)) {
         return;
     }
     if (!$html_inserts) {
         if (!($otype_def = $this->scoper->data_sources->member_property($src_name, 'object_types', $object_type))) {
             return;
         }
         if (isset($otype_def->admin_inserts->bottom)) {
             $html_inserts = $otype_def->admin_inserts->bottom;
         } elseif (!($html_inserts = $src->admin_inserts->bottom)) {
             if (!is_object($html_inserts)) {
                 $html_inserts = (object) array();
             }
             // TODO: CSS
             $html_inserts->open = (object) array('container' => '<br />', 'headline' => '<h3 style="margin-bottom: 0">', 'content' => '<div style="border:2px solid #ccc; margin-top: 0; padding: 0 0.2em 0 0.2em;">');
             $html_inserts->close = (object) array('container' => '', 'headline' => '</h3>', 'content' => '</div>');
         }
     }
     if (!isset($this->all_agents) || $src_name != $this->loaded_src_name || $object_type != $this->loaded_object_type || $object_id != $this->loaded_object_id) {
         $this->load_roles($src_name, $object_type, $object_id);
     }
     $group_members = array();
     $role_defs = $this->scoper->role_defs->get_matching('rs', $src_name, $object_type);
     foreach ($role_defs as $role_handle => $role_def) {
         if (!isset($role_def->valid_scopes[OBJECT_SCOPE_RS]) || !$this->scoper_admin->user_can_admin_role($role_handle, $object_id, $src_name, $object_type)) {
             continue;
         }
         echo "\r\n" . sprintf($html_inserts->open->container, "objrole_{$role_handle}");
         $count_sfx = $this->get_rolecount_caption($role_handle);
         echo $html_inserts->open->headline . $this->scoper->role_defs->get_abbrev($role_handle, OBJECT_UI_RS) . $count_sfx . $html_inserts->close->headline . $html_inserts->open->content;
         $this->draw_object_roles_content($src_name, $object_type, $role_handle, $object_id, true);
         // arg: skip_user_validation
         echo "\r\n" . $html_inserts->close->content . "\r\n" . $html_inserts->close->container . "\r\n";
     }
     // end foreach role
 }
    function ui_hide_add_menu()
    {
        $tx_obj = get_taxonomy('nav_menu');
        if (!empty($GLOBALS['current_user']->allcaps['edit_theme_options'])) {
            $use_term_roles = scoper_get_otype_option('use_term_roles', 'post');
            if (empty($use_term_roles['nav_menu'])) {
                return;
            }
        }
        if (cr_user_can($tx_obj->cap->manage_terms, BLOG_SCOPE_RS)) {
            return;
        }
        ?>

<script type="text/javascript">
/* <![CDATA[ */
jQuery(document).ready( function($) {
	$('.menu-add-new').hide();
});
/* ]]> */
</script>
<?php 
    }
 function get_teaser_text($teaser_operation, $variable, $src_name, $object_type, $user = '')
 {
     if (!is_object($user)) {
         global $current_user;
         $user = $current_user;
     }
     $anon = $user->ID == 0 ? '_anon' : '';
     if ($msg = scoper_get_otype_option("teaser_{$teaser_operation}_{$variable}{$anon}", 'post', $object_type, CURRENT_ACCESS_NAME_RS)) {
         if (defined('SCOPER_TRANSLATE_TEASER')) {
             scoper_load_textdomain();
             // otherwise this is only loaded for wp-admin
             $msg = translate($msg, 'scoper');
             if (!empty($msg) && !is_null($msg) && is_string($msg)) {
                 $msg = htmlspecialchars_decode($msg);
             }
         }
         return $msg;
     }
 }
 function act_check_admin_referer($referer_name)
 {
     if (!empty($_POST['tag_ID']) && 'update-tag_' . $_POST['tag_ID'] == $referer_name) {
         // filter category parent selection for Category editing
         if (!isset($_POST['tag_ID'])) {
             return;
         }
         $taxonomy = $_POST['taxonomy'];
         if (!($tx = get_taxonomy($taxonomy))) {
             return;
         }
         if (!$tx->hierarchical) {
             return;
         }
         $stored_term = get_term_by('id', $_POST['tag_ID'], $taxonomy);
         $selected_parent = $_POST['parent'];
         if (-1 == $selected_parent) {
             $selected_parent = 0;
         }
         if ($stored_term->parent != $selected_parent) {
             global $scoper;
             if ($tx_obj = get_taxonomy($taxonomy)) {
                 if ($selected_parent) {
                     $user_terms = $scoper->qualify_terms($tx_obj->cap->manage_terms, $taxonomy);
                     $permit = in_array($selected_parent, $user_terms);
                 } else {
                     $permit = cr_user_can($tx_obj->cap->manage_terms, 0, 0, array('skip_id_generation' => true, 'skip_any_term_check' => true));
                 }
             }
             if (!$permit) {
                 wp_die(__('You do not have permission to select that Category Parent', 'scoper'));
             }
         }
     } elseif ('update-nav_menu' == $referer_name) {
         $tx = get_taxonomy('nav_menu');
         $use_term_roles = scoper_get_otype_option('use_term_roles', 'post', 'nav_menu');
         if (empty($GLOBALS['current_user']->allcaps['edit_theme_options']) || !empty($use_term_roles['nav_menu'])) {
             if (!cr_user_can($tx->cap->manage_terms, $_REQUEST['menu'], 0, array('skip_id_generation' => true, 'skip_any_term_check' => true))) {
                 if ($_REQUEST['menu']) {
                     wp_die(__('You do not have permission to update that Navigation Menu', 'scoper'));
                 } else {
                     wp_die(__('You do not have permission to create new Navigation Menus', 'scoper'));
                 }
             }
         }
     } elseif (false !== strpos($referer_name, 'delete-menu_item_')) {
         if (scoper_get_option('admin_nav_menu_filter_items')) {
             $menu_item_id = substr($referer_name, strlen('delete-menu_item_'));
             require_once SCOPER_ABSPATH . '/admin/filters-admin-nav_menus_rs.php';
             _rs_mnt_modify_nav_menu_item($menu_item_id, 'delete');
         }
     } elseif ($referer_name == 'move-menu_item') {
         if (scoper_get_option('admin_nav_menu_filter_items')) {
             require_once SCOPER_ABSPATH . '/admin/filters-admin-nav_menus_rs.php';
             _rs_mnt_modify_nav_menu_item($_REQUEST['menu-item'], 'move');
         }
     } elseif ('add-bookmark' == $referer_name) {
         require_once dirname(__FILE__) . '/hardway-admin-links_rs.php';
         $link_category = !empty($_POST['link_category']) ? $_POST['link_category'] : array();
         $_POST['link_category'] = scoper_flt_newlink_category($link_category);
     } elseif (0 === strpos($referer_name, 'update-bookmark_')) {
         require_once dirname(__FILE__) . '/hardway-admin-links_rs.php';
         $link_category = !empty($_POST['link_category']) ? $_POST['link_category'] : array();
         $_POST['link_category'] = scoper_flt_link_category($link_category);
     }
 }
Example #27
0
 function get_for_taxonomy($src, $taxonomy = '', $args = array())
 {
     $defaults = array('one_otype_per_role' => true, 'ignore_usage_settings' => false);
     $args = array_merge($defaults, (array) $args);
     extract($args);
     if (!is_object($src)) {
         $src = $GLOBALS['scoper']->data_sources->get($src);
     }
     if (!$src) {
         return;
     }
     $otype_roles = array();
     if (!in_array($taxonomy, array('category', 'post_tag')) && $one_otype_per_role) {
         if ($tx = get_taxonomy($taxonomy)) {
             if (!empty($tx->object_type)) {
                 $use_otypes = array_unique((array) $tx->object_type);
             }
         }
     }
     if (empty($use_otypes)) {
         $use_otypes = array_keys($src->object_types);
     }
     foreach ($use_otypes as $object_type) {
         $use_term_roles = scoper_get_otype_option('use_term_roles', $src->name, $object_type);
         if (!$ignore_usage_settings && empty($use_term_roles[$taxonomy])) {
             continue;
         }
         if ($roles = $this->get_matching('rs', $src->name, $object_type)) {
             if ($one_otype_per_role) {
                 foreach (array_keys($otype_roles) as $existing_object_type) {
                     $roles = array_diff_key($roles, $otype_roles[$existing_object_type]);
                 }
             }
             $otype_roles[$object_type] = $roles;
         }
     }
     //note: term roles are defined with src_name property corresponding to their object source (i.e. manage_categories has src_name 'post')
     if ($taxonomy) {
         if ($roles = $this->get_matching('rs', $src->name, $taxonomy)) {
             if ($one_otype_per_role) {
                 foreach (array_keys($otype_roles) as $object_type) {
                     $roles = array_diff_key($roles, $otype_roles[$object_type]);
                 }
             }
             if ($roles) {
                 $otype_roles[$taxonomy] = $roles;
             }
         }
     }
     return $otype_roles;
 }