function get_page_ancestors() { $ancestors = get_option("scoper_page_ancestors"); if (is_array($ancestors)) { return $ancestors; } $ancestors = array(); global $wpdb; if (awp_ver('3.0')) { $post_types = get_post_types(array('hierarchical' => true, 'public' => true)); $where = "WHERE post_type IN ('" . implode("','", $post_types) . "') AND post_status != 'auto-draft'"; } else { $where = "WHERE post_type != 'revision' AND post_type != 'post' AND post_status != 'auto-draft'"; } if ($pages = scoper_get_results("SELECT ID, post_parent FROM {$wpdb->posts} {$where}")) { $parents = array(); foreach ($pages as $page) { if ($page->post_parent) { $parents[$page->ID] = $page->post_parent; } } foreach ($pages as $page) { $ancestors[$page->ID] = ScoperAncestry::_walk_ancestors($page->ID, array(), $parents); if (empty($ancestors[$page->ID])) { unset($ancestors[$page->ID]); } } update_option("scoper_page_ancestors", $ancestors); } return $ancestors; }
function rs_get_post_revisions($post_id, $status = 'inherit', $args = array()) { global $wpdb; $defaults = array('order' => 'DESC', 'orderby' => 'post_modified_gmt', 'use_memcache' => true, 'fields' => COLS_ALL_RS, 'return_flipped' => false, 'where' => ''); $args = wp_parse_args($args, $defaults); extract($args); if (COL_ID_RS == $fields) { // performance opt for repeated calls by user_has_cap filter if ($use_memcache) { static $last_results; if (!isset($last_results)) { $last_results = array(); } elseif (isset($last_results[$post_id][$status])) { return $last_results[$post_id][$status]; } } $revisions = scoper_get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type = 'revision' AND post_parent = '{$post_id}' AND post_status = '{$status}' {$where}"); if ($return_flipped) { $revisions = array_fill_keys($revisions, true); } if ($use_memcache) { if (!isset($last_results[$post_id])) { $last_results[$post_id] = array(); } $last_results[$post_id][$status] = $revisions; } } else { $order_clause = $order && $orderby ? "ORDER BY {$orderby} {$order}" : ''; $revisions = scoper_get_results("SELECT * FROM {$wpdb->posts} WHERE post_type = 'revision' AND post_parent = '{$post_id}' AND post_status = '{$status}' {$order_clause}"); } return $revisions; }
function get_user_level($user_ids) { static $user_levels; $return_array = is_array($user_ids); // if an array was passed in, return results as an array if (!is_array($user_ids)) { if (IS_MU_RS && function_exists('is_super_admin') && is_super_admin()) { // mu site administrator may not be a user for the current blog return 10; } $orig_user_id = $user_ids; $user_ids = (array) $user_ids; } if (!isset($user_levels)) { $user_levels = array(); } if (array_diff($user_ids, array_keys($user_levels))) { // one or more of the users were not already logged $role_levels = ScoperUserEdit::get_role_levels(); // local buffer for performance // If the listed user ids were logged following a search operation, save extra DB queries by getting the levels of all those users now global $wp_user_search; if (!empty($wp_user_search->results)) { $query_users = $wp_user_search->results; $query_users = array_unique(array_merge($query_users, $user_ids)); } else { $query_users = $user_ids; } // get the WP roles for user global $wpdb; $results = scoper_get_results("SELECT user_id, role_name FROM {$wpdb->user2role2object_rs} WHERE scope = 'blog' AND role_type = 'wp' AND user_id IN ('" . implode("','", array_map('intval', $query_users)) . "')"); //echo("SELECT user_id, role_name FROM $wpdb->user2role2object_rs WHERE scope = 'blog' AND role_type = 'wp' AND user_id IN ('" . implode( "','", $query_users ) . "')"); // credit each user for the highest role level they have foreach ($results as $row) { if (!isset($role_levels[$row->role_name])) { continue; } if (!isset($user_levels[$row->user_id]) || $role_levels[$row->role_name] > $user_levels[$row->user_id]) { $user_levels[$row->user_id] = $role_levels[$row->role_name]; } } // note any "No Role" users if ($no_role_users = array_diff($query_users, array_keys($user_levels))) { $user_levels = $user_levels + array_fill_keys($no_role_users, 0); } } if ($return_array) { $return = array_intersect_key($user_levels, array_fill_keys($user_ids, true)); } else { $return = isset($user_levels[$orig_user_id]) ? $user_levels[$orig_user_id] : 0; } return $return; }
function scoper_apply_custom_default_options($options_var) { global $wpdb, $scoper_options_sitewide; if ($results = scoper_get_results("SELECT meta_key, meta_value FROM {$wpdb->sitemeta} WHERE site_id = '{$wpdb->siteid}' AND meta_key LIKE 'scoper_default_%'")) { foreach ($results as $row) { $option_basename = str_replace('scoper_default_', '', $row->meta_key); if (!empty($scoper_options_sitewide[$option_basename])) { continue; } // custom defaults are only for blog-specific options if (isset($GLOBALS[$options_var][$option_basename])) { $GLOBALS[$options_var][$option_basename] = maybe_unserialize($row->meta_value); } } } }
function scoper_fix_page_parent_recursion() { global $wpdb; $arr_parent = array(); $arr_children = array(); if ($results = scoper_get_results("SELECT ID, post_parent FROM {$wpdb->posts} WHERE post_type = 'page'")) { foreach ($results as $row) { $arr_parent[$row->ID] = $row->post_parent; if (!isset($arr_children[$row->post_parent])) { $arr_children[$row->post_parent] = array(); } $arr_children[$row->post_parent][] = $row->ID; } // if a page's parent is also one of its children, set parent to Main foreach ($arr_parent as $page_id => $parent_id) { if (isset($arr_children[$page_id]) && in_array($parent_id, $arr_children[$page_id])) { scoper_query($wpdb->prepare("UPDATE {$wpdb->posts} SET post_parent = '0' WHERE ID = %d", $page_id)); } } } }
function get_assigned_roles($scope, $role_basis, $src_or_tx_name, $args = array()) { global $wpdb; $defaults = array('id' => false, 'ug_id' => 0, 'join' => '', 'role_handles' => ''); $args = array_merge($defaults, (array) $args); extract($args); $id = is_string($id) ? (int) $id : $id; $ug_id = is_string($ug_id) ? (int) $ug_id : $ug_id; if (BLOG_SCOPE_RS == $scope) { return ScoperRoleAssignments::get_assigned_blog_roles($role_basis); } $roles = array(); switch ($role_basis) { case ROLE_BASIS_USER: $col_ug_id = 'user_id'; $ug_clause = $ug_id ? " AND user_id = '{$ug_id}'" : 'AND user_id > 0'; break; case ROLE_BASIS_GROUPS: $col_ug_id = 'group_id'; $ug_clause = $ug_id ? " AND group_id = '{$ug_id}'" : 'AND group_id > 0'; break; } $id_clause = false === $id ? '' : "AND obj_or_term_id = '{$id}'"; if ($role_handles) { if (!is_array($role_handles)) { $role_handles = (array) $role_handles; } $role_clause = $role_handles ? "AND role_name IN ('" . implode("', '", scoper_role_handles_to_names($role_handles)) . "')" : ''; } else { $role_clause = ''; } $qry = "SELECT {$col_ug_id}, obj_or_term_id, role_name, assign_for, assignment_id, inherited_from, date_limited, start_date_gmt, end_date_gmt, content_date_limited, content_min_date_gmt, content_max_date_gmt FROM {$wpdb->user2role2object_rs} AS uro " . "{$join} WHERE role_type = 'rs' {$role_clause} AND scope = %s AND src_or_tx_name = %s {$id_clause} {$ug_clause}"; $results = scoper_get_results($wpdb->prepare($qry, $scope, $src_or_tx_name)); foreach ($results as $role) { $role_handle = 'rs_' . $role->role_name; $roles[$role->obj_or_term_id][$role_handle][$role->{$col_ug_id}] = (array) $role; } return $roles; }
function groups_who_can($reqd_caps, $cols = COLS_ALL_RS, $object_src_name = '', $object_id = 0, $args = array()) { global $wpdb; $defaults = array('orderby' => '', 'disable_memcache' => false, 'force_refresh' => false); $args = array_merge($defaults, (array) $args); extract($args); $cache_flag = "rs_groups_who_can"; $cache_id = md5(serialize($reqd_caps) . $cols . 'src' . $object_src_name . 'id' . $object_id . serialize($args)); if (!$force_refresh) { $groups = wpp_cache_get($cache_id, $cache_flag); if (is_array($groups)) { return $groups; } } if (!is_array($reqd_caps)) { $reqd_caps = $reqd_caps ? array($reqd_caps) : array(); } if (!$orderby && (COLS_ALL_RS == $cols || COLS_ID_DISPLAYNAME_RS == $cols)) { $orderby = " ORDER BY display_name"; } if (!is_array($args)) { $args = array(); } if (isset($args['ignore_group_roles'])) { unset($args['ignore_group_roles']); } $args['ignore_user_roles'] = 1; $args['querying_groups'] = 1; $where = $this->flt_users_where('', $reqd_caps, $object_src_name, $object_id, $args); if (COL_ID_RS == $cols) { $qry = "SELECT DISTINCT group_id as ID FROM {$wpdb->user2role2object_rs} AS gro WHERE 1=1 {$where} AND gro.group_id > 0 {$orderby}"; $groups = scoper_get_col($qry); } else { $grp = $wpdb->groups_rs; $qry = "SELECT DISTINCT {$grp}.{$wpdb->groups_id_col} AS ID, {$grp}.{$wpdb->groups_name_col} AS display_name, {$grp}.{$wpdb->groups_descript_col} as descript FROM {$grp}" . " INNER JOIN {$wpdb->user2group_rs} as u2g ON u2g.{$wpdb->user2group_gid_col} = {$grp}.{$wpdb->groups_id_col}" . " INNER JOIN {$wpdb->user2role2object_rs} AS gro ON {$grp}.{$wpdb->groups_id_col} = gro.group_id WHERE 1=1 {$where} {$orderby}"; $groups = scoper_get_results($qry); } wpp_cache_set($cache_id, $groups, $cache_flag); return $groups; }
function scoper_attach_linked_uploads($echo = false) { global $wpdb; require_once SCOPER_ABSPATH . '/uploads_rs.php'; if (MULTISITE) { global $wpdb, $blog_id; $blog_ids = scoper_get_col("SELECT blog_id FROM {$wpdb->blogs} ORDER BY blog_id"); $orig_blog_id = $blog_id; } else { $blog_ids = array('1'); } foreach ($blog_ids as $id) { if (count($blog_ids) > 1) { switch_to_blog($id); _e("<br /><strong>site {$id} :</strong><br />"); } $uploads = scoper_get_upload_info(); $site_url = untrailingslashit(get_option('siteurl')); if (false === strpos($uploads['baseurl'], $site_url)) { if ($echo) { _e('<strong>Note</strong>: Direct access to uploaded file attachments cannot be filtered because your WP_CONTENT_DIR is not in the WordPress branch.', 'scoper'); echo '<br /><br />'; _e('The operation was terminated due to an invalid configuration.', 'scoper'); } return false; } $post_types = array_diff(get_post_types(array('public' => true)), array('attachment')); $post_type_in = "'" . implode("','", $post_types) . "'"; if ($post_ids = scoper_get_col("SELECT ID FROM {$wpdb->posts} WHERE post_type IN ({$post_type_in}) ORDER BY post_type, post_title")) { $stored_attachments = array(); if ($results = scoper_get_results("SELECT post_parent, guid FROM {$wpdb->posts} WHERE post_type = 'attachment'")) { foreach ($results as $row) { if (!isset($stored_attachments[$row->post_parent])) { $stored_attachments[$row->post_parent] = array(); } $stored_attachments[$row->post_parent][$row->guid] = true; } } // for reasonable memory usage, only hold 10 posts in memory at a time $found_links = 0; $num_inserted = 0; $num_posts = count($post_ids); $bite_size = 10; $num_bites = $num_posts / $bite_size; if ($num_posts % $bite_size) { $num_bites++; } $upload_path = $uploads['baseurl']; $upload_dir = $uploads['basedir']; if ($echo) { printf(__("<strong>checking %s posts / pages...</strong>", 'scoper'), $num_posts); echo '<br /><br />'; } for ($i = 0; $i < $num_bites; $i++) { $id_in = "'" . implode("','", array_slice($post_ids, $i * $bite_size, $bite_size)) . "'"; if (!($results = scoper_get_results("SELECT ID, post_content, post_author, post_title, post_type FROM {$wpdb->posts} WHERE ID IN ({$id_in})"))) { continue; } foreach ($results as $row) { $linked_uploads = array(); // preg_match technique learned from http://stackoverflow.com/questions/138313/how-to-extract-img-src-title-and-alt-from-html-using-php $tags = array('img' => array(), 'a' => array()); $content = $row->post_content; preg_match_all('/<img[^>]+>/i', $row->post_content, $tags['img']); preg_match_all('/<a[^>]+>/i', $row->post_content, $tags['a']); // don't care that this will terminate with any enclosed tags (i.e. img) foreach (array_keys($tags) as $tag_type) { foreach ($tags[$tag_type]['0'] as $found_tag) { $found_attribs = array('src' => '', 'href' => '', 'title' => '', 'alt' => ''); if (!preg_match_all('/(alt|title|src|href)=("[^"]*")/i', $found_tag, $tag_attributes)) { continue; } foreach ($tag_attributes[1] as $key => $attrib_name) { $found_attribs[$attrib_name] = trim($tag_attributes[2][$key], "'" . '"'); } if (!$found_attribs['href'] && !$found_attribs['src']) { continue; } $file_url = $found_attribs['src'] ? $found_attribs['src'] : $found_attribs['href']; if (!strpos($file_url, '.')) { continue; } if (MULTISITE && strpos($uploads['url'], 'blogs.dir')) { $file_url = str_replace('/files/', "/wp-content/blogs.dir/{$blog_id}/files/", $file_url); } // links can't be registered as attachments unless they're in the WP uploads path if (false === strpos($file_url, $upload_path)) { if ($echo) { //printf( _ x( '<span class="rs-brown">skipping unfilterable file in %1$s "%2$s":</span> %3$s', 'post_type, post_title, file_url', 'scoper' ), __(ucwords($row->post_type)), $row->post_title, $file_url); printf(__('<span class="rs-brown">skipping unfilterable file in %1$s "%2$s":</span> %3$s', 'scoper'), __(ucwords($row->post_type)), $row->post_title, $file_url); echo '<br /><br />'; } continue; } // make sure the linked file actually exists if (!file_exists(str_replace($upload_path, $upload_dir, $file_url))) { if ($echo) { //printf( _ x( '<span class="rs-brown">skipping unfilterable file in %1$s "%2$s":</span> %3$s', 'post_type, post_title, file_url', 'scoper' ), __(ucwords($row->post_type)), $row->post_title, $file_url); printf(__('<span class="rs-red">skipping missing file in %1$s "%2$s":</span> %3$s', 'scoper'), __(ucwords($row->post_type)), $row->post_title, $file_url); echo '<br /><br />'; } continue; } $caption = $found_attribs['title'] ? $found_attribs['title'] : $found_attribs['alt']; // we might find the same file sourced in both link and img tags if (!isset($linked_uploads[$file_url]) || !$linked_uploads[$file_url]) { $found_links++; $linked_uploads[$file_url] = $caption; } } // end foreach found tag } // end foreach loop on 'img' and 'a' foreach ($linked_uploads as $file_url => $caption) { $unsuffixed_file_url = preg_replace("/-[0-9]{2,4}x[0-9]{2,4}./", '.', $file_url); $file_info = wp_check_filetype($unsuffixed_file_url); if (!isset($stored_attachments[$row->ID][$unsuffixed_file_url])) { $att = array(); $att['guid'] = $unsuffixed_file_url; $info = pathinfo($unsuffixed_file_url); if (isset($info['filename'])) { $att['post_name'] = $info['filename']; $att['post_title'] = $info['filename']; } $att['post_excerpt'] = $caption; $att['post_author'] = $row->post_author; $att['post_parent'] = $row->ID; $att['post_category'] = wp_get_post_categories($row->ID); if (isset($file_info['type'])) { $att['post_mime_type'] = $file_info['type']; } $num_inserted++; if ($echo) { printf(__('<span class="rs-green"><strong>new attachment</strong> in %1$s "%2$s":</span> %3$s', 'scoper'), __(ucwords($row->post_type)), $row->post_title, $file_url); } //printf(_ x( '<span class="rs-green"><strong>new attachment</strong> in %1$s "%2$s":</span> %3$s', 'post_type, post_title, file_url', 'scoper' ), __(ucwords($row->post_type)), $row->post_title, $file_url); wp_insert_attachment($att); } else { if ($echo) { printf(__('<span class="rs-blue">attachment OK in %1$s "%2$s":</span> %3$s', 'scoper'), __(ucwords($row->post_type)), $row->post_title, $file_url); } //printf(_ x( '<span class="rs-blue">attachment OK in %1$s "%2$s":</span> %3$s', 'post_type, post_title, file_url', 'scoper' ), __(ucwords($row->post_type)), $row->post_title, $file_url); } if ($echo) { echo '<br /><br />'; } } // end foreach linked_uploads } // end foreach post in this bite } // endif for each 10-post bite if ($echo) { echo '<strong>'; printf(__("Operation complete: %s linked uploads were found in your post / page content.", 'scoper'), $found_links); echo '<br /><br />'; if ($num_inserted) { printf(__('<strong>%s attachment records were added to the database.</strong>', 'scoper'), $num_inserted); echo '<br /><br />'; } elseif ($found_links) { _e('All linked uploads are already registered as attachments.', 'scoper'); echo '<br /><br />'; } } } if (count($blog_ids) > 1) { echo '<hr />'; } } // end foreach site if (count($blog_ids) > 1) { switch_to_blog($orig_blog_id); } return true; }
function flt_get_others_drafts($results) { global $wpdb, $current_user, $scoper; // buffer titles in case they were filtered previously $titles = scoper_get_property_array($results, 'ID', 'post_title'); // WP 2.3 added pending status, but no new hook or hook argument $draft_query = strpos($wpdb->last_query, 'draft'); $pending_query = strpos($wpdb->last_query, 'pending'); if ($draft_query && $pending_query) { $status_clause = "AND ( post_status = 'draft' OR post_status = 'pending' )"; } elseif ($draft_query) { $status_clause = "AND post_status = 'draft'"; } else { $status_clause = "AND post_status = 'pending'"; } $object_type = cr_find_post_type(); if (!$object_type) { $object_type = 'post'; } if (!($otype_val = $scoper->data_sources->member_property('post', 'object_types', $object_type, 'val'))) { $otype_val = $object_type; } $qry = "SELECT ID, post_title, post_author FROM {$wpdb->posts} WHERE post_type = '{$otype_val}' AND post_author != '{$current_user->ID}' {$status_clause}"; $qry = apply_filters('objects_request_rs', $qry, 'post', '', ''); $items = scoper_get_results($qry); // restore buffered titles in case they were filtered previously scoper_restore_property_array($items, $titles, 'ID', 'post_title'); return $items; }
function scoper_retrieve_options($sitewide = false) { global $wpdb; if ($sitewide) { global $scoper_site_options; $scoper_site_options = array(); if ($results = scoper_get_results("SELECT meta_key, meta_value FROM {$wpdb->sitemeta} WHERE site_id = '{$wpdb->siteid}' AND meta_key LIKE 'scoper_%'")) { foreach ($results as $row) { $scoper_site_options[$row->meta_key] = $row->meta_value; } } $scoper_site_options = apply_filters('site_options_rs', $scoper_site_options); return $scoper_site_options; } else { global $scoper_blog_options; $scoper_blog_options = array(); if ($results = scoper_get_results("SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE 'scoper_%'")) { foreach ($results as $row) { $scoper_blog_options[$row->option_name] = $row->option_value; } } $scoper_blog_options = apply_filters('options_rs', $scoper_blog_options); return $scoper_blog_options; } }
function scoper_get_parent_roles($obj_or_term_id, $scope, $src_or_tx_name, $parent_id, $object_type = '') { global $wpdb, $scoper; $role_clause = ''; if (!$parent_id && OBJECT_SCOPE_RS == $scope) { // for default roles, need to distinguish between otype-specific roles // (note: this only works w/ RS role type. Default object roles are disabled for WP role type because we'd be stuck assigning all default roles to both post & page.) $src = $scoper->data_sources->get($src_or_tx_name); if (!empty($src->cols->type)) { if (!$object_type) { $object_type = cr_find_object_type($src_name, $object_id); } if ($object_type) { $role_defs = $scoper->role_defs->get_matching('rs', $src_or_tx_name, $object_type); if ($role_names = scoper_role_handles_to_names(array_keys($role_defs))) { $role_clause = "AND role_type = 'rs' AND role_name IN ('" . implode("', '", $role_names) . "')"; } } } } // Since this is a new object, propagate roles from parent (if any are marked for propagation) $qry = "SELECT * FROM {$wpdb->user2role2object_rs} WHERE scope = %s AND assign_for IN ('children', 'both') {$role_clause} AND src_or_tx_name = %s AND obj_or_term_id = %d ORDER BY role_type, role_name"; $results = scoper_get_results($wpdb->prepare($qry, $scope, $src_or_tx_name, $parent_id)); return $results; }
function restrict_roles($scope, $src_or_tx_name, $item_id, $roles, $args = array()) { $defaults = array('implicit_removal' => false, 'is_auto_insertion' => false, 'force_flush' => false); $args = array_merge($defaults, (array) $args); extract($args); global $wpdb; $is_administrator = is_administrator_rs($src_or_tx_name, 'user'); $delete_reqs = array(); $role_change = false; $default_strict_modes = array(false); $strict_role_in = ''; // for object restriction, handle auto-setting of equivalent object roles ( 'post reader' for 'private post reader', 'post author' for 'post editor' ). There is no logical distinction between these roles where a single object is concerned. if (OBJECT_SCOPE_RS == $scope) { foreach (array_keys($roles) as $role_handle) { $equiv_role_handles = array(); if ($objscope_equivalents = $this->scoper->role_defs->member_property($role_handle, 'objscope_equivalents')) { foreach ($objscope_equivalents as $equiv_role_handle) { if (!isset($roles[$equiv_role_handle])) { // if the equiv role was set manually, leave it alone. This would not be normal RS behavior $roles[$equiv_role_handle] = $roles[$role_handle]; } } } } } if ($item_id) { $default_restrictions = $this->scoper->get_default_restrictions($scope); $default_strict_roles = !empty($default_restrictions[$src_or_tx_name]) ? array_keys($default_restrictions[$src_or_tx_name]) : array(); if ($default_strict_roles) { $strict_role_in = "'" . implode("', '", scoper_role_handles_to_names($default_strict_roles)) . "'"; $default_strict_modes[] = true; } } foreach ($default_strict_modes as $default_strict) { $stored_reqs = array(); $req_ids = array(); if ($default_strict && $strict_role_in) { $role_clause = "AND role_name IN ({$strict_role_in})"; } elseif ($strict_role_in) { $role_clause = "AND role_name NOT IN ({$strict_role_in})"; } else { $role_clause = ''; } // IMPORTANT: max_scope value determines whether we are inserting / updating RESTRICTIONS or UNRESTRICTIONS if (TERM_SCOPE_RS == $scope) { $query_max_scope = $default_strict ? 'blog' : 'term'; } else { $query_max_scope = $default_strict ? 'blog' : 'object'; } // Storage of 'blog' max_scope as object restriction does not eliminate any term restrictions. It merely indicates, for data sources that are default strict, that this object does not restrict roles $qry = "SELECT requirement_id AS assignment_id, require_for AS assign_for, inherited_from, role_name FROM {$wpdb->role_scope_rs} WHERE topic = %s AND max_scope = %s" . " AND src_or_tx_name = %s AND obj_or_term_id = %d AND role_type = 'rs' {$role_clause}"; if ($results = scoper_get_results($wpdb->prepare($qry, $scope, $query_max_scope, $src_or_tx_name, $item_id))) { foreach ($results as $key => $req) { $role_handle = 'rs_' . $req->role_name; if (OBJECT_SCOPE_RS == $scope && isset($is_objscope_equiv[$role_handle])) { $role_handle = $is_objscope_equiv[$role_handle]; } $stored_reqs[$role_handle] = array('assignment_id' => $req->assignment_id, 'assign_for' => $req->assign_for, 'inherited_from' => $req->inherited_from); $req_ids[$role_handle][$req->assignment_id] = array(); } } if (!$is_administrator) { $user_has_role = $this->_validate_assigner_roles($scope, $src_or_tx_name, $item_id, $roles); } if ($implicit_removal) { // Stored restrictions which are not mirrored in $roles will be deleted (along with their prodigy) foreach (array_keys($stored_reqs) as $role_handle) { $max_scope = isset($roles[$role_handle]['max_scope']) ? $roles[$role_handle]['max_scope'] : false; if ($max_scope != $query_max_scope) { $delete_reqs = $delete_reqs + $req_ids[$role_handle]; } } } foreach ($roles as $role_handle => $setting) { if (!$is_administrator && empty($user_has_role[$role_handle])) { continue; } if ($default_strict && !in_array($role_handle, $default_strict_roles)) { continue; } if (!$default_strict && !empty($default_strict_roles) && in_array($role_handle, $default_strict_roles)) { continue; } $max_scope = $setting['max_scope']; if ($max_scope != $query_max_scope) { $require_for = REMOVE_ASSIGNMENT_RS; } elseif ($setting['for_item']) { $require_for = $setting['for_children'] ? ASSIGN_FOR_BOTH_RS : ASSIGN_FOR_ENTITY_RS; } else { $require_for = $setting['for_children'] ? ASSIGN_FOR_CHILDREN_RS : REMOVE_ASSIGNMENT_RS; } $update_require_for = array(ASSIGN_FOR_ENTITY_RS => array(), ASSIGN_FOR_CHILDREN_RS => array(), ASSIGN_FOR_BOTH_RS => array()); $stored_req = isset($stored_reqs[$role_handle]) ? $stored_reqs[$role_handle] : array(); $unused_byref_arg = ''; $comparison = $this->_compare_role_settings($require_for, $stored_req, $delete_reqs, $update_require_for, $unused_byref_arg, $unused_byref_arg); $insert_restriction = $comparison['unset'] ? false : $require_for; // Mark assignment for propagation to child items (But don't do so on storage of default restriction to root item. Default restrictions are only applied at item creation.) $propagate_restriction = $item_id && isset($comparison['new_propagation']) ? $comparison['new_propagation'] : ''; if ($comparison['role_change']) { $role_change = true; } if (!empty($req_ids[$role_handle])) { $id_in = "'" . implode("', '", array_keys($req_ids[$role_handle])) . "'"; // do this for each role prior to insert call because insert function will consider inherited_from value foreach ($update_require_for as $require_for => $this_ass_ids) { if ($this_ass_ids) { $id_in = "'" . implode("', '", $this_ass_ids) . "'"; $qry = "UPDATE {$wpdb->role_scope_rs} SET require_for = '{$require_for}', inherited_from = '0' WHERE requirement_id IN ({$id_in})"; scoper_query($qry); if ('entity' == $require_for) { // If a parent restriction is changed from "both" or "children" to "entity", delete propagated restrictions $qry = "DELETE FROM {$wpdb->role_scope_rs} WHERE inherited_from IN ({$id_in})"; scoper_query($qry); } } } } if ($insert_restriction || $propagate_restriction) { $this->insert_role_restrictions($scope, $max_scope, $role_handle, $src_or_tx_name, $item_id, $insert_restriction, $propagate_restriction, $args); } } // end foreach roles } // delete assignments; flush user,group results cache if ($role_change || !empty($delete_reqs) || $update_require_for || $force_flush) { $this->role_restriction_aftermath($scope, $delete_reqs); if (!$item_id) { $this->scoper->default_restrictions = array(); } } // possible TODO: reinstate this after further testing //$this->delete_orphan_restrictions($scope, $src_or_tx_name); }
function dropdown_pages($object_id = '', $stored_parent_id = '') { global $scoper, $wpdb; // buffer titles in case they are filtered on get_pages hook $titles = ScoperAdminBulkParent::get_page_titles(); if (!is_numeric($object_id)) { global $post_ID; if (empty($post_ID)) { $object_id = $scoper->data_sources->detect('id', 'post', 0, 'post'); } else { $object_id = $post_ID; } } if ($object_id && !is_numeric($stored_parent_id)) { $stored_parent_id = $scoper->data_sources->detect('parent', 'post', $object_id); } // make sure the currently stored parent page remains in dropdown regardless of current user roles if ($stored_parent_id) { $preserve_or_clause = " {$wpdb->posts}.ID = '{$stored_parent_id}' "; $args['preserve_or_clause'] = array(); foreach (array_keys($scoper->data_sources->member_property('post', 'statuses')) as $status_name) { $args['preserve_or_clause'][$status_name] = $preserve_or_clause; } } // alternate_caps is a 2D array because objects_request / objects_where filter supports multiple alternate sets of qualifying caps $args['force_reqd_caps']['page'] = array(); foreach (array_keys($scoper->data_sources->member_property('post', 'statuses')) as $status_name) { $args['force_reqd_caps']['page'][$status_name] = array('edit_others_pages'); } $args['alternate_reqd_caps'][0] = array('create_child_pages'); $all_pages_by_id = array(); if ($results = scoper_get_results("SELECT ID, post_parent, post_title FROM {$wpdb->posts} WHERE post_type = 'page'")) { foreach ($results as $row) { $all_pages_by_id[$row->ID] = $row; } } $object_type = awp_post_type_from_uri(); // Editable / associable draft and pending pages will be included in Page Parent dropdown in Edit Forms, but not elsewhere if (is_admin() && 'page' != $object_type) { $status_clause = "AND {$wpdb->posts}.post_status IN ('publish', 'private')"; } else { $status_clause = "AND {$wpdb->posts}.post_status IN ('publish', 'private', 'pending', 'draft')"; } $qry_parents = "SELECT ID, post_parent, post_title FROM {$wpdb->posts} WHERE post_type = 'page' {$status_clause} ORDER BY menu_order"; $qry_parents = apply_filters('objects_request_rs', $qry_parents, 'post', 'page', $args); $filtered_pages_by_id = array(); if ($results = scoper_get_results($qry_parents)) { foreach ($results as $row) { $filtered_pages_by_id[$row->ID] = $row; } } $hidden_pages_by_id = array_diff_key($all_pages_by_id, $filtered_pages_by_id); // temporarily add in the hidden parents so we can order the visible pages by hierarchy $pages = ScoperAdminBulkParent::add_missing_parents($filtered_pages_by_id, $hidden_pages_by_id, 'post_parent'); // convert keys from post ID to title+ID so we can alpha sort them $args['pages'] = array(); foreach (array_keys($pages) as $id) { $args['pages'][$pages[$id]->post_title . chr(11) . $id] = $pages[$id]; } // natural case alpha sort uksort($args['pages'], "strnatcasecmp"); $args['pages'] = ScoperAdminBulkParent::order_by_hierarchy($args['pages'], 'ID', 'post_parent'); // take the hidden parents back out foreach ($args['pages'] as $key => $page) { if (isset($hidden_pages_by_id[$page->ID])) { unset($args['pages'][$key]); } } $output = ''; // restore buffered titles in case they were filtered on get_pages hook scoper_restore_property_array($args['pages'], $titles, 'ID', 'post_title'); if ($object_id) { $args['object_id'] = $object_id; $args['retain_page_ids'] = true; // retain static log to avoid redundant entries by subsequent call with use_parent_clause=false ScoperHardwayParentLegacy::walk_parent_dropdown($output, $args, true, $stored_parent_id); } // next we'll add disjointed branches, but don't allow this page's descendants to be offered as a parent $arr_parent = array(); $arr_children = array(); if ($results = scoper_get_results("SELECT ID, post_parent FROM {$wpdb->posts} WHERE post_type = 'page' {$status_clause}")) { foreach ($results as $row) { $arr_parent[$row->ID] = $row->post_parent; if (!isset($arr_children[$row->post_parent])) { $arr_children[$row->post_parent] = array(); } $arr_children[$row->post_parent][] = $row->ID; } $descendants = array(); if (!empty($arr_children[$object_id])) { foreach ($arr_parent as $page_id => $parent_id) { if (!$parent_id || $page_id == $object_id) { continue; } do { if ($object_id == $parent_id) { $descendants[$page_id] = true; break; } $parent_id = $arr_parent[$parent_id]; } while ($parent_id); } } $args['descendants'] = $descendants; } ScoperHardwayParentLegacy::walk_parent_dropdown($output, $args, false, $stored_parent_id); //log_mem_usage_rs( 'end dropdown_pages()' ); return $output; }
function load_roles($src_name, $object_type, $object_id) { //log_mem_usage_rs( 'start ItemRolesUI::load_roles()' ); if ('edit.php' == $GLOBALS['pagenow']) { return; } if (!scoper_get_otype_option('use_object_roles', $src_name, $object_type)) { return; } if (!($src = $this->scoper->data_sources->get($src_name))) { return; } $this->loaded_src_name = $src_name; $this->loaded_object_type = $object_type; $this->loaded_object_id = $object_id; $this->indicate_blended_roles = scoper_get_option('indicate_blended_roles'); $this->all_agents = array(); $this->agent_captions = array(); $this->agent_captions_plural = array(); $this->eligible_agent_ids = array(); // note: if object_id = 0, default roles will be retrieved $get_defaults = !$object_id; $obj_roles = array(); $role_defs = $this->scoper->role_defs->get_matching('rs', $src_name, $object_type); $this->role_handles = array_keys($role_defs); // for default roles, distinguish between various object types $filter_role_handles = $object_id ? '' : array_keys($role_defs); if (GROUP_ROLES_RS) { $this->current_roles[ROLE_BASIS_GROUPS] = ScoperRoleAssignments::organize_assigned_roles(OBJECT_SCOPE_RS, $src_name, $object_id, $filter_role_handles, ROLE_BASIS_GROUPS, $get_defaults); } //log_mem_usage_rs( 'load_roles: organize_assigned_roles for groups' ); if (USER_ROLES_RS) { $this->current_roles[ROLE_BASIS_USER] = ScoperRoleAssignments::organize_assigned_roles(OBJECT_SCOPE_RS, $src_name, $object_id, $filter_role_handles, ROLE_BASIS_USER, $get_defaults); } //log_mem_usage_rs( 'load_roles: organize_assigned_roles for users' ); if (GROUP_ROLES_RS) { $this->all_groups = ScoperAdminLib::get_all_groups(UNFILTERED_RS); //log_mem_usage_rs( 'load_roles: get_all_groups' ); if (!empty($this->all_groups)) { $this->agent_captions[ROLE_BASIS_GROUPS] = __('Group', 'scoper'); $this->agent_captions_plural[ROLE_BASIS_GROUPS] = __('Groups', 'scoper'); $this->all_agents[ROLE_BASIS_GROUPS] = $this->all_groups; $this->all_agents[ROLE_BASIS_GROUPS] = $this->all_groups; } //log_mem_usage_rs( 'load_roles: set all_groups properties' ); } if (USER_ROLES_RS) { $this->agent_captions[ROLE_BASIS_USER] = __('User', 'scoper'); $this->agent_captions_plural[ROLE_BASIS_USER] = __awp('Users'); // note: all users are eligible for a reading role assignment, but we may not be displaying user checkboxes $user_csv_input = scoper_get_option("user_role_assignment_csv"); if (!$user_csv_input) { $this->all_agents[ROLE_BASIS_USER] = $this->scoper->users_who_can('', COLS_ID_NAME_RS); } elseif ($object_id) { $assignees = array(); if ($this->current_roles[ROLE_BASIS_USER]) { foreach (array_keys($this->current_roles[ROLE_BASIS_USER]) as $role_handle) { $assignees = array_merge($assignees, array_keys($this->current_roles[ROLE_BASIS_USER][$role_handle]['assigned'])); } } $assignees = array_unique($assignees); global $wpdb; $this->all_agents[ROLE_BASIS_USER] = scoper_get_results("SELECT ID, display_name FROM {$wpdb->users} WHERE ID IN ('" . implode("','", $assignees) . "')"); } else { $this->all_agents[ROLE_BASIS_USER] = array(); } //log_mem_usage_rs( 'load_roles: users_who_can for all_agents' ); //users eligible for an editing role assignments are those who have the basic edit cap via taxonomy or blog role if (scoper_get_otype_option('limit_object_editors', $src_name, $object_type)) { // Limit eligible page contribs/editors based on blog ownership of "edit_posts" // Otherwise, since pages are generally not categorized, only Blog Editors and Admins are eligible for object role ass'n // It's more useful to exclude Blog Subscribers while including all others $role_object_type = 'page' == $object_type ? 'post' : $object_type; $reqd_caps = $this->scoper->cap_defs->get_matching($src_name, $role_object_type, OP_EDIT_RS, '', BASE_CAPS_RS); // status-specific and 'others' caps will not be returned $args = array('ignore_strict_terms' => true, 'ignore_group_roles' => true, 'skip_object_roles' => true); $this->eligible_agent_ids[ROLE_BASIS_USER][OP_EDIT_RS] = $this->scoper->users_who_can(array_keys($reqd_caps), COL_ID_RS, '', 0, $args); //log_mem_usage_rs( 'load_roles: users_who_can for eligible_agent_ids' ); } } $this->blog_term_roles = array(); // Pull object and blog/term role assignments for all roles // Do this first so contained / containing roles can be accounted for in UI foreach ($role_defs as $role_handle => $role_def) { if ($this->indicate_blended_roles && isset($role_def->valid_scopes[OBJECT_SCOPE_RS])) { // might need to check term/blog assignment of a different role to reflect object's current status if (!empty($role_def->other_scopes_check_role) && !empty($src->cols->status)) { $status = $this->scoper->data_sources->detect('status', $src, $object_id); if (isset($role_def->other_scopes_check_role[$status])) { $blog_term_role_handle = $role_def->other_scopes_check_role[$status]; } elseif (isset($role_def->other_scopes_check_role[''])) { $blog_term_role_handle = $role_def->other_scopes_check_role['']; } else { $blog_term_role_handle = $role_handle; } } else { $blog_term_role_handle = $role_handle; } $this_args = array('skip_object_roles' => true, 'object_type' => $object_type, 'ignore_group_roles' => true); if (empty($user_csv_input)) { $this->blog_term_roles[ROLE_BASIS_USER][$role_handle] = $this->scoper->users_who_can($blog_term_role_handle, COL_ID_RS, $src_name, $object_id, $this_args); //log_mem_usage_rs( "load_roles: users_who_can for $role_handle users" ); } else { $this->blog_term_roles[ROLE_BASIS_USER][$role_handle] = array(); } $this->blog_term_roles[ROLE_BASIS_GROUPS][$role_handle] = $this->scoper->groups_who_can($blog_term_role_handle, COL_ID_RS, $src_name, $object_id, $this_args); //log_mem_usage_rs( "load_roles: groups_who_can for $role_handle groups" ); } } $this->do_propagation_cboxes = !empty($src->cols->parent) && !$this->scoper->data_sources->member_property($src_name, 'object_types', $object_type, 'ignore_object_hierarchy'); $this->object_strict_roles = array(); $this->child_strict_roles = array(); $args = array('id' => $object_id, 'include_child_restrictions' => true); if ($restrictions = $this->scoper->get_restrictions(OBJECT_SCOPE_RS, $src_name, $args)) { //log_mem_usage_rs( "load_roles: get_restrictions" ); foreach ($this->role_handles as $role_handle) { // defaults for this role if (isset($restrictions['unrestrictions'][$role_handle]) && is_array($restrictions['unrestrictions'][$role_handle])) { $this->object_strict_roles[$role_handle] = true; $this->child_strict_roles[$role_handle] = true; } else { $this->object_strict_roles[$role_handle] = false; $this->child_strict_roles[$role_handle] = false; } // role is not default strict, and a restriction is set if (isset($restrictions['restrictions'][$role_handle][$object_id])) { switch ($restrictions['restrictions'][$role_handle][$object_id]) { case ASSIGN_FOR_ENTITY_RS: $this->object_strict_roles[$role_handle] = true; $this->child_strict_roles[$role_handle] = false; break; case ASSIGN_FOR_CHILDREN_RS: $this->object_strict_roles[$role_handle] = false; $this->child_strict_roles[$role_handle] = true; break; case ASSIGN_FOR_BOTH_RS: $this->object_strict_roles[$role_handle] = true; $this->child_strict_roles[$role_handle] = true; } // end switch // role IS default strict, and no unrestriction is set } elseif (isset($restrictions['unrestrictions'][$role_handle][$object_id])) { switch ($restrictions['unrestrictions'][$role_handle][$object_id]) { case ASSIGN_FOR_ENTITY_RS: $this->object_strict_roles[$role_handle] = false; $this->child_strict_roles[$role_handle] = true; break; case ASSIGN_FOR_CHILDREN_RS: $this->object_strict_roles[$role_handle] = true; $this->child_strict_roles[$role_handle] = false; break; case ASSIGN_FOR_BOTH_RS: $this->object_strict_roles[$role_handle] = false; $this->child_strict_roles[$role_handle] = false; } // end switch } } // end foreach Role Handle } //log_mem_usage_rs( 'end ItemRolesUI::load_roles()' ); }
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 rs_tally_term_counts(&$terms, $taxonomy, $args = array()) { global $wpdb, $scoper; $defaults = array('pad_counts' => true, 'skip_teaser' => false, 'post_type' => ''); $args = array_merge($defaults, (array) $args); extract($args); if (!$terms) { return; } $term_items = array(); $terms_by_id = array(); foreach ($terms as $key => $term) { $terms_by_id[$term->term_id] =& $terms[$key]; $term_ids[$term->term_taxonomy_id] = $term->term_id; // key and value will match for non-taxonomy category types } $tx_obj = get_taxonomy($taxonomy); $post_types = array_unique((array) $tx_obj->object_type); $enabled_types = array(); foreach ($post_types as $_post_type) { if (scoper_get_otype_option('use_term_roles', 'post', $_post_type)) { $enabled_types[] = $_post_type; } } if (!$enabled_types) { return; } if ($post_type) { $post_type = (array) $post_type; $enabled_types = array_intersect($enabled_types, $post_type); } // Get the object and term ids and stick them in a lookup table $request = "SELECT DISTINCT {$wpdb->posts}.ID, tt.term_taxonomy_id, tt.term_id, tr.object_id" . " FROM {$wpdb->posts}" . " INNER JOIN {$wpdb->term_relationships} AS tr ON {$wpdb->posts}.ID = tr.object_id " . " INNER JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id " . " WHERE tt.taxonomy = '{$taxonomy}' AND tt.term_id IN ('" . implode("','", $term_ids) . "') " . " AND {$wpdb->posts}.post_type IN ('" . implode("','", $enabled_types) . "')"; // no need to pass any parameters which do not pertain to the objects_request filter $args = array_intersect_key($args, array_flip(array('skip_teaser'))); //$post_type = reset($enabled_types); $post_type = $enabled_types; // note: don't pass in a taxonomies arg because we need to consider restrictions associated with any taxonomy to determine readable objects for terms of this taxonomy $request = apply_filters('objects_request_rs', $request, 'post', $post_type, $args); $results = scoper_get_results($request); foreach ($results as $row) { $id = $term_ids[$row->term_taxonomy_id]; if (isset($term_items[$id][$row->object_id])) { ++$term_items[$id][$row->object_id]; } else { $term_items[$id][$row->object_id] = 1; } } // credit each term for every object contained in any of its descendant terms if ($pad_counts && ScoperAncestry::get_terms_children($taxonomy)) { foreach ($term_ids as $term_id) { $child_term_id = $term_id; while (isset($terms_by_id[$child_term_id]->parent)) { if (!($parent_term_id = $terms_by_id[$child_term_id]->parent)) { break; } if (!empty($term_items[$term_id])) { foreach (array_keys($term_items[$term_id]) as $item_id) { $term_items[$parent_term_id][$item_id] = 1; } } $child_term_id = $parent_term_id; } } } // Tally and apply the item credits foreach ($term_items as $term_id => $items) { if (isset($terms_by_id[$term_id])) { $terms_by_id[$term_id]->count = count($items); } } // update count property for zero-item terms too foreach (array_keys($terms_by_id) as $term_id) { if (!isset($term_items[$term_id])) { if (is_object($terms_by_id[$term_id])) { $terms_by_id[$term_id]->count = 0; } } } }
/** * Updates the status of a User-Group relationship * * @param int $group_id - Group Identifier * @param int $user_id - Identifier of the User to remove **/ function update_group_user($group_id, $user_ids, $status) { global $wpdb; $user_ids = (array) $user_ids; $id_in = "'" . implode("', '", $user_ids) . "'"; $prev_status = array(); $qry = "SELECT {$wpdb->user2group_uid_col} AS user_id, {$wpdb->user2group_status_col} AS status FROM {$wpdb->user2group_rs} WHERE {$wpdb->user2group_gid_col}='{$group_id}' AND {$wpdb->user2group_uid_col} IN ({$id_in})"; if ($results = scoper_get_results($qry)) { foreach ($results as $row) { $prev_status[$row->user_id] = $row->status; } } $qry = "UPDATE {$wpdb->user2group_rs} SET {$wpdb->user2group_status_col}='{$status}' WHERE {$wpdb->user2group_gid_col}='{$group_id}' AND {$wpdb->user2group_uid_col} IN ({$id_in})"; scoper_query($qry); foreach ($user_ids as $user_id) { $prev = isset($prev_status[$user_id]) ? $prev_status[$user_id] : ''; do_action('update_group_user_rs', $group_id, $user_id, $status, $prev); } ScoperAdminLib::flush_groups_cache_for_user($user_ids); }
function flt_get_tags($results, $taxonomies, $args) { if (!is_array($taxonomies)) { $taxonomies = (array) $taxonomies; } if ('post_tag' != $taxonomies[0] || count($taxonomies) > 1) { return $results; } global $wpdb; $defaults = array('exclude' => '', 'include' => '', 'number' => '', 'offset' => '', 'slug' => '', 'name__like' => '', 'search' => '', 'hide_empty' => true); $args = wp_parse_args($args, $defaults); extract($args, EXTR_SKIP); if ('ids' == $fields || !$hide_empty) { return $results; } global $scoper, $current_rs_user; $filter_key = has_filter('list_terms_exclusions') ? serialize($GLOBALS['wp_filter']['list_terms_exclusions']) : ''; $ckey = md5(serialize(compact(array_keys($defaults))) . serialize($taxonomies) . $filter_key); $cache_flag = 'rs_get_terms'; if ($cache = $current_rs_user->cache_get($cache_flag)) { if (isset($cache[$ckey])) { return apply_filters('get_tags_rs', $cache[$ckey], 'post_tag', $args); } } //------------ WP argument application code from get_terms(), with hierarchy-related portions removed ----------------- // // NOTE: must change 'tt.count' to 'count' in orderby and hide_empty settings // Also change default orderby to name // $where = ''; $inclusions = ''; if (!empty($include)) { $exclude = ''; $exclude_tree = ''; $interms = wp_parse_id_list($include); if (count($interms)) { foreach ((array) $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; $exclusions = ''; if (!empty($exclude)) { $exterms = wp_parse_id_list($exclude); if (count($exterms)) { foreach ((array) $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 .= ')'; } $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}%'"; } // don't limit the query results when we have to descend the family tree if (!empty($number)) { 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}%')"; } // ------------- end get_terms() argument application code -------------- $post_type = cr_find_post_type(); // embedded select statement for posts ID IN clause $posts_qry = "SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} WHERE 1=1"; $posts_qry = apply_filters('objects_request_rs', $posts_qry, 'post', $post_type, array('skip_teaser' => true)); $qry = "SELECT DISTINCT t.*, tt.*, COUNT(p.ID) AS count FROM {$wpdb->terms} AS t" . " INNER JOIN {$wpdb->term_taxonomy} AS tt ON tt.term_id = t.term_id AND tt.taxonomy = 'post_tag'" . " INNER JOIN {$wpdb->term_relationships} AS tagr ON tagr.term_taxonomy_id = tt.term_taxonomy_id" . " INNER JOIN {$wpdb->posts} AS p ON p.ID = tagr.object_id WHERE p.ID IN ({$posts_qry})" . " {$where} GROUP BY t.term_id ORDER BY count DESC {$limit}"; // must hardcode orderby clause to always query top tags $results = scoper_get_results($qry); $cache[$ckey] = $results; $current_rs_user->cache_set($cache, $cache_flag); $results = apply_filters('get_tags_rs', $results, 'post_tag', $args); return $results; }
function scoper_sync_wproles($user_ids = '', $role_name_arg = '', $blog_id_arg = '') { global $wpdb, $wp_roles; if ($user_ids && !is_array($user_ids)) { $user_ids = array($user_ids); } if (empty($wp_roles->role_objects)) { return; } $wp_rolenames = array_keys($wp_roles->role_objects); $uro_table = $blog_id_arg ? $wpdb->base_prefix . $blog_id_arg . '_' . 'user2role2object_rs' : $wpdb->user2role2object_rs; $groups_table = $wpdb->groups_rs; $user2group_table = $wpdb->user2group_rs; // Delete any role entries for WP roles which were deleted or renamed while Role Scoper was deactivated // (users will be re-synched to new role name) $name_in = "'" . implode("', '", $wp_rolenames) . "'"; $qry = "DELETE FROM {$uro_table} WHERE role_type = 'wp' AND scope = 'blog' AND role_name NOT IN ({$name_in})"; scoper_query($qry); // also sync WP Role metagroups if (!empty($user_ids)) { foreach ($user_ids as $user_id) { wpp_cache_delete($user_id, 'group_membership_for_user'); } } $metagroup_ids = array(); $metagroup_names = array(); $metagroup_descripts = array(); foreach ($wp_rolenames as $role_name) { $metagroup_id = "wp_role_" . trim(substr($role_name, 0, 40)); // if the name is too long and its truncated ID already taken, just exclude it from eligible metagroups if (in_array($metagroup_id, $metagroup_ids)) { continue; } $metagroup_ids[] = $metagroup_id; $metagroup_names["wp_role_{$role_name}"] = sprintf('[WP %s]', $role_name); $metagroup_descripts["wp_role_{$role_name}"] = sprintf('All users with the WordPress %s blog role', $role_name); } // add a metagroup for anonymous users $metagroup_ids[] = "wp_anon"; $metagroup_names["wp_anon"] = '[Anonymous]'; $metagroup_descripts["wp_anon"] = 'Anonymous users (not logged in)'; // add a metagroup for pending revision e-mail notification recipients $metagroup_ids[] = "rv_pending_rev_notice_ed_nr_"; $metagroup_names["rv_pending_rev_notice_ed_nr_"] = '[Pending Revision Monitors]'; $metagroup_descripts["rv_pending_rev_notice_ed_nr_"] = 'Administrators / Publishers to notify (by default) of pending revisions'; // add a metagroup for pending revision e-mail notification recipients $metagroup_ids[] = "rv_scheduled_rev_notice_ed_nr_"; $metagroup_names["rv_scheduled_rev_notice_ed_nr_"] = '[Scheduled Revision Monitors]'; $metagroup_descripts["rv_scheduled_rev_notice_ed_nr_"] = 'Administrators / Publishers to notify when any scheduled revision is published'; $stored_metagroup_ids = array(); $qry = "SELECT {$wpdb->groups_meta_id_col}, {$wpdb->groups_id_col}, {$wpdb->groups_name_col} FROM {$groups_table} WHERE NOT ISNULL({$wpdb->groups_meta_id_col}) AND ( {$wpdb->groups_meta_id_col} != '' )"; // LIKE 'wp_%'"; if ($results = scoper_get_results($qry)) { //rs_errlog("metagroup results: " . serialize($stored_metagroup_ids)'); $delete_metagroup_ids = array(); $update_metagroup_ids = array(); foreach ($results as $row) { if (!in_array($row->{$wpdb->groups_meta_id_col}, $metagroup_ids)) { $delete_metagroup_ids[] = $row->{$wpdb->groups_id_col}; } else { $stored_metagroup_ids[] = $row->{$wpdb->groups_meta_id_col}; if ($row->{$wpdb->groups_name_col} != $metagroup_names[$row->{$wpdb->groups_meta_id_col}]) { $update_metagroup_ids[] = $row->{$wpdb->groups_meta_id_col}; } } } if ($delete_metagroup_ids) { $id_in = "'" . implode("', '", $delete_metagroup_ids) . "'"; scoper_query("DELETE FROM {$groups_table} WHERE {$wpdb->groups_id_col} IN ({$id_in})"); } if ($update_metagroup_ids) { foreach ($update_metagroup_ids as $metagroup_id) { if ($metagroup_id) { scoper_query("UPDATE {$groups_table} SET {$wpdb->groups_name_col} = '{$metagroup_names[$metagroup_id]}', {$wpdb->groups_descript_col} = '{$metagroup_descripts[$metagroup_id]}' WHERE {$wpdb->groups_meta_id_col} = '{$metagroup_id}'"); } } } } if ($insert_metagroup_ids = array_diff($metagroup_ids, $stored_metagroup_ids)) { //rs_errlog("inserting metagroup ids: " . serialize($insert_metagroup_ids)'); foreach ($insert_metagroup_ids as $metagroup_id) { scoper_query("INSERT INTO {$groups_table} ( {$wpdb->groups_meta_id_col}, {$wpdb->groups_name_col}, {$wpdb->groups_descript_col} ) VALUES ( '{$metagroup_id}', '{$metagroup_names[$metagroup_id]}', '{$metagroup_descripts[$metagroup_id]}' )"); //rs_errlog( "INSERT INTO $groups_table ( $wpdb->groups_meta_id_col, $wpdb->groups_name_col, $wpdb->groups_descript_col ) VALUES ( '$metagroup_id', '$metagroup_names[$metagroup_id]', '$metagroup_descripts[$metagroup_id]' )" ); } } if (!empty($delete_metagroup_ids) || !empty($update_metagroup_ids)) { wpp_cache_flush(); // role deletion / rename might affect other cached data or settings, so flush the whole cache } elseif (!empty($insert_group_ids)) { wpp_cache_flush_group('all_usergroups'); wpp_cache_flush_group('usergroups_for_groups'); wpp_cache_flush_group('usergroups_for_user'); wpp_cache_flush_group('usergroups_for_ug'); } // Now step through every WP usermeta record, // synchronizing the user's user2role2object_rs blog role entries with their WP role and custom caps // get each user's WP roles and caps $user_clause = $user_ids ? 'AND user_id IN (' . implode(', ', $user_ids) . ')' : ''; $qry = "SELECT user_id, meta_value FROM {$wpdb->usermeta} WHERE meta_key = '{$wpdb->prefix}capabilities' {$user_clause}"; if (!($usermeta = scoper_get_results($qry))) { return; } //rs_errlog("got " . count($usermeta) . " usermeta records"); $wp_rolecaps = array(); foreach ($wp_roles->role_objects as $role_name => $role) { $wp_rolecaps[$role_name] = $role->capabilities; } //rs_errlog(serialize($wp_rolecaps)); $strip_vals = array('', 0, false); $stored_assignments = array('wp' => array(), 'wp_cap' => array()); foreach (array_keys($stored_assignments) as $role_type) { $results = scoper_get_results("SELECT user_id, role_name, assignment_id FROM {$uro_table} WHERE role_type = '{$role_type}' AND user_id > 0 {$user_clause}"); foreach ($results as $key => $row) { $stored_assignments[$role_type][$row->user_id][$row->assignment_id] = $row->role_name; unset($results[$key]); } } foreach (array_keys($usermeta) as $key) { $user_id = $usermeta[$key]->user_id; $user_caps = maybe_unserialize($usermeta[$key]->meta_value); if (empty($user_caps) || !is_array($user_caps)) { continue; } //rs_errlog("user caps: " . serialize($user_caps)); $user_roles = array(); // just in case, strip out any entries with false value $user_caps = array_diff($user_caps, $strip_vals); $user_roles = array('wp' => array(), 'wp_cap' => array()); //Filter out caps that are not role names $user_roles['wp'] = array_intersect(array_keys($user_caps), $wp_rolenames); // Store any custom-assigned caps as single-cap roles // This will be invisible and only used to support the users query filter // With current implementation, the custom cap will only be honored when // users_who_can is called with a single capreq $user_roles['wp_cap'] = array_diff(array_keys($user_caps), $user_roles['wp']); // which roles are already stored in user2role2object_rs table? $stored_roles = array(); $delete_roles = array(); foreach (array_keys($user_roles) as $role_type) { //$results = scoper_get_results("SELECT role_name, assignment_id FROM $uro_table WHERE role_type = '$role_type' AND user_id = '$user_id'"); //if ( $results ) { if (isset($stored_assignments[$role_type][$user_id])) { //rs_errlog("results: " . serialize($results)); foreach ($stored_assignments[$role_type][$user_id] as $assignment_id => $role_name) { // Log stored roles, and delete any roles which user no longer has (possibly because the WP role definition was deleted). // Only Role Scoper's mirroring of WP blog roles is involved here unless Role Scoper was configured and used with a Role Type of "WP". // This also covers any WP role changes made while Role Scoper was deactivated. if (in_array($role_name, $user_roles[$role_type])) { $stored_roles[$role_type][] = $role_name; } else { $delete_roles[] = $assignment_id; } } } else { $stored_roles[$role_type] = array(); } } if ($delete_roles) { $id_in = implode(', ', $delete_roles); scoper_query("DELETE FROM {$uro_table} WHERE assignment_id IN ({$id_in})"); } //rs_errlog("user roles " . serialize($user_roles) '); //rs_errlog("stored roles " . serialize($stored_roles)'); // add any missing roles foreach (array_keys($user_roles) as $role_type) { if (!empty($stored_roles[$role_type])) { $user_roles[$role_type] = array_diff($user_roles[$role_type], $stored_roles[$role_type]); } if (!empty($user_roles[$role_type])) { foreach ($user_roles[$role_type] as $role_name) { //rs_errlog("INSERT INTO $uro_table (user_id, role_name, role_type, scope) VALUES ('$user_id', '$role_name', '$role_type', 'blog')"); scoper_query("INSERT INTO {$uro_table} (user_id, role_name, role_type, scope) VALUES ('{$user_id}', '{$role_name}', '{$role_type}', 'blog')"); } } } } // end foreach WP usermeta // disable orphaned role deletion until we can recreate and eliminate improper deletion as reported in support forum (http://agapetry.net/forum/role-scoper/permissions-reset-randomly-for-a-section-of-pages/page-1/post-3513/) // Delete any role assignments for users which no longer exist //delete_roles_orphaned_from_user(); // Delete any role assignments for WP groups which no longer exist //delete_roles_orphaned_from_group(); // Delete any role assignments for posts/pages which no longer exist //delete_roles_orphaned_from_item( OBJECT_SCOPE_RS, 'post' ); //delete_restrictions_orphaned_from_item( OBJECT_SCOPE_RS, 'post' ); // hold off on this until delete_roles_orphaned_from_item() call has a long, clear track record // Delete any role assignments for categories which no longer exist //delete_roles_orphaned_from_item( TERM_SCOPE_RS, 'category' ); //delete_restrictions_orphaned_from_item( TERM_SCOPE_RS, 'category' ); //rs_errlog("finished syncroles "'); }
function flt_wp_dropdown_users($wp_output) { // just filter Post Author dropdown if (!strpos($wp_output, "name='post_author_override'")) { return $wp_output; } // this is meant to filter the post author selection if (!is_admin()) { return $wp_output; } // if (even after our blogcap tinkering) the author list is already locked due to insufficient blog-wide caps, don't mess if (!($pos = strpos($wp_output, '<option'))) { return $wp_output; } if (!strpos($wp_output, '<option', $pos + 1)) { return $wp_output; } global $wpdb, $scoper; $last_query = $wpdb->last_query; if (!($object_type = cr_find_post_type())) { return $wp_output; } if (!($post_type_obj = get_post_type_object($object_type))) { return $wp_output; } global $current_user; $is_ngg_edit = strpos($_SERVER['REQUEST_URI'], 'nggallery-manage-gallery'); if (!$is_ngg_edit) { $src_name = 'post'; $object_id = scoper_get_object_id('post', $object_type); // only modify the default authors list if current user has Editor role for the current post/page $have_cap = cr_user_can($post_type_obj->cap->edit_others_posts, $object_id, 0, array('require_full_object_role' => true)); } else { $src_name = 'ngg_gallery'; $object_id = $_REQUEST['gid']; $have_cap = !empty($current_user->allcaps[$post_type_obj->cap->edit_others_posts]); // $post_type_obj defaults to 'post' type on NGG Manage Gallery page } //if ( ! $have_cap ) // return $wp_output; $orderpos = strpos($last_query, 'ORDER BY'); $orderby = $orderpos ? substr($last_query, $orderpos) : ''; if (!strpos($orderby, 'display_name')) { // sanity check in case the last_query buffer gets messed up $orderby = ''; } $id_in = $id_not_in = $show_option_all = $show_option_none = ''; $pos = strpos($last_query, 'AND ID IN('); if ($pos) { $pos_close = strpos($last_query, ')', $pos); if ($pos_close) { $id_in = substr($last_query, $pos, $pos_close - $pos + 1); } } $pos = strpos($last_query, 'AND ID NOT IN('); if ($pos) { $pos_close = strpos($last_query, ')', $pos); if ($pos_close) { $id_not_in = substr($last_query, $pos, $pos_close - $pos + 1); } } $search = "<option value='0'>"; $pos = strpos($wp_output, $search . __awp('Any')); if ($pos) { $pos_close = strpos($wp_output, '</option>', $pos); if ($pos_close) { $show_option_all = substr($wp_output, $pos + strlen($search), $pos_close - $pos - strlen($search)); } } $search = "<option value='-1'>"; $pos = strpos($wp_output, $search . __awp('None')); if ($pos) { $pos_close = strpos($wp_output, '</option>', $pos); if ($pos_close) { $show_option_none = substr($wp_output, $pos + strlen($search), $pos_close - $pos - strlen($search)); } } $search = "<select name='"; $pos = strpos($wp_output, $search); if (false !== $pos) { $pos_close = strpos($wp_output, "'", $pos + strlen($search)); if ($pos_close) { $name = substr($wp_output, $pos + strlen($search), $pos_close - $pos - strlen($search)); } } $search = " id='"; $multi = !strpos($wp_output, $search); // beginning with WP 2.7, some users dropdowns lack id attribute $search = " class='"; $pos = strpos($wp_output, $search); if ($pos) { $pos_close = strpos($wp_output, "'", $pos + strlen($search)); if ($pos_close) { $class = substr($wp_output, $pos + strlen($search), $pos_close - $pos - strlen($search)); } } $search = " selected='selected'"; $pos = strpos($wp_output, $search); if ($pos) { $search = "<option value='"; $str_left = substr($wp_output, 0, $pos); $pos = strrpos($str_left, $search); //back up to previous option tag $pos_close = strpos($wp_output, "'", $pos + strlen($search)); if ($pos_close) { $selected = substr($wp_output, $pos + strlen($search), $pos_close - ($pos + strlen($search))); } } if (empty($selected)) { $selected = $current_user->ID; } // precaution prevents default-selection of non-current user // Role Scoper filter application $where = "{$id_in} {$id_not_in}"; $args = array(); $args['where'] = $where; $args['orderby'] = $orderby; if ($object_id > 0) { if ($current_author = $scoper->data_sources->get_from_db('owner', $src_name, $object_id)) { $force_user_id = $current_author; } } else { $force_user_id = $current_user->ID; } if ($have_cap) { if ($force_user_id) { $args['preserve_or_clause'] = " uro.user_id = '{$force_user_id}'"; } $users = $scoper->users_who_can($post_type_obj->cap->edit_posts, COLS_ID_DISPLAYNAME_RS, 'post', $object_id, $args); } else { $display_name = $wpdb->get_var("SELECT display_name FROM {$wpdb->users} WHERE ID = '{$force_user_id}'"); $users = array((object) array('ID' => $force_user_id, 'display_name' => $display_name)); } if (empty($users)) { // sanity check: users_who_can should always return Administrators if ($admin_roles = awp_administrator_roles()) { $users = scoper_get_results("SELECT DISTINCT ID, display_name FROM {$wpdb->users} INNER JOIN {$wpdb->user2role2object_rs} AS uro ON uro.user_id = {$wpdb->users}.ID AND uro.scope = 'blog' AND uro.role_type = 'wp' AND uro.role_name IN ('" . implode("','", $admin_roles) . "')"); } else { return $wp_output; } // the user data must be messed up } $show = 'display_name'; // no way to back this out // ----------- begin wp_dropdown_users code copy (from WP 2.7) ------------- $id = $multi ? "" : "id='{$name}'"; $output = "<select name='{$name}' {$id} class='{$class}'>\n"; if ($show_option_all) { $output .= "\t<option value='0'>{$show_option_all}</option>\n"; } if ($show_option_none) { $output .= "\t<option value='-1'>{$show_option_none}</option>\n"; } foreach ((array) $users as $user) { $user->ID = (int) $user->ID; $_selected = $user->ID == $selected ? " selected='selected'" : ''; $display = !empty($user->{$show}) ? $user->{$show} : '(' . $user->user_login . ')'; $output .= "\t<option value='{$user->ID}'{$_selected}>" . esc_html($display) . "</option>\n"; } $output .= "</select>"; // ----------- end wp_dropdown_users code copy (from WP 2.7) ------------- return $output; }
function get_objects_info($object_ids, &$object_names, &$object_status, &$unlisted_objects, $src, $otype, $ignore_hierarchy) { global $wpdb; // buffer titles in case they are translated if ('page' == $otype->name) { // todo: other hierarchical types? $titles = ScoperAdminBulkParent::get_page_titles(); } $col_id = $src->cols->id; $col_name = $src->cols->name; $cols = "{$col_name}, {$col_id}"; if (isset($src->cols->parent) && !$ignore_hierarchy) { $col_parent = $src->cols->parent; $cols .= ", {$col_parent}"; } else { $col_parent = ''; } $col_status = !empty($src->cols->status) ? $src->cols->status : ''; if ($col_status) { $cols .= ", {$col_status}"; } $unroled_count = 0; $unroled_limit = !empty($otype->admin_max_unroled_objects) ? $otype->admin_max_unroled_objects : 999999; if (!empty($src->cols->type)) { $otype_clause = "AND {$src->cols->type} = '{$otype->name}'"; if ('post' == $src->name) { $otype_clause .= "AND {$src->cols->status} != 'auto-draft'"; } } else { $otype_clause = ''; } $obj = ''; if ($results = scoper_get_results("SELECT {$cols} FROM {$src->table} WHERE 1=1 {$otype_clause} ORDER BY {$col_id} DESC")) { foreach ($results as $row) { if (isset($titles[$row->{$col_id}])) { $object_names[$row->{$col_id}] = $titles[$row->{$col_id}]; } elseif ('post' == $src->name) { $object_names[$row->{$col_id}] = apply_filters('the_title', $row->{$col_name}, $row->{$col_id}); } else { $object_names[$row->{$col_id}] = $row->{$col_name}; } if ($col_status) { $object_status[$row->{$col_id}] = $row->{$col_status}; } unset($obj); if ($col_parent) { // temporarily key by name for alpha sort of additional items prior to hierarchy sort $obj = (object) array($col_id => $row->{$col_id}, $col_name => $row->{$col_name}, $col_parent => $row->{$col_parent}); } else { $obj = (object) array($col_id => $row->{$col_id}, $col_name => $row->{$col_name}); } // List only a limited number of unroled objects if ($unroled_limit >= 0 && !isset($object_ids[$row->{$col_id}])) { if ($unroled_count >= $unroled_limit) { $unlisted_objects[$row->{$col_id}] = $obj; continue; } $unroled_count++; } $listed_objects[$row->{$col_id}] = $obj; } } // restore buffered page titles in case they were filtered previously if ('page' == $otype->name) { scoper_restore_property_array($listed_objects, $titles, 'ID', 'post_title'); scoper_restore_property_array($unlisted_objects, $titles, 'ID', 'post_title'); } return $listed_objects; }
function flt_get_pages($results, $args = array()) { $results = (array) $results; global $wpdb; // === BEGIN Role Scoper ADDITION: global var; various special case exemption checks === // global $scoper, $current_rs_user; // need to skip cache retrieval if QTranslate is filtering get_pages with a priority of 1 or less $no_cache = !defined('SCOPER_QTRANSLATE_COMPAT') && awp_is_plugin_active('qtranslate'); // buffer titles in case they were filtered previously $titles = scoper_get_property_array($results, 'ID', 'post_title'); // depth is not really a get_pages arg, but remap exclude arg to exclude_tree if wp_list_terms called with depth=1 if (!empty($args['exclude']) && empty($args['exclude_tree']) && !empty($args['depth']) && 1 == $args['depth']) { if (0 !== strpos($args['exclude'], ',')) { // work around wp_list_pages() bug of attaching leading comma if a plugin uses wp_list_pages_excludes filter $args['exclude_tree'] = $args['exclude']; } } // // === END Role Scoper ADDITION === // ================================= $defaults = array('child_of' => 0, 'sort_order' => 'ASC', 'sort_column' => 'post_title', 'hierarchical' => 1, 'exclude' => array(), 'include' => array(), 'meta_key' => '', 'meta_value' => '', 'authors' => '', 'parent' => -1, 'exclude_tree' => '', 'number' => '', 'offset' => 0, 'post_type' => 'page', 'post_status' => 'publish', 'depth' => 0, 'suppress_filters' => 0, 'remap_parents' => -1, 'enforce_actual_depth' => -1, 'remap_thru_excluded_parent' => -1); // Role Scoper arguments added above // === BEGIN Role Scoper ADDITION: support front-end optimization $post_type = isset($args['post_type']) ? $args['post_type'] : $defaults['post_type']; $use_post_types = (array) scoper_get_option('use_post_types'); if (empty($use_post_types[$post_type])) { return $results; } if ($scoper->is_front()) { if ('page' == $post_type && defined('SCOPER_GET_PAGES_LEAN')) { // custom types are likely to have custom fields $defaults['fields'] = "{$wpdb->posts}.ID, {$wpdb->posts}.post_title, {$wpdb->posts}.post_parent, {$wpdb->posts}.post_date, {$wpdb->posts}.post_date_gmt, {$wpdb->posts}.post_status, {$wpdb->posts}.post_name, {$wpdb->posts}.post_modified, {$wpdb->posts}.post_modified_gmt, {$wpdb->posts}.guid, {$wpdb->posts}.menu_order, {$wpdb->posts}.comment_count"; } else { $defaults['fields'] = "{$wpdb->posts}.*"; if (!defined('SCOPER_FORCE_PAGES_CACHE')) { $no_cache = true; } // serialization / unserialization of post_content for all pages is too memory-intensive for sites with a lot of pages } } else { // required for xmlrpc getpagelist method $defaults['fields'] = "{$wpdb->posts}.*"; if (!defined('SCOPER_FORCE_PAGES_CACHE')) { $no_cache = true; } } // === END Role Scoper MODIFICATION === $r = wp_parse_args($args, $defaults); extract($r, EXTR_SKIP); $number = (int) $number; $offset = (int) $offset; $child_of = (int) $child_of; // Role Scoper modification: null value will confuse children array check // Make sure the post type is hierarchical $hierarchical_post_types = get_post_types(array('public' => true, 'hierarchical' => true)); if (!in_array($post_type, $hierarchical_post_types)) { return $results; } // Make sure we have a valid post status if (!in_array($post_status, get_post_stati())) { return $results; } // for the page parent dropdown, return no available selections for a published main page if the logged user isn't allowed to de-associate it from Main if (!empty($name) && 'parent_id' == $name) { global $post; if (!$post->post_parent && !$GLOBALS['scoper_admin_filters']->user_can_associate_main($post_type)) { $status_obj = get_post_status_object($post->post_status); if ($status_obj->public || $status_obj->private) { return array(); } } if (!empty($post) && $post_type == $post->post_type) { if ($post->post_parent) { $append_page = get_post($post->post_parent); } $exclude_tree = $post->ID; } } //$scoper->last_get_pages_args = $r; // don't copy entire args array unless it proves necessary $scoper->last_get_pages_depth = $depth; $scoper->last_get_pages_suppress_filters = $suppress_filters; if ($suppress_filters) { return $results; } // === BEGIN Role Scoper MODIFICATION: wp-cache key and flag specific to access type and user/groups // if (!scoper_get_otype_option('use_object_roles', 'post', $post_type)) { return $results; } $key = md5(serialize(compact(array_keys($defaults)))); $ckey = md5($key . CURRENT_ACCESS_NAME_RS); $cache_flag = 'rs_get_pages'; $cache = $current_rs_user->cache_get($cache_flag); if (false !== $cache) { if (!is_array($cache)) { $cache = array(); } if (!$no_cache && isset($cache[$ckey])) { // alternate filter name (WP core already applied get_pages filter) return apply_filters('get_pages_rs', $cache[$ckey], $r); } } // // === END Role Scoper MODIFICATION === // ==================================== $inclusions = ''; if (!empty($include)) { $child_of = 0; //ignore child_of, parent, exclude, meta_key, and meta_value params if using include $parent = -1; $exclude = ''; $meta_key = ''; $meta_value = ''; $hierarchical = false; $incpages = wp_parse_id_list($include); if (!empty($incpages)) { foreach ($incpages as $incpage) { if (empty($inclusions)) { $inclusions = ' AND ( ID = ' . intval($incpage) . ' '; } else { $inclusions .= ' OR ID = ' . intval($incpage) . ' '; } } } } if (!empty($inclusions)) { $inclusions .= ')'; } $exclusions = ''; if (!empty($exclude)) { $expages = wp_parse_id_list($exclude); if (!empty($expages)) { foreach ($expages as $expage) { if (empty($exclusions)) { $exclusions = ' AND ( ID <> ' . intval($expage) . ' '; } else { $exclusions .= ' AND ID <> ' . intval($expage) . ' '; } } } } if (!empty($exclusions)) { $exclusions .= ')'; } $author_query = ''; if (!empty($authors)) { $post_authors = wp_parse_id_list($authors); if (!empty($post_authors)) { foreach ($post_authors as $post_author) { //Do we have an author id or an author login? if (0 == intval($post_author)) { $post_author = get_userdatabylogin($post_author); if (empty($post_author)) { continue; } if (empty($post_author->ID)) { continue; } $post_author = $post_author->ID; } if ('' == $author_query) { $author_query = ' post_author = ' . intval($post_author) . ' '; } else { $author_query .= ' OR post_author = ' . intval($post_author) . ' '; } } if ('' != $author_query) { $author_query = " AND ({$author_query})"; } } } $join = ''; $where = "{$exclusions} {$inclusions} "; if (!empty($meta_key) || !empty($meta_value)) { $join = " INNER JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id"; // Role Scoper modification: was LEFT JOIN in WP 3.0 core (TODO: would that botch uro join results? // meta_key and meta_value might be slashed $meta_key = stripslashes($meta_key); $meta_value = stripslashes($meta_value); if (!empty($meta_key)) { $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_key = %s", $meta_key); } if (!empty($meta_value)) { $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_value = %s", $meta_value); } } if ($parent >= 0) { $where .= $wpdb->prepare(' AND post_parent = %d ', $parent); } // === BEGIN Role Scoper MODIFICATION: // allow pages of multiple statuses to be displayed (requires default status=publish to be ignored) // $where_post_type = $wpdb->prepare("post_type = '%s'", $post_type); $where_status = ''; $is_front = $scoper->is_front(); $is_teaser_active = $scoper->is_front() && scoper_get_otype_option('do_teaser', 'post') && scoper_get_otype_option('use_teaser', 'post', $post_type); $private_teaser = $is_teaser_active && scoper_get_otype_option('use_teaser', 'post', $post_type) && !scoper_get_otype_option('teaser_hide_private', 'post', $post_type); if ($is_front && (!empty($current_rs_user->ID) || $private_teaser)) { $frontend_list_private = scoper_get_otype_option('private_items_listable', 'post', 'page'); } else { $frontend_list_private = false; } // WP core does not include private pages in query. Include private statuses in anticipation of user-specific filtering if ($post_status && ('publish' != $post_status || $is_front && !$frontend_list_private)) { $where_status = $wpdb->prepare("post_status = '%s'", $post_status); } else { // since we will be applying status clauses based on content-specific roles and restrictions, only a sanity check safeguard is needed when post_status is unspecified or defaulted to "publish" $safeguard_statuses = array(); foreach (get_post_stati(array('internal' => false), 'object') as $status_name => $status_obj) { if (!$is_front || $status_obj->private || $status_obj->public) { $safeguard_statuses[] = $status_name; } } $where_status = "post_status IN ('" . implode("','", $safeguard_statuses) . "')"; } $query = "SELECT {$fields} FROM {$wpdb->posts} {$join} WHERE 1=1 AND {$where_post_type} AND ( {$where_status} {$where} {$author_query} ) ORDER BY {$sort_column} {$sort_order}"; if (!empty($number)) { $query .= ' LIMIT ' . $offset . ',' . $number; } if ($is_teaser_active && !defined('SCOPER_TEASER_HIDE_PAGE_LISTING')) { // We are in the front end and the teaser is enabled for pages $query = apply_filters('objects_request_rs', $query, 'post', $post_type, array('force_teaser' => true)); $pages = scoper_get_results($query); // execute unfiltered query // Pass results of unfiltered query through the teaser filter. // If listing private pages is disabled, they will be omitted completely, but restricted published pages // will still be teased. This is a slight design compromise to satisfy potentially conflicting user goals without yet another option $pages = apply_filters('objects_results_rs', $pages, 'post', (array) $post_type, array('request' => $query, 'force_teaser' => true, 'object_type' => $post_type)); // restore buffered titles in case they were filtered previously scoper_restore_property_array($pages, $titles, 'ID', 'post_title'); $pages = apply_filters('objects_teaser_rs', $pages, 'post', $post_type, array('request' => $query, 'force_teaser' => true)); if ($frontend_list_private) { if (!scoper_get_otype_option('teaser_hide_private', 'post', $post_type)) { $tease_all = true; } } } else { $_args = array('skip_teaser' => true); if (in_array($GLOBALS['pagenow'], array('post.php', 'post-new.php'))) { if ($post_type_obj = get_post_type_object($post_type)) { $plural_name = plural_name_from_cap_rs($post_type_obj); $_args['alternate_reqd_caps'][0] = array("create_child_{$plural_name}"); } } // Pass query through the request filter $query = apply_filters('objects_request_rs', $query, 'post', $post_type, $_args); // Execute the filtered query $pages = scoper_get_results($query); // restore buffered titles in case they were filtered previously scoper_restore_property_array($pages, $titles, 'ID', 'post_title'); } if (empty($pages)) { // alternate hook name (WP core already applied get_pages filter) return apply_filters('get_pages_rs', array(), $r); } // // === END Role Scoper MODIFICATION === // ==================================== // Role Scoper note: WP core get_pages has already updated wp_cache and pagecache with unfiltered results. update_page_cache($pages); // === BEGIN Role Scoper MODIFICATION: Support a disjointed pages tree with some parents hidden ======== if ($child_of || empty($tease_all)) { // if we're including all pages with teaser, no need to continue thru tree remapping $ancestors = ScoperAncestry::get_page_ancestors(); // array of all ancestor IDs for keyed page_id, with direct parent first $orderby = $sort_column; if ($parent > 0 || !$hierarchical) { $remap_parents = false; } else { // if these settings were passed into this get_pages call, use them if (-1 === $remap_parents) { $remap_parents = scoper_get_option('remap_page_parents'); } if ($remap_parents) { if (-1 === $enforce_actual_depth) { $enforce_actual_depth = scoper_get_option('enforce_actual_page_depth'); } if (-1 === $remap_thru_excluded_parent) { $remap_thru_excluded_parent = scoper_get_option('remap_thru_excluded_page_parent'); } } } $remap_args = compact('child_of', 'parent', 'exclude', 'depth', 'orderby', 'remap_parents', 'enforce_actual_depth', 'remap_thru_excluded_parent'); // one or more of these args may have been modified after extraction ScoperHardway::remap_tree($pages, $ancestors, 'ID', 'post_parent', $remap_args); } // === END Role Scoper MODIFICATION === // ==================================== if (!empty($exclude_tree)) { $exclude = array(); $exclude = (int) $exclude_tree; $children = get_page_children($exclude, $pages); // RS note: okay to use unfiltered function here since it's only used for excluding $excludes = array(); foreach ($children as $child) { $excludes[] = $child->ID; } $excludes[] = $exclude; $total = count($pages); for ($i = 0; $i < $total; $i++) { if (in_array($pages[$i]->ID, $excludes)) { unset($pages[$i]); } } } if (!empty($append_page) && !empty($pages)) { $found = false; foreach (array_keys($pages) as $key) { if ($post->post_parent == $pages[$key]->ID) { $found = true; break; } } if (empty($found)) { $pages[] = $append_page; } } // re-index the array, just in case anyone cares $pages = array_values($pages); // === BEGIN Role Scoper MODIFICATION: cache key and flag specific to access type and user/groups // if (!$no_cache) { $cache[$ckey] = $pages; $current_rs_user->cache_set($cache, $cache_flag); } // alternate hook name (WP core already applied get_pages filter) $pages = apply_filters('get_pages_rs', $pages, $r); // // === END Role Scoper MODIFICATION === // ==================================== return $pages; }
function flt_get_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 &build_blog_file_rules() { $new_rules = ''; require_once dirname(__FILE__) . '/analyst_rs.php'; if (!($attachment_results = ScoperAnalyst::identify_protected_attachments())) { return $new_rules; } global $wpdb; require_once dirname(__FILE__) . '/uploads_rs.php'; $home_root = parse_url(get_option('home')); $home_root = trailingslashit($home_root['path']); $uploads = scoper_get_upload_info(); $baseurl = trailingslashit($uploads['baseurl']); $arr_url = parse_url($baseurl); $rewrite_base = $arr_url['path']; $file_keys = array(); $has_postmeta = array(); if ($key_results = scoper_get_results("SELECT pm.meta_value, p.guid, p.ID FROM {$wpdb->postmeta} AS pm INNER JOIN {$wpdb->posts} AS p ON p.ID = pm.post_id WHERE pm.meta_key = '_rs_file_key'")) { foreach ($key_results as $row) { $file_keys[$row->guid] = $row->meta_value; $has_postmeta[$row->ID] = $row->meta_value; } } $new_rules = "<IfModule mod_rewrite.c>\n"; $new_rules .= "RewriteEngine On\n"; $new_rules .= "RewriteBase {$rewrite_base}\n\n"; $main_rewrite_rule = "RewriteRule ^(.*) {$home_root}index.php?attachment=\$1&rs_rewrite=1 [NC,L]\n"; $htaccess_urls = array(); foreach ($attachment_results as $row) { if (false !== strpos($row->guid, $baseurl)) { // no need to include any attachments which are not in the uploads folder if (!empty($file_keys[$row->guid])) { $key = $file_keys[$row->guid]; } else { $key = urlencode(str_replace('.', '', uniqid(strval(rand()), true))); $file_keys[$row->guid] = $key; } if (!isset($has_postmeta[$row->ID]) || $key != $has_postmeta[$row->ID]) { update_post_meta($row->ID, "_rs_file_key", $key); } if (isset($htaccess_urls[$row->guid])) { // if a file is attached to multiple protected posts, use a single rewrite rule for it continue; } $htaccess_urls[$row->guid] = true; $rel_path = str_replace($baseurl, '', $row->guid); // escape spaces $file_path = str_replace(' ', '\\s', $rel_path); // escape horiz tabs (yes, at least one user has them in filenames) $file_path = str_replace(chr(9), '\\t', $file_path); // strip out all other nonprintable characters. Affected files will not be filtered, but we avoid 500 error. Possible TODO: advisory in file attachment utility $file_path = preg_replace('/[\\x00-\\x1f\\x7f]/', '', $file_path); // escape all other regular expression operator characters $file_path = preg_replace('/[\\^\\$\\.\\+\\[\\]\\(\\)\\{\\}]/', '\\\\$0', $file_path); $new_rules .= "RewriteCond %{REQUEST_URI} ^(.*)/{$file_path}" . "\$ [NC]\n"; $new_rules .= "RewriteCond %{QUERY_STRING} !^(.*)rs_file_key={$key}(.*)\n"; $new_rules .= $main_rewrite_rule; if ($pos_ext = strrpos($file_path, '\\.')) { $thumb_path = substr($file_path, 0, $pos_ext); $ext = substr($file_path, $pos_ext + 2); $new_rules .= "RewriteCond %{REQUEST_URI} ^(.*)/{$thumb_path}" . '-[0-9]{2,4}x[0-9]{2,4}\\.' . $ext . "\$ [NC]\n"; $new_rules .= "RewriteCond %{QUERY_STRING} !^(.*)rs_file_key={$key}(.*)\n"; $new_rules .= $main_rewrite_rule; // if resized image file(s) exist, include rules for them $guid_pos_ext = strrpos($rel_path, '.'); $pattern = $uploads['path'] . '/' . substr($rel_path, 0, $guid_pos_ext) . '-??????????????' . substr($rel_path, $guid_pos_ext); if (glob($pattern)) { $new_rules .= "RewriteCond %{REQUEST_URI} ^(.*)/{$thumb_path}" . '-[0-9,a-f]{14}\\.' . $ext . "\$ [NC]\n"; $new_rules .= "RewriteCond %{QUERY_STRING} !^(.*)rs_file_key={$key}(.*)\n"; $new_rules .= $main_rewrite_rule; } } } } // end foreach protected attachment if (IS_MU_RS) { global $blog_id; $file_filtered_sites = (array) get_site_option('scoper_file_filtered_sites'); if (!in_array($blog_id, $file_filtered_sites)) { // this site needs a file redirect rule in root .htaccess scoper_flush_site_rules(); } if (defined('SCOPER_MU_FILE_PROCESSING')) { // unless SCOPER_MU_FILE_PROCESSING is defined (indicating blogs.php has been modified for compatibility), blogs.php processing will be bypassed for all files $content_path = trailingslashit(str_replace($strip_path, '', str_replace('\\', '/', WP_CONTENT_DIR))); $new_rules .= "\n# Default WordPress cache handling\n"; $new_rules .= "RewriteRule ^(.*) {$content_path}blogs.php?file=\$1 [L]\n"; } } $new_rules .= "</IfModule>\n"; return $new_rules; }
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 get_term_roles_daterange($taxonomy = 'category', $role_type = 'rs', $args = array()) { $defaults = array('enforce_duration_limits' => true, 'retrieve_content_date_limits' => true, 'include_role_duration_key' => false, 'no_cache' => false); $args = array_merge($defaults, (array) $args); extract($args); $taxonomy = sanitize_key($taxonomy); global $wpdb; if ($enforce_duration_limits = $enforce_duration_limits && scoper_get_option('role_duration_limits')) { $duration_clause = $enforce_duration_limits ? scoper_get_duration_clause() : ''; $no_cache = $no_cache || strpos($duration_clause, 'start_date_gmt') || strpos($duration_clause, 'end_date_gmt'); } else { $duration_clause = ''; } $no_cache = $no_cache || $include_role_duration_key || !$retrieve_content_date_limits; if (!$no_cache) { $cache_flag = "{$role_type}_term-roles_{$taxonomy}"; // changed cache key from "term_roles" to "term-roles" to prevent retrieval of arrays stored without date_key dimension $tx_term_roles = $this->cache_get($cache_flag); } else { $tx_term_roles = ''; } if (!is_array($tx_term_roles)) { // no need to check for this on cache retrieval, since a role_type change results in a rol_defs change, which triggers a full scoper cache flush $tx_term_roles = array('' => array()); $u_g_clause = $this->get_user_clause('uro'); $extra_cols = $include_role_duration_key ? ", uro.date_limited, uro.start_date_gmt, uro.end_date_gmt" : ''; $qry = "SELECT uro.obj_or_term_id, uro.role_name, uro.assignment_id, uro.content_date_limited, uro.content_min_date_gmt, uro.content_max_date_gmt {$extra_cols} FROM {$wpdb->user2role2object_rs} AS uro "; $qry .= "WHERE uro.scope = 'term' AND uro.assign_for IN ('entity', 'both') AND uro.role_type = 'rs' AND uro.src_or_tx_name = '{$taxonomy}' {$duration_clause} {$u_g_clause}"; if ($results = scoper_get_results($qry)) { foreach ($results as $termrole) { $date_key = $retrieve_content_date_limits && $termrole->content_date_limited ? serialize((object) array('content_min_date_gmt' => $termrole->content_min_date_gmt, 'content_max_date_gmt' => $termrole->content_max_date_gmt)) : ''; $role_handle = 'rs_' . $termrole->role_name; if ($include_role_duration_key) { $role_duration_key = $termrole->date_limited ? serialize((object) array('start_date_gmt' => $termrole->start_date_gmt, 'end_date_gmt' => $termrole->end_date_gmt)) : ''; $tx_term_roles[$role_duration_key][$date_key][$role_handle][] = $termrole->obj_or_term_id; } else { $tx_term_roles[$date_key][$role_handle][] = $termrole->obj_or_term_id; } } } if (!$no_cache) { $this->cache_set($tx_term_roles, $cache_flag); } } if ($retrieve_content_date_limits && !$include_role_duration_key) { // normal usage (only internal call to skip this block is for user profile) $this->assigned_term_roles[$taxonomy] = $tx_term_roles; global $scoper; if (!empty($scoper)) { // this method is only called after Scoper is initialized, but include this sanity check foreach (array_keys($this->assigned_term_roles[$taxonomy]) as $date_key) { // strip out any assignments for roles which are no longer defined (such as Revisionary roles after Revisionary is deactivated) $this->assigned_term_roles[$taxonomy][$date_key] = array_intersect_key($this->assigned_term_roles[$taxonomy][$date_key], $scoper->role_defs->role_caps); $this->term_roles[$taxonomy][$date_key] = $scoper->role_defs->add_contained_term_roles($this->assigned_term_roles[$taxonomy][$date_key]); } // support legacy template code using $current_user->term_roles or $current_user->assigned_term_roles if (!awp_ver('3.3-dev')) { if ($this->ID == $GLOBALS['current_user']->ID) { $GLOBALS['current_user']->assigned_term_roles[$taxonomy] = $this->assigned_term_roles[$taxonomy]; $GLOBALS['current_user']->term_roles[$taxonomy] = $this->term_roles[$taxonomy]; } } } } return $tx_term_roles; }
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 users_who_can($reqd_caps, $cols = COLS_ALL_RS, $object_src_name = '', $object_id = 0, $args = array()) { // if there are not capability requirements, no need to load Users_Interceptor filtering class if (!$reqd_caps) { if (COL_ID_RS == $cols) { $qcols = 'ID'; } elseif (COLS_ID_NAME_RS == $cols) { $qcols = "ID, user_login AS display_name"; } elseif (COLS_ID_DISPLAYNAME_RS == $cols) { $qcols = "ID, display_name"; } elseif (COLS_ALL_RS == $cols) { $qcols = "*"; } else { $qcols = $cols; } global $wpdb; $orderby = $cols == COL_ID_RS ? '' : 'ORDER BY display_name'; if (IS_MU_RS && !scoper_get_option('mu_sitewide_groups') && !defined('FORCE_ALL_SITE_USERS_RS')) { $qry = "SELECT {$qcols} FROM {$wpdb->users} INNER JOIN {$wpdb->usermeta} AS um ON {$wpdb->users}.ID = um.user_id AND um.meta_key = '{$wpdb->prefix}capabilities' {$orderby}"; } else { $qry = "SELECT {$qcols} FROM {$wpdb->users} {$orderby}"; } if (COL_ID_RS == $cols) { return scoper_get_col($qry); } else { return scoper_get_results($qry); } } else { $defaults = array('where' => '', 'orderby' => '', 'disable_memcache' => false, 'group_ids' => '', 'force_refresh' => false, 'force_all_users' => false); $args = array_merge($defaults, (array) $args); extract($args); $cache_flag = "rs_users_who_can"; $cache_id = md5(serialize($reqd_caps) . $cols . 'src' . $object_src_name . 'id' . $object_id . serialize($args)); if (!$force_refresh) { // if we already have the results cached, no need to load Users_Interceptor filtering class $users = wpp_cache_get($cache_id, $cache_flag); if (is_array($users)) { return $users; } } $this->init_users_interceptor(); $users = $GLOBALS['users_interceptor']->users_who_can($reqd_caps, $cols, $object_src_name, $object_id, $args); wpp_cache_set($cache_id, $users, $cache_flag); return $users; } }
function identify_protected_posts($attachment_id = 0, $attachments = false, $cols = '', $args = array()) { $defaults = array('use_object_restrictions' => true, 'use_term_restrictions' => true, 'use_private_status' => true, 'guid' => ''); $args = array_merge($defaults, (array) $args); extract($args); global $wpdb, $scoper; if (!isset($scoper) || is_null($scoper)) { scoper_get_init_options(); scoper_init(); } if (empty($scoper->taxonomies)) { $scoper->load_config(); } $restricted_roles = array(); $unrestricted_roles = array(); // TODO: also protect uploads based on restriction of other taxonomies $restricted_terms = array(); $restricted_objects = array(); $term_restriction_clause = ''; $object_restriction_clause = ''; $limit_clause = ''; $unattached_clause = ''; global $scoper; $reader_roles = array(); foreach ($scoper->role_defs->role_caps as $role_handle => $role_caps) { $caps_by_op = $scoper->cap_defs->organize_caps_by_op(array_keys($role_caps)); if (count($caps_by_op) == 1 && 'read' == key($caps_by_op)) { $reader_roles[] = $role_handle; } } $role_clause = "AND rs.role_name IN ('" . implode("','", scoper_role_handles_to_names($reader_roles)) . "')"; //if ( $use_private_status ) // $role_clause = ( 'rs' == SCOPER_ROLE_TYPE ) ? "AND rs.role_name IN ('post_reader', 'page_reader')" : ''; // if also checking for private status, don't need to check for restriction of private_reader roles //else // $role_clause = ( 'rs' == SCOPER_ROLE_TYPE ) ? "AND rs.role_name IN ('post_reader', 'page_reader', 'private_post_reader', 'private_page_reader')" : ''; if ($use_term_restrictions) { $term_restriction_query = "SELECT rs.obj_or_term_id AS term_id, rs.role_name, rs.max_scope FROM {$wpdb->role_scope_rs} AS rs " . "INNER JOIN {$wpdb->term_taxonomy} AS tt ON tt.taxonomy = rs.src_or_tx_name AND tt.taxonomy = 'category' AND tt.term_taxonomy_id = rs.obj_or_term_id " . "WHERE rs.role_type = 'rs' AND rs.require_for IN ('entity', 'both') AND rs.topic = 'term' {$role_clause}"; $term_default_restriction_query = "SELECT rs.role_name FROM {$wpdb->role_scope_rs} AS rs " . "WHERE rs.role_type = 'rs' AND rs.require_for IN ('children', 'both') AND rs.topic = 'term' AND rs.max_scope = 'term' AND rs.src_or_tx_name = 'category' AND rs.obj_or_term_id = '0' {$role_clause}"; $all_terms = array(); $all_terms['category'] = $scoper->get_terms('category', false, COL_ID_RS); if ($results = scoper_get_results($term_restriction_query)) { foreach ($results as $row) { if ('blog' == $row->max_scope) { $unrestricted_roles['category'][$row->role_name][] = $row->term_id; } else { $restricted_roles['category'][$row->role_name][] = $row->term_id; } } } // if there a role is default-restricted, mark all terms as restricted (may be unrestricted later) if ($results = scoper_get_col($term_default_restriction_query)) { foreach ($results as $role_name) { if (isset($unrestricted_roles['category'][$role_name])) { $default_restricted = array_diff($all_terms['category'], $unrestricted_roles['category'][$role_name]); } else { $default_restricted = $all_terms['category']; } if (isset($restricted_roles['category'][$role_name])) { $restricted_roles['category'][$role_name] = array_unique(array_merge($restricted_roles['category'][$role_name], $default_restricted)); } else { $restricted_roles['category'][$role_name] = $default_restricted; } } } $restricted_terms['category'] = isset($restricted_roles['category']) ? agp_array_flatten($restricted_roles['category']) : array(); if ($restricted_terms['category']) { $term_restriction_clause = "OR post_parent IN ( SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} " . "INNER JOIN {$wpdb->term_relationships} AS tr ON tr.object_id = {$wpdb->posts}.ID " . "WHERE tr.term_taxonomy_id IN ('" . implode("','", $restricted_terms['category']) . "') )"; } } if ($attachment_id) { if (is_array($attachment_id)) { $id_clause = "AND ID IN ('" . implode("','", $attachment_id) . "')"; } else { $id_clause = "AND ID = '{$attachment_id}'"; $limit_clause = 'LIMIT 1'; } } elseif ($guid) { $id_clause = "AND guid = '{$file_path}'"; } else { $id_clause = ''; } if (defined('SCOPER_NO_THUMBNAIL_FILTER')) { if ($thumbnail_ids = scoper_get_col("SELECT DISTINCT meta_value FROM {$wpdb->postmeta} WHERE meta_key = '_thumbnail_id'")) { $id_clause .= " AND ID NOT IN ('" . implode("','", $thumbnail_ids) . "')"; } } if ($attachments) { // to reduce pool of objects, we only care about those that have an attachment $attachment_query = "SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} WHERE {$wpdb->posts}.ID IN ( SELECT post_parent FROM {$wpdb->posts} WHERE post_type = 'attachment' {$id_clause} ) "; } if ($use_object_restrictions) { $object_restriction_query = "SELECT rs.obj_or_term_id AS obj_id, rs.role_name, rs.max_scope FROM {$wpdb->role_scope_rs} AS rs " . "WHERE rs.role_type = 'rs' AND rs.require_for IN ('entity', 'both') AND rs.topic = 'object' AND rs.src_or_tx_name = 'post' {$role_clause} AND rs.obj_or_term_id IN ( {$attachment_query} )"; $object_default_restriction_query = "SELECT rs.role_name FROM {$wpdb->role_scope_rs} AS rs " . "WHERE rs.require_for IN ('children', 'both') AND rs.topic = 'object' AND rs.max_scope = 'object' AND rs.src_or_tx_name = 'post' AND rs.obj_or_term_id = '0' {$role_clause}"; $all_objects = array(); $all_objects['post'] = scoper_get_col($attachment_query); $restricted_roles = array(); $unrestricted_roles = array(); if ($results = scoper_get_results($object_restriction_query)) { foreach ($results as $row) { if ('blog' == $row->max_scope) { $unrestricted_roles['post'][$row->role_name][] = $row->obj_id; } else { $restricted_roles['post'][$row->role_name][] = $row->obj_id; } } } // if there a role is default-restricted, mark all terms as restricted (may be unrestricted later) if ($results = scoper_get_col($object_default_restriction_query)) { foreach ($results as $role_name) { if (isset($unrestricted_roles['category'][$role_name])) { $default_restricted = array_diff($all_terms['post'], $unrestricted_roles['post'][$role_name]); } else { $default_restricted = $all_objects['post']; } if (isset($restricted_roles['post'][$role_name])) { $restricted_roles['post'][$role_name] = array_unique(array_merge($restricted_roles['post'][$role_name], $default_restricted)); } else { $restricted_roles['post'][$role_name] = $default_restricted; } } } if (!empty($restricted_roles)) { $restricted_objects['post'] = array_unique(agp_array_flatten($restricted_roles['post'])); if ($restricted_objects['post']) { $object_restriction_clause = "OR post_parent IN ( SELECT ID FROM {$wpdb->posts} WHERE ID IN ('" . implode("','", $restricted_objects['post']) . "') )"; } } } if ($use_private_status) { $status_query = "AND post_parent IN ( SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} WHERE {$wpdb->posts}.post_status = 'private' )"; } if ($attachments) { $attachment_type_clause = "post_type = 'attachment' AND"; $unattached_clause = defined('SCOPER_BLOCK_UNATTACHED_UPLOADS') ? " OR post_parent < 1" : ''; } $single_col = false; if (COLS_ALL_RS === $cols) { $query_cols = '*'; } elseif (COL_ID_RS == $cols) { $query_cols = 'ID'; $single_col = true; } elseif (COLS_ID_DISPLAYNAME_RS == $cols) { if ($attachment) { $query_cols = 'ID, post_title, guid'; } else { $query_cols = 'ID, post_title'; } } else { if ($attachments) { $query_cols = 'ID, guid'; } else { $query_cols = 'ID'; $single_col = true; } } $query = "SELECT {$query_cols} FROM {$wpdb->posts} WHERE {$attachment_type_clause} ( 1=1 {$status_query} {$term_restriction_clause} {$object_restriction_clause} {$unattached_clause} ) {$id_clause} ORDER BY ID DESC {$limit_clause}"; if ($attachment_id && !is_array($attachment_id)) { if ($single_col) { $results = scoper_get_var($query); } else { $results = scoper_get_row($query); } } else { if ($single_col) { $results = scoper_get_col($query); } else { $results = scoper_get_results($query); } } return $results; }
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; } }