function dropdown_pages($object_id = '', $stored_parent_id = '')
 {
     global $scoper, $wpdb;
     // buffer titles in case they are filtered on get_pages hook
     $titles = ScoperAdminBulkParent::get_page_titles();
     if (!is_numeric($object_id)) {
         global $post_ID;
         if (empty($post_ID)) {
             $object_id = $scoper->data_sources->detect('id', 'post', 0, 'post');
         } else {
             $object_id = $post_ID;
         }
     }
     if ($object_id && !is_numeric($stored_parent_id)) {
         $stored_parent_id = $scoper->data_sources->detect('parent', 'post', $object_id);
     }
     // make sure the currently stored parent page remains in dropdown regardless of current user roles
     if ($stored_parent_id) {
         $preserve_or_clause = " {$wpdb->posts}.ID = '{$stored_parent_id}' ";
         $args['preserve_or_clause'] = array();
         foreach (array_keys($scoper->data_sources->member_property('post', 'statuses')) as $status_name) {
             $args['preserve_or_clause'][$status_name] = $preserve_or_clause;
         }
     }
     // alternate_caps is a 2D array because objects_request / objects_where filter supports multiple alternate sets of qualifying caps
     $args['force_reqd_caps']['page'] = array();
     foreach (array_keys($scoper->data_sources->member_property('post', 'statuses')) as $status_name) {
         $args['force_reqd_caps']['page'][$status_name] = array('edit_others_pages');
     }
     $args['alternate_reqd_caps'][0] = array('create_child_pages');
     $all_pages_by_id = array();
     if ($results = scoper_get_results("SELECT ID, post_parent, post_title FROM {$wpdb->posts} WHERE post_type = 'page'")) {
         foreach ($results as $row) {
             $all_pages_by_id[$row->ID] = $row;
         }
     }
     $object_type = awp_post_type_from_uri();
     // Editable / associable draft and pending pages will be included in Page Parent dropdown in Edit Forms, but not elsewhere
     if (is_admin() && 'page' != $object_type) {
         $status_clause = "AND {$wpdb->posts}.post_status IN ('publish', 'private')";
     } else {
         $status_clause = "AND {$wpdb->posts}.post_status IN ('publish', 'private', 'pending', 'draft')";
     }
     $qry_parents = "SELECT ID, post_parent, post_title FROM {$wpdb->posts} WHERE post_type = 'page' {$status_clause} ORDER BY menu_order";
     $qry_parents = apply_filters('objects_request_rs', $qry_parents, 'post', 'page', $args);
     $filtered_pages_by_id = array();
     if ($results = scoper_get_results($qry_parents)) {
         foreach ($results as $row) {
             $filtered_pages_by_id[$row->ID] = $row;
         }
     }
     $hidden_pages_by_id = array_diff_key($all_pages_by_id, $filtered_pages_by_id);
     // temporarily add in the hidden parents so we can order the visible pages by hierarchy
     $pages = ScoperAdminBulkParent::add_missing_parents($filtered_pages_by_id, $hidden_pages_by_id, 'post_parent');
     // convert keys from post ID to title+ID so we can alpha sort them
     $args['pages'] = array();
     foreach (array_keys($pages) as $id) {
         $args['pages'][$pages[$id]->post_title . chr(11) . $id] = $pages[$id];
     }
     // natural case alpha sort
     uksort($args['pages'], "strnatcasecmp");
     $args['pages'] = ScoperAdminBulkParent::order_by_hierarchy($args['pages'], 'ID', 'post_parent');
     // take the hidden parents back out
     foreach ($args['pages'] as $key => $page) {
         if (isset($hidden_pages_by_id[$page->ID])) {
             unset($args['pages'][$key]);
         }
     }
     $output = '';
     // restore buffered titles in case they were filtered on get_pages hook
     scoper_restore_property_array($args['pages'], $titles, 'ID', 'post_title');
     if ($object_id) {
         $args['object_id'] = $object_id;
         $args['retain_page_ids'] = true;
         // retain static log to avoid redundant entries by subsequent call with use_parent_clause=false
         ScoperHardwayParentLegacy::walk_parent_dropdown($output, $args, true, $stored_parent_id);
     }
     // next we'll add disjointed branches, but don't allow this page's descendants to be offered as a parent
     $arr_parent = array();
     $arr_children = array();
     if ($results = scoper_get_results("SELECT ID, post_parent FROM {$wpdb->posts} WHERE post_type = 'page' {$status_clause}")) {
         foreach ($results as $row) {
             $arr_parent[$row->ID] = $row->post_parent;
             if (!isset($arr_children[$row->post_parent])) {
                 $arr_children[$row->post_parent] = array();
             }
             $arr_children[$row->post_parent][] = $row->ID;
         }
         $descendants = array();
         if (!empty($arr_children[$object_id])) {
             foreach ($arr_parent as $page_id => $parent_id) {
                 if (!$parent_id || $page_id == $object_id) {
                     continue;
                 }
                 do {
                     if ($object_id == $parent_id) {
                         $descendants[$page_id] = true;
                         break;
                     }
                     $parent_id = $arr_parent[$parent_id];
                 } while ($parent_id);
             }
         }
         $args['descendants'] = $descendants;
     }
     ScoperHardwayParentLegacy::walk_parent_dropdown($output, $args, false, $stored_parent_id);
     //log_mem_usage_rs( 'end dropdown_pages()' );
     return $output;
 }
