function scoper_display_rs_roledefs($args = array()) { global $scoper; echo "<div id='rs-roledefs' style='clear:both;margin:0;' class='rs-options agp_js_hide {$args['bgcolor_class']}'>"; if (scoper_get_option('display_hints')) { echo '<div class="rs-optionhint">'; echo '<p style="margin-top:0">'; _e('These roles are defined by Role Scoper (and possibly other plugins) for your use in designating content-specific access or supplemental site-wide access. Although the default capabilities are ideal for most installations, you may modify them at your discretion.', 'scoper'); echo '</p>'; echo '<p>'; _e('Since Role Scoper role definitions pertain to a particular object type, available capabilities are defined by the provider of that object type. WordPress core or plugins can add or revise default role definitions based on available capabilities.', 'scoper'); echo '</p>'; echo '<p>'; if (awp_ver('3.0-dev')) { _e('WordPress Role assignments function as a default which may be supplemented or overriden by site-wide or content-specific assignment of these RS Roles.', 'scoper'); } else { _e('WordPress Role assignments function as a default which may be supplemented or overriden by blog-wide or content-specific assignment of these RS Roles.', 'scoper'); } echo '</p>'; echo '</div>'; } echo "<input type='hidden' name='rs_role_defs' value='1' />"; if (empty($args['customize_defaults'])) { $rs_role_defs = $scoper->role_defs; } else { global $scoper_role_types; $rs_role_defs = new CR_Roles(); //$this->load_role_caps(); $rs_role_defs->role_caps = apply_filters('define_role_caps_rs', cr_role_caps()); if ($user_role_caps = scoper_get_option('user_role_caps', -1, true)) { $rs_role_defs->add_role_caps($user_role_caps); } if ($disabled_role_caps = scoper_get_option('disabled_role_caps', -1, true)) { $rs_role_defs->remove_role_caps($disabled_role_caps); } $rs_role_defs->add_member_objects(cr_role_defs()); $rs_role_defs = apply_filters('define_roles_rs', $rs_role_defs); $rs_role_defs->remove_invalid(); // currently don't allow additional custom-defined post, page or link roles // To support merging in of WP role assignments, always note actual WP-defined roles // regardless of which role type we are scoping with. $scoper->log_wp_roles($rs_role_defs); $rs_role_defs->lock(); // prevent inadvertant improper API usage } // object_type association of roles needs to be based on default role_caps, otherwise roles with all caps disabled will be excluded from UI // This also allows the default bolding to be based on custom default settings when role defs are defined per-blog in wp-mu global $scoper_role_types; $rs_default_role_defs = new CR_Roles(); $rs_default_role_defs->role_caps = apply_filters('define_role_caps_rs', cr_role_caps()); $rs_default_role_defs->add_member_objects(cr_role_defs()); $rs_default_cap_defs = new CR_Capabilities(); $rs_default_cap_defs->add_member_objects(cr_cap_defs()); $rs_default_cap_defs = apply_filters('define_capabilities_rs', $rs_default_cap_defs); $scoper->log_cap_usage($rs_default_role_defs, $rs_default_cap_defs); if (IS_MU_RS && !$args['customize_defaults'] && !$args['sitewide']) { if ($user_role_caps = scoper_get_option('user_role_caps', -1, true)) { $rs_default_role_defs->add_role_caps($user_role_caps); } if ($disabled_role_caps = scoper_get_option('disabled_role_caps', -1, true)) { $rs_default_role_defs->remove_role_caps($disabled_role_caps); } } $rs_default_role_defs = apply_filters('define_roles_rs', $rs_default_role_defs); $rs_default_role_defs->remove_invalid(); if (has_filter('define_roles_rs')) { require_once SCOPER_ABSPATH . '/extension-helper_rs.php'; scoper_adjust_legacy_extension_cfg($rs_default_role_defs, $rs_default_cap_defs); } $reviewed_roles = array(); foreach ($scoper->data_sources->get_all() as $src_name => $src) { $object_types = $src->object_types; if ('post' == $src_name) { global $wp_taxonomies; foreach ($wp_taxonomies as $tx) { if ($_tx = $scoper->taxonomies->get($tx->name)) { // use RS taxonomy object so we can pull plural_name property $object_types[$tx->name] = $_tx; } } $use_post_types = scoper_get_option('use_post_types'); $use_taxonomies = scoper_get_option('use_taxonomies'); } foreach ($object_types as $object_type => $otype) { if ('post' == $src_name && empty($use_post_types[$object_type]) && empty($use_taxonomies[$object_type])) { continue; } $otype_roles = array(); $otype_display_names = array(); if ($obj_roles = $rs_default_role_defs->get_matching('rs', $src_name, $object_type)) { $otype_roles[$object_type] = $obj_roles; } if (!empty($otype->labels->name)) { $otype_display_names[$object_type] = $otype->labels->singular_name; } else { $otype_display_names[$object_type] = $otype->display_name; } if (!$otype_roles) { continue; } if ('post' == $src_name) { $plural_name = plural_name_from_cap_rs(get_post_type_object($object_type)); } else { $plural_name = ''; } foreach ($otype_roles as $object_type => $roles) { //display each role which has capabilities for this object type echo '<br />'; echo '<h3>' . sprintf(__('%s Roles'), $otype_display_names[$object_type]) . '</h3>'; ?> <table class='widefat rs-backwhite'> <thead> <tr class="thead"> <th width="15%"><?php echo __awp('Role'); ?> </th> <th><?php _e('Capabilities (abbreviated, defaults are bolded)', 'scoper'); ?> </th> </tr> </thead> <tbody> <?php $wp_role_sync = array('rs_post_contributor' => 'contributor', 'rs_post_revisor' => 'revisor', 'rs_post_author' => 'author', 'rs_post_editor' => 'editor', 'rs_page_editor' => 'editor'); if (defined('RVY_VERSION')) { $wp_role_sync['rs_page_revisor'] = 'revisor'; } global $wp_roles; $style = ''; foreach ($roles as $rs_role_handle => $role_def) { $reviewed_roles[] = $rs_role_handle; $style = ' class="alternate"' == $style ? '' : ' class="alternate"'; echo "\n\t" . "<tr{$style}><td><strong>" . $rs_role_defs->get_display_name($rs_role_handle) . '</strong>'; if (isset($wp_role_sync[$rs_role_handle])) { if (isset($wp_roles->role_objects[$wp_role_sync[$rs_role_handle]])) { $wp_role_handle = "wp_" . $wp_role_sync[$rs_role_handle]; $wp_display_name = $wp_roles->role_names[$wp_role_sync[$rs_role_handle]]; $contained_roles = $rs_role_defs->get_contained_roles($wp_role_handle); if (!isset($contained_roles[$rs_role_handle])) { echo '<br /><br /><span class="rs-warning">'; printf(__('Warning: Since the WP %1$s role def lacks some caps selected here, it will be treated as a lesser role if Restrictions are applied.', 'scoper'), $wp_display_name); echo '</span>'; $missing_caps = true; } else { $missing_caps = false; } // only display "sync WP role" checkbox if the WP role has missing caps or extra caps $otype_caps = $scoper->cap_defs->get_matching($src_name, $object_type, '', STATUS_ANY_RS); $wp_defined_caps = array_intersect_key($wp_roles->role_objects[$wp_role_sync[$rs_role_handle]]->capabilities, $otype_caps); $wp_extra_caps = array_diff_key($wp_defined_caps, $rs_role_defs->role_caps[$rs_role_handle]); /* if ( $wp_extra_caps ) $sync_caption = sprintf( _ x( 'sync WP %1$s <br />to these selections (currently includes %2$s)', 'role name', 'scoper' ), $wp_display_name, implode( ", ", array_keys($wp_extra_caps) ) ); else $sync_caption = sprintf( _ x( 'sync WP %s <br />to these selections', 'role name', 'scoper' ), $wp_display_name); */ if ($wp_extra_caps) { $sync_caption = sprintf(__('sync WP %1$s <br />to these selections (currently includes %2$s)', 'scoper'), $wp_display_name, implode(", ", array_keys($wp_extra_caps))); } else { $sync_caption = sprintf(__('sync WP %s <br />to these selections', 'scoper'), $wp_display_name); } echo '<br /><br />'; $title = __('note: only the capabilities listed here will be affected', 'scoper'); echo "<input type='checkbox' name='sync_wp_roles[]' id='sync_wp_role_{$rs_role_handle}' value='{$rs_role_handle}:{$wp_role_handle}' title='{$title}' />" . "<label for='sync_wp_role_{$rs_role_handle}' title='{$title}'>" . $sync_caption . '</label>'; } } echo "</td><td><ul class='rs-cap_list'>"; $active_cap_names = array_keys($rs_role_defs->role_caps[$rs_role_handle]); if (!empty($role_def->anon_user_blogrole) || !empty($role_def->no_custom_caps)) { $disabled_role = 'disabled="disabled"'; $available_cap_names = $active_cap_names; } else { $disabled_role = ''; $available_caps = $rs_default_cap_defs->get_matching($src_name, $object_type, '', STATUS_ANY_RS); $available_cap_names = array_keys($available_caps); sort($available_cap_names); $available_cap_names = array_merge($available_cap_names, $active_cap_names); } // abbreviate type caps and reorder display $show_cap_names = array(); foreach ($available_cap_names as $cap_name) { if ($plural_name && strpos($cap_name, "_{$plural_name}")) { $display = str_replace("_{$plural_name}", '', $cap_name); $display = sprintf(__('%s...', 'scoper'), $display); } else { $display = $cap_name; } $show_cap_names[$display] = $cap_name; } ksort($show_cap_names); foreach ($show_cap_names as $display => $cap_name) { $checked = in_array($cap_name, $active_cap_names) ? 'checked="checked"' : ''; $is_default = !empty($rs_default_role_defs->role_caps[$rs_role_handle][$cap_name]); $disabled_cap = $disabled_role || $is_default && !empty($available_caps[$cap_name]->no_custom_remove) || !$is_default && !empty($available_caps[$cap_name]->no_custom_add); $disabled = $disabled_cap ? 'disabled="disabled"' : ''; $style = $is_default ? "style='font-weight: bold'" : ''; $cap_safename = str_replace(' ', '_', $cap_name); echo "<li><input type='checkbox' name='{$rs_role_handle}_caps[]' id='{$rs_role_handle}_{$cap_safename}' value='{$cap_name}' {$checked} {$disabled} />" . "<label for='{$rs_role_handle}_{$cap_safename}' title='{$cap_name}' {$style}>" . str_replace(' ', ' ', ucwords(str_replace('_', ' ', $display))) . '</label></li>'; } echo '</ul></td></tr>'; } echo '</tbody></table>'; echo '<br /><br />'; } // foreach otype_role (distinguish object roles from term roles) } // end foreach object_type } // end foreach data source $reviewed_roles = implode(',', array_unique($reviewed_roles)); echo "<input type='hidden' name='reviewed_roles' value='{$reviewed_roles}' />"; echo '<span class="alignright">'; echo '<label for="rs_role_resync"><input name="rs_role_resync" type="checkbox" id="rs_role_resync" value="1" />'; echo ' '; _e('Re-sync with WordPress roles on next Update', 'scoper'); echo '</label></span>'; echo '<br />'; ?> </div> <?php }
function flt_get_pages($results, $args = array()) { $results = (array) $results; global $wpdb; // === BEGIN Role Scoper ADDITION: global var; various special case exemption checks === // global $scoper, $current_rs_user; // need to skip cache retrieval if QTranslate is filtering get_pages with a priority of 1 or less $no_cache = !defined('SCOPER_QTRANSLATE_COMPAT') && awp_is_plugin_active('qtranslate'); // buffer titles in case they were filtered previously $titles = scoper_get_property_array($results, 'ID', 'post_title'); // depth is not really a get_pages arg, but remap exclude arg to exclude_tree if wp_list_terms called with depth=1 if (!empty($args['exclude']) && empty($args['exclude_tree']) && !empty($args['depth']) && 1 == $args['depth']) { if (0 !== strpos($args['exclude'], ',')) { // work around wp_list_pages() bug of attaching leading comma if a plugin uses wp_list_pages_excludes filter $args['exclude_tree'] = $args['exclude']; } } // // === END Role Scoper ADDITION === // ================================= $defaults = array('child_of' => 0, 'sort_order' => 'ASC', 'sort_column' => 'post_title', 'hierarchical' => 1, 'exclude' => array(), 'include' => array(), 'meta_key' => '', 'meta_value' => '', 'authors' => '', 'parent' => -1, 'exclude_tree' => '', 'number' => '', 'offset' => 0, 'post_type' => 'page', 'post_status' => 'publish', 'depth' => 0, 'suppress_filters' => 0, 'remap_parents' => -1, 'enforce_actual_depth' => -1, 'remap_thru_excluded_parent' => -1); // Role Scoper arguments added above // === BEGIN Role Scoper ADDITION: support front-end optimization $post_type = isset($args['post_type']) ? $args['post_type'] : $defaults['post_type']; $use_post_types = (array) scoper_get_option('use_post_types'); if (empty($use_post_types[$post_type])) { return $results; } if ($scoper->is_front()) { if ('page' == $post_type && defined('SCOPER_GET_PAGES_LEAN')) { // custom types are likely to have custom fields $defaults['fields'] = "{$wpdb->posts}.ID, {$wpdb->posts}.post_title, {$wpdb->posts}.post_parent, {$wpdb->posts}.post_date, {$wpdb->posts}.post_date_gmt, {$wpdb->posts}.post_status, {$wpdb->posts}.post_name, {$wpdb->posts}.post_modified, {$wpdb->posts}.post_modified_gmt, {$wpdb->posts}.guid, {$wpdb->posts}.menu_order, {$wpdb->posts}.comment_count"; } else { $defaults['fields'] = "{$wpdb->posts}.*"; if (!defined('SCOPER_FORCE_PAGES_CACHE')) { $no_cache = true; } // serialization / unserialization of post_content for all pages is too memory-intensive for sites with a lot of pages } } else { // required for xmlrpc getpagelist method $defaults['fields'] = "{$wpdb->posts}.*"; if (!defined('SCOPER_FORCE_PAGES_CACHE')) { $no_cache = true; } } // === END Role Scoper MODIFICATION === $r = wp_parse_args($args, $defaults); extract($r, EXTR_SKIP); $number = (int) $number; $offset = (int) $offset; $child_of = (int) $child_of; // Role Scoper modification: null value will confuse children array check // Make sure the post type is hierarchical $hierarchical_post_types = get_post_types(array('public' => true, 'hierarchical' => true)); if (!in_array($post_type, $hierarchical_post_types)) { return $results; } // Make sure we have a valid post status if (!in_array($post_status, get_post_stati())) { return $results; } // for the page parent dropdown, return no available selections for a published main page if the logged user isn't allowed to de-associate it from Main if (!empty($name) && 'parent_id' == $name) { global $post; if (!$post->post_parent && !$GLOBALS['scoper_admin_filters']->user_can_associate_main($post_type)) { $status_obj = get_post_status_object($post->post_status); if ($status_obj->public || $status_obj->private) { return array(); } } if (!empty($post) && $post_type == $post->post_type) { if ($post->post_parent) { $append_page = get_post($post->post_parent); } $exclude_tree = $post->ID; } } //$scoper->last_get_pages_args = $r; // don't copy entire args array unless it proves necessary $scoper->last_get_pages_depth = $depth; $scoper->last_get_pages_suppress_filters = $suppress_filters; if ($suppress_filters) { return $results; } // === BEGIN Role Scoper MODIFICATION: wp-cache key and flag specific to access type and user/groups // if (!scoper_get_otype_option('use_object_roles', 'post', $post_type)) { return $results; } $key = md5(serialize(compact(array_keys($defaults)))); $ckey = md5($key . CURRENT_ACCESS_NAME_RS); $cache_flag = 'rs_get_pages'; $cache = $current_rs_user->cache_get($cache_flag); if (false !== $cache) { if (!is_array($cache)) { $cache = array(); } if (!$no_cache && isset($cache[$ckey])) { // alternate filter name (WP core already applied get_pages filter) return apply_filters('get_pages_rs', $cache[$ckey], $r); } } // // === END Role Scoper MODIFICATION === // ==================================== $inclusions = ''; if (!empty($include)) { $child_of = 0; //ignore child_of, parent, exclude, meta_key, and meta_value params if using include $parent = -1; $exclude = ''; $meta_key = ''; $meta_value = ''; $hierarchical = false; $incpages = wp_parse_id_list($include); if (!empty($incpages)) { foreach ($incpages as $incpage) { if (empty($inclusions)) { $inclusions = ' AND ( ID = ' . intval($incpage) . ' '; } else { $inclusions .= ' OR ID = ' . intval($incpage) . ' '; } } } } if (!empty($inclusions)) { $inclusions .= ')'; } $exclusions = ''; if (!empty($exclude)) { $expages = wp_parse_id_list($exclude); if (!empty($expages)) { foreach ($expages as $expage) { if (empty($exclusions)) { $exclusions = ' AND ( ID <> ' . intval($expage) . ' '; } else { $exclusions .= ' AND ID <> ' . intval($expage) . ' '; } } } } if (!empty($exclusions)) { $exclusions .= ')'; } $author_query = ''; if (!empty($authors)) { $post_authors = wp_parse_id_list($authors); if (!empty($post_authors)) { foreach ($post_authors as $post_author) { //Do we have an author id or an author login? if (0 == intval($post_author)) { $post_author = get_userdatabylogin($post_author); if (empty($post_author)) { continue; } if (empty($post_author->ID)) { continue; } $post_author = $post_author->ID; } if ('' == $author_query) { $author_query = ' post_author = ' . intval($post_author) . ' '; } else { $author_query .= ' OR post_author = ' . intval($post_author) . ' '; } } if ('' != $author_query) { $author_query = " AND ({$author_query})"; } } } $join = ''; $where = "{$exclusions} {$inclusions} "; if (!empty($meta_key) || !empty($meta_value)) { $join = " INNER JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id"; // Role Scoper modification: was LEFT JOIN in WP 3.0 core (TODO: would that botch uro join results? // meta_key and meta_value might be slashed $meta_key = stripslashes($meta_key); $meta_value = stripslashes($meta_value); if (!empty($meta_key)) { $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_key = %s", $meta_key); } if (!empty($meta_value)) { $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_value = %s", $meta_value); } } if ($parent >= 0) { $where .= $wpdb->prepare(' AND post_parent = %d ', $parent); } // === BEGIN Role Scoper MODIFICATION: // allow pages of multiple statuses to be displayed (requires default status=publish to be ignored) // $where_post_type = $wpdb->prepare("post_type = '%s'", $post_type); $where_status = ''; $is_front = $scoper->is_front(); $is_teaser_active = $scoper->is_front() && scoper_get_otype_option('do_teaser', 'post') && scoper_get_otype_option('use_teaser', 'post', $post_type); $private_teaser = $is_teaser_active && scoper_get_otype_option('use_teaser', 'post', $post_type) && !scoper_get_otype_option('teaser_hide_private', 'post', $post_type); if ($is_front && (!empty($current_rs_user->ID) || $private_teaser)) { $frontend_list_private = scoper_get_otype_option('private_items_listable', 'post', 'page'); } else { $frontend_list_private = false; } // WP core does not include private pages in query. Include private statuses in anticipation of user-specific filtering if ($post_status && ('publish' != $post_status || $is_front && !$frontend_list_private)) { $where_status = $wpdb->prepare("post_status = '%s'", $post_status); } else { // since we will be applying status clauses based on content-specific roles and restrictions, only a sanity check safeguard is needed when post_status is unspecified or defaulted to "publish" $safeguard_statuses = array(); foreach (get_post_stati(array('internal' => false), 'object') as $status_name => $status_obj) { if (!$is_front || $status_obj->private || $status_obj->public) { $safeguard_statuses[] = $status_name; } } $where_status = "post_status IN ('" . implode("','", $safeguard_statuses) . "')"; } $query = "SELECT {$fields} FROM {$wpdb->posts} {$join} WHERE 1=1 AND {$where_post_type} AND ( {$where_status} {$where} {$author_query} ) ORDER BY {$sort_column} {$sort_order}"; if (!empty($number)) { $query .= ' LIMIT ' . $offset . ',' . $number; } if ($is_teaser_active && !defined('SCOPER_TEASER_HIDE_PAGE_LISTING')) { // We are in the front end and the teaser is enabled for pages $query = apply_filters('objects_request_rs', $query, 'post', $post_type, array('force_teaser' => true)); $pages = scoper_get_results($query); // execute unfiltered query // Pass results of unfiltered query through the teaser filter. // If listing private pages is disabled, they will be omitted completely, but restricted published pages // will still be teased. This is a slight design compromise to satisfy potentially conflicting user goals without yet another option $pages = apply_filters('objects_results_rs', $pages, 'post', (array) $post_type, array('request' => $query, 'force_teaser' => true, 'object_type' => $post_type)); // restore buffered titles in case they were filtered previously scoper_restore_property_array($pages, $titles, 'ID', 'post_title'); $pages = apply_filters('objects_teaser_rs', $pages, 'post', $post_type, array('request' => $query, 'force_teaser' => true)); if ($frontend_list_private) { if (!scoper_get_otype_option('teaser_hide_private', 'post', $post_type)) { $tease_all = true; } } } else { $_args = array('skip_teaser' => true); if (in_array($GLOBALS['pagenow'], array('post.php', 'post-new.php'))) { if ($post_type_obj = get_post_type_object($post_type)) { $plural_name = plural_name_from_cap_rs($post_type_obj); $_args['alternate_reqd_caps'][0] = array("create_child_{$plural_name}"); } } // Pass query through the request filter $query = apply_filters('objects_request_rs', $query, 'post', $post_type, $_args); // Execute the filtered query $pages = scoper_get_results($query); // restore buffered titles in case they were filtered previously scoper_restore_property_array($pages, $titles, 'ID', 'post_title'); } if (empty($pages)) { // alternate hook name (WP core already applied get_pages filter) return apply_filters('get_pages_rs', array(), $r); } // // === END Role Scoper MODIFICATION === // ==================================== // Role Scoper note: WP core get_pages has already updated wp_cache and pagecache with unfiltered results. update_page_cache($pages); // === BEGIN Role Scoper MODIFICATION: Support a disjointed pages tree with some parents hidden ======== if ($child_of || empty($tease_all)) { // if we're including all pages with teaser, no need to continue thru tree remapping $ancestors = ScoperAncestry::get_page_ancestors(); // array of all ancestor IDs for keyed page_id, with direct parent first $orderby = $sort_column; if ($parent > 0 || !$hierarchical) { $remap_parents = false; } else { // if these settings were passed into this get_pages call, use them if (-1 === $remap_parents) { $remap_parents = scoper_get_option('remap_page_parents'); } if ($remap_parents) { if (-1 === $enforce_actual_depth) { $enforce_actual_depth = scoper_get_option('enforce_actual_page_depth'); } if (-1 === $remap_thru_excluded_parent) { $remap_thru_excluded_parent = scoper_get_option('remap_thru_excluded_page_parent'); } } } $remap_args = compact('child_of', 'parent', 'exclude', 'depth', 'orderby', 'remap_parents', 'enforce_actual_depth', 'remap_thru_excluded_parent'); // one or more of these args may have been modified after extraction ScoperHardway::remap_tree($pages, $ancestors, 'ID', 'post_parent', $remap_args); } // === END Role Scoper MODIFICATION === // ==================================== if (!empty($exclude_tree)) { $exclude = array(); $exclude = (int) $exclude_tree; $children = get_page_children($exclude, $pages); // RS note: okay to use unfiltered function here since it's only used for excluding $excludes = array(); foreach ($children as $child) { $excludes[] = $child->ID; } $excludes[] = $exclude; $total = count($pages); for ($i = 0; $i < $total; $i++) { if (in_array($pages[$i]->ID, $excludes)) { unset($pages[$i]); } } } if (!empty($append_page) && !empty($pages)) { $found = false; foreach (array_keys($pages) as $key) { if ($post->post_parent == $pages[$key]->ID) { $found = true; break; } } if (empty($found)) { $pages[] = $append_page; } } // re-index the array, just in case anyone cares $pages = array_values($pages); // === BEGIN Role Scoper MODIFICATION: cache key and flag specific to access type and user/groups // if (!$no_cache) { $cache[$ckey] = $pages; $current_rs_user->cache_set($cache, $cache_flag); } // alternate hook name (WP core already applied get_pages filter) $pages = apply_filters('get_pages_rs', $pages, $r); // // === END Role Scoper MODIFICATION === // ==================================== return $pages; }
function establish_status_caps() { global $wp_post_types; $use_post_types = scoper_get_option('use_post_types'); $post_types = array_diff_key(get_post_types(array('public' => true)), array('attachment' => true)); $stati = get_post_stati(array('internal' => false), 'object'); foreach ($post_types as $post_type) { $plural_name = plural_name_from_cap_rs($wp_post_types[$post_type]); // copy existing cap values so we don't overwrite them $type_caps = (array) $wp_post_types[$post_type]->cap; if ('attachment' == $post_type) { $is_attachment_type = true; $post_type = 'post'; } else { $is_attachment_type = false; if (empty($use_post_types[$post_type])) { continue; } } // force edit_published, edit_private, delete_published, delete_private cap definitions foreach ($stati as $status => $status_obj) { if (empty($status_obj->moderation) && !$status_obj->public && !$status_obj->private) { // don't mess with draft or future continue; } foreach (array('read', 'edit', 'delete') as $op) { if ('read' == $op && ($status_obj->public || !empty($status_obj->moderation))) { continue; } $status_string = 'publish' == $status ? 'published' : $status; $posts_cap_name = "{$op}_{$status_string}_posts"; // only alter the cap setting if it's not already set if (empty($type_caps[$posts_cap_name])) { if (!empty($status_obj->customize_caps)) { // TODO: RS Options to set this // this status is built in or was marked for full enforcement of custom capabilities $type_caps[$posts_cap_name] = "{$op}_{$status_string}_{$plural_name}"; } else { // default to this post type's own equivalent private or published cap if ($status_obj->private) { $type_caps[$posts_cap_name] = "{$op}_private_{$plural_name}"; } elseif ($status_obj->public) { $type_caps[$posts_cap_name] = "{$op}_published_{$plural_name}"; } } } } // end foreach op (read/edit/delete) // also define a "set_status" cap for custom statuses (to accompany "publish_posts" cap requirement when setting or removing this post status) if (!in_array($status, array('publish', 'private'))) { $posts_cap_name = "set_{$status}_posts"; if (empty($type_caps[$posts_cap_name])) { if (!empty($status_obj->customize_caps)) { // TODO: RS Options to set this // this status was marked for full enforcement of custom capabilities $type_caps[$posts_cap_name] = "set_{$status}_{$plural_name}"; } elseif ($status_obj->public || $status_obj->private) { $type_caps[$posts_cap_name] = "publish_{$plural_name}"; } } } } // end foreach front end status if (empty($type_caps['delete_posts'])) { $type_caps['delete_posts'] = "delete_{$plural_name}"; } if (empty($type_caps['delete_others_posts'])) { $type_caps['delete_others_posts'] = "delete_others_{$plural_name}"; } if ($is_attachment_type) { $post_type = 'attachment'; } $wp_post_types[$post_type]->cap = (object) $type_caps; } // end foreach post type }
function cr_post_role_caps() { $arr = array(); $post_types = array_diff_key(get_post_types(array('public' => true), 'object'), array('attachment' => true)); $use_post_types = scoper_get_option('use_post_types'); foreach ($post_types as $name => $post_type_obj) { if (empty($use_post_types[$name])) { continue; } $cap = $post_type_obj->cap; $arr["rs_{$name}_reader"] = array("read" => true); $arr["rs_private_{$name}_reader"] = array($cap->read_private_posts => true, "read" => true); $arr["rs_{$name}_contributor"] = array($cap->edit_posts => true, $cap->delete_posts => true, "read" => true); if (defined('RVY_VERSION')) { $arr["rs_{$name}_revisor"] = array($cap->edit_posts => true, $cap->delete_posts => true, "read" => true, $cap->read_private_posts => true, $cap->edit_others_posts => true); } $arr["rs_{$name}_author"] = array("upload_files" => true, $cap->publish_posts => true, $cap->edit_published_posts => true, $cap->delete_published_posts => true, $cap->edit_posts => true, $cap->delete_posts => true, "read" => true); $arr["rs_{$name}_editor"] = array("moderate_comments" => true, $cap->delete_others_posts => true, $cap->edit_others_posts => true, "upload_files" => true, "unfiltered_html" => true, $cap->publish_posts => true, $cap->delete_private_posts => true, $cap->edit_private_posts => true, $cap->delete_published_posts => true, $cap->edit_published_posts => true, $cap->delete_posts => true, $cap->edit_posts => true, $cap->read_private_posts => true, "read" => true); // Note: create_child_pages should only be present in associate role, which is used as an object-assigned alternate to blog-wide edit role // This way, blog-assignment of author role allows user to create new pages, but only as subpages of pages they can edit (or for which Associate role is object-assigned) if ($post_type_obj->hierarchical) { $plural_name = plural_name_from_cap_rs($post_type_obj); $arr["rs_{$name}_associate"] = array("create_child_{$plural_name}" => true, 'read' => true); } } return $arr; }
function _cr_get_reqd_caps($src_name, $op, $object_type = '-1', $status = '-1', $base_caps_only = false, $preview_future = false) { if ('admin' == $op) { $op = 'delete'; } if ($object_type == -1 && $status == -1 && !$base_caps_only && !$preview_future) { // only set / retrieve the static buffer for default Query_Interceptor usage static $reqd_caps; if (!isset($reqd_caps)) { $reqd_caps = array(); } } else { $reqd_caps = array(); } if (!isset($reqd_caps[$src_name][$op])) { $arr = array(); switch ($src_name) { case 'post': $property = "{$op}_posts"; $others_property = "{$op}_others_posts"; if (-1 != $object_type && post_type_exists($object_type)) { $post_types = array($object_type => get_post_type_object($object_type)); } else { $post_types = array_diff_key(get_post_types(array('public' => true), 'object'), array('attachment' => true)); $use_post_types = scoper_get_option('use_post_types'); } if (-1 != $status && isset($GLOBALS['wp_post_statuses'][$status])) { $post_statuses = array($status => get_post_status_object($status)); } else { $post_statuses = get_post_stati(array('internal' => null), 'object'); $post_statuses[] = get_post_status_object('trash'); } foreach ($post_types as $_post_type => $post_type_obj) { if (-1 == $object_type && empty($use_post_types[$_post_type])) { continue; } $plural_name = plural_name_from_cap_rs($post_type_obj); $cap = $post_type_obj->cap; if ('read' != $op) { // for "delete" op, select a value from stored cap property in this order of preference, if the proerpty is defined: delete_others_posts, delete_posts, edit_others_posts, edit_posts if (!empty($cap->{$others_property}) && !$base_caps_only) { $main_cap = $cap->{$others_property}; } elseif (!empty($cap->{$property})) { $main_cap = $cap->{$property}; } elseif (!empty($cap->edit_others_posts) && !$base_caps_only) { $main_cap = $cap->edit_others_posts; } else { $main_cap = $cap->edit_posts; } } $use_statuses = !empty($post_type_obj->statuses) ? $post_type_obj->statuses : $post_statuses; $use_statuses = array_intersect_key($use_statuses, $post_statuses); foreach ($use_statuses as $status_obj) { $_status = $status_obj->name; if ('read' == $op) { if ('trash' == $_status) { continue; } if ('future' == $_status && !$preview_future) { continue; } if (!$status_obj->protected && !$status_obj->internal) { // read $arr['read'][$_post_type][$_status] = array('read'); if (!$base_caps_only) { // read_private_posts if ($status_obj->private) { $arr['read'][$_post_type][$_status][] = $cap->read_private_posts; } // read_{$_status}_posts (if defined) if ('publish' != $_status) { $status_cap = "read_{$_status}_{$plural_name}"; if (!empty($cap->{$status_cap})) { $arr['read'][$_post_type][$_status][] = $status_cap; } } $arr['read'][$_post_type][$_status] = array_unique($arr['read'][$_post_type][$_status]); } } elseif (('future' == $_status || !empty($_GET['preview'])) && 'trash' != $_status) { // preview supports non-published statuses, but requires edit capability // array ( 'draft' => array($cap->edit_others_posts), 'pending' => array('edit_others_posts'), 'future' => array('edit_others_posts'), 'publish' => array('read'), 'private' => array('read', 'read_private_posts') ); if ($base_caps_only) { $arr['read'][$_post_type][$_status] = array($cap->edit_posts); } else { $arr['read'][$_post_type][$_status] = array($cap->edit_others_posts); } $status_cap = "read_published_{$plural_name}"; if (!empty($cap->{$status_cap})) { $arr['read'][$_post_type][$_status][] = $status_cap; } } } else { // op == delete / edit / other // edit_posts / edit_others_posts $arr[$op][$_post_type][$_status][] = $main_cap; // edit_published_posts if ($status_obj->public || $status_obj->private || 'future' == $_status) { $property = "{$op}_published_posts"; $arr[$op][$_post_type][$_status][] = $cap->{$property}; } if (!$base_caps_only) { // edit private posts if ($status_obj->private) { $property = "{$op}_private_posts"; $arr[$op][$_post_type][$_status][] = $cap->{$property}; } // edit_{$_status}_posts (if defined) $status_string = 'publish' == $_status ? 'published' : $_status; $status_cap = "{$op}_{$status_string}_posts"; if (!empty($cap->{$status_cap})) { $arr[$op][$_post_type][$_status][] = $cap->{$status_cap}; } } $arr[$op][$_post_type][$_status] = array_unique($arr[$op][$_post_type][$_status]); } } // end foreach status } // end foreach post type // TODO: re-implement OP_ADMIN distinction with dedicated admin caps //$arr['admin'] = $arr['edit']; break; case 'link': $arr['read']['link'][''] = array('read'); $arr['edit']['link'][''] = array('manage_links'); // object types with a single status store nullstring status key //$arr['admin']['link'][''] = array( 'manage_links' ); break; case 'group': $arr['edit']['group'][''] = array('manage_groups'); //$arr['admin']['group'][''] = array( 'manage_groups' ); break; default: global $scoper; if ($src = $scoper->data_sources->get($src_name)) { if (isset($src->reqd_caps)) { // legacy API support $arr = $src->reqd_caps; } } } // end src_name switch if (empty($arr[$op])) { $arr[$op] = array(); } $reqd_caps[$src_name][$op] = apply_filters('define_required_caps_rs', $arr[$op], $src_name, $op); } // endif pulling from static buffer if (-1 != $status && -1 != $object_type) { if (isset($reqd_caps[$src_name][$op][$object_type][$status])) { return $reqd_caps[$src_name][$op][$object_type][$status]; } else { return array(); } } elseif (-1 != $object_type) { if (isset($reqd_caps[$src_name][$op][$object_type])) { return $reqd_caps[$src_name][$op][$object_type]; } else { return array(); } } else { if (isset($reqd_caps[$src_name][$op])) { return $reqd_caps[$src_name][$op]; } else { return array(); } } }
function scoper_flt_page_parent($parent_id) { if ('no_parent_filter' == scoper_get_option('lock_top_pages')) { return (int) $parent_id; } if (!empty($_REQUEST['post_ID'])) { $post_id = $_REQUEST['post_ID']; } elseif (!empty($_REQUEST['post_id'])) { $post_id = $_REQUEST['post_id']; } else { return (int) $parent_id; } if (!empty($post_id)) { if ($parent_id == $post_id) { // normal revision save return (int) $parent_id; } } if (defined('RVY_VERSION')) { global $revisionary; if (!empty($revisionary->admin->revision_save_in_progress)) { return (int) $parent_id; } } if (empty($_POST['post_type'])) { return (int) $parent_id; } // Make sure the selected parent is valid. Merely an anti-hacking precaution to deal with manually fudged POST data global $scoper, $wpdb; $post_type = sanitize_key($_POST['post_type']); $plural_name = plural_name_from_cap_rs(get_post_type_object($post_type)); $args = array(); $args['alternate_reqd_caps'][0] = array("create_child_{$plural_name}"); if ($descendant_ids = scoper_get_page_descendant_ids($post_id)) { $exclusion_clause = "AND ID NOT IN('" . implode("','", $descendant_ids) . "')"; } else { $exclusion_clause = ''; } $qry_parents = "SELECT ID FROM {$wpdb->posts} WHERE post_type = '{$post_type}' AND post_status != 'auto-draft' {$exclusion_clause}"; $qry_parents = apply_filters('objects_request_rs', $qry_parents, 'post', $post_type, $args); $valid_parents = scoper_get_col($qry_parents); $post = get_post($post_id); if ($parent_id) { if ($post && !in_array($parent_id, $valid_parents)) { $parent_id = $post->post_parent; } } else { if (!$GLOBALS['scoper_admin_filters']->user_can_associate_main($post_type)) { $already_published = false; if ($post) { if ($saved_status_object = get_post_status_object($post->post_status)) { $already_published = $saved_status_object->public || $saved_status_object->private; } } if ($already_published) { // If post was previously published to another parent, revert it $parent_id = $post->post_parent; } elseif ($valid_parents) { // otherwise default to a valid parent sort($valid_parents); $parent_id = reset($valid_parents); $_POST['parent_id'] = (int) $parent_id; // for subsequent post_status filter } } } return (int) $parent_id; }