function flt_sticky_posts($post_ids) { if ($post_ids && !is_content_administrator_rs()) { global $wpdb; $post_ids = scoper_get_col(apply_filters('objects_request_rs', "SELECT ID FROM {$wpdb->posts} WHERE ID IN ('" . implode("','", $post_ids) . "')", 'post')); } return $post_ids; }
function flt_recent_comments($query) { // Due to missing get_comments hook prior to WP 3.1, this filter operates on every front-end query. // If query doesn't pertain to comments, skip out with as little overhead as possible. if (strpos($query, 'comment') && strpos($query, "ELECT") && !strpos($query, 'posts as parent') && !strpos($query, "COUNT") && strpos($query, "comment_approved")) { if (!is_attachment() && !is_content_administrator_rs()) { global $wpdb; if (strpos($query, " {$wpdb->posts} ")) { return $query; } if (awp_is_plugin_active('wp-wall')) { $options = WPWall_GetOptions(); if (strpos($query, 'comment_post_ID=' . $options['pageId'])) { return $query; } } if (strpos($query, $wpdb->comments)) { $query = str_replace(" post_status = 'publish'", " {$wpdb->posts}.post_status = 'publish'", $query); // theoretically, a slight performance enhancement if we can simplify the query to skip filtering of attachment comments if (defined('SCOPER_NO_ATTACHMENT_COMMENTS') || false !== strpos($query, 'comment_post_ID =')) { if (!strpos($query, "JOIN {$wpdb->posts}")) { $query = preg_replace("/FROM\\s*{$wpdb->comments}\\s*WHERE /", "FROM {$wpdb->comments} INNER JOIN {$wpdb->posts} ON {$wpdb->posts}.ID = {$wpdb->comments}.comment_post_ID WHERE ", $query); } $query = apply_filters('objects_request_rs', $query, 'post', '', array('skip_teaser' => true)); } else { $query = str_replace("user_id ", "{$wpdb->comments}.user_id ", $query); $query = str_replace("SELECT {$wpdb->comments}.* FROM {$wpdb->comments}", "SELECT DISTINCT {$wpdb->comments}.* FROM {$wpdb->comments}", $query); if (!strpos($query, ' DISTINCT ')) { $query = str_replace("SELECT ", "SELECT DISTINCT ", $query); } $post_types = array_diff(get_post_types(array('public' => true)), array('attachment')); $post_type_in = "'" . implode("','", $post_types) . "'"; $join = "LEFT JOIN {$wpdb->posts} as parent ON parent.ID = {$wpdb->posts}.post_parent AND parent.post_type IN ({$post_type_in}) AND {$wpdb->posts}.post_type = 'attachment'"; $use_post_types = scoper_get_option('use_post_types'); $where = array(); foreach ($post_types as $type) { if (!empty($use_post_types[$type])) { $where_post = apply_filters('objects_where_rs', '', 'post', $type, array('skip_teaser' => true)); } else { $where_post = "AND 1=1"; } $where[] = "{$wpdb->posts}.post_type = '{$type}' {$where_post}"; $where[] = "{$wpdb->posts}.post_type = 'attachment' AND parent.post_type = '{$type}' " . str_replace("{$wpdb->posts}.", "parent.", $where_post); } $where = agp_implode(' ) OR ( ', $where, ' ( ', ' ) '); if (!strpos($query, "JOIN {$wpdb->posts}")) { $query = str_replace("WHERE ", "INNER JOIN {$wpdb->posts} ON {$wpdb->posts}.ID = {$wpdb->comments}.comment_post_ID {$join} WHERE ( {$where} ) AND ", $query); } else { $query = str_replace("WHERE ", "{$join} WHERE {$where} AND ", $query); } } } } } return $query; }
function user_can_admin_object_rs($src_name, $object_type, $object_id = false, $any_obj_role_check = false, $user = '') { if (is_content_administrator_rs()) { return true; } global $scoper; // TODO: is this necessary? $is_new_object = !$object_id && false !== $object_id || 'post' == $src_name && !empty($GLOBALS['post']) && 'auto-draft' == $GLOBALS['post']->post_status; if ($is_new_object) { $status_name = 'post' == $src_name ? 'draft' : ''; } else { $status_name = sanitize_key($scoper->data_sources->detect('status', $src_name, $object_id)); } // TODO: is multi-value array ever passed? if (is_array($object_type)) { if (count($object_type) == 1) { $object_type = reset($object_type); } else { // only WP roles should ever have multiple sources / otypes $object_type = $scoper->data_sources->get_from_db('type', $src_name, $object_id); } } $base_caps_only = $is_new_object; // Possible TODO: re-implement OP_ADMIN distinction with admin-specific capabilities //$admin_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_ADMIN_RS, $status_name, $base_caps_only); $admin_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_EDIT_RS, $status_name, $base_caps_only); $delete_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_DELETE_RS, $status_name, $base_caps_only); $reqd_caps = array_merge(array_keys($admin_caps), array_keys($delete_caps)); if (!$reqd_caps) { return true; } // apparantly this src/otype has no admin caps, so no restriction to apply // Note on 'require_full_object_role' argument: // Normally we want to disregard "others" cap requirements if a role is assigned directly for an object // This is an exception - we need to retain a "delete_others" cap requirement in case it is the // distinguishing cap of an object administrator $return = cr_user_can($reqd_caps, $object_id, 0, array('require_full_object_role' => true, 'skip_revision_allowance' => true)); if (!$return && !$object_id && $any_obj_role_check) { // No object ID was specified, and current user does not have the cap blog-wide. Credit user for capability on any individual object. // Possible TODO: re-implement OP_ADMIN distinction with admin-specific capabilities //$admin_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_ADMIN_RS, STATUS_ANY_RS); $admin_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_EDIT_RS, STATUS_ANY_RS); $delete_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_DELETE_RS, STATUS_ANY_RS); if ($reqd_caps = array_merge(array_keys($admin_caps), array_keys($delete_caps))) { if (!defined('DISABLE_QUERYFILTERS_RS')) { global $cap_interceptor; if ($cap_interceptor->user_can_for_any_object($reqd_caps)) { $return = true; } } } } return $return; }
function act_attachment_access() { if (is_admin() || defined('DISABLE_QUERYFILTERS_RS') || is_content_administrator_rs() || !scoper_get_option('file_filtering')) { return; } // if ( is_attachment() ) { as of WP 2.6, is_attachment() returns false for custom permalink attachment URL if (is_attachment_rs()) { //rs_errlog( 'IS an attachment:' ); require_once dirname(__FILE__) . '/attachment-template_rs.php'; AttachmentTemplate_RS::attachment_access(); } }
function flt_comments_clauses($clauses, &$qry_obj) { global $wpdb; if (is_content_administrator_rs()) { $stati = array_merge(get_post_stati(array('public' => true)), get_post_stati(array('private' => true))); if (!defined('SCOPER_NO_ATTACHMENT_COMMENTS')) { $stati[] = 'inherit'; } $status_csv = "'" . implode("','", $stati) . "'"; $clauses['where'] = preg_replace("/\\s*AND\\s*{$wpdb->posts}.post_status\\s*=\\s*[']?publish[']?/", "AND {$wpdb->posts}.post_status IN ({$status_csv})", $clauses['where']); } return $clauses; }
function _validate_assigner_roles($scope, $src_or_tx_name, $item_id, $roles) { if (!$item_id && !is_user_administrator_rs()) { return false; } $user_has_role = array(); if (TERM_SCOPE_RS == $scope) { foreach (array_keys($roles) as $role_handle) { $role_attributes = $this->scoper->role_defs->get_role_attributes($role_handle); $args = array('src_name' => $role_attributes->src_name, 'object_type' => $role_attributes->object_type); $user_has_role[$role_handle] = $this->user_has_role_in_term($role_handle, $src_or_tx_name, $item_id, $args); } } else { if ($require_blogwide_editor = scoper_get_option('role_admin_blogwide_editor_only')) { global $current_user; $is_user_administrator = is_user_administrator_rs(); $is_content_administrator = is_content_administrator_rs(); } foreach (array_keys($roles) as $role_handle) { // a user must have a blog-wide edit cap to modify editing role assignments (even if they have Editor role assigned for some current object) if ($require_blogwide_editor) { if (!$is_user_administrator && 'admin' == $require_blogwide_editor) { $user_has_role[$role_handle] = false; continue; } if (!$is_content_administrator && 'admin_content' == $require_blogwide_editor) { $user_has_role[$role_handle] = false; continue; } $src_name = $this->scoper->role_defs->member_property($role_handle, 'src_name'); $object_type = $this->scoper->role_defs->member_property($role_handle, 'object_type'); static $can_edit_blogwide; if (!isset($can_edit_blogwide)) { $can_edit_blogwide = array(); } if (!isset($can_edit_blogwide[$src_name][$object_type])) { $can_edit_blogwide[$src_name][$object_type] = $this->scoper->user_can_edit_blogwide($src_name, $object_type, array('require_others_cap' => true)); } if (!$can_edit_blogwide[$src_name][$object_type]) { $user_has_role[$role_handle] = false; continue; } } if (!empty($this->scoper->role_defs->role_caps[$role_handle])) { $user_has_role[$role_handle] = cr_user_can(array_keys($this->scoper->role_defs->role_caps[$role_handle]), $item_id); } } } return $user_has_role; }
function flt_admin_bar_menu(&$bar) { if (is_content_administrator_rs()) { return; } $type = 'new-content'; foreach (get_post_types(array('public' => true), 'object') as $_post_type => $type_obj) { $var = 'new-' . $_post_type; if (isset($bar->menu->{$type}['children']->{$var})) { if (!cr_user_can($type_obj->cap->edit_posts, 0, 0, array('skip_id_generation' => true, 'skip_any_object_check' => true))) { unset($bar->menu->{$type}['children']->{$var}); } } } }
function get_page_titles() { global $wpdb; $is_administrator = is_content_administrator_rs(); if (!$is_administrator) { remove_filter('get_pages', array('ScoperHardway', 'flt_get_pages'), 1, 2); } // don't retrieve post_content, to save memory $all_pages = scoper_get_results("SELECT ID, post_parent, post_title, post_date, post_date_gmt, post_status, post_name, post_modified, post_modified_gmt, guid, menu_order, comment_count FROM {$wpdb->posts} WHERE post_type = 'page'"); foreach (array_keys($all_pages) as $key) { $all_pages[$key]->post_content = ''; } // add an empty post_content property to each item, in case some plugin filter requires it $all_pages = apply_filters('get_pages', $all_pages); if (!$is_administrator) { add_filter('get_pages', array('ScoperHardway', 'flt_get_pages'), 1, 2); } return scoper_get_property_array($all_pages, 'ID', 'post_title'); }
function police_xmlrpc_action($method_name) { if (function_exists('is_content_administrator_rs') && is_content_administrator_rs()) { return; } switch ($method_name) { // This method has no business passing an empty array of categories. It usually means none are selected for a new post, and does not provide a hook for RS to filtering the default category prior to insertion case 'mt.setPostCategories': global $scoper_last_raw_post_data; if (empty($scoper_last_raw_post_data)) { return; } if (!$this->load_ixr()) { return; } $msg = new IXR_Message($scoper_last_raw_post_data); if ($msg->parse()) { // params[0] = object id, params[3] = categories if (is_array($msg->params) && !empty($msg->params[0]) && isset($msg->params[3]) && !$msg->params[3]) { if ($terms = wp_get_object_terms($msg->params[0], 'category', array('fields' => 'ids'))) { foreach ($terms as $key => $val) { $terms[$key] = (int) $val; } // otherwise wp_set_object_terms will store as a new category named "id" if (empty($this->scheduled_term_restoration)) { $this->scheduled_term_restoration = array(); add_action('set_object_terms', array(&$this, 'maybe_restore_object_terms'), 99, 6); } $this->scheduled_term_restoration[$msg->params[0]]['category'] = $terms; } } } break; // 'mt.setPostCategories' } // end switch }
function act_maybe_hide_quickedit() { if (is_content_administrator_rs()) { return; } $object_type = awp_post_type_from_uri(); if (!$GLOBALS['scoper']->user_can_edit_blogwide('post', $object_type, array('require_others_cap' => true))) { echo "<div id='rs_hide_quickedit'></div>"; } }
function scoper_init() { global $scoper; // Work around bug in More Taxonomies (and possibly other plugins) where category taxonomy is overriden without setting it public foreach (array('category', 'post_tag') as $taxonomy) { if (isset($GLOBALS['wp_taxonomies'][$taxonomy])) { $GLOBALS['wp_taxonomies'][$taxonomy]->public = true; } } if (IS_MU_RS && agp_is_plugin_network_active(SCOPER_BASENAME)) { global $scoper_sitewide_options; $scoper_sitewide_options = apply_filters('sitewide_options_rs', $scoper_sitewide_options); } require_once dirname(__FILE__) . '/wp-cap-helper_cr.php'; WP_Cap_Helper_CR::establish_status_caps(); WP_Cap_Helper_CR::force_distinct_post_caps(); WP_Cap_Helper_CR::force_distinct_taxonomy_caps(); if (is_admin()) { require_once dirname(__FILE__) . '/admin/admin-init_rs.php'; // TODO: why is the require statement up top not sufficient for NGG 1.7.2 uploader? scoper_admin_init(); } //log_mem_usage_rs( 'scoper_admin_init done' ); require_once dirname(__FILE__) . '/scoped-user.php'; require_once dirname(__FILE__) . '/role-scoper_main.php'; //log_mem_usage_rs( 'require role-scoper_main' ); if (empty($scoper)) { // set_current_user may have already triggered scoper creation and role_cap load $scoper = new Scoper(); //log_mem_usage_rs( 'new Scoper done' ); $scoper->init(); } // ensure that content administrators (as defined by SCOPER_CONTENT_ADMIN_CAP) have all caps for custom types by default if (is_content_administrator_rs()) { global $current_rs_user; if (!empty($current_rs_user)) { // user object not set when scoper_init() is manually invoked to support htaccess rule generation on plugin activation foreach (get_post_types(array('public' => true, '_builtin' => false)) as $name) { $current_rs_user->assigned_blog_roles[ANY_CONTENT_DATE_RS]["rs_{$name}_editor"] = true; } $taxonomies = get_taxonomies(array('public' => true, '_builtin' => false)); $taxonomies[] = 'nav_menu'; foreach ($taxonomies as $name) { $current_rs_user->assigned_blog_roles[ANY_CONTENT_DATE_RS]["rs_{$name}_manager"] = true; } $current_rs_user->merge_scoped_blogcaps(); $GLOBALS['current_user']->allcaps = array_merge($GLOBALS['current_user']->allcaps, $current_rs_user->allcaps); $GLOBALS['current_user']->assigned_blog_roles = $current_rs_user->assigned_blog_roles; } } if (!empty($_GET['action']) && 'expire_file_rules' == $_GET['action']) { require_once dirname(__FILE__) . '/attachment-helper_rs.php'; scoper_requested_file_rule_expire(); } //log_mem_usage_rs( 'scoper->init() done' ); }
function add_main_filters() { $is_admin = is_admin(); $is_administrator = is_content_administrator_rs(); $disable_queryfilters = defined('DISABLE_QUERYFILTERS_RS'); $frontend_admin = false; if (!defined('DOING_CRON')) { if ($this->is_front()) { if (!$disable_queryfilters) { require_once dirname(__FILE__) . '/query-interceptor-front_rs.php'; } if (!$is_administrator) { require_once dirname(__FILE__) . '/qry-front_non-administrator_rs.php'; $GLOBALS['feed_interceptor'] = new FeedInterceptor_RS(); // file already required in role-scoper.php } require_once dirname(__FILE__) . '/template-interceptor_rs.php'; $GLOBALS['template_interceptor'] = new TemplateInterceptor_RS(); $frontend_admin = !scoper_get_option('no_frontend_admin'); // potential performance enhancement if (!empty($_REQUEST['s']) && function_exists('relevanssi_query')) { require_once dirname(__FILE__) . '/relevanssi-helper-front_rs.php'; $rel_helper_rs = new Relevanssi_Search_Filter_RS(); } } // ===== Filters which are always loaded (except on plugin scripts), for any access type include_once dirname(__FILE__) . '/hardway/wp-patches_agp.php'; // simple patches for WP if ($this->is_front() || 'edit.php' == $GLOBALS['pagenow']) { require_once dirname(__FILE__) . '/query-interceptor-base_rs.php'; $GLOBALS['query_interceptor_base'] = new QueryInterceptorBase_RS(); // listing filter used for role status indication in edit posts/pages and on front end by template functions } } // ===== Filters which support automated role maintenance following content creation/update // Require an explicitly set option to skip these for front end access, just in case other plugins modify content from the front end. if ($is_admin || defined('XMLRPC_REQUEST') || $frontend_admin || defined('DOING_CRON')) { require_once dirname(__FILE__) . '/admin/cache_flush_rs.php'; require_once dirname(__FILE__) . '/admin/filters-admin_rs.php'; $GLOBALS['scoper_admin_filters'] = new ScoperAdminFilters(); if (defined('RVY_VERSION')) { // Support Revisionary references to $scoper->filters_admin (TODO: eventually phase this out) $this->filters_admin =& $GLOBALS['scoper_admin_filters']; } } // ===== }
function user_can_associate_main($post_type) { if (is_content_administrator_rs()) { return true; } if ('no_parent_filter' == scoper_get_option('lock_top_pages')) { return true; } if (!($post_type_obj = get_post_type_object($post_type))) { return true; } if (!$post_type_obj->hierarchical) { return true; } // currently used only for page type, or for all if constant is set $top_pages_locked = scoper_get_option('lock_top_pages'); if ('page' == $post_type || defined('SCOPER_LOCK_OPTION_ALL_TYPES')) { if ('1' === $top_pages_locked) { // only administrators can change top level structure return false; } elseif ('no_parent_filter' === $top_pages_locked) { return true; } else { $reqd_caps = 'author' === $top_pages_locked ? array($post_type_obj->cap->publish_posts) : array($post_type_obj->cap->edit_others_posts); $roles = $GLOBALS['scoper']->role_defs->qualify_roles($reqd_caps); return array_intersect_key($roles, $GLOBALS['current_rs_user']->blog_roles[ANY_CONTENT_DATE_RS]); } } else { return true; } }
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(' ', ' ', $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 scoper_flt_pre_object_terms($selected_terms, $taxonomy, $args = array()) { //rs_errlog( "scoper_flt_pre_object_terms input: " . serialize($selected_terms) ); // strip out fake term_id -1 (if applied) if ($selected_terms && is_array($selected_terms)) { $selected_terms = array_diff($selected_terms, array(-1, 0, '0', '-1', '')); } // not sure who is changing empty $_POST['post_category'] array to an array with nullstring element, but we have to deal with that if (defined('DISABLE_QUERYFILTERS_RS')) { return $selected_terms; } if (!is_array($selected_terms)) { // don't filter term selection for non-hierarchical taxonomies if (isset($GLOBALS['wp_taxonomies'][$taxonomy]) && empty($GLOBALS['wp_taxonomies'][$taxonomy]->hierarchical)) { return $selected_terms; } } global $scoper, $current_user, $wpdb; if (!($src_name = $scoper->taxonomies->member_property($taxonomy, 'object_source'))) { return $selected_terms; } // don't filter selected terms for content administrator, but still need to apply default term as needed when none were selected if (is_content_administrator_rs()) { $user_terms = $selected_terms; } else { if (defined('RVY_VERSION')) { global $revisionary; if (!empty($revisionary->admin->impose_pending_rev)) { return $selected_terms; } } $orig_selected_terms = $selected_terms; if (!is_array($selected_terms)) { $selected_terms = array(); } require_once dirname(__FILE__) . '/filters-admin-term-selection_rs.php'; $user_terms = array(); // will be returned by filter_terms_for_status $selected_terms = scoper_filter_terms_for_status($taxonomy, $selected_terms, $user_terms); if ('post' == $src_name) { // TODO: abstract for other data sources if ($object_id = (int) $scoper->data_sources->detect('id', $src_name)) { $stored_terms = wp_get_object_terms($object_id, $taxonomy, array('fields' => 'ids')); if ($deselected_terms = array_diff($stored_terms, $selected_terms)) { if ($unremovable_terms = array_diff($deselected_terms, $user_terms)) { // --- work around storage of autodraft to default category --- $_post = get_post($object_id); if ('category' == $taxonomy && 'draft' == $_post->post_status) { $default_terms = (array) maybe_unserialize(scoper_get_var("SELECT option_value FROM {$wpdb->options} WHERE option_name = 'default_category'")); $unremovable_terms = array_diff($unremovable_terms, $default_terms); } // --- end workaround --- $selected_terms = array_merge($selected_terms, $unremovable_terms); } } } } } //rs_errlog( "$taxonomy - user terms: " . serialize($user_terms) ); //rs_errlog( "selected terms: " . serialize($selected_terms) ); if (empty($selected_terms)) { // For now, always check the DB for default terms. TODO: only if the default_term_option property is set if (!($default_term_option = $scoper->taxonomies->member_property($taxonomy, 'default_term_option'))) { $default_term_option = "default_{$taxonomy}"; } // avoid recursive filtering. Todo: use remove_filter so we can call get_option, supporting filtering by other plugins $default_terms = (array) maybe_unserialize(scoper_get_var("SELECT option_value FROM {$wpdb->options} WHERE option_name = '{$default_term_option}'")); //$selected_terms = (array) get_option( $tx->default_term_option ); // but if the default term is not defined or is not in user's subset of usable terms, substitute first available if ($user_terms) { $_default_terms = array_intersect($default_terms, $user_terms); if (!$_default_terms) { if ($default_terms || defined('SCOPER_AUTO_DEFAULT_TERM')) { // substitute 1st available only if default term option is set or constant defined //if ( $scoper->taxonomies->member_property( $taxonomy, 'requires_term' ) ) $default_terms = (array) $user_terms[0]; } else { $use_taxonomies = scoper_get_option('use_taxonomies'); // If a 'requires_term' taxonomy (i.e. hierarchical) is enabled for RS filtering, a term must be stored if (!empty($use_taxonomies[$taxonomy])) { $default_terms = (array) $user_terms[0]; } else { $default_terms = array(); } } } } //rs_errlog( "default_terms: " . serialize($default_terms) ); $selected_terms = $default_terms; } //rs_errlog( "returning selected terms: " . serialize($selected_terms) ); return $selected_terms; }
function _user_can_read_file($file, &$return_attachment_id, &$matched_published_post, $uploads = '') { // don't filter the direct file URL request if filtering is disabled, or if the request is from wp-admin if (defined('DISABLE_QUERYFILTERS_RS') || is_content_administrator_rs() || !scoper_get_option('file_filtering') || !empty($_SERVER['HTTP_REFERER']) && false !== strpos($_SERVER['HTTP_REFERER'], '/wp-admin') && false !== strpos($_SERVER['HTTP_REFERER'], get_option('siteurl') . '/wp-admin')) { // note: image links from wp-admin should now never get here due to http_referer RewriteRule, but leave above check just in case - inexpensive since we're checking for wp-admin before calling get_option //rs_errlog("skipping filtering for $file"); return true; } if (!is_array($uploads) || empty($uploads['basedir'])) { require_once dirname(__FILE__) . '/uploads_rs.php'; $uploads = scoper_get_upload_info(); } //rs_errlog('_user_can_read_file'); $file_path = $uploads['basedir'] . "/{$file}"; //rs_errlog("$file_path exists."); global $wpdb, $wp_query; $file_url = $uploads['baseurl'] . "/{$file}"; // auto-resized copies have -NNNxNNN suffix, but the base filename is stored as attachment. Strip the suffix out for db query. $orig_file_url = preg_replace("/-[0-9]{2,4}x[0-9]{2,4}./", '.', $file_url); // manually resized copies have -?????????????? suffix, but the base filename is stored as attachment. Strip the suffix out for db query. $orig_file_url = preg_replace("/-[0-9,a-z]{14}./", '.', $orig_file_url); $qry = "SELECT * FROM {$wpdb->posts} WHERE post_type = 'attachment' AND post_parent > 0 AND guid = '{$orig_file_url}'"; $results = scoper_get_results($qry); $matched_published_post = array(); $return_attachment_id = 0; if (empty($results)) { $args = array('skip_any_object_check' => true, 'skip_any_term_check' => true); return cr_user_can('edit_others_posts', 0, 0, $args) || cr_user_can('edit_others_pages', 0, 0, $args); } else { // set global flag (checked by flt_user_has_cap, which filters current_user_Can) global $scoper_checking_attachment_access; $scoper_checking_attachment_access = true; foreach ($results as $attachment) { //rs_errlog( "found attachment: " . serialize($attachment) ); if (is_content_administrator_rs()) { $return_attachment_id = $attachment->ID; break; } if ($attachment->post_parent) { if ($parent_post = scoper_get_row("SELECT post_type, post_status FROM {$wpdb->posts} WHERE ID = '{$attachment->post_parent}' LIMIT 1")) { $object_type = $parent_post->post_type; $containing_post_status = $parent_post->post_status; // Only return content that is attached to published (potentially including private) posts/pages // If some other statuses for published posts are introduced in later WP versions, // the failure mode here will be to overly suppress attachments if ('publish' == $containing_post_status || 'private' == $containing_post_status) { if (current_user_can("read_{$object_type}", $attachment->post_parent)) { $return_attachment_id = $attachment->ID; break; } else { global $current_user; $matched_published_post[$object_type] = $attachment->post_name; } } } } } // clear global flag $scoper_checking_attachment_access = false; } if ($return_attachment_id) { return true; } }
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 _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); } }
<?php if (basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME'])) { die; } // WP 2.5 - 2.7 autosave wipes out page parent. WP 2.5 autosave sets author to current user if (isset($_POST['action']) && $_POST['action'] == 'autosave' && isset($_POST['post_type'])) { add_filter('query', array('ScoperAdminHardway', 'flt_autosave_bugstomper')); } if (!is_content_administrator_rs()) { require_once dirname(__FILE__) . '/hardway-admin_non-administrator_rs.php'; if (!awp_ver('3.1') || defined('SCOPER_LEGACY_HW_FILTERS')) { require_once dirname(__FILE__) . '/hardway-admin_non-administrator-legacy_rs.php'; } } // Note: we are not filtering the QuickEdit author dropdown on edit.php if (in_array($GLOBALS['pagenow'], array('post.php', 'post-new.php')) || strpos($_SERVER['REQUEST_URI'], 'nggallery-manage-gallery')) { if (scoper_get_option('filter_users_dropdown')) { require_once dirname(__FILE__) . '/hardway-users_rs.php'; } } //if ( ! awp_ver('2.7-dev') ) // require_once( dirname(__FILE__).'/hardway-admin-legacy_rs.php'); /** * ScoperAdminHardway PHP class for the WordPress plugin Role Scoper * hardway-admin_rs.php * * @author Kevin Behrens * @copyright Copyright 2011 * * Used by Role Role Scoper Plugin as a container for statically-called functions
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 user_can_admin_object($src_name, $object_type, $object_id = false, $any_obj_role_check = false, $user = '') { if (is_content_administrator_rs()) { return true; } require_once dirname(__FILE__) . '/permission_lib_rs.php'; return user_can_admin_object_rs($src_name, $object_type, $object_id, $any_obj_role_check, $user); }
function skip_filtering($taxonomies, $args) { global $scoper; if (!empty($args['rs_no_filter'])) { return true; } // this filtering 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 (count($taxonomies) > 1) { return true; } $taxonomy = reset($taxonomies); if (!($tx_obj = get_taxonomy($taxonomy))) { return true; } $use_taxonomies = array(); if (is_admin()) { if ('nav-menus.php' == $GLOBALS['pagenow'] && 'nav_menu' != $taxonomy) { if (!scoper_get_option('admin_nav_menu_filter_items')) { return true; } } } else { 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 true; } } } // no wp-admin filtering for administrators (filters not added in that case) if ((is_admin() || defined('XMLRPC_REQUEST')) && is_content_administrator_rs()) { return true; } // link category roles / restrictions are only scoped for management (TODO: review this) if ('link_category' == $taxonomy && $scoper->is_front()) { return true; } if ($args['child_of'] || $args['parent']) { $children = ScoperAncestry::get_terms_children($taxonomy); if ($args['child_of'] && !isset($children[$args['child_of']])) { return 'empty_result'; } // get_terms filter will return empty result array if ($args['parent'] && !isset($children[$args['parent']])) { return 'empty_result'; } // get_terms filter will return empty result array } return false; }
function flt_get_bookmarks($results, $args) { global $wpdb; $defaults = array('orderby' => 'name', 'order' => 'ASC', 'limit' => -1, 'category' => '', 'category_name' => '', 'hide_invisible' => 1, 'show_updated' => 0, 'include' => '', 'exclude' => '', 'search' => ''); $r = wp_parse_args($args, $defaults); extract($r, EXTR_SKIP); // === BEGIN RoleScoper ADDITION: exemption for content administrators if (is_content_administrator_rs()) { return $results; } // === END RoleScoper ADDITION === // === BEGIN RoleScoper MODIFICATION: wp-cache key and flag specific to access type and user/groups --// // global $current_rs_user; $ckey = md5(serialize($r) . CURRENT_ACCESS_NAME_RS); $cache_flag = 'rs_get_bookmarks'; $cache = $current_rs_user->cache_get($cache_flag); if (false !== $cache) { if (!is_array($cache)) { $cache = array(); } if (isset($cache[$ckey])) { //alternate filter name (WP core already called get_bookmarks filter) return apply_filters('get_bookmarks_rs', $cache[$ckey], $r); } } // // === END RoleScoper MODIFICATION === // =================================== $inclusions = ''; if (!empty($include)) { $exclude = ''; //ignore exclude, category, and category_name params if using include $category = ''; $category_name = ''; $inclinks = wp_parse_id_list($include); if (count($inclinks)) { foreach ($inclinks as $inclink) { if (empty($inclusions)) { $inclusions = ' AND ( link_id = ' . intval($inclink) . ' '; } else { $inclusions .= ' OR link_id = ' . intval($inclink) . ' '; } } } } if (!empty($inclusions)) { $inclusions .= ')'; } $exclusions = ''; if (!empty($exclude)) { $exlinks = wp_parse_id_list($exclude); if (count($exlinks)) { foreach ($exlinks as $exlink) { if (empty($exclusions)) { $exclusions = ' AND ( link_id <> ' . intval($exlink) . ' '; } else { $exclusions .= ' AND link_id <> ' . intval($exlink) . ' '; } } } } if (!empty($exclusions)) { $exclusions .= ')'; } if (!empty($category_name)) { if ($category = get_term_by('name', $category_name, 'link_category')) { $category = $category->term_id; } else { return array(); } } if (!empty($search)) { $search = like_escape($search); $search = " AND ( (link_url LIKE '%{$search}%') OR (link_name LIKE '%{$search}%') OR (link_description LIKE '%{$search}%') ) "; } $category_query = ''; $join = ''; if (!empty($category)) { $incategories = wp_parse_id_list($category); if (count($incategories)) { foreach ($incategories as $incat) { if (empty($category_query)) { $category_query = ' AND ( tt.term_id = ' . intval($incat) . ' '; } else { $category_query .= ' OR tt.term_id = ' . intval($incat) . ' '; } } } } if (!empty($category_query)) { $category_query .= ") AND taxonomy = 'link_category'"; $join = " INNER JOIN {$wpdb->term_relationships} AS tr ON ({$wpdb->links}.link_id = tr.object_id) INNER JOIN {$wpdb->term_taxonomy} as tt ON tt.term_taxonomy_id = tr.term_taxonomy_id"; } if (get_option('links_recently_updated_time')) { $recently_updated_test = ", IF (DATE_ADD(link_updated, INTERVAL " . get_option('links_recently_updated_time') . " MINUTE) >= NOW(), 1,0) as recently_updated "; } else { $recently_updated_test = ''; } if ($show_updated) { $get_updated = ", UNIX_TIMESTAMP(link_updated) AS link_updated_f "; } else { $get_updated = ''; } $orderby = strtolower($orderby); $length = ''; switch ($orderby) { case 'length': $length = ", CHAR_LENGTH(link_name) AS length"; break; case 'rand': $orderby = 'rand()'; break; default: $orderparams = array(); foreach (explode(',', $orderby) as $ordparam) { $orderparams[] = 'link_' . trim($ordparam); } $orderby = implode(',', $orderparams); } if ('link_id' == $orderby) { $orderby = "{$wpdb->links}.link_id"; } $visible = ''; if ($hide_invisible) { $visible = "AND link_visible = 'Y'"; } $query = "SELECT * {$length} {$recently_updated_test} {$get_updated} FROM {$wpdb->links} {$join} WHERE 1=1 {$visible} {$category_query}"; $query .= " {$exclusions} {$inclusions} {$search}"; $query .= " ORDER BY {$orderby} {$order}"; if ($limit != -1) { $query .= " LIMIT {$limit}"; } // === BEGIN RoleScoper MODIFICATION: run query through scoping filter, cache key specific to user/group $query = apply_filters('objects_request_rs', $query, 'link', '', ''); $results = scoper_get_results($query); // cache key and flag specific to access type and user/groups $cache[$ckey] = $results; $current_rs_user->cache_set($cache, $cache_flag); // alternate hook name (WP core already applied get_bookmarks) $links = apply_filters('get_bookmarks_rs', $results, $r); // // === END RoleScoper MODIFICATION === // =================================== // === BEGIN RoleScoper ADDITION: memory cache akin to page_cache to assist bulk operations // global $scoper; $ilim = count($links); for ($i = 0; $i < $ilim; $i++) { $scoper->listed_ids['link'][$links[$i]->link_id] = true; } // // === END RoleScoper ADDITION === // =================================== return $links; }
function flt_objects_results($results, $src_name, $object_types, $args = array()) { if (!$object_types || is_array($object_types) && count($object_types) > 1) { $object_type = cr_find_post_type(); } else { $object_type = strval($object_types); } if ('edit.php' == $GLOBALS['pagenow'] && !is_content_administrator_rs()) { $post_type_obj = get_post_type_object($object_type); if (!empty($post_type_obj->hierarchical)) { // ScoperAncestry class is loaded by hardway_rs.php $ancestors = ScoperAncestry::get_page_ancestors(); // array of all ancestor IDs for keyed page_id, with direct parent first $args = array('remap_parents' => false); ScoperHardway::remap_tree($results, $ancestors, 'ID', 'post_parent', $args); } } if ($this->scoper->is_front() && empty($this->skip_teaser)) { if ($tease_otypes = $this->_get_teaser_object_types($src_name, $object_types, $args)) { require_once dirname(__FILE__) . '/teaser_rs.php'; $args['force_teaser'] = true; return ScoperTeaser::posts_teaser_prep_results($results, $tease_otypes, $args); } // won't do anything unless teaser is enabled for object type(s) //$results = apply_filters('objects_teaser_pre_results_rs', $results, 'post', $object_type, array('force_teaser' => true)); } return $results; }
function ui_hide_appearance_submenus() { global $current_user; if (is_content_administrator_rs() || !empty($current_user->allcaps['edit_theme_options'])) { return; } ?> <script type="text/javascript"> /* <![CDATA[ */ jQuery(document).ready( function($) { $('#menu-appearance a[href!="nav-menus.php"]').hide(); $('#menu-appearance a[class*="wp-has-submenu"]').show(); <?php if ('nav-menus.php' == $GLOBALS['pagenow']) { ?> $('#nav-menu-header .delete-action a').hide(); <?php } ?> }); /* ]]> */ </script> <?php }
function scoper_object_roles_list($viewing_user, $args = array()) { $html = ''; if (!USER_ROLES_RS && !GROUP_ROLES_RS) { wp_die(__awp('Cheatin’ uh?')); } $defaults = array('enforce_duration_limits' => true, 'is_user_profile' => false, 'echo' => true); $args = array_merge($defaults, (array) $args); extract($args); global $scoper, $wpdb, $current_user; if ($viewing_user) { if (!is_object($viewing_user)) { global $current_rs_user; if ($viewing_user == $current_rs_user->ID) { $viewing_user = $current_rs_user; } else { $viewing_user = new WP_Scoped_User($viewing_user); } } } $all_roles = array(); $role_display = array(); foreach ($scoper->role_defs->get_all_keys() as $role_handle) { if ($viewing_user) { $role_display[$role_handle] = $scoper->role_defs->get_display_name($role_handle, OBJECT_UI_RS); } else { $role_display[$role_handle] = $scoper->role_defs->get_abbrev($role_handle, OBJECT_UI_RS); } } if (!$is_user_profile) { $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; } } else { $require_blogwide_editor = false; } foreach ($scoper->data_sources->get_all() as $src_name => $src) { $otype_count = 0; if (!empty($src->taxonomy_only) || $src_name == 'group' && !$viewing_user) { continue; } $strict_objects = $scoper->get_restrictions(OBJECT_SCOPE_RS, $src_name); foreach ($src->object_types as $object_type => $otype) { $otype_count++; $disable_role_admin = false; if ($require_blogwide_editor) { if (!$scoper->user_can_edit_blogwide('post', $object_type, array('require_others_cap' => true))) { $disable_role_admin = true; } } if (!empty($src->cols->type) && !empty($otype->name)) { $col_type = $src->cols->type; $otype_clause = "AND {$src->table}.{$col_type} = '{$otype->name}'"; } elseif ($otype_count < 2) { $otype_clause = ''; } else { continue; } $col_id = $src->cols->id; $col_name = $src->cols->name; $ug_clause_for_user_being_viewed = $viewing_user ? $viewing_user->get_user_clause('uro') : ''; // TODO: replace join with uro subselect $qry = "SELECT DISTINCT {$src->table}.{$col_name}, {$src->table}.{$col_id}, uro.role_name, uro.date_limited, uro.start_date_gmt, uro.end_date_gmt" . " FROM {$src->table} "; $join = " 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'"; $duration_clause = $enforce_duration_limits ? scoper_get_duration_clause("{$src->table}.{$src->cols->date}") : ''; $status_clause = 'post' == $src_name ? "AND post_status != 'auto-draft'" : ''; // TODO: version update script to delete post roles on auto-drafts (stored via default roles) $where = " WHERE 1=1 {$status_clause} {$otype_clause} {$duration_clause} {$ug_clause_for_user_being_viewed}"; $orderby = " ORDER BY {$src->table}.{$col_name} ASC, uro.role_name ASC"; $qry .= $join . $where . $orderby; $results = scoper_get_results($qry); if (!is_user_administrator_rs()) { // no need to filter admins - just query the assignments // only list role assignments which the logged-in user can administer $args['required_operation'] = OP_EDIT_RS; // Possible TODO: re-implement OP_ADMIN distinction with admin-specific capabilities /* if ( cr_get_reqd_caps( $src_name, OP_ADMIN_RS, $object_type ) { $args['required_operation'] = OP_ADMIN_RS; } else { $reqd_caps = array(); foreach (array_keys($src->statuses) as $status_name) { $admin_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_ADMIN_RS, $status_name); $delete_caps = $scoper->cap_defs->get_matching($src_name, $object_type, OP_DELETE_RS, $status_name); $reqd_caps[$object_type][$status_name] = array_merge(array_keys($admin_caps), array_keys($delete_caps)); } $args['force_reqd_caps'] = $reqd_caps; } */ $qry = "SELECT {$src->table}.{$col_id} FROM {$src->table} WHERE 1=1"; $args['require_full_object_role'] = true; $qry_flt = apply_filters('objects_request_rs', $qry, $src_name, $object_type, $args); $cu_admin_results = scoper_get_col($qry_flt); if (empty($viewing_user) || $current_user->ID != $viewing_user->ID) { foreach ($results as $key => $row) { if (!in_array($row->{$col_id}, $cu_admin_results)) { unset($results[$key]); } } } else { // for current user's view of their own user profile, just de-link unadminable objects $link_roles = array(); $link_objects = array(); if (!$disable_role_admin) { foreach ($results as $key => $row) { if (in_array($row->{$col_id}, $cu_admin_results)) { $link_roles[$row->{$col_id}] = true; } } $args['required_operation'] = OP_EDIT_RS; $args['require_full_object_role'] = false; if (isset($args['force_reqd_caps'])) { unset($args['force_reqd_caps']); } $qry_flt = apply_filters('objects_request_rs', $qry, $src_name, $object_type, $args); $cu_edit_results = scoper_get_col($qry_flt); foreach ($results as $key => $row) { if (in_array($row->{$col_id}, $cu_edit_results)) { $link_objects[$row->{$col_id}] = true; } } } } } $object_roles = array(); $objnames = array(); if ($results) { $got_object_roles = true; foreach ($results as $row) { if (!isset($objnames[$row->{$col_id}])) { if ('post' == $src->name) { $objnames[$row->{$col_id}] = apply_filters('the_title', $row->{$col_name}, $row->{$col_id}); } else { $objnames[$row->{$col_id}] = $row->{$col_name}; } } $role_handle = 'rs_' . $row->role_name; if ($row->date_limited) { $duration_key = serialize(array('start_date_gmt' => $row->start_date_gmt, 'end_date_gmt' => $row->end_date_gmt)); } else { $duration_key = ''; } $object_roles[$duration_key][$row->{$col_id}][$role_handle] = true; } } else { continue; } ?> <?php $title_roles = __('edit roles', 'scoper'); foreach (array_keys($object_roles) as $duration_key) { $date_caption = ''; $limit_class = ''; $limit_style = ''; $link_class = ''; if ($duration_key) { $html .= "<h3 style='margin-bottom:0'>{$date_caption}</h3>"; $duration_limits = unserialize($duration_key); $duration_limits['date_limited'] = true; ScoperAdminUI::set_agent_formatting($duration_limits, $date_caption, $limit_class, $link_class, $limit_style); $title = "title='{$date_caption}'"; $date_caption = '<span class="rs-gray"> ' . trim($date_caption) . '</span>'; } else { $title = "title='{$title_roles}'"; } if (!$disable_role_admin && (is_user_administrator_rs() || $cu_admin_results)) { //if ( ( $src_name != $object_type ) && ( 'post' != $object_type ) ) { // menu links currently assume unique object type names // $roles_page = "rs-roles-{$object_type}_{$src_name}"; //} else { $roles_page = "rs-{$object_type}-roles"; //} $url = "admin.php?page={$roles_page}"; $html .= "<h4><a name='{$object_type}' href='{$url}'><strong>" . sprintf(__('%1$s Roles%2$s:', 'scoper'), $otype->labels->singular_name, '</strong></a><span style="font-weight:normal">' . $date_caption) . "</span></h4>"; } else { $html .= "<h4><strong>" . sprintf(__('%1$s Roles%2$s:', 'scoper'), $otype->labels->singular_name, $date_caption) . "</strong></h4>"; } $html .= "<ul class='rs-termlist'><li>" . "<table class='widefat'>" . "<thead>" . "<tr class='thead'>" . "\t<th class='rs-tightcol'>" . __('ID') . "</th>" . "\t<th>" . __awp('Name') . "</th>" . "\t<th>" . __('Role Assignments', 'scoper') . "</th>" . "</tr>" . "</thead>"; $id_clause = isset($role_codes[$role_handle]) ? "id='roles-{$role_codes[$role_handle]}'" : ''; $html .= "<tbody {$id_clause}>"; $style = ' class="rs-backwhite"'; $title_item = sprintf(__('edit %s', 'scoper'), agp_strtolower($otype->labels->singular_name)); foreach ($object_roles[$duration_key] as $obj_id => $roles) { $object_name = esc_attr($objnames[$obj_id]); $html .= "\n\t<tr{$style}>"; $link_this_object = !isset($link_objects) || isset($link_objects[$obj_id]); // link from object ID to the object type's default editor, if defined if ($link_this_object && !empty($src->edit_url)) { $src_edit_url = sprintf($src->edit_url, $obj_id); $html .= "<td><a href='{$src_edit_url}' class='edit' title='{$title_item}'>{$obj_id}</a></td>"; } else { $html .= "<td>{$obj_id}</td>"; } $name = !empty($objnames[$obj_id]) ? $objnames[$obj_id] : __('(untitled)', 'scoper'); // link from object name to our "Edit Object Role Assignment" interface $link_this_role = !isset($link_roles) || isset($link_roles[$obj_id]); if ($link_this_role) { if ('group' == $object_type) { $rs_edit_url = sprintf($src->edit_url, $obj_id); } else { $rs_edit_url = "admin.php?page=rs-object_role_edit&src_name={$src_name}&object_type={$object_type}&object_id={$obj_id}&object_name={$object_name}"; } $html .= "\n\t<td><a {$title}{$limit_style}class='{$link_class}{$limit_class}' href='{$rs_edit_url}'>{$name}</a></td>"; } else { $html .= "\n\t<td>{$name}</td>"; } $html .= "<td>"; $role_list = array(); foreach (array_keys($roles) as $role_handle) { // roles which require object assignment are asterisked (bolding would contradict the notation of term roles list, where propogating roles are bolded) if (isset($strict_objects['restrictions'][$role_handle][$obj_id]) || isset($strict_objects['unrestrictions'][$role_handle]) && is_array($strict_objects['unrestrictions'][$role_handle]) && !isset($strict_objects['unrestrictions'][$role_handle][$obj_id])) { $role_list[] = "<span class='rs-backylw'>" . $role_display[$role_handle] . '</span>'; } else { $role_list[] = $role_display[$role_handle]; } } $html .= implode(', ', $role_list); $html .= '</td></tr>'; $style = ' class="alternate"' == $style ? ' class="rs-backwhite"' : ' class="alternate"'; } // end foreach object_roles $html .= '</tbody></table>'; $html .= '</li></ul><br />'; } // end foreach role date range } // end foreach object_types } // end foreach data source if ($echo) { echo $html; } else { return $html; } }
function flt_dropdown_pages($orig_options_html) { if (!strpos($orig_options_html, 'parent_id') || !$orig_options_html || is_content_administrator_rs()) { return $orig_options_html; } $post_type = awp_post_type_from_uri(); // User can't associate or de-associate a page with Main page unless they have edit_pages blog-wide. // Prepend the Main Page option if appropriate (or, to avoid submission errors, if we generated no other options) if (!$GLOBALS['scoper_admin_filters']->user_can_associate_main($post_type)) { $is_new = $GLOBALS['post']->post_status == 'auto-draft'; if (!$is_new) { global $post; $object_id = !empty($post->ID) ? $post->ID : $GLOBALS['scoper']->data_sources->detect('id', 'post', 0, 'post'); $stored_parent_id = !empty($post->ID) ? $post->post_parent : get_post_field('post_parent', $object_id); } if ($is_new || $stored_parent_id) { $mat = array(); preg_match('/<option[^v]* value="">[^<]*<\\/option>/', $orig_options_html, $mat); if (!empty($mat[0])) { return str_replace($mat[0], '', $orig_options_html); } } } return $orig_options_html; }