function scoper_admin_object_restrictions($src_name, $object_type)
{
    global $scoper, $scoper_admin;
    if (!($src = $scoper->data_sources->get($src_name)) || !empty($src->no_object_roles) || !empty($src->taxonomy_only) || $src_name == 'group') {
        wp_die(__('Invalid data source', 'scoper'));
    }
    $is_administrator = is_administrator_rs($src, 'user');
    $role_bases = array();
    if (USER_ROLES_RS && ($is_administrator || $scoper_admin->user_can_admin_object($src_name, $object_type, 0, true))) {
        $role_bases[] = ROLE_BASIS_USER;
    }
    if (GROUP_ROLES_RS && ($is_administrator || $scoper_admin->user_can_admin_object($src_name, $object_type, 0, true) || current_user_can('manage_groups'))) {
        $role_bases[] = ROLE_BASIS_GROUPS;
    }
    if (empty($role_bases)) {
        wp_die(__awp('Cheatin’ uh?'));
    }
    $otype = $scoper->data_sources->member_property($src_name, 'object_types', $object_type);
    require_once dirname(__FILE__) . '/admin-bulk_rs.php';
    require_once dirname(__FILE__) . '/admin_lib-bulk-parent_rs.php';
    $role_assigner = init_role_assigner();
    $nonce_id = 'scoper-assign-roles';
    $role_codes = ScoperAdminBulk::get_role_codes();
    echo '<a name="scoper_top"></a>';
    // ==== Process Submission =====
    $err = 0;
    if (isset($_POST['rs_submit'])) {
        $err = ScoperAdminBulk::role_submission(OBJECT_SCOPE_RS, ROLE_RESTRICTION_RS, '', $src_name, $role_codes, '', $nonce_id);
        if (scoper_get_option('file_filtering')) {
            scoper_flush_file_rules();
        }
    }
    ?>


<div class="wrap agp-width97">
<?php 
    $src_otype = isset($src->object_types) ? "{$src_name}:{$object_type}" : $src_name;
    $item_label_singular = $scoper_admin->interpret_src_otype($src_otype, 'singular_name');
    $item_label = $scoper_admin->interpret_src_otype($src_otype);
    echo '<h2>' . sprintf(__('%s Restrictions', 'scoper'), $item_label_singular) . '&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">';
        $link_open = "<a href='admin.php?page=rs-{$object_type}-roles'>";
        $uses_taxonomies = scoper_get_taxonomy_usage($src_name, $object_type);
        if ($uses_taxonomies && 1 == count($uses_taxonomies)) {
            $tx_display = $scoper->taxonomies->member_property(reset($uses_taxonomies), 'display_name');
            printf(__('Reduce access to a specific %1$s by requiring some role(s) to be %2$s%3$s-assigned%4$s. Corresponding WP-assigned Roles and RS-assigned General and %5$s Role assignments are ignored.', 'scoper'), $item_label_singular, $link_open, $item_label_singular, '</a>', $tx_display);
        } elseif (count($uses_taxonomies)) {
            printf(__('Reduce access to a specific %1$s by requiring some role(s) to be %2$s%3$s-assigned%4$s. Corresponding WP-assigned Roles and RS-assigned General and Term Role assignments are ignored.', 'scoper'), $item_label_singular, $link_open, $item_label_singular, '</a>');
        } else {
            printf(__('Reduce access to a specific %1$s by requiring some role(s) to be %2$s%3$s-assigned%4$s. Corresponding WP-assigned Roles and RS-assigned General Role assignments are ignored.', 'scoper'), $item_label_singular, $link_open, $item_label_singular, '</a>');
        }
        echo '</div>';
    }
    $ignore_hierarchy = !empty($otype->ignore_object_hierarchy);
    ?>


