PageRenderTime 52ms CodeModel.GetById 9ms RepoModel.GetById 0ms app.codeStats 1ms

/role-scoper/role-scoper_main.php

https://github.com/adityag2/suneha
PHP | 1105 lines | 737 code | 259 blank | 109 comment | 256 complexity | dede4713aaf221bcb4f3077d5d1c1683 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause
  1. <?php
  2. if( basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME']) )
  3. die( 'This page cannot be called directly.' );
  4. /**
  5. * Scoper PHP class for the WordPress plugin Role Scoper
  6. * role-scoper_main.php
  7. *
  8. * @author Kevin Behrens
  9. * @copyright Copyright 2012
  10. *
  11. */
  12. class Scoper
  13. {
  14. var $definitions;
  15. var $access_types;
  16. var $data_sources;
  17. var $taxonomies;
  18. var $cap_defs;
  19. var $role_defs;
  20. var $cap_interceptor; // legacy API
  21. // === Temporary status variables ===
  22. var $direct_file_access;
  23. var $listed_ids = array(); // $listed_ids[src_name][object_id] = true : general purpose memory cache for non-post data sources; primary use is with has_cap filter to avoid a separate db query for each listed item
  24. var $default_restrictions = array();
  25. // minimal config retrieval to support pre-init usage by WP_Scoped_User before text domain is loaded
  26. function Scoper() {
  27. $this->definitions = array( 'data_sources' => 'Data_Sources', 'taxonomies' => 'Taxonomies', 'cap_defs' => 'Capabilities', 'role_defs' => 'Roles' );
  28. require_once( dirname(__FILE__).'/definitions_cr.php' );
  29. if ( defined( 'RVY_VERSION' ) )
  30. $this->cap_interceptor = (object) array(); // legacy support for Revisionary < 1.1 which set flags on this object property
  31. }
  32. function load_config() {
  33. require_once( dirname(__FILE__).'/lib/agapetry_config_items.php');
  34. $this->access_types = new AGP_Config_Items();
  35. $this->access_types->init( cr_access_types() ); // 'front' and 'admin' are the hardcoded access types
  36. // establish access type for this http request
  37. $access_name = ( is_admin() || defined('XMLRPC_REQUEST') ) ? 'admin' : 'front';
  38. $access_name = apply_filters( 'scoper_access_name', $access_name ); // others plugins can apply additional criteria for treating a particular URL with wp-admin or front-end filtering
  39. if ( ! defined('CURRENT_ACCESS_NAME_RS') )
  40. define('CURRENT_ACCESS_NAME_RS', $access_name);
  41. // disable RS filtering of access type(s) if specified in realm options
  42. if ( ! is_admin() || ! defined('SCOPER_REALM_ADMIN_RS') ) { // don't remove items if the option is being editied
  43. if ( $disabled_access_types = scoper_get_option('disabled_access_types') )
  44. $this->access_types->remove_members_by_key($disabled_access_types, true);
  45. // If the detected access type (admin, front or custom) was "disabled", it is still detected, but we note that query filters should not be applied
  46. if ( ! $this->access_types->is_member($access_name) )
  47. define('DISABLE_QUERYFILTERS_RS', true);
  48. }
  49. // populate data_sources, taxonomies, cap_defs, role_defs arrays
  50. foreach( array_keys($this->definitions) as $topic )
  51. $this->load_definition( $topic );
  52. foreach( array_keys($this->definitions) as $topic )
  53. $this->$topic->lock();
  54. // clean up after 3rd party plugins (such as Role Scoping for NGG) which don't set object type and src_name properties for roles
  55. if ( has_filter( 'define_roles_rs' ) ) {
  56. require_once( dirname(__FILE__).'/extension-helper_rs.php' );
  57. scoper_adjust_legacy_extension_cfg( $this->role_defs, $this->cap_defs );
  58. }
  59. add_action( 'set_current_user', array( &$this, 'credit_blogroles' ) );
  60. $this->credit_blogroles();
  61. do_action('config_loaded_rs');
  62. }
  63. function credit_blogroles() {
  64. // credit non-logged and "no role" users for any anonymous roles
  65. global $current_rs_user;
  66. if ( $current_rs_user ) {
  67. if ( empty($current_rs_user->ID) ) {
  68. foreach ( $this->role_defs->filter_keys( -1, array( 'anon_user_blogrole' => true ) ) as $role_handle) {
  69. $current_rs_user->assigned_blog_roles[ANY_CONTENT_DATE_RS][$role_handle] = true;
  70. $current_rs_user->blog_roles[ANY_CONTENT_DATE_RS][$role_handle] = true;
  71. }
  72. }
  73. if ( isset($current_rs_user->assigned_blog_roles) )
  74. $this->refresh_blogroles();
  75. }
  76. }
  77. function refresh_blogroles() {
  78. global $current_rs_user;
  79. if ( empty($current_rs_user) )
  80. return;
  81. $current_rs_user->merge_scoped_blogcaps();
  82. $GLOBALS['current_user']->allcaps = array_merge( $GLOBALS['current_user']->allcaps, $current_rs_user->allcaps );
  83. if ( empty($GLOBALS['current_user']->data) )
  84. $GLOBALS['current_user']->data = (object) array();
  85. foreach( array( 'groups', 'blog_roles', 'assigned_blog_roles' ) as $var ) {
  86. if ( isset($current_rs_user->$var) )
  87. $GLOBALS['current_user']->$var = $current_rs_user->$var;
  88. }
  89. if ( $current_rs_user->ID || defined( 'SCOPER_ANON_METAGROUP' ) ) {
  90. foreach ( array_keys($current_rs_user->assigned_blog_roles) as $date_key )
  91. $current_rs_user->blog_roles[$date_key] = $this->role_defs->add_contained_roles( $current_rs_user->assigned_blog_roles[$date_key] );
  92. }
  93. }
  94. function load_definition( $topic ) {
  95. $class_name = "CR_" . $this->definitions[$topic];
  96. require_once( strtolower($this->definitions[$topic]) . '_rs.php' );
  97. $filter_name = "define_" . strtolower($this->definitions[$topic]) . "_rs";
  98. $this->$topic = apply_filters( $filter_name, new $class_name( call_user_func("cr_{$topic}") ) );
  99. if ( 'role_defs' == $topic ) {
  100. $this->role_defs->role_caps = apply_filters('define_role_caps_rs', cr_role_caps() );
  101. if ( $user_role_caps = scoper_get_option( 'user_role_caps' ) )
  102. $this->role_defs->add_role_caps( $user_role_caps );
  103. $this->log_cap_usage( $this->role_defs, $this->cap_defs ); // add any otype associations from new user_role_caps, but don't remove an otype association due to disabled_role_caps
  104. if ( $disabled_role_caps = scoper_get_option( 'disabled_role_caps' ) )
  105. $this->role_defs->remove_role_caps( $disabled_role_caps );
  106. $this->role_defs->remove_invalid(); // currently don't allow additional custom-defined post, page or link roles
  107. $this->customize_role_objscope();
  108. // To support merging in of WP role assignments, always note actual WP-defined roles
  109. // regardless of which role type we are scoping with.
  110. $this->log_wp_roles( $this->role_defs );
  111. }
  112. }
  113. function log_cap_usage( &$role_defs, &$cap_defs ) {
  114. foreach( $role_defs->members as $role_handle => $role_def ) {
  115. foreach( array_keys( $role_defs->role_caps[$role_handle] ) as $cap_name ) {
  116. if ( empty( $cap_defs->members[$cap_name]->object_types ) || ! in_array( $role_def->object_type, $cap_defs->members[$cap_name]->object_types ) ) {
  117. if ( 'post' == $role_def->src_name )
  118. $cap_defs->members[$cap_name]->object_types[] = $role_def->object_type;
  119. elseif ( in_array( $role_def->src_name, array( 'link', 'group' ) ) ) // TODO: other data sources?
  120. $cap_defs->members[$cap_name]->object_types[] = $role_def->src_name;
  121. }
  122. }
  123. }
  124. }
  125. function customize_role_objscope() {
  126. foreach ( $this->role_defs->get_all_keys() as $role_handle ) {
  127. if ( ! empty($this->role_defs->members[$role_handle]->objscope_equivalents) ) {
  128. foreach( $this->role_defs->members[$role_handle]->objscope_equivalents as $equiv_key => $equiv_role_handle ) {
  129. if ( scoper_get_option( "{$equiv_role_handle}_role_objscope" ) ) { // If "Additional Object Role" option is set for this role, treat it as a regular direct-assigned Object Role
  130. if ( isset($this->role_defs->members[$equiv_role_handle]->valid_scopes) )
  131. $this->role_defs->members[$equiv_role_handle]->valid_scopes = array('blog' => 1, 'term' => 1, 'object' => 1);
  132. unset( $this->role_defs->members[$role_handle]->objscope_equivalents[$equiv_key] );
  133. if ( ! defined( 'DISABLE_OBJSCOPE_EQUIV_' . $role_handle ) )
  134. define( 'DISABLE_OBJSCOPE_EQUIV_' . $role_handle, true ); // prevent Role Caption / Abbrev from being substituted from equivalent role
  135. }
  136. }
  137. }
  138. }
  139. }
  140. function log_wp_roles( &$role_defs ) {
  141. global $wp_roles;
  142. if ( ! isset($wp_roles) )
  143. $wp_roles = new WP_Roles();
  144. // populate WP roles least-role-first to match RS roles
  145. $keys = array_keys($wp_roles->role_objects);
  146. $keys = array_reverse($keys);
  147. $cr_cap_names = $this->cap_defs->get_all_keys();
  148. $last_lock = $role_defs->locked;
  149. $role_defs->locked = false;
  150. foreach ( $keys as $role_name ) {
  151. if ( ! empty( $wp_roles->role_objects[$role_name]->capabilities ) ) {
  152. // remove any WP caps which are in array, but have value = false
  153. if ( $caps = array_intersect( $wp_roles->role_objects[$role_name]->capabilities, array(true) ) )
  154. $caps = array_intersect_key( $caps, array_flip($cr_cap_names) ); // we only care about WP caps that are RS-defined
  155. } else
  156. $caps = array();
  157. $role_defs->add( $role_name, 'wordpress', '', '', 'wp' );
  158. // temp hardcode for site-wide Nav Menu cap
  159. if ( ! empty( $caps['edit_theme_options'] ) )
  160. $caps['manage_nav_menus'] = true;
  161. $role_defs->role_caps['wp_' . $role_name] = $caps;
  162. }
  163. $role_defs->locked = $last_lock;
  164. }
  165. function init() {
  166. scoper_version_check();
  167. if ( ! isset($this->data_sources) )
  168. $this->load_config();
  169. $is_administrator = is_content_administrator_rs();
  170. if ( $doing_cron = defined('DOING_CRON') )
  171. if ( ! defined('DISABLE_QUERYFILTERS_RS') )
  172. define('DISABLE_QUERYFILTERS_RS', true);
  173. if ( ! $this->direct_file_access = strpos($_SERVER['QUERY_STRING'], 'rs_rewrite') )
  174. $this->add_main_filters();
  175. // ===== Special early exit if this is a plugin install script
  176. if ( is_admin() ) {
  177. if ( in_array( $GLOBALS['pagenow'], array( 'plugin-install.php', 'plugin-editor.php' ) ) ) {
  178. // flush RS cache on activation of any plugin, in case we cached results based on its presence / absence
  179. if ( ( ! empty($_POST) ) || ( ! empty($_REQUEST['action']) ) ) {
  180. if ( ! empty($_POST['networkwide']) || ( 'plugin-editor.php' == $GLOBALS['pagenow'] ) )
  181. wpp_cache_flush_all_sites();
  182. else
  183. wpp_cache_flush();
  184. }
  185. do_action( 'scoper_init' );
  186. return; // no further filtering on WP plugin maintenance scripts
  187. }
  188. }
  189. // =====
  190. require_once( dirname(__FILE__).'/attachment-interceptor_rs.php');
  191. $GLOBALS['attachment_interceptor'] = new AttachmentInterceptor_RS(); // .htaccess file is always there, so we always need to handle its rewrites
  192. // ===== Content Filters to limit/enable the current user
  193. $disable_queryfilters = defined('DISABLE_QUERYFILTERS_RS');
  194. if ( $disable_queryfilters ) {
  195. // Some wp-admin pages need to list pages or categories based on front-end access. Classic example is Subscribe2 categories checklist, included in Subscriber profile
  196. // In that case, filtering will be applied even if wp-admin filtering is disabled. API hook enables other plugins to defined their own "always filter" URIs.
  197. $always_filter_uris = apply_filters( 'scoper_always_filter_uris', array( 'p-admin/profile.php' ) );
  198. if ( in_array( $GLOBALS['pagenow'], $always_filter_uris ) || in_array( $GLOBALS['plugin_page_cr'], $always_filter_uris ) ) {
  199. $disable_queryfilters = false;
  200. break;
  201. }
  202. }
  203. // register a map_meta_cap filter to handle the type-specific meta caps we are forcing
  204. require_once( dirname(__FILE__).'/meta_caps_rs.php' );
  205. if ( ! $disable_queryfilters ) {
  206. if ( ! $is_administrator ) {
  207. if ( $this->direct_file_access ) {
  208. require_once( dirname(__FILE__).'/cap-interceptor-basic_rs.php'); // only need to support basic read_post / read_page check for direct file access
  209. $GLOBALS['cap_interceptor_basic'] = new CapInterceptorBasic_RS();
  210. } else {
  211. require_once( dirname(__FILE__).'/cap-interceptor_rs.php');
  212. $GLOBALS['cap_interceptor'] = new CapInterceptor_RS();
  213. }
  214. }
  215. // (also use content filters on front end to FILTER IN private content which WP inappropriately hides from administrators)
  216. if ( ( ! $is_administrator ) || $this->is_front() ) {
  217. require_once( dirname(__FILE__).'/query-interceptor_rs.php');
  218. $GLOBALS['query_interceptor'] = new QueryInterceptor_RS();
  219. }
  220. if ( ( ! $this->direct_file_access ) && ( ! $is_administrator || ! defined('XMLRPC_REQUEST') ) ) { // don't tempt trouble by adding hardway filters on XMLRPC for logged administrator
  221. $this->add_hardway_filters();
  222. if ( $this->is_front() || ! $is_administrator ) {
  223. require_once( dirname(__FILE__).'/terms-query-lib_rs.php');
  224. if ( awp_ver( '3.1' ) && ! defined( 'SCOPER_LEGACY_TERMS_FILTER' ) ) {
  225. require_once( dirname(__FILE__).'/terms-interceptor_rs.php');
  226. $GLOBALS['terms_interceptor'] = new TermsInterceptor_RS();
  227. } else
  228. require_once( dirname(__FILE__).'/hardway/hardway-taxonomy-legacy_rs.php');
  229. }
  230. }
  231. } // endif query filtering not disabled for this access type
  232. if ( $is_administrator ) {
  233. if ( $this->is_front() )
  234. require_once( 'comments-int-administrator_rs.php' );
  235. } else
  236. require_once( 'comments-interceptor_rs.php' );
  237. if ( is_admin() )
  238. $this->add_admin_ui_filters( $is_administrator );
  239. do_action( 'scoper_init' );
  240. // ===== end Content Filters
  241. } // end function init
  242. // filters which are only needed for the wp-admin UI
  243. function add_admin_ui_filters( $is_administrator ) {
  244. global $pagenow;
  245. // ===== Admin filters (menu and other basics) which are (almost) always loaded
  246. require_once( dirname(__FILE__).'/admin/admin_rs.php');
  247. $GLOBALS['scoper_admin'] = new ScoperAdmin();
  248. if ( 'async-upload.php' != $pagenow ) {
  249. if ( ! defined('DISABLE_QUERYFILTERS_RS') || $is_administrator ) {
  250. require_once( dirname(__FILE__).'/admin/filters-admin-ui_rs.php' );
  251. $GLOBALS['scoper_admin_filters_ui'] = new ScoperAdminFiltersUI();
  252. }
  253. }
  254. // =====
  255. // ===== Script-specific Admin filters
  256. if ( 'users.php' == $pagenow ) {
  257. require_once( dirname(__FILE__).'/admin/filters-admin-users_rs.php' );
  258. } elseif ( 'edit.php' == $pagenow ) {
  259. if ( ! defined('DISABLE_QUERYFILTERS_RS') || $is_administrator )
  260. require_once( dirname(__FILE__).'/admin/filters-admin-ui-listing_rs.php' );
  261. } elseif ( in_array( $pagenow, array( 'edit-tags.php', 'edit-link-categories.php' ) ) ) {
  262. if ( ! defined('DISABLE_QUERYFILTERS_RS') )
  263. require_once( dirname(__FILE__).'/admin/filters-admin-terms_rs.php' );
  264. }
  265. // =====
  266. if ( scoper_get_option( 'group_ajax' ) && ( isset( $_GET['rs_user_search'] ) || isset( $_GET['rs_group_search'] ) ) ) {
  267. require_once( dirname(__FILE__).'/admin/user_query_rs.php' );
  268. exit;
  269. }
  270. }
  271. function add_hardway_filters() {
  272. // port or low-level query filters to work around limitations in WP core API
  273. require_once( dirname(__FILE__).'/hardway/hardway_rs.php'); // need get_pages() filtering to include private pages for some 3rd party plugin config UI (Simple Section Nav)
  274. // buffering of taxonomy children is disabled with non-admin user logged in
  275. // But that non-admin user may add cats. Don't allow unfiltered admin to rely on an old copy of children
  276. global $wp_taxonomies;
  277. if ( ! empty($wp_taxonomies) ) {
  278. foreach ( array_keys($wp_taxonomies) as $taxonomy )
  279. add_filter ( "option_{$taxonomy}_children", create_function( '$option_value', "return rs_get_terms_children('$taxonomy', " . '$option_value );') );
  280. //add_filter("option_{$taxonomy}_children", create_function( '', "return rs_get_terms_children('$taxonomy');") );
  281. }
  282. if ( is_admin() || defined('XMLRPC_REQUEST') ) {
  283. global $pagenow;
  284. if ( ! in_array( $pagenow, array( 'plugin-editor.php', 'plugins.php' ) ) ) {
  285. global $plugin_page_cr;
  286. // low-level filtering for miscellaneous admin operations which are not well supported by the WP API
  287. $hardway_uris = array(
  288. 'index.php', 'revision.php', 'admin.php?page=rvy-revisions',
  289. 'post.php', 'post-new.php', 'edit.php',
  290. 'upload.php', 'edit-comments.php', 'edit-tags.php',
  291. 'profile.php', 'admin-ajax.php',
  292. 'link-manager.php', 'link-add.php', 'link.php',
  293. 'edit-link-category.php', 'edit-link-categories.php',
  294. 'media-upload.php', 'nav-menus.php'
  295. );
  296. $hardway_uris = apply_filters( 'scoper_admin_hardway_uris', $hardway_uris );
  297. // support for rs-config-ngg <= 1.0
  298. if ( defined('XMLRPC_REQUEST') || in_array( $pagenow, $hardway_uris ) || in_array( $plugin_page_cr, $hardway_uris ) || in_array( "p-admin/admin.php?page=$plugin_page_cr", $hardway_uris ) )
  299. require_once( dirname(__FILE__).'/hardway/hardway-admin_rs.php' );
  300. }
  301. } // endif is_admin or xmlrpc
  302. }
  303. // add filters which were skipped due to direct file access, but are now needed for the error page display
  304. function add_main_filters() {
  305. $is_admin = is_admin();
  306. $is_administrator = is_content_administrator_rs();
  307. $disable_queryfilters = defined('DISABLE_QUERYFILTERS_RS');
  308. $frontend_admin = false;
  309. if ( ! defined('DOING_CRON') ) {
  310. if ( $this->is_front() ) {
  311. if ( ! $disable_queryfilters )
  312. require_once( dirname(__FILE__).'/query-interceptor-front_rs.php');
  313. if ( ! $is_administrator ) {
  314. require_once( dirname(__FILE__).'/qry-front_non-administrator_rs.php');
  315. $GLOBALS['feed_interceptor'] = new FeedInterceptor_RS(); // file already required in role-scoper.php
  316. }
  317. require_once( dirname(__FILE__).'/template-interceptor_rs.php');
  318. $GLOBALS['template_interceptor'] = new TemplateInterceptor_RS();
  319. $frontend_admin = ! scoper_get_option('no_frontend_admin'); // potential performance enhancement
  320. if ( ! empty($_REQUEST['s']) && function_exists('relevanssi_query') ) {
  321. require_once( dirname(__FILE__).'/relevanssi-helper-front_rs.php' );
  322. $rel_helper_rs = new Relevanssi_Search_Filter_RS();
  323. }
  324. }
  325. // ===== Filters which are always loaded (except on plugin scripts), for any access type
  326. include_once( dirname(__FILE__).'/hardway/wp-patches_agp.php' ); // simple patches for WP
  327. if ( $this->is_front() || ( 'edit.php' == $GLOBALS['pagenow'] ) ) {
  328. require_once( dirname(__FILE__).'/query-interceptor-base_rs.php');
  329. $GLOBALS['query_interceptor_base'] = new QueryInterceptorBase_RS(); // listing filter used for role status indication in edit posts/pages and on front end by template functions
  330. }
  331. }
  332. // ===== Filters which support automated role maintenance following content creation/update
  333. // Require an explicitly set option to skip these for front end access, just in case other plugins modify content from the front end.
  334. if ( ( $is_admin || defined('XMLRPC_REQUEST') || $frontend_admin || defined('DOING_CRON') ) ) {
  335. require_once( dirname(__FILE__).'/admin/cache_flush_rs.php' );
  336. require_once( dirname(__FILE__).'/admin/filters-admin_rs.php' );
  337. $GLOBALS['scoper_admin_filters'] = new ScoperAdminFilters();
  338. if ( defined( 'RVY_VERSION' ) ) // Support Revisionary references to $scoper->filters_admin (TODO: eventually phase this out)
  339. $this->filters_admin =& $GLOBALS['scoper_admin_filters'];
  340. }
  341. // =====
  342. }
  343. function init_users_interceptor() {
  344. if ( ! isset($GLOBALS['users_interceptor']) ) {
  345. require_once( dirname(__FILE__).'/users-interceptor_rs.php');
  346. $GLOBALS['users_interceptor'] = new UsersInterceptor_RS();
  347. //log_mem_usage_rs( 'init Users Interceptor' );
  348. }
  349. return $GLOBALS['users_interceptor'];
  350. }
  351. // Primarily for internal use. Drops some features of WP core get_terms while adding the following versatility:
  352. // - supports any RS-defined taxonomy, with or without WP taxonomy schema
  353. // - optionally return term_id OR term_taxonomy_id as single column
  354. // - specify filtered or unfiltered via argument
  355. // - optionally get terms for a specific object
  356. // - option to order by term hierarchy (but structure as flat array)
  357. function get_terms($taxonomy, $filtering = true, $cols = COLS_ALL_RS, $object_id = 0, $args = array()) {
  358. if ( ! $tx = $this->taxonomies->get($taxonomy) )
  359. return array();
  360. global $wpdb;
  361. $defaults = array( 'order_by' => '', 'use_object_roles' => false, 'operation' => '' ); // IMPORTANT to default operation to nullstring
  362. $args = array_merge( $defaults, (array) $args );
  363. extract($args);
  364. if ( is_administrator_rs( $this->taxonomies->member_property( $taxonomy, 'object_source' ) ) )
  365. $filtering = false;
  366. // try to pull it out of wpcache
  367. $ckey = md5( $taxonomy . $cols . $object_id . serialize($args) . $order_by );
  368. if ( $filtering ) {
  369. $src_name = $this->taxonomies->member_property($taxonomy, 'object_source', 'name');
  370. $args['reqd_caps_by_otype'] = $this->get_terms_reqd_caps( $taxonomy, $operation, ADMIN_TERMS_FILTER_RS === $filtering );
  371. $ckey = md5( $ckey . serialize($args['reqd_caps_by_otype']) ); ; // can vary based on request URI
  372. global $current_rs_user;
  373. $cache_flag = 'rs_scoper_get_terms';
  374. $cache = $current_rs_user->cache_get($cache_flag);
  375. } else {
  376. $cache_flag = "all_terms";
  377. $cache_id = 'all';
  378. $cache = wpp_cache_get( $cache_id, $cache_flag );
  379. }
  380. if ( isset( $cache[ $ckey ] ) ) {
  381. return $cache[ $ckey ];
  382. }
  383. // call base class method to build query
  384. $terms_only = ( ! $filtering || empty($use_object_roles) );
  385. $query_base = $this->taxonomies->get_terms_query($taxonomy, $cols, $object_id, $terms_only );
  386. if ( ! $query_base )
  387. return array();
  388. $query = ( $filtering ) ? apply_filters('terms_request_rs', $query_base, $taxonomy, $args) : $query_base;
  389. // avoid sending alarms to SQL purists if this query was not modified by RS filter
  390. if ( $query_base == $query )
  391. $query = str_replace( 'WHERE 1=1 AND', 'WHERE', $query );
  392. if ( COL_ID_RS == $cols )
  393. $results = scoper_get_col($query);
  394. elseif ( COL_COUNT_RS == $cols )
  395. $results = intval( scoper_get_var($query) );
  396. else {
  397. // TODO: why is this still causing an extra (and costly) scoped query?
  398. /*
  399. // for COLS_ALL query, need to call core get_terms call in case another plugin is translating term names
  400. if ( has_filter( 'get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms') ) ) {
  401. remove_filter( 'get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 1, 3 );
  402. $all_terms = get_terms($taxonomy);
  403. add_filter( 'get_terms', array('ScoperHardwayTaxonomy', 'flt_get_terms'), 1, 3 );
  404. $term_names = scoper_get_property_array( $all_terms, 'term_id', 'name' );
  405. }
  406. */
  407. $results = scoper_get_results($query);
  408. //scoper_restore_property_array( $results, $term_names, 'term_id', 'name' );
  409. if ( ORDERBY_HIERARCHY_RS == $order_by ) {
  410. require_once( dirname(__FILE__).'/admin/admin_lib_rs.php');
  411. if ( $src = $this->data_sources->get( $tx->source ) ) {
  412. if ( ! empty($src->cols->id) && ! empty($src->cols->parent) ) {
  413. require_once( dirname(__FILE__).'/admin/admin_lib-bulk-parent_rs.php');
  414. $results = ScoperAdminBulkParent::order_by_hierarchy($results, $src->cols->id, $src->cols->parent);
  415. }
  416. }
  417. }
  418. }
  419. $cache[ $ckey ] = $results;
  420. if ( $results || empty( $_POST ) ) { // todo: why do we get an empty array for unfiltered request for object terms early in POST processing? (on submission of a new post by a contributor)
  421. if ( $filtering )
  422. $current_rs_user->cache_force_set( $cache, $cache_flag );
  423. else
  424. wpp_cache_force_set( $cache_id, $cache, $cache_flag );
  425. }
  426. return $results;
  427. }
  428. function get_default_restrictions($scope, $args = array()) {
  429. $defaults = array( 'force_refresh' => false );
  430. $args = array_merge( $defaults, (array) $args );
  431. extract($args);
  432. if ( isset($this->default_restrictions[$scope]) && ! $force_refresh )
  433. return $this->default_restrictions[$scope];
  434. if ( empty($force_refresh) ) {
  435. $cache_flag = "rs_{$scope}_def_restrictions";
  436. $cache_id = md5(''); // maintain default id generation from previous versions
  437. $default_strict = wpp_cache_get($cache_id, $cache_flag);
  438. }
  439. if ( $force_refresh || ! is_array($default_strict) ) {
  440. global $wpdb;
  441. $qry = "SELECT src_or_tx_name, role_name FROM $wpdb->role_scope_rs WHERE role_type = 'rs' AND topic = '$scope' AND max_scope = '$scope' AND obj_or_term_id = '0'";
  442. $default_strict = array();
  443. if ( $results = scoper_get_results($qry) ) {
  444. foreach ( $results as $row ) {
  445. $role_handle = scoper_get_role_handle($row->role_name, 'rs');
  446. $default_strict[$row->src_or_tx_name][$role_handle] = true;
  447. if (OBJECT_SCOPE_RS == $scope) {
  448. if ( $objscope_equivalents = $this->role_defs->member_property($role_handle, 'objscope_equivalents') )
  449. foreach ( $objscope_equivalents as $equiv_role_handle )
  450. $default_strict[$row->src_or_tx_name][$equiv_role_handle] = true;
  451. }
  452. }
  453. }
  454. }
  455. $this->default_restrictions[$scope] = $default_strict;
  456. wpp_cache_set($cache_id, $default_strict, $cache_flag);
  457. return $default_strict;
  458. }
  459. // for any given role requirement, a strict term is one which won't blend in blog role assignments
  460. // (i.e. a term which requires the specified role to be assigned as a term role or object role)
  461. //
  462. // returns $arr['restrictions'][role_handle][obj_or_term_id] = array( 'assign_for' => $row->assign_for, 'inherited_from' => $row->inherited_from ),
  463. // ['unrestrictions'][role_handle][obj_or_term_id] = array( 'assign_for' => $row->assign_for, 'inherited_from' => $row->inherited_from )
  464. function get_restrictions($scope, $src_or_tx_name, $args = array()) {
  465. $def_cols = COL_ID_RS;
  466. // Note: propogating child restrictions are always directly assigned to the child term(s).
  467. // Use include_child_restrictions to force inclusion of restrictions that are set for child items only,
  468. // for direct admin of these restrictions and for propagation on term/object creation.
  469. $defaults = array( 'id' => 0, 'include_child_restrictions' => false,
  470. 'force_refresh' => false,
  471. 'cols' => $def_cols, 'return_array' => false );
  472. $args = array_merge( $defaults, (array) $args );
  473. extract($args);
  474. $cache_flag = "rs_{$scope}_restrictions_{$src_or_tx_name}";
  475. $cache_id = md5($src_or_tx_name . $cols . strval($return_array) . strval($include_child_restrictions) );
  476. if ( ! $force_refresh ) {
  477. $items = wpp_cache_get($cache_id, $cache_flag);
  478. if ( is_array($items) ) {
  479. if ( $id ) {
  480. foreach ( $items as $setting_type => $roles )
  481. foreach ( array_keys($roles) as $role_handle )
  482. $items[$setting_type][$role_handle] = array_intersect_key( $items[$setting_type][$role_handle], array( $id => true ) );
  483. }
  484. return $items;
  485. }
  486. }
  487. if ( ! isset($this->default_restrictions[$scope]) )
  488. $this->default_restrictions[$scope] = $this->get_default_restrictions($scope);
  489. global $wpdb;
  490. if ( ! empty($this->default_restrictions[$scope][$src_or_tx_name]) ) {
  491. if ( $strict_roles = array_keys($this->default_restrictions[$scope][$src_or_tx_name]) ) {
  492. if ( OBJECT_SCOPE_RS == $scope ) {
  493. // apply default_strict handling to objscope equivalents of each strict role
  494. foreach ( $strict_roles as $role_handle )
  495. if ( $objscope_equivalents = $this->role_defs->member_property($role_handle, 'objscope_equivalents') )
  496. $strict_roles = array_merge($strict_roles, $objscope_equivalents);
  497. $strict_roles = array_unique($strict_roles);
  498. }
  499. }
  500. $strict_role_in = "'" . implode("', '", scoper_role_handles_to_names($strict_roles) ) . "'";
  501. } else
  502. $strict_role_in = '';
  503. $items = array();
  504. if ( ! empty($strict_roles) ) {
  505. foreach ( $strict_roles as $role_handle )
  506. $items['unrestrictions'][$role_handle] = array(); // calling code will use this as an indication that the role is default strict
  507. }
  508. $default_strict_modes = array( false );
  509. if ( $strict_role_in )
  510. $default_strict_modes []= true;
  511. foreach ( $default_strict_modes as $default_strict ) {
  512. $setting_type = ( $default_strict ) ? 'unrestrictions' : 'restrictions';
  513. if ( TERM_SCOPE_RS == $scope )
  514. $max_scope = ( $default_strict ) ? 'blog' : 'term'; // note: max_scope='object' entries are treated as separate, overriding requirements
  515. else
  516. $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
  517. if ( $default_strict )
  518. $role_clause = "AND role_name IN ($strict_role_in)";
  519. elseif ($strict_role_in)
  520. $role_clause = "AND role_name NOT IN ($strict_role_in)";
  521. else
  522. $role_clause = '';
  523. $for_clause = ( $include_child_restrictions ) ? '' : "AND require_for IN ('entity', 'both')";
  524. $qry_base = "FROM $wpdb->role_scope_rs WHERE role_type = 'rs' AND topic = '$scope' AND max_scope = '$max_scope' AND src_or_tx_name = '$src_or_tx_name' $for_clause $role_clause";
  525. if ( COL_COUNT_RS == $cols )
  526. $qry = "SELECT role_name, count(obj_or_term_id) AS item_count, require_for $qry_base GROUP BY role_name";
  527. else
  528. $qry = "SELECT role_name, obj_or_term_id, require_for AS assign_for, inherited_from $qry_base";
  529. if ( $results = scoper_get_results($qry) ) {
  530. foreach( $results as $row) {
  531. $role_handle = scoper_get_role_handle($row->role_name, 'rs');
  532. if ( COL_COUNT_RS == $cols )
  533. $items[$setting_type][$role_handle] = $row->item_count;
  534. elseif ( $return_array )
  535. $items[$setting_type][$role_handle][$row->obj_or_term_id] = array( 'assign_for' => $row->assign_for, 'inherited_from' => $row->inherited_from );
  536. else
  537. $items[$setting_type][$role_handle][$row->obj_or_term_id] = $row->assign_for;
  538. }
  539. }
  540. } // end foreach default_strict_mode
  541. wpp_cache_force_set($cache_id, $items, $cache_flag);
  542. if ( $id ) {
  543. foreach ( $items as $setting_type => $roles )
  544. foreach ( array_keys($roles) as $role_handle )
  545. $items[$setting_type][$role_handle] = array_intersect_key( $items[$setting_type][$role_handle], array( $id => true ) );
  546. }
  547. return $items;
  548. }
  549. // wrapper for back-compat with calling code expecting array without date limit dimension
  550. function qualify_terms($reqd_caps, $taxonomy = 'category', $qualifying_roles = '', $args = array()) {
  551. $terms = $this->qualify_terms_daterange( $reqd_caps, $taxonomy, $qualifying_roles, $args );
  552. if ( isset($terms['']) && is_array($terms['']) )
  553. return $terms[''];
  554. else
  555. return array();
  556. }
  557. // $qualifying_roles = array[role_handle] = 1 : qualifying roles
  558. // returns array of term_ids (terms which have at least one of the qualifying roles assigned)
  559. function qualify_terms_daterange($reqd_caps, $taxonomy = 'category', $qualifying_roles = '', $args = array()) {
  560. $defaults = array( 'user' => '', 'return_id_type' => COL_ID_RS, 'use_blog_roles' => true, 'ignore_restrictions' => false );
  561. if ( isset($args['qualifying_roles']) )
  562. unset($args['qualifying_roles']);
  563. if ( isset($args['reqd_caps']) )
  564. unset($args['reqd_caps']);
  565. $args = array_merge( $defaults, (array) $args );
  566. extract($args);
  567. if ( ! $qualifying_roles ) // calling function might save a little work or limit to a subset of qualifying roles
  568. $qualifying_roles = $this->role_defs->qualify_roles( $reqd_caps );
  569. if ( ! $this->taxonomies->is_member($taxonomy) )
  570. return array( '' => array() );
  571. if ( ! is_object($user) ) {
  572. $user = $GLOBALS['current_rs_user'];
  573. }
  574. // If the taxonomy does not require objects to have at least one term, there are no strict terms.
  575. if ( ! $this->taxonomies->member_property($taxonomy, 'requires_term') )
  576. $ignore_restrictions = true;
  577. if ( ! is_array($qualifying_roles) )
  578. $qualifying_roles = array($qualifying_roles => 1);
  579. // no need to serialize and md5 the whole user object
  580. if ( ! empty($user) )
  581. $args['user'] = $user->ID;
  582. // try to pull previous result out of memcache
  583. ksort($qualifying_roles);
  584. $rolereq_key = md5( serialize($reqd_caps) . serialize( array_keys($qualifying_roles) ) . serialize($args) );
  585. if ( isset($user->qualified_terms[$taxonomy][$rolereq_key]) )
  586. return $user->qualified_terms[$taxonomy][$rolereq_key];
  587. if ( ! $qualifying_roles )
  588. return array( '' => array() );
  589. $all_terms = $this->get_terms($taxonomy, UNFILTERED_RS, COL_ID_RS); // returns term_id, even for WP > 2.3
  590. if ( ! isset($user->term_roles[$taxonomy]) )
  591. $user->get_term_roles_daterange($taxonomy); // returns term_id for categories
  592. $good_terms = array( '' => array() );
  593. if ( $user->term_roles[$taxonomy] ) {
  594. foreach ( array_keys($user->term_roles[$taxonomy]) as $date_key ) {
  595. //narrow down to roles which satisfy this call AND are owned by current user
  596. if ( $good_terms[$date_key] = array_intersect_key( $user->term_roles[$taxonomy][$date_key], $qualifying_roles ) )
  597. // flatten from term_roles_terms[role_handle] = array of term_ids
  598. // to term_roles_terms = array of term_ids
  599. $good_terms[$date_key] = agp_array_flatten( $good_terms[$date_key] );
  600. }
  601. }
  602. if ( $use_blog_roles ) {
  603. foreach ( array_keys($user->blog_roles) as $date_key ) {
  604. $user_blog_roles = array_intersect_key( $user->blog_roles[$date_key], $qualifying_roles );
  605. // Also include user's WP blogrole(s) which correspond to the qualifying RS role(s)
  606. if ( $wp_qualifying_roles = $this->role_defs->qualify_roles($reqd_caps, 'wp') ) {
  607. if ( $user_blog_roles_wp = array_intersect_key( $user->blog_roles[$date_key], $wp_qualifying_roles ) ) {
  608. // Credit user's qualifying WP blogrole via equivalent RS role(s)
  609. // so we can also enforce "term restrictions", which are based on RS roles
  610. $user_blog_roles_via_wp = $this->role_defs->get_contained_roles( array_keys($user_blog_roles_wp), false, 'rs' );
  611. $user_blog_roles_via_wp = array_intersect_key( $user_blog_roles_via_wp, $qualifying_roles );
  612. $user_blog_roles = array_merge( $user_blog_roles, $user_blog_roles_via_wp );
  613. }
  614. }
  615. if ( $user_blog_roles ) {
  616. if ( empty($ignore_restrictions) ) {
  617. // array of term_ids that require the specified role to be assigned via taxonomy or object role (user blog caps ignored)
  618. $strict_terms = $this->get_restrictions(TERM_SCOPE_RS, $taxonomy);
  619. } else
  620. $strict_terms = array();
  621. foreach ( array_keys($user_blog_roles) as $role_handle ) {
  622. if ( isset($strict_terms['restrictions'][$role_handle]) && is_array($strict_terms['restrictions'][$role_handle]) )
  623. $terms_via_this_role = array_diff( $all_terms, array_keys($strict_terms['restrictions'][$role_handle]) );
  624. elseif ( isset($strict_terms['unrestrictions'][$role_handle]) && is_array($strict_terms['unrestrictions'][$role_handle]) )
  625. $terms_via_this_role = array_intersect( $all_terms, array_keys( $strict_terms['unrestrictions'][$role_handle] ) );
  626. else
  627. $terms_via_this_role = $all_terms;
  628. if( $good_terms[$date_key] )
  629. $good_terms[$date_key] = array_merge( $good_terms[$date_key], $terms_via_this_role );
  630. else
  631. $good_terms[$date_key] = $terms_via_this_role;
  632. }
  633. }
  634. }
  635. }
  636. foreach ( array_keys($good_terms) as $date_key ) {
  637. if ( $good_terms[$date_key] = array_intersect( $good_terms[$date_key], $all_terms ) ) // prevent orphaned category roles from skewing access
  638. $good_terms[$date_key] = array_unique( $good_terms[$date_key] );
  639. // if COL_TAXONOMY_ID_RS, return a term_taxonomy_id instead of term_id
  640. if ( $good_terms[$date_key] && (COL_TAXONOMY_ID_RS == $return_id_type) && taxonomy_exists($taxonomy) ) {
  641. $all_terms_cols = $this->get_terms( $taxonomy, UNFILTERED_RS );
  642. $good_tt_ids = array();
  643. foreach ( $good_terms[$date_key] as $term_id )
  644. foreach ( array_keys($all_terms_cols) as $termkey )
  645. if ( $all_terms_cols[$termkey]->term_id == $term_id ) {
  646. $good_tt_ids []= $all_terms_cols[$termkey]->term_taxonomy_id;
  647. break;
  648. }
  649. $good_terms[$date_key] = $good_tt_ids;
  650. }
  651. }
  652. $user->qualified_terms[$taxonomy][$rolereq_key] = $good_terms;
  653. return $good_terms;
  654. }
  655. // account for different contexts of get_terms calls
  656. // (Scoped roles can dictate different results for front end, edit page/post, manage categories)
  657. function get_terms_reqd_caps( $taxonomy, $operation = '', $is_term_admin = false ) {
  658. global $pagenow;
  659. if ( ! $src_name = $this->taxonomies->member_property( $taxonomy, 'object_source' ) ) {
  660. if ( taxonomy_exists( $taxonomy ) )
  661. $src_name = 'post';
  662. }
  663. $return_caps = array();
  664. $is_term_admin = $is_term_admin
  665. || in_array( $pagenow, array( 'edit-tags.php' ) )
  666. || ( 'nav_menu' == $taxonomy && ( 'nav-menus.php' == $pagenow )
  667. || ( ( 'admin-ajax.php' == $pagenow ) && ( ! empty($_REQUEST['action']) && in_array( $_REQUEST['action'], array( 'add-menu-item', 'menu-locations-save' ) ) ) )
  668. ); // possible TODO: abstract for non-WP taxonomies
  669. if ( $is_term_admin ) {
  670. // query pertains to the management of terms
  671. if ( 'post' == $src_name ) {
  672. $taxonomy_obj = get_taxonomy( $taxonomy );
  673. $return_caps[$taxonomy] = array( $taxonomy_obj->cap->manage_terms );
  674. } elseif ( 'link_category' == $taxonomy ) {
  675. $return_caps[$taxonomy] = array( 'manage_categories' );
  676. } else {
  677. global $scoper;
  678. $cap_defs = $scoper->cap_defs->get_matching( $src_name, $taxonomy, OP_ADMIN_RS );
  679. $return_caps[$taxonomy] = $cap_defs ? array_keys( $cap_defs ) : array();
  680. }
  681. } else {
  682. // query pertains to reading or editing content within certain terms, or adding terms to content
  683. $base_caps_only = true;
  684. if ( 'post' == $src_name ) {
  685. if ( ! $operation )
  686. $operation = ( $this->is_front() || ( 'profile.php' == $pagenow ) || ( is_admin() && array_key_exists('plugin_page', $GLOBALS) && ( 's2' == $GLOBALS['plugin_page'] ) ) ) ? 'read' : 'edit'; // hack to support subscribe2 categories checklist
  687. $status = ( 'read' == $operation ) ? 'publish' : 'draft';
  688. // terms query should be limited to a single object type for post.php, post-new.php, so only return caps for that object type (TODO: do this in wp-admin regardless of URI ?)
  689. if ( in_array( $pagenow, array( 'post.php', 'post-new.php' ) ) )
  690. $object_type = cr_find_post_type();
  691. } else {
  692. if ( ! $operation )
  693. $operation = ( $this->is_front() ) ? 'read' : 'edit';
  694. $status = '';
  695. }
  696. // The return array will indicate term role enable / disable, as well as associated capabilities
  697. if ( ! empty($object_type) )
  698. $check_object_types = array( $object_type );
  699. else {
  700. if ( $check_object_types = (array) $this->data_sources->member_property( $src_name, 'object_types' ) )
  701. $check_object_types = array_keys( $check_object_types );
  702. }
  703. if ( 'post' == $src_name )
  704. $use_post_types = scoper_get_option( 'use_post_types' );
  705. $enabled_object_types = array();
  706. foreach ( $check_object_types as $_object_type ) {
  707. if ( $use_term_roles = scoper_get_otype_option( 'use_term_roles', $src_name, $_object_type ) )
  708. if ( ! empty( $use_term_roles[$taxonomy] ) ) {
  709. if ( ( 'post' != $src_name ) || ! empty( $use_post_types[$_object_type] ) )
  710. $enabled_object_types []= $_object_type;
  711. }
  712. }
  713. foreach( $enabled_object_types as $object_type )
  714. $return_caps[$object_type] = cr_get_reqd_caps( $src_name, $operation, $object_type, $status, $base_caps_only );
  715. }
  716. return $return_caps;
  717. }
  718. function users_who_can($reqd_caps, $cols = COLS_ALL_RS, $object_src_name = '', $object_id = 0, $args = array() ) {
  719. // if there are not capability requirements, no need to load Users_Interceptor filtering class
  720. if ( ! $reqd_caps ) {
  721. if ( COL_ID_RS == $cols )
  722. $qcols = 'ID';
  723. elseif ( COLS_ID_NAME_RS == $cols )
  724. $qcols = "ID, user_login AS display_name"; // calling code assumes display_name property for user or group object
  725. elseif ( COLS_ID_DISPLAYNAME_RS == $cols )
  726. $qcols = "ID, display_name";
  727. elseif ( COLS_ALL_RS == $cols )
  728. $qcols = "*";
  729. else
  730. $qcols = $cols;
  731. global $wpdb;
  732. $orderby = ( $cols == COL_ID_RS ) ? '' : 'ORDER BY display_name';
  733. if ( IS_MU_RS && ! scoper_get_option( 'mu_sitewide_groups' ) && ! defined( 'FORCE_ALL_SITE_USERS_RS' ) )
  734. $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";
  735. else
  736. $qry = "SELECT $qcols FROM $wpdb->users $orderby";
  737. if ( COL_ID_RS == $cols )
  738. return scoper_get_col( $qry );
  739. else
  740. return scoper_get_results( $qry );
  741. } else {
  742. $defaults = array( 'where' => '', 'orderby' => '', 'disable_memcache' => false, 'group_ids' => '', 'force_refresh' => false, 'force_all_users' => false );
  743. $args = array_merge( $defaults, (array) $args );
  744. extract($args);
  745. $cache_flag = "rs_users_who_can";
  746. $cache_id = md5(serialize($reqd_caps) . $cols . 'src' . $object_src_name . 'id' . $object_id . serialize($args) );
  747. if ( ! $force_refresh ) {
  748. // if we already have the results cached, no need to load Users_Interceptor filtering class
  749. $users = wpp_cache_get($cache_id, $cache_flag);
  750. if ( is_array($users) )
  751. return $users;
  752. }
  753. $this->init_users_interceptor();
  754. $users = $GLOBALS['users_interceptor']->users_who_can($reqd_caps, $cols, $object_src_name, $object_id, $args );
  755. wpp_cache_set($cache_id, $users, $cache_flag);
  756. return $users;
  757. }
  758. }
  759. function groups_who_can($reqd_caps, $cols = COLS_ALL_RS, $object_src_name = '', $object_id = 0, $args = array() ) {
  760. $this->init_users_interceptor();
  761. return $GLOBALS['users_interceptor']->groups_who_can($reqd_caps, $cols, $object_src_name, $object_id, $args );
  762. }
  763. function is_front() {
  764. return ( defined('CURRENT_ACCESS_NAME_RS') && ( 'front' == CURRENT_ACCESS_NAME_RS ) );
  765. }
  766. // returns array of role names which have the required caps (or their basecap equivalent)
  767. // AND have been applied to at least one object, for any user or group
  768. function qualify_object_roles( $reqd_caps, $object_type = '', $user = '', $base_caps_only = false ) {
  769. $roles = array();
  770. if ( $base_caps_only )
  771. $reqd_caps = $this->cap_defs->get_base_caps($reqd_caps);
  772. $roles = $this->role_defs->qualify_roles($reqd_caps, 'rs', $object_type);
  773. return $this->confirm_object_scope( $roles, $user );
  774. }
  775. // $roles[$role_handle] = array
  776. // returns arr[$role_handle]
  777. function confirm_object_scope( $roles, $user = '' ) {
  778. foreach ( array_keys($roles) as $role_handle ) {
  779. if ( empty( $this->role_defs->members[$role_handle]->valid_scopes['object'] ) )
  780. unset( $roles[$role_handle] );
  781. }
  782. if ( ! $roles )
  783. return array();
  784. if ( is_object($user) )
  785. $applied_obj_roles = $this->get_applied_object_roles( $user );
  786. elseif ( empty($user) ) {
  787. $applied_obj_roles = $this->get_applied_object_roles( $GLOBALS['current_rs_user'] );
  788. } else // -1 value passed to indicate check for all users
  789. $applied_obj_roles = $this->get_applied_object_roles();
  790. return array_intersect_key( $roles, $applied_obj_roles );
  791. }
  792. // returns array of role_handles which have been applied to any object
  793. // if $user arg is supplied, returns only roles applied for that user (or that user's groups)
  794. function get_applied_object_roles( $user = '' ) {
  795. if ( is_object( $user ) ) {
  796. $cache_flag = 'rs_object-roles'; // v 1.1: changed cache key from "object_roles" to "object-roles" to match new key format for blog, term roles
  797. $cache = $user->cache_get($cache_flag);
  798. $limit = '';
  799. $u_g_clause = $user->get_user_clause('');
  800. } else {
  801. $cache_flag = 'rs_applied_object-roles'; // v 1.1: changed cache key from "object_roles" to "object-roles" to match new key format for blog, term roles
  802. $cache_id = 'all';
  803. $cache = wpp_cache_get($cache_id, $cache_flag);
  804. $u_g_clause = '';
  805. }
  806. if ( is_array($cache) )
  807. return $cache;
  808. $role_handles = array();
  809. global $wpdb;
  810. // object roles support date limits, but content date limits (would be redundant and a needless performance hit)
  811. $duration_clause = scoper_get_duration_clause( '', $wpdb->user2role2object_rs );
  812. if ( $role_names = scoper_get_col("SELECT DISTINCT role_name FROM $wpdb->user2role2object_rs WHERE role_type='rs' AND scope='object' $duration_clause $u_g_clause") )
  813. $role_handles = scoper_role_names_to_handles($role_names, 'rs', true); //arg: return role keys as array key
  814. if ( is_object($user) ) {
  815. $user->cache_force_set($role_handles, $cache_flag);
  816. } else
  817. wpp_cache_force_set($cache_id, $role_handles, $cache_flag);
  818. return $role_handles;
  819. }
  820. function user_can_edit_blogwide( $src_name = '', $object_type = '', $args = '' ) {
  821. if ( is_administrator_rs($src_name) )
  822. return true;
  823. require_once( dirname(__FILE__).'/admin/permission_lib_rs.php' );
  824. return user_can_edit_blogwide_rs($src_name, $object_type, $args);
  825. }
  826. } // end Scoper class
  827. // (needed to stop using shared core library function with Revisionary due to changes in meta_flag handling)
  828. if ( ! function_exists('awp_user_can') ) {
  829. function awp_user_can( $reqd_caps, $object_id = 0, $user_id = 0, $meta_flags = array() ) {
  830. return cr_user_can( $reqd_caps, $object_id, $user_id, $meta_flags );
  831. }
  832. }
  833. // equivalent to current_user_can,
  834. // except it supports array of reqd_caps, supports non-current user, and does not support numeric reqd_caps
  835. function cr_user_can( $reqd_caps, $object_id = 0, $user_id = 0, $meta_flags = array() ) {
  836. if ( ! $user_id ) {
  837. if ( function_exists('is_super_admin') && is_super_admin() )
  838. return true;
  839. if ( is_content_administrator_rs() || ! function_exists( '_cr_user_can' ) )
  840. return current_user_can( $reqd_caps );
  841. }
  842. if ( function_exists( '_cr_user_can' ) )
  843. return _cr_user_can( $reqd_caps, $object_id, $user_id, $meta_flags );
  844. }
  845. ?>