<form action="" method="post" name="role_assign" id="role_assign">
<?php 
    wp_nonce_field($nonce_id);
    // ============ Users / Groups and Assignment Mode Selection Display ================
    if (empty($src->cols->parent) || $ignore_hierarchy) {
        $assignment_modes = array(ASSIGN_FOR_ENTITY_RS => sprintf(__('for selected %s', 'scoper'), $item_label));
    } else {
        $assignment_modes = array(ASSIGN_FOR_ENTITY_RS => sprintf(__('for selected %s', 'scoper'), $item_label), ASSIGN_FOR_CHILDREN_RS => sprintf(__('for sub-%s of selected', 'scoper'), $item_label), ASSIGN_FOR_BOTH_RS => sprintf(__('for selected and sub-%s', 'scoper'), $item_label));
    }
    $max_scopes = array('object' => __('Restrict selected roles', 'scoper'), 'blog' => __('Unrestrict selected roles', 'scoper'));
    $args = array('max_scopes' => $max_scopes, 'scope' => OBJECT_SCOPE_RS);
    ScoperAdminBulk::display_inputs(ROLE_RESTRICTION_RS, $assignment_modes, $args);
    echo '<br />';
    $args = array('default_hide_empty' => !empty($otype->admin_default_hide_empty), 'hide_roles' => true, 'scope' => OBJECT_SCOPE_RS, 'src' => $src, 'otype' => $otype);
    ScoperAdminBulk::item_tree_jslinks(ROLE_RESTRICTION_RS, $args);
    // buffer prev/next caption for display with each obj type
    //$prevtext = _ x('prev', 'abbreviated link to previous item', 'scoper');
    //$nexttext = _ x('next', 'abbreviated link to next item', 'scoper');
    $prevtext = __('prev', 'scoper');
    $nexttext = __('next', 'scoper');
    $site_url = get_option('siteurl');
    $args = array('include_child_restrictions' => true, 'return_array' => true, 'role_type' => 'rs', 'force_refresh' => true);
    $strict_objects = $scoper->get_restrictions(OBJECT_SCOPE_RS, $src_name, $args);
    $object_names = array();
    $object_status = array();
    $listed_objects = array();
    $unlisted_objects = array();
    $col_id = $src->cols->id;
    $col_parent = isset($src->cols->parent) && !$ignore_hierarchy ? $src->cols->parent : '';
    $object_ids = array();
    if (isset($strict_objects['restrictions'])) {
        foreach (array_keys($strict_objects['restrictions']) as $role_handle) {
            $object_ids = $object_ids + array_keys($strict_objects['restrictions'][$role_handle]);
        }
    } elseif (isset($strict_objects['unrestrictions'])) {
        foreach (array_keys($strict_objects['unrestrictions']) as $role_handle) {
            $object_ids = $object_ids + array_keys($strict_objects['unrestrictions'][$role_handle]);
        }
    }
    $object_ids = array_flip(array_unique($object_ids));
    // Get the obj name, parent associated with each role (also sets $object_names, $unlisted objects)
    $listed_objects = ScoperAdminBulkParent::get_objects_info($object_ids, $object_names, $object_status, $unlisted_objects, $src, $otype, $ignore_hierarchy);
    if ($col_parent) {
        if ($listed_objects) {
            if ($unlisted_objects) {
                // query for any parent objects which don't have their own role assignments
                $listed_objects = ScoperAdminBulkParent::add_missing_parents($listed_objects, $unlisted_objects, $col_parent);
            }
            // convert keys from object ID to title+ID so we can alpha sort them
            $listed_objects_alpha = array();
            foreach (array_keys($listed_objects) as $id) {
                $listed_objects_alpha[$listed_objects[$id]->{$src->cols->name} . chr(11) . $id] = $listed_objects[$id];
            }
            uksort($listed_objects_alpha, "strnatcasecmp");
            $listed_objects = ScoperAdminBulkParent::order_by_hierarchy($listed_objects_alpha, $col_id, $col_parent);
        }
        // endif any listed objects
    } else {
        // endif doing object hierarchy
        if ($listed_objects) {
            // convert keys from object ID to title+ID so we can alpha sort them
            $listed_objects_alpha = array();
            foreach (array_keys($listed_objects) as $id) {
                $listed_objects_alpha[$listed_objects[$id]->{$src->cols->name} . chr(11) . $id] = $listed_objects[$id];
            }
            uksort($listed_objects_alpha, "strnatcasecmp");
            // convert to ordinal integer index
            $listed_objects = array_combine(array_keys(array_fill(0, count($listed_objects_alpha), true)), $listed_objects_alpha);
        }
    }
    if (!$is_administrator) {
        $cu_admin_results = ScoperAdminBulk::filter_objects_listing(ROLE_RESTRICTION_RS, $strict_objects, $src, $object_type);
    } else {
        $cu_admin_results = '';
    }
    // no need to filter admins
    // membuffer ids so user_can_admin_role() doesn't trigger a separate has_cap query for each one
    if ($cu_admin_results) {
        $scoper->listed_ids[$src_name] = $cu_admin_results;
    }
    global $scoper_admin;
    $role_display = array();
    $editable_roles = array();
    $role_defs_by_otype = array();
    $role_defs_by_otype[$object_type] = $scoper->role_defs->get_matching('rs', $src_name, $object_type);
    foreach (array_keys($role_defs_by_otype[$object_type]) as $role_handle) {
        $role_display[$role_handle] = $scoper->role_defs->get_abbrev($role_handle, OBJECT_UI_RS);
        if ($cu_admin_results && !is_user_administrator_rs()) {
            foreach (array_keys($cu_admin_results) as $object_id) {
                if ($scoper_admin->user_can_admin_role($role_handle, $object_id, $src_name, $object_type)) {
                    $editable_roles[$object_id][$role_handle] = true;
                }
            }
        }
    }
    $table_captions = ScoperAdminUI::restriction_captions(OBJECT_SCOPE_RS, '', $item_label_singular, $item_label);
    $args = array('admin_items' => $cu_admin_results, 'editable_roles' => $editable_roles, 'default_hide_empty' => !empty($otype->admin_default_hide_empty), 'ul_class' => 'rs-objlist', 'object_names' => $object_names, 'object_status' => $object_status, 'table_captions' => $table_captions, 'ie_link_style' => '', 'err' => $err);
    ScoperAdminBulk::item_tree(OBJECT_SCOPE_RS, ROLE_RESTRICTION_RS, $src, $otype, $listed_objects, '', $strict_objects, $role_defs_by_otype, $role_codes, $args);
    //ScoperAdminBulk::item_tree( OBJECT_SCOPE_RS, ROLE_ASSIGNMENT_RS, $src, $otype, $all_objects, $object_roles, $strict_objects, $role_defs_by_otype, $role_codes, $args);
    echo '<hr /><div style="background-color: white;"></div>';
    echo '<div class="rs-objlistkey">';
    $args = array('display_links' => true, 'display_restriction_key' => true);
    ScoperAdminUI::role_owners_key($otype, $args);
    echo '</div>';
    echo '</form><br /><h4 style="margin-bottom:0.1em"><a name="scoper_notes"></a>' . __("Notes", 'scoper') . ':</h4><ul class="rs-notes">';
    echo '<li>';
    printf(__('To edit all roles for any %1$s, click on the %1$s name.', 'scoper'), $otype->labels->singular_name);
    echo '</li>';
    echo '<li>';
    printf(__("To edit the %s via its default editor, click on the ID link.", 'scoper'), $otype->labels->singular_name);
    echo '</li>';
    if (!$is_administrator) {
        echo '<li>';
        printf(__('To enhance performance, the role editing checkboxes here may not include some roles which you can only edit due to your own %1$s-specific role. In such cases, click on the editing link to edit roles for the individual %1$s.', 'scoper'), $otype->labels->singular_name);
        echo '</li>';
    }
    echo '</ul>';
    echo '<a href="#scoper_top">' . __('top', 'scoper') . '</a>';
    ?>

</div>
<?php 
}