/wp-content/plugins/role-scoper/query-interceptor_rs.php
PHP | 1517 lines | 953 code | 319 blank | 245 comment | 393 complexity | 9b10864ca15e79de19b7bea6cdeb2075 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-3.0, Apache-2.0, GPL-2.0, LGPL-2.1
- <?php
- if( basename(__FILE__) == basename($_SERVER['SCRIPT_FILENAME']) )
- die();
-
- /**
- * QueryInterceptor_RS PHP class for the WordPress plugin Role Scoper
- * query-interceptor_rs.php
- *
- * @author Kevin Behrens
- * @copyright Copyright 2011
- *
- */
-
- class QueryInterceptor_RS
- {
- var $scoper;
- var $skip_teaser; // this is only used by templates making a direct call to query_posts but wishing to get non-teased results
- var $last_request = array();
-
- function QueryInterceptor_RS() {
- $this->scoper =& $GLOBALS['scoper'];
-
- $is_administrator = is_content_administrator_rs();
-
- // ---- ABSTRACT ROLE SCOPER HOOKS - wrap around source-specific hooks based on DataSources config ------
- //
- // Request / Where Filter:
- // Support filtering of any query request (WP or plugin-defined) based on scoped roles.
- // Resulting content may be narrowed or expanded from WP core results.
- // (currently require request/where/join string as first hook arg, ignore other args)
- //
- // Results Teaser:
- // Alternately, if a results hook is defined, unqualified records can
- // be left in the result set, but with the content stripped and the excerpt
- // replaced or appended with a teaser message.
- // (currently require results as array of objects in first hook arg, ignore other args)
- //
- // suported filter interface:
- // request hooks: $arg1 = full request query
- // results hooks: $arg1 = results set
-
- // filter args: $item, $src_name, $object_type, $args (note: to customize other args, filter must be called directly)
-
- add_filter('objects_where_rs', array(&$this, 'flt_objects_where'), 2, 4);
- add_filter('objects_request_rs', array(&$this, 'flt_objects_request'), 2, 4);
- add_filter('objects_results_rs', array(&$this, 'flt_objects_results'), 50, 4);
- add_filter('objects_teaser_rs', array(&$this, 'flt_objects_teaser'), 50, 4);
-
- if ( ! $this->scoper->direct_file_access ) {
- // Append any limiting clauses to WHERE clause for taxonomy query
- // args: ($where, $taxonomy, $object_type = '', $reqd_op = '') e.g. ($where, 'categories', 'post', 'edit')
- // Note: If any of the optional args are missing or nullstring, an attempt is made
- // to determine them from URI based on Scoped_Taxonomy properties
- add_filter('terms_request_rs', array(&$this, 'flt_terms_request'), 50, 4);
- add_filter('terms_where_rs', array(&$this, 'flt_terms_where'), 50, 3);
- }
-
- // note: If DISABLE_QUERYFILTERS_RS is set, the RS filters are still defined above for selective internal use,
- // but in that case are not mapped to the defined data source hooks ('posts_where', etc.) below
- if ( ! defined('DISABLE_QUERYFILTERS_RS') ) {
- //in effect, make WP pass the hook name so multiple hooks can be registered to a single handler
- $rs_hooks = array();
-
- foreach ( $this->scoper->data_sources->get_all() as $src_name => $src ) {
- if ( empty($src->query_hooks) )
- continue;
-
- if ( ! $is_administrator ) {
- if ( isset($src->query_hooks->where) ) {
- $rs_hooks[$src->query_hooks->where] = (object) array( 'name' => 'objects_where_rs', 'rs_args' => "'$src_name', '', '' ");
-
- } elseif ( isset($src->query_hooks->request) )
- $rs_hooks[$src->query_hooks->request] = (object) array( 'name' => 'objects_request_rs', 'rs_args' => "'$src_name', '', '' ");
- }
-
- // log results (to identify restricted posts) even for admin. Also, possibly apply front end teaser
- if ( isset($src->query_hooks->results) )
- $rs_hooks[$src->query_hooks->results] = (object) array( 'name' => 'objects_results_rs', 'rs_args' => "'$src_name', '', '' ");
-
- } //foreach data_sources
-
- if ( ! $is_administrator ) {
- // use late-firing filter so teaser filtering is also applied to sticky posts
- add_filter( 'the_posts', array( &$this, 'flt_the_posts' ), 50, 2 );
-
- // manually hook posts_request to pass on object_type value in the referenced wp_query object
- add_filter( 'posts_request', array( &$this, 'flt_posts_request'), 50, 2 );
- }
-
- // ...but don't include this hook in the filter-wrapping loop below
- if ( isset( $rs_hooks['posts_request'] ) )
- unset( $rs_hooks['posts_request'] );
-
-
- // call our abstract handlers with a lambda function that passes in original hook name
- foreach ( $rs_hooks as $original_hook => $rs_hook ) {
- if ( ! $original_hook )
- continue;
-
- $arg_str = '$a';
- $comma = ( $rs_hook->rs_args ) ? ',' : '';
- $func = "return apply_filters( '$rs_hook->name', $arg_str $comma $rs_hook->rs_args );";
- add_filter( $original_hook, create_function( $arg_str, $func ), 50, 1 );
-
- //d_echo ("adding filter: $original_hook -> $func <br />");
- }
- }
-
- //add_filter( 'posts_request', array( &$this, 'flt_debug_query'), 999 );
- }
-
-
- //function flt_debug_query( $query ) {
- // d_echo( $query . '<br /><br />' );
- // return $query;
- //}
-
-
- function flt_posts_request( $request, $_wp_query = false ) {
- if ( is_object( $_wp_query ) && ! empty( $_wp_query->query_vars['post_type'] ) ) {
- $object_types = $_wp_query->query_vars['post_type'];
-
- if ( 'any' == $object_types )
- $object_types = '';
- } else
- $object_types = '';
-
- return $this->flt_objects_request( $request, 'post', $object_types );
- }
-
- // Append any limiting clauses to WHERE clause for taxonomy query
- //$reqd_caps_by_taxonomy[tx_name][op_type] = array of cap names
- function flt_terms_request($request, $taxonomies, $args = array()) {
- //$defaults = array( 'reqd_caps_by_otype' => array(), 'is_term_admin' => false, 'required_operation' => '', 'post_type' => '' );
-
- // determine term id col (term_id or term_taxonomy_id) for term management queries
- if ( strpos( $request, 'AS tt' ) )
- $args['term_id_col'] = 'tt.term_taxonomy_id';
- elseif ( strpos( $request, 'AS t' ) )
- $args['term_id_col'] = 't.term_id';
- else {
- global $wpdb;
- if ( strpos( $request, $wpdb->terms ) )
- $args['term_id_col'] = "$wpdb->terms.term_id";
- elseif ( strpos( $request, $wpdb->term_taxonomy ) )
- $args['term_id_col'] = "$wpdb->term_taxonomy.term_taxonomy_id";
- }
-
- if ( $rs_where = $this->flt_terms_where('', $taxonomies, $args) ) {
- if ( strpos( $request, ' WHERE ' ) )
- $request = str_replace( ' WHERE ', " WHERE 1=1 $rs_where AND ", $request );
- elseif ( $pos_suffix = agp_get_suffix_pos( $request ) )
- $request = substr( $request, 0, $pos_suffix ) . " WHERE 1=1 $rs_where " . substr( $request, $pos_suffix );
- else
- $request .= " WHERE 1=1 $rs_where ";
- }
-
- //d_echo ("<br /><br />terms_request output:$request<br /><br />");
-
- return $request;
- }
-
- function flt_terms_where($where, $taxonomies, $args = array()) {
- $defaults = array( 'reqd_caps_by_otype' => array(), 'is_term_admin' => false, 'required_operation' => '', 'post_type' => '', 'term_id_col' => '' );
- $args = array_merge( $defaults, (array) $args );
- extract( $args, EXTR_SKIP );
-
- $taxonomies = (array) $taxonomies;
- if ( ! $taxonomies )
- return $where;
-
- if ( $post_type )
- $post_type = (array) $post_type;
-
- // support multiple taxonomies, but only if they all use the same object data source
- $taxonomy_sources = array();
- foreach ( $taxonomies as $taxonomy ) {
- if ( ! $this->scoper->taxonomies->is_member( $taxonomy ) )
- continue;
-
- $src_name = $this->scoper->taxonomies->member_property( $taxonomy, 'object_source' );
-
- if ( is_object($src_name) ) // support legacy code which stored object variable to property (TODO: eliminate this)
- $src_name = $src_name->name;
-
- $taxonomy_sources[$src_name] = true;
- }
-
- if ( count($taxonomy_sources) != 1 )
- return $where;
-
- // if the filter call did not specify required caps...
- if ( ! $reqd_caps_by_otype ) {
- $reqd_caps_by_otype = array();
-
- // try to determine context from URI (if taxonomy definition includes such clues)
- foreach( $taxonomies as $taxonomy ) {
- $reqd_caps_by_otype = array_merge( $reqd_caps_by_otype, $this->scoper->get_terms_reqd_caps( $taxonomy, $required_operation, $is_term_admin ) ); // NOTE: get_terms_reqd_caps() returns term management caps on edit-tags.php, otherwise post edit caps
- }
-
- if ( $post_type )
- $reqd_caps_by_otype = array_intersect_key( $reqd_caps_by_otype, array_flip( $post_type ) );
-
- // if required operation still unknown, default based on access type
- if ( ! $reqd_caps_by_otype )
- return $where;
- }
-
- // prevent hardway-admin filtering of any queries which may be triggered by this filter
- $GLOBALS['scoper_status']->querying_db = true;
-
- // Note that term management capabilities (i.e. "manage_categories") are implemented via Term Roles on the Posts data source, with taxonomy as the object type
- //
- // if this is a term management query, no need to involve objects query filtering
- if ( ( 'post' == $src_name ) && isset( $reqd_caps_by_otype[ $taxonomies[0] ] ) ) {
- $qualifying_roles = $this->scoper->role_defs->qualify_roles( $reqd_caps_by_otype[$taxonomies[0]], 'rs', $taxonomies[0] ); // otherwise qualify_terms() will not filter out other taxonomy manager roles that also use manage_categories cap
-
- if ( ! $term_id_col ) {
- // can't attempt filtering without this info
- $GLOBALS['scoper_status']->querying_db = false;
- return $where;
- }
-
- $return_id_type = ( strpos( $term_id_col, 'term_taxonomy_id' ) ) ? COL_TAXONOMY_ID_RS : COL_ID_RS;
-
- if ( $ids = $this->scoper->qualify_terms( $reqd_caps_by_otype[$taxonomies[0]], $taxonomies[0], $qualifying_roles, compact('return_id_type') ) ) { // returns term_id since COL_TAXONOMY_ID_RS is not passed as args['return_id_type']
- $where .= " AND $term_id_col IN ('" . implode( "','", $ids ) . "')";
- } else
- $where = ' AND 1=2';
- } else {
- // Call objects_where_role_clauses() with src_name of the taxonomy source.
- // This works as a slight subversion of the normal flt_objects_where query building because we are also forcing taxonomies explicitly and passing the terms_query arg.
- $args['terms_query'] = true;
- $args['use_object_roles'] = false;
- $args['skip_owner_clause'] = true;
- $args['terms_reqd_caps'] = $reqd_caps_by_otype;
- $args['taxonomies'] = $taxonomies;
-
- if ( is_admin() )
- $args['alternate_reqd_caps'][0] = array( "assign_$taxonomy" );
-
- $where .= $this->flt_objects_where('', $src_name, '', $args);
-
- // For Edit Form display, include currently stored terms. User will still not be able to remove them without proper editing roles for object. (TODO: abstract for other data sources)
- if ( ( 'post.php' == $GLOBALS['pagenow'] ) && empty( $_REQUEST['admin_bar'] ) ) {
- if ( 'post' == $src_name ) {
- if ( $object_id = $this->scoper->data_sources->detect( 'id', $src_name ) ) {
- if ( $stored_terms = wp_get_object_terms( $object_id, $taxonomies[0] ) ) {
- $tt_ids = array();
- foreach( array_keys($stored_terms) as $key )
- $tt_ids []= $stored_terms[$key]->term_taxonomy_id;
-
- $where .= " OR tt.term_taxonomy_id IN ('" . implode( "','", $tt_ids ) . "')";
- }
- }
- }
- }
- }
-
- $GLOBALS['scoper_status']->querying_db = false; // re-enable hardway-admin filtering
-
- return $where;
- }
-
- function flt_objects_request($request, $src_name, $object_types = '', $args = array()) {
- if ( $args ) {
- $defaults = array( 'skip_teaser' => false );
- $args = array_diff_key($args, array_flip( array('request', 'src_name', 'object_types' ) ) );
- $args = array_merge( $defaults, (array) $args );
- extract($args);
- }
-
- // if Media Library filtering is disabled, don't filter listing for TinyMCE popup either
- if ( is_admin() && defined( 'SCOPER_ALL_UPLOADS_EDITABLE' ) && strpos( $_SERVER['SCRIPT_NAME'], 'wp-admin/media-upload.php' ) )
- return $request;
-
- // Filtering in user_has_cap sufficiently controls revision access; a match here should be for internal, pre-validation purposes
- if ( strpos( $request, "post_type = 'revision'") )
- return $request;
-
- // no need to apply objects query filtering within NextGEN Gallery / Grand Flash Gallery upload operation (was failing with undefined $current_user)
- if ( is_admin() ) {
- if ( defined( 'SCOPER_ALL_UPLOADS_EDITABLE' ) && ( $GLOBALS['pagenow'] == 'upload.php' ) )
- return $request;
-
- $nofilter_scripts = array( '/admin/upload.php' );
- if ( $nofilter_scripts = apply_filters( 'noqueryfilter_scripts_rs', $nofilter_scripts ) ) {
- foreach( $nofilter_scripts as $_script_name ) {
- if ( false !== strpos( $_SERVER['SCRIPT_NAME'], $_script_name ) )
- return $request;
- }
- }
- }
-
- // prevent hardway-admin filtering of any queries which may be triggered by this filter
- $GLOBALS['scoper_status']->querying_db = true;
-
- if ( empty($skip_teaser) ) {
- $this->last_request[$src_name] = $request; // Store for potential use by subsequent teaser filter
- }
-
- //$request = agp_force_distinct($request); // in case data source didn't provide a hook for objects_distinct
-
- if ( ! preg_match('/\s*WHERE\s*1=1/', $request) )
- $request = preg_replace('/\s*WHERE\s*/', ' WHERE 1=1 AND ', $request);
-
- $pos_where = 0;
- $pos_suffix = 0;
- $where = agp_parse_after_WHERE_11( $request, $pos_where, $pos_suffix ); // any existing where, orderby or group by clauses remain in $where
- if ( ! $pos_where && $pos_suffix ) {
- $request = substr($request, 0, $pos_suffix) . ' WHERE 1=1' . substr($request, $pos_suffix);
- $pos_where = $pos_suffix;
- }
-
- if ( 'post' == $src_name ) {
- // If the query uses an alias for the posts table, be sure to use that alias in the WHERE clause also.
- //
- // NOTE: if query refers to non-active blog, this code will prevent a DB syntax error, but will not cause the correct roles / restrictions to be applied.
- // Other plugins need to use switch_to_blog() rather than just executing a query on a non-main blog.
- $matches = array();
- if ( $return = preg_match( '/SELECT .* FROM [^ ]+posts AS ([^ ]) .*/', $request, $matches ) )
- $args['source_alias'] = $matches[2];
- elseif ( $return = preg_match( '/SELECT .* FROM ([^ ]+)posts .*/', $request, $matches ) )
- $args['source_alias'] = $matches[1] . 'posts';
- }
-
- // TODO: abstract this
- if ( strpos( $request, "post_type = 'attachment'" ) ) {
- global $wpdb;
-
- if ( ! is_admin() && ! empty($_REQUEST['attachment_id']) && ! defined('SCOPER_BLOCK_UNATTACHED_UPLOADS') ) {
- if ( $_att = get_post($_REQUEST['attachment_id']) ) {
- if ( 0 === $_att->post_parent )
- return $request;
- }
- }
-
- // filter attachments by inserting a scoped subquery based on user roles on the post/page attachment is tied to
- $rs_where = $this->flt_objects_where( '', $src_name, '', $args );
- $subqry = "SELECT ID FROM $wpdb->posts WHERE 1=1 $rs_where";
-
- if ( is_admin() ) {
- // The listed objects are attachments, so query filter is based on objects they inherit from
- $admin_others_attached = scoper_get_option( 'admin_others_attached_files' );
- $admin_others_unattached = scoper_get_option( 'admin_others_unattached_files' );
-
- if ( ( ! $admin_others_attached ) || ! $admin_others_unattached )
- $can_edit_others_blogwide = $this->scoper->user_can_edit_blogwide( 'post', '', array( 'require_others_cap' => true, 'status' => 'publish' ) );
-
- global $current_user;
-
- // optionally hide other users' unattached uploads, but not from blog-wide Editors
- if ( $admin_others_unattached || $can_edit_others_blogwide )
- $author_clause = '';
- else
- $author_clause = "AND $wpdb->posts.post_author = '{$current_user->ID}'";
-
- if ( is_admin() && ( ! defined('SCOPER_BLOCK_UNATTACHED_UPLOADS') || ! SCOPER_BLOCK_UNATTACHED_UPLOADS ) )
- $unattached_clause = "( $wpdb->posts.post_parent = 0 $author_clause ) OR";
- else
- $unattached_clause = '';
-
- $attached_clause = ( $admin_others_attached || $can_edit_others_blogwide ) ? '' : "AND $wpdb->posts.post_author = '{$current_user->ID}'";
-
- $request = str_replace( "$wpdb->posts.post_type = 'attachment'", "( $wpdb->posts.post_type = 'attachment' AND ( $unattached_clause ( $wpdb->posts.post_parent IN ($subqry) $attached_clause ) ) )", $request );
- } else
- $request = str_replace( "$wpdb->posts.post_type = 'attachment'", "( $wpdb->posts.post_type = 'attachment' AND ( $wpdb->posts.post_parent IN ($subqry) ) )", $request );
-
- } else {
- // Generate a query filter based on roles for the listed objects
- $rs_where = $this->flt_objects_where($where, $src_name, $object_types, $args);
-
- if ( $pos_where === false )
- $request = $request . ' WHERE 1=1 ' . $where;
- else
- $request = substr($request, 0, $pos_where) . ' WHERE 1=1 ' . $rs_where; // any pre-exising join clauses remain in $request
- }
-
- // re-enable hardway-admin filtering
- $GLOBALS['scoper_status']->querying_db = false;
-
- //d_echo( "<br />filtered: $request<br /><br />" );
- return $request;
- }
-
- // called by flt_objects_where, flt_objects_results
- function _get_object_types( $src, $object_types = '' ) {
- if ( ! $object_types ) {
- if ( ! is_object($src) )
- if ( ! $src = $this->scoper->data_sources->get($src) )
- return array();
-
- return array_keys($src->object_types); // include all defined otypes in the query if none were specified
- } else
- return (array) $object_types; // make sure the passed-in value is an array
- }
-
- // called by flt_objects_where, flt_objects_results
- function _get_teaser_object_types($src_name, $object_types, $args = array()) {
- $args = (array) $args;
-
- if ( ! empty($args['skip_teaser']) || is_admin() || is_content_administrator_rs() || is_attachment_rs() || defined('XMLRPC_REQUEST') || ! empty($this->skip_teaser) )
- return array();
-
- if ( is_feed() && defined( 'SCOPER_NO_FEED_TEASER' ) )
- return array();
-
- if ( ( ! empty( $args['required_operation'] ) && ( 'read' != $args['required_operation'] ) ) )
- return array();
-
- if ( empty($object_types) )
- $object_types = $this->_get_object_types($src_name);
-
- $tease_otypes = array();
-
- if ( scoper_get_otype_option('do_teaser', $src_name) ) {
- global $current_user;
-
- foreach ( $object_types as $object_type )
- if ( scoper_get_otype_option('use_teaser', $src_name, $object_type) ) {
- $teased_users = scoper_get_otype_option( 'teaser_logged_only', $src_name, $object_type );
-
- if ( empty( $teased_users )
- || ( ( 'anon' == $teased_users ) && empty($current_user->ID) )
- || ( ( 'anon' != $teased_users ) && ! empty($current_user->ID) ) )
- $tease_otypes []= $object_type;
- }
- }
-
- return $tease_otypes;
- }
-
- // NOTE: Setting use_object_roles or use_term_roles to a boolean forces enable/disable for all types / taxonomies. Otherwise stored options will be retrieved for each object type / taxonomy.
- function flt_objects_where($where, $src_name, $object_types = '', $args = array() ) {
- $defaults = array( 'user' => '', 'use_object_roles' => -1, 'use_term_roles' => -1,
- 'taxonomies' => array(), 'request' => '', 'terms_query' => 0,
- 'force_reqd_caps' => '', 'alternate_reqd_caps' => '', 'source_alias' => '',
- 'required_operation' => '', 'terms_reqd_caps' => '', 'skip_teaser' => false
- );
- $args = array_merge( $defaults, (array) $args );
- extract($args);
-
- // filtering in user_has_cap sufficiently controls revision access; a match here should be for internal, pre-validation purposes
- if ( strpos( $where, "post_type = 'revision'") )
- return $where;
-
- $where_prepend = '';
-
- //rs_errlog ("object_where input: $where");
- //rs_errlog ('');
-
- //d_echo ("<br /><strong>object_where input:</strong> $where<br />");
- //echo "<br />$where<br />";
-
- if ( ! is_object($user) ) {
- $user = $GLOBALS['current_rs_user'];
- $args['user'] = $user;
- }
-
- if ( ! $src = $this->scoper->data_sources->get($src_name) )
- return $where; // the specified data source is not know to Role Scoper
-
- $src_table = ( ! empty($source_alias) ) ? $source_alias : $src->table;
-
- // verify table name and id col definition (the actual existance checked at time of admin entry)
- if ( ! ($src->table && $src->cols->id) ) {
- rs_notice( sprintf( 'Role Scoper Configuration Error: table_basename or col_id are undefined for the %s data source.', $src_name) );
- return $where;
- }
-
- // need to allow ambiguous object type for special cap requirements like comment filtering
- $object_types = $this->_get_object_types($src, $object_types);
- $tease_otypes = array_intersect( $object_types, $this->_get_teaser_object_types($src_name, $object_types, $args) );
-
- if ( ! empty($src->no_object_roles) )
- $use_object_roles = false;
-
- if ( $terms_query && $terms_reqd_caps ) {
- foreach ( array_keys($terms_reqd_caps) as $_object_type )
- $otype_status_reqd_caps[$_object_type][''] = $terms_reqd_caps[$_object_type]; // terms request does not support multiple statuses
-
- } else {
- if ( $force_reqd_caps && is_array($force_reqd_caps) ) {
- $otype_status_reqd_caps = $force_reqd_caps;
- } else {
- global $wpdb;
-
- if ( ! $required_operation )
- $required_operation = ( 'front' == CURRENT_ACCESS_NAME_RS ) ? OP_READ_RS : OP_EDIT_RS;
-
- $preview_future = strpos( $where, "$wpdb->posts.post_name =" ) || strpos( $where, "$wpdb->posts.ID =" );
-
- if ( ! $otype_status_reqd_caps = cr_get_reqd_caps( $src_name, $required_operation, -1, -1, false, $preview_future ) )
- return $where;
- }
-
- $otype_status_reqd_caps = array_intersect_key($otype_status_reqd_caps, array_flip($object_types) );
- }
-
- // Since Role Scoper can restrict or expand access regardless of post_status, query must be modified such that
- // * the default owner inclusion clause "OR post_author = [user_id] AND post_status = 'private'" is removed
- // * all statuses are listed apart from owner inclusion clause (and each of these status clauses is subsequently replaced with a scoped equivalent which imposes any necessary access limits)
- // * a new scoped owner clause is constructed where appropriate (see $where[$cap_name]['owner'] in function objects_where_role_clauses()
- //
- if ( $src->cols->owner && $user->ID ) {
- // force standard query padding
- $where = preg_replace("/{$src->cols->owner}\s*=\s*/", "{$src->cols->owner} = ", $where);
-
- $where = str_replace( " {$src->cols->owner} =", " $src_table.{$src->cols->owner} =", $where);
- $where = str_replace( " {$src->cols->owner} IN", " $src_table.{$src->cols->owner} IN", $where);
- }
-
- if ( ! empty($src->query_replacements) ) {
- foreach ( $src->query_replacements as $find => $replace ) {
- // for posts_request, remove the owner inclusion clause "OR post_author = [user_id] AND post_status = 'private'" because we'll account for each status based on properties of required caps
- $find_ = str_replace('[user_id]', $user->ID, $find);
- if ( false !== strpos($find_, '[') || false !== strpos($find_, ']') ) {
- rs_notice( sprintf( 'Role Scoper Config Error: invalid query clause search criteria for %1$s (%2$s).<br /><br />Valid placeholders are:<br />', $src_name, $find) . print_r(array_keys($map)) );
- return ' AND 1=2 ';
- }
-
- $replace_ = str_replace('[user_id]', $user->ID, $replace);
-
- if ( false !== strpos($replace_, '[') || false !== strpos($replace_, ']') ) {
- rs_notice( sprintf( 'Role Scoper Config Error: invalid query clause replacement criteria for %1$s (%2$s).<br /><br />Valid placeholders are:<br />', $src_name, $replace) . print_r(array_keys($map)) );
- return ' AND 1=2 ';
- }
-
- $where = str_replace($find_, $replace_, $where);
- }
- }
-
- $force_single_type = false;
-
- $col_type = ( ! empty( $src->cols->type ) ) ? $src->cols->type : '';
- if ( $col_type ) {
- // If the passed request contains a single object type criteria, maintain that status exclusively (otherwise include type-specific conditions for each available type)
- $matches = array();
- $num_matches = preg_match_all( "/$col_type\s*=\s*'([^']+)'/", $where, $matches );
- if ( 1 == $num_matches ) {
- $force_single_type = true;
- $object_types = array( $matches[1][0] );
-
- if ( $matched_reqd_caps = array_intersect_key( $otype_status_reqd_caps, array_flip($object_types) ) ) // sanity check prevents running with an empty reqd_caps array if something goes wrong with otype detection
- $otype_status_reqd_caps = $matched_reqd_caps;
- }
- }
-
- if ( ( 'post' == $src_name ) && ! array_intersect( $object_types, array_keys( array_intersect( scoper_get_option( 'use_post_types' ), array( true ) ) ) ) )
- return $where;
- elseif ( empty( $otype_status_reqd_caps) )
- return ' AND 1=2 ';
-
- $basic_status_clause = array();
- $force_single_status = false;
- $status_clause_pos = 0;
-
- $col_status = ( ! empty( $src->cols->status ) ) ? $src->cols->status : '';
- if ( $col_status ) {
- // force standard query padding
- $where = preg_replace("/$col_status\s*=\s*'/", "$col_status = '", $where);
-
- $where = str_replace(" $col_status =", " {$src_table}.$col_status =", $where);
- $where = str_replace(" $col_status IN", " {$src_table}.$col_status IN", $where);
-
- foreach ( array_keys( $otype_status_reqd_caps ) as $listing_otype )
- foreach( array_keys( $otype_status_reqd_caps[$listing_otype] ) as $status )
- $basic_status_clause[$status] = "{$src_table}.$col_status = '$status'";
-
- // If the passed request contains a single status criteria, maintain that status exclusively (otherwise include status-specific conditions for each available status)
- // (But not if user is anon and hidden content teaser is enabled. In that case, we need to replace the default "status=publish" clause)
- $matches = array();
- if ( $num_matches = preg_match_all( "/{$src_table}.$col_status\s*=\s*'([^']+)'/", $where, $matches ) )
- $status_clause_pos = strpos( $where, $matches[0][0] ); // note the match position for use downstream
-
- if ( 1 == $num_matches ) {
- $use_status = $matches[1][0];
-
- // Eliminate a primary plugin incompatibility by skipping this preservation of existing single status requirements if we're on the front end and the requirement is 'publish'.
- // (i.e. include private posts that this user has access to via RS role assignment).
- if ( ! $this->scoper->is_front() || ( 'publish' != $use_status ) || ( empty( $args['user']->ID ) && empty($tease_otypes) ) || defined('SCOPER_RETAIN_PUBLISH_FILTER') ) {
- $force_single_status = true;
-
- foreach ( array_keys($otype_status_reqd_caps) as $_object_type )
- $otype_status_reqd_caps[$_object_type] = array_intersect_key( $otype_status_reqd_caps[$_object_type], array( $use_status => true ) );
- }
- }
- } else {
- // this source doesn't define statuses
- $basic_status_clause = array ( '' => '');
- }
-
- if ( empty($skip_teaser) && ! array_diff($object_types, $tease_otypes) ) {
- if ( $status_clause_pos && $force_single_type ) { // All object types potentially returned by this query will have a teaser filter applied to results, so we don't need to filter the query
-
- // override our sanity safeguard against exposing private posts to anonymous readers
- if ( empty($user->ID) ) {
-
- // Since we're dropping out of this function early in advance of teaser filtering,
- // must take this opportunity to add private status to the query (otherwise WP excludes private for anon user)
- // (But don't do this if teaser is configured to hide private content)
- $check_otype = ( count($tease_otypes) && in_array('post', $tease_otypes) ) ? 'post' : $tease_otypes[0];
-
- $post_type_obj = get_post_type_object($check_otype);
-
- if ( ! scoper_get_otype_option('teaser_hide_private', $src_name, $check_otype) && ( ! $post_type_obj->hierarchical || scoper_get_otype_option('private_items_listable', 'post', 'page') ) ) {
- if ( $col_status && isset( $otype_status_reqd_caps[$check_otype] ) ) {
- $status_or = "{$src_table}.$col_status = '" . implode("' OR {$src_table}.$col_status = '", array_keys($otype_status_reqd_caps[$check_otype]) ) . "'";
- $where = str_replace( $basic_status_clause['publish'], "( $status_or )", $where);
- } else {
- $where = str_replace( $basic_status_clause['publish'], "1=1", $where);
- }
- }
- }
- }
-
- return $where;
- }
-
- $is_administrator = is_content_administrator_rs(); // make sure administrators never have content limited
-
- $status_or = '';
- $status_where = array();
-
- foreach ($otype_status_reqd_caps as $object_type => $status_reqd_caps) {
- if ( ! is_array($status_reqd_caps) ) {
- rs_notice( sprintf( 'Role Scoper Configuration Error: reqd_caps for the %s data source must be array[operation][object_type][status] where operation is "read", "edit" or "admin".', $src_name) );
- return $where;
- }
-
- // don't bother generating these parameters if we're just going to pass the object type through for teaser filtering
- if ( ! in_array($object_type, $tease_otypes) ) {
- if ( true === $use_term_roles ) { // if boolean true was passed in, force usage of all term roles
- if ( 'post' == $src_name ) {
- //$otype_use_term_roles = array_fill_keys( get_taxonomies( array( 'public' => true, 'object_type' => $object_type ) ), 1 );
- $otype_use_term_roles = array();
- foreach( get_taxonomies( array( 'public' => true ), 'object' ) as $taxonomy => $taxonomy_obj )
- if ( in_array( $object_type, $taxonomy_obj->object_type ) )
- $otype_use_term_roles[$taxonomy] = 1;
- } else
- $otype_use_term_roles = ( ! empty( $src->uses_taxonomies ) ) ? array_fill_keys( $src->uses_taxonomies, true ) : array();
- } else {
- $check_object_type = ( 'link_category' == $object_type ) ? 'link' : $object_type;
- $otype_use_term_roles = ( -1 == $use_term_roles ) ? scoper_get_otype_option('use_term_roles', $src_name, $check_object_type) : false;
- }
-
- if ( ( ! $otype_use_term_roles ) && $terms_query )
- continue;
-
- // if a boolean was passed in, override the stored option
- $otype_use_object_roles = ( -1 == $use_object_roles ) ? scoper_get_otype_option('use_object_roles', $src_name, $object_type) : $use_object_roles;
- } else {
- $otype_use_term_roles = false;
- $otype_use_object_roles = false;
- }
-
- //now step through all statuses and corresponding cap requirements for this otype and access type
- // (will replace "col_status = status_name" with "col_status = status_name AND ( [scoper requirements] )
- foreach ($status_reqd_caps as $status_name => $reqd_caps) {
- if ( 'trash' == $status_name ) // in wp-admin, we need to include trash posts for the count query, but not for the listing query unless trash status is requested
- if ( ( empty($this->last_request[$src_name]) || ! strpos($this->last_request[$src_name], 'COUNT') ) && ( empty( $_GET['post_status'] ) || ( 'trash' != $_GET['post_status'] ) ) )
- continue;
-
- if ( $is_administrator )
- $status_where[$status_name][$object_type] = '1=1';
- elseif ( empty($skip_teaser) && in_array($object_type, $tease_otypes) )
- if ( $terms_query && ! $otype_use_object_roles )
- $status_where[$status_name][$object_type] = '1=1';
- else
- $status_where[$status_name][$object_type] = "{$src_table}.{$src->cols->type} = '$object_type'"; // this object type will be teaser-filtered
- else {
- // filter defs for otypes which don't define a status will still have a single status element with value ''
- $args = array_merge( $args, array( 'object_type' => $object_type, 'otype_use_term_roles' => $otype_use_term_roles, 'otype_use_object_roles' => $otype_use_object_roles ) );
-
- $clause = $this->objects_where_role_clauses($src_name, $reqd_caps, $args);
-
- if ( empty($clause) || ( '1=2' == $clause ) ) // this means no qualifying roles are available
- $status_where[$status_name][$object_type] = '1=2';
-
- // array key order status/object is reversed intentionally for subsequent processing
- elseif ( (count($otype_status_reqd_caps) > 1) && ( ! $terms_query || $otype_use_object_roles) ) // more than 1 object type
- $status_where[$status_name][$object_type] = "( {$src_table}.{$src->cols->type} = '$object_type' AND ( $clause ) )";
- else
- $status_where[$status_name][$object_type] = $clause;
- }
- }
- }
-
- // all otype clauses concat: object_type1 clause [OR] [object_type2 clause] [OR] ...
- foreach ( array_keys($status_where) as $status_name ) {
- if ( isset($preserve_or_clause[$status_name]) )
- $status_where[$status_name][] = $preserve_or_clause[$status_name];
-
- if ( $tease_otypes )
- $check_otype = ( count($tease_otypes) && in_array('post', $tease_otypes) ) ? 'post' : $tease_otypes[0];
-
- // extra line of defense: even if upstream logic goes wrong, never disclose a private item to anon user (but if the where clause was passed in with explicit status=private, must include our condition)
- if ( ('private' == $status_name) && ! $force_single_status && empty($GLOBALS['current_user']->ID) && ( ! $tease_otypes || scoper_get_otype_option('teaser_hide_private', $src_name, $check_otype) ) )
- unset( $status_where[$status_name] );
- else
- $status_where[$status_name] = agp_implode(' ) OR ( ', $status_where[$status_name], ' ( ', ' ) ');
- }
-
- // combine identical status clauses
- $duplicate_clause = array();
- $replace_clause = array();
- if ( $col_status && count($status_where) > 1 ) { // more than one status clause
- foreach ( $status_where as $status_name => $status_clause) {
- if ( isset($duplicate_clause[$status_name]) )
- continue;
-
- reset($status_where);
- if ( $other_status_name = array_search($status_clause, $status_where) ) {
- if ( $other_status_name == $status_name ) $other_status_name = array_search($status_clause, $status_where);
- if ( $other_status_name && ( $other_status_name != $status_name ) ) {
- $duplicate_clause[$other_status_name][$status_name] = true;
- $replace_clause[$status_name] = true;
- }
- }
- }
- }
-
- $status_where = array_diff_key($status_where, $replace_clause);
-
- foreach ( $status_where as $status_name => $this_status_where) {
-
- if ( $status_clause_pos && $force_single_status ) {
- //We are maintaining the single status which was specified in original query
-
- if ( ! $this_status_where || ( $this_status_where == '1=2' ) )
- $where_prepend = '1=2';
-
- elseif ( $this_status_where == '1=1' )
- $where_prepend = '';
-
- else {
- //insert at original status clause position
- $where_prepend = '';
- $where = substr($where, 0, $status_clause_pos) . "( $this_status_where ) AND " . substr($where, $status_clause_pos);
- }
-
- break;
- }
-
- // We may be replacing or inserting status clauses
-
- if ( ! empty($duplicate_clause[$status_name]) ) {
- // We generated duplicate clauses for some statuses
- foreach ( array_keys($duplicate_clause[$status_name]) as $other_status_name ) {
- $where = str_replace($basic_status_clause[$other_status_name], '1=2', $where);
- }
-
- $duplicate_clause[$status_name] = array_merge($duplicate_clause[$status_name], array($status_name=>1) );
-
- if ( $col_status ) {
- $name_in = "'" . implode("', '", array_keys($duplicate_clause[$status_name])) . "'";
- $status_prefix = "{$src_table}.$col_status IN ($name_in)";
- } else {
- $status_prefix = "1=1";
- }
- } elseif ( $col_status && $status_name ) {
- $status_prefix = $basic_status_clause[$status_name];
- } else
- $status_prefix = '';
-
- if ( $this_status_where && ( $this_status_where != '1=2' || count($status_where) > 1 ) ) { //todo: confirm we can OR the 1=2 even if only one status clause
- if ( '1=1' == $this_status_where )
- $status_clause = ( $status_prefix ) ? "$status_prefix " : '';
- else {
- $status_clause = ( $col_status && $status_prefix ) ? "$status_prefix AND " : '';
- $status_clause .= "( $this_status_where )"; // TODO: reduce number of parentheses
- $status_clause = " ( $status_clause )";
- }
- } else
- $status_clause = '1=2';
-
- if ( $status_clause ) {
- if ( $col_status && $status_name && strpos($where, $basic_status_clause[$status_name]) ) {
- // Replace existing status clause with our scoped equivalent
- $where = str_replace($basic_status_clause[$status_name], "$status_clause", $where);
-
- } elseif ( $status_clause_pos && ( $status_clause != '1=2' ) ) {
- // This status was not in the original query, but we now insert it with scoping clause at the position of another existing status clause
- $where = substr($where, 0, $status_clause_pos) . "$status_clause OR " . substr($where, $status_clause_pos);
-
- } else {
- // Default query makes no mention of status (perhaps because this data source doesn't define statuses),
- // so prepend this clause to front of where clause
- $where_prepend .= "$status_or $status_clause";
- $status_or = ' OR';
- }
- }
- }
-
- // Existance of this variable means no status clause exists in default WHERE. AND away we go.
- // Prepend so we don't disturb any orderby/groupby/limit clauses which are along for the ride
- if ( $where_prepend ) {
- if ( $where )
- $where = " AND ( $where_prepend ) $where";
- else
- $where = " AND ( $where_prepend )";
- }
-
- //d_echo ("<br /><br /><strong>objects_where output:</strong> $where<br /><br />");
- //echo "<br />$where<br />";
-
- //rs_errlog ("object_where output: $where");
- //rs_errlog ('');
- //rs_errlog ('');
-
- return $where;
- }
-
-
- // core Role Scoper where clause concatenation called by listing filter (flt_objects_request) and single access filter (flt_user_has_cap)
- // $reqd_caps[cap_name] = min scope
- //
- // required args: user, object_type, otype_use_object_roles, otype_use_term_roles
- //
- function objects_where_role_clauses($src_name, $reqd_caps, $args = array() ) {
- $defaults = array( 'taxonomies' => array(), 'terms_query' => false, 'alternate_reqd_caps' => '',
- 'custom_user_blogcaps' => '', 'skip_owner_clause' => false, 'require_full_object_role' => false );
-
- // Required Args
- // NOTE: use_object_roles is a boolean for the single object_type in question, but otype_use_object_roles is array[taxonomy] = true or false
- $required = array_fill_keys( array( 'user', 'object_type', 'otype_use_term_roles', 'otype_use_object_roles' ), true );
-
- if ( $missing = array_diff_key( $required, $args ) ) {
- rs_notice ( sprintf( 'Role Scoper Runtime Error (%1$s) - Missing argument(s): %2$s', 'objects_where_scope_clauses', implode( ", ", array_keys($missing) ) ) );
- return ' 1=2 ';
- }
-
- $defaults = array_merge( $defaults, $required );
- $args = array_merge( $defaults, (array) $args );
- extract($args);
-
- if ( '' === $custom_user_blogcaps )
- $custom_user_blogcaps = SCOPER_CUSTOM_USER_BLOGCAPS;
-
- $reqd_caps = (array) $reqd_caps;
- $reqd_caps = $this->scoper->role_defs->role_handles_to_caps($reqd_caps);
-
- // accomodate editing of published posts/pages to revision
- if ( defined( 'RVY_VERSION' ) && rvy_get_option('pending_revisions') ) {
- if ( empty( $GLOBALS['revisionary']->skip_revision_allowance ) ) {
- $revision_uris = apply_filters( 'scoper_revision_uris', array( 'edit.php', 'upload.php', 'widgets.php', 'admin-ajax.php', 'rvy-revisions' ) );
-
- if ( is_admin() || ! empty( $_GET['preview'] ) )
- $revision_uris []= 'index.php';
-
- $plugin_page = is_admin() ? $GLOBALS['plugin_page_cr'] : '';
-
- if ( is_preview() || in_array( $GLOBALS['pagenow'], $revision_uris ) || in_array( $plugin_page, $revision_uris ) ) {
- $strip_capreqs = array();
-
- foreach( (array) $object_type as $_object_type ) {
- if ( $type_obj = get_post_type_object( $_object_type ) ) {
- $strip_capreqs = array_merge( $strip_capreqs, array( $type_obj->cap->edit_published_posts, $type_obj->cap->edit_private_posts ) );
-
- if ( array_intersect( $reqd_caps, $strip_capreqs ) )
- $reqd_caps []= $type_obj->cap->edit_posts;
- }
- }
-
- $reqd_caps = array_unique( array_diff($reqd_caps, $strip_capreqs) );
- }
-
- $do_revision_clause = true;
- }
- }
-
- if ( ! is_object($user) ) { // TODO: can we skip this now that user is a required arg?
- $user = $GLOBALS['current_rs_user'];
- }
-
- if ( ! $src = $this->scoper->data_sources->get($src_name) ) {
- rs_notice ( sprintf( 'Role Scoper Config Error (%1$s): Data source (%2$s) is not defined.', 'objects_where_role_clauses', $src_name) );
- return ' 1=2 ';
- }
-
- $src_table = ( ! empty($source_alias) ) ? $source_alias : $src->table;
- // special case to include pending / scheduled revisions by object role
- if ( ! isset( $args['objrole_revisions_clause'] ) ) {
- $args['objrole_revisions_clause'] = ( 'edit.php' == $GLOBALS['pagenow'] );
- }
-
- // These arguments are simply passed on to objects_where_scope_clauses()
- if ( 'group' == $src_name )
- $args['otype_use_object_roles'] = true;
- elseif ( ! empty($src->no_object_roles) )
- $args['otype_use_object_roles'] = false;
-
- if ( $args['otype_use_object_roles'] ) {
- // Return all object_ids that require any role to be object-assigned
- // We will use an ID NOT IN clause so these are not satisfied by blog/term role assignment
- $args['objscope_objects'] = $this->scoper->get_restrictions(OBJECT_SCOPE_RS, $src_name);
- }
-
- $where = array();
-
- foreach ( $reqd_caps as $cap_name ) {
- // If supporting custom user blogcaps, a separate role clause for each cap
- // Otherwise (default) all reqd_caps from one role assignment (whatever scope it may be)
- if ( $custom_user_blogcaps ) {
- $reqd_caps_arg = array($cap_name);
- } else {
- $reqd_caps_arg = $reqd_caps;
- $cap_name = '';
- }
-
- $qualifying_roles = $this->scoper->role_defs->qualify_roles($reqd_caps_arg, '', $object_type );
-
- /*
- rs_errlog( '' );
- rs_errlog( "reqd_caps arg: " . serialize($reqd_caps_arg) );
- rs_errlog( "qualifying roles for $object_type: " . serialize($qualifying_roles) );
- rs_errlog( '' );
- */
-
- if ( $alternate_reqd_caps && is_array( $alternate_reqd_caps ) ) { // $alternate_reqd_caps[setnum] = array of cap_names
- foreach ( $alternate_reqd_caps as $alternate_capset ) {
- foreach ( $alternate_capset as $alternate_reqd_caps ) {
- if ( $alternate_roles = $this->scoper->role_defs->qualify_roles($alternate_reqd_caps) )
- $qualifying_roles = array_merge($qualifying_roles, $alternate_roles);
- }
- }
- }
-
- // this is needed mainly for the chicken-egg situation of uploading a file into a post before a category is stored, when editing rights are based on category
- //if ( $args['otype_use_object_roles'] )
- $args['ignore_restrictions'] = ( 1 == count($reqd_caps_arg) ) && $this->scoper->cap_defs->member_property( reset($reqd_caps_arg), 'ignore_restrictions' );
-
- if ( $owner_reqd_caps = $this->scoper->cap_defs->get_base_caps($reqd_caps_arg) ) {
- $owner_roles = ( $require_full_object_role ) ? $qualifying_roles : $this->scoper->role_defs->qualify_roles($owner_reqd_caps, '', $object_type);
-
- if ( ! empty($alternate_roles ) )
- $owner_roles = array_merge( $owner_roles, $alternate_roles );
- } else
- $owner_roles = array();
-
- // have to pass qualifying_object_roles in for 'user' call because qualifying_roles may not include a qualifying object role (i.e. Page Contributor object role assignment)
- if ( $owner_roles && ( empty( $GLOBALS['revisionary'] ) || empty( $GLOBALS['revisionary']->skip_revision_allowance ) ) )
- $qualifying_object_roles = $this->scoper->confirm_object_scope( $owner_roles );
- else
- $qualifying_object_roles = $this->scoper->confirm_object_scope( $qualifying_roles ); // get_base_caps() strips out edit_private_* cap requirement for post owner, in compliance with WP metacap mapping. But for Revisionary, that causes Revisors to have full editing caps if a page is privately published (but not if it's publicly published).
-
- if ( $qualifying_roles || ! empty($qualifying_object_roles) ) {
- //d_echo( "regular objects_where_scope_clauses for " . serialize( $reqd_caps ) );
- $args = array_merge( $args, compact( 'qualifying_roles', 'qualifying_object_roles' ) );
- $where[$cap_name]['user'] = $this->objects_where_scope_clauses($src_name, $reqd_caps_arg, $args );
- }
-
- if ( ! empty($src->cols->owner) && ! $skip_owner_clause && $user->ID ) {
- if ( ! $require_full_object_role ) {
- // if owner qualifies for the operation by any different roles than other users, add separate owner clause
- $src_table = ( ! empty($source_alias) ) ? $source_alias : $src->table;
-
- if ( ! $owner_reqd_caps ) {
- // all reqd_caps are granted to owner automatically
- $where[$cap_name]['owner'] = "$src_table.{$src->cols->owner} = '$user->ID'";
- } elseif ( $owner_reqd_caps != $reqd_caps_arg ) {
- if ( $owner_roles ) {
- //d_echo( "owner objects_where_scope_clauses: " );
- $args = array_merge($args, array( 'qualifying_roles' => $owner_roles ) );
- $scope_temp = $this->objects_where_scope_clauses($src_name, $owner_reqd_caps, $args );
-
- if ( ( $scope_temp != $where[$cap_name]['user'] ) && ! is_null($scope_temp) ) { // TODO: why is null ever returned?
- $parent_clause = '';
-
- // enable authors to view / edit / approve revisions to their published posts
- if ( ! empty( $do_revision_clause ) && ! defined( 'HIDE_REVISIONS_FROM_AUTHOR' ) ) {
- static $owner_ids = array();
-
- if ( ! isset( $owner_ids[$user->ID][$object_type] ) ) { // also keying by user ID in case this filter is invoked for a non-current user
- $type_clause = ( ! empty($src->cols->type) ) ? "{$src->cols->type} = '$object_type' AND" : '';
-
- $owner_ids[$user->ID][$object_type] = scoper_get_col( "SELECT {$src->cols->id} FROM $src->table WHERE $type_clause {$src->cols->owner} = '$user->ID'" );
- }
-
- if ( ! empty($src->cols->type) && ! empty($src->cols->parent) && $owner_ids[$user->ID][$object_type] )
- $parent_clause = "OR $src_table.{$src->cols->type} = 'revision' AND $src_table.{$src->cols->parent} IN ('" . implode( "','", $owner_ids[$user->ID][$object_type] ) . "')";
- }
-
- $where[$cap_name]['owner'] = '( ' . $scope_temp . " ) AND ( $src_table.{$src->cols->owner} = '$user->ID' $parent_clause )";
- }
- }
- }
- }
- }
-
- // all role clauses concat: user clauses [OR] [owner clauses]
- if ( ! empty($where[$cap_name]) )
- $where[$cap_name] = agp_implode(' ) OR ( ', $where[$cap_name], ' ( ', ' ) ');
-
- // if not supporting custom caps, we actually passed all reqd_caps in first iteration
- if ( ! $custom_user_blogcaps )
- break;
- }
-
- // all reqd caps concat: cap1 clauses [AND] [cap2 clauses] [AND] ...
- if ( ! empty($where) )
- $where = agp_implode(' ) AND ( ', $where, ' ( ', ' ) ');
- else
- return '1=2';
-
- return $where;
- }
-
-
- function objects_where_scope_clauses($src_name, $reqd_caps, $args ) {
-
- // Optional Args (will be defaulted to meaningful values)
- // Note: ignore_restrictions affects Scoper::qualify_terms() output
- $defaults = array( 'taxonomies' => '', 'use_blog_roles' => true, 'terms_query' => false, 'qualifying_object_roles' => false,
- 'skip_objscope_check' => false, 'require_full_object_role' => false, 'objrole_revisions_clause' => false, 'ignore_restrictions' => false );
-
- // Required Args
- // NOTE: use_object_roles is a boolean for the single object_type in question, but use_term_roles is array[taxonomy] = true or false
- $required = array_fill_keys( array( 'user', 'object_type', 'qualifying_roles', 'otype_use_term_roles', 'otype_use_object_roles' ), true );
-
- if ( $missing = array_diff_key( $required, $args ) ) {
- rs_notice ( sprintf( 'Role Scoper Runtime Error (%1$s) - Missing argument(s): %2$s', 'objects_where_scope_clauses', implode( ", ", array_keys($missing) ) ) );
- return ' 1=2 ';
- }
-
- $defaults = array_merge( $defaults, $required );
- $args = array_merge( $defaults, (array) $args );
- extract($args);
-
- if ( ! $src = $this->scoper->data_sources->get($src_name) ) {
- rs_notice ( sprintf( 'Role Scoper Config Error (%1$s): Data source (%2$s) is not defined.', 'objects_where_scope_clauses', $src_name ) );
- return ' 1=2 ';
- }
-
- $src_table = ( ! empty($source_alias) ) ? $source_alias : $src->table;
-
- if ( 'group' == $src_name )
- $otype_use_object_roles = true;
- elseif ( ! empty($src->no_object_roles) )
- $otype_use_object_roles = false;
-
- // primary qualifying_roles array should contain only RS roles
- $qualifying_roles = $this->scoper->role_defs->filter( $qualifying_roles, array( 'role_type' => 'rs' ), 'names_as_key' );
-
- if ( $otype_use_object_roles ) {
- // For object assignment, replace any "others" reqd_caps array.
- // Also exclude any roles which have never been assigned to any object
- if ( ! is_array( $qualifying_object_roles ) )
- $qualifying_object_roles = $this->scoper->confirm_object_scope( $qualifying_roles, $user );
-
- if ( $skip_objscope_check )
- $objscope_objects = array();
- else
- $objscope_objects = $this->scoper->get_restrictions(OBJECT_SCOPE_RS, $src_name); // this is buffered so redundant calling is not a concern
- }
- //---------------------------------------------------------------------------------
-
- //dump($qualifying_object_roles);
- //dump($objscope_objects);
-
- if ( $otype_use_object_roles )
- $user_qualifies_for_obj_roles = ( $user->ID || defined( 'SCOPER_ANON_METAGROUP' ) );
-
- $where = array();
-
- if ( $terms_query ) {
- $_taxonomies = $taxonomies;
-
- } elseif ( $otype_use_term_roles && is_array($otype_use_term_roles) ) {
- $_taxonomies = array_keys( array_intersect( $otype_use_term_roles, array( 1, '1', true ) ) );
-
- // taxonomies arg is for limiting; default is to include all associated taxonomies in where clause
- if ( $taxonomies )
- $_taxonomies = array_intersect( $_taxonomies, $taxonomies );
- } else {
- $_taxonomies = array();
- }
-
- if ( $_taxonomies && ( 'post' == $src_name ) ) {
- $enabled_taxonomies = array_keys( array_intersect( scoper_get_option( 'use_taxonomies' ), array( 1, '1', true ) ) );
- $_taxonomies = array_intersect( $_taxonomies, $enabled_taxonomies );
- }
-
- $user_blog_roles = array( '' => array() );
-
- if ( $use_blog_roles ) {
- foreach( array_keys($user->blog_roles) as $date_key )
- $user_blog_roles[$date_key] = array_intersect_key( $user->blog_roles[$date_key], $qualifying_roles );
-
- // Also include user's WP blogrole(s),
- // but via equivalent RS role(s) to support scoping requirements (strict (i.e. restricted) terms, objects)
- if ( $wp_qualifying_roles = $this->scoper->role_defs->qualify_roles($reqd_caps, 'wp') ) {
- if ( $user_blog_roles_wp = array_intersect_key( $user->blog_roles[ANY_CONTENT_DATE_RS], $wp_qualifying_roles ) ) {
- // Credit user's qualifying WP blogrole via contained RS role(s)
- // so we can also enforce "term restrictions", which are based on RS roles
- $user_blog_roles_via_wp = $this->scoper->role_defs->get_contained_roles( array_keys($user_blog_roles_wp), false, 'rs');
- $user_blog_roles_via_wp = array_intersect_key($user_blog_roles_via_wp, $qualifying_roles);
-
- $user_blog_roles[ANY_CONTENT_DATE_RS] = array_merge( $user_blog_roles[ANY_CONTENT_DATE_RS], $user_blog_roles_via_wp);
- }
- }
- }
-
- /*
- // --- optional hack to require read_private cap via blog role AND object role
- // if the required capabilities include a read_private cap but no edit caps
- $require_blog_and_obj_role = ( in_array('read_private_posts', $reqd_caps) || in_array('read_private_pages', $reqd_caps) ) && ( ! array_diff( $reqd_caps, array('read_private_posts', 'read_private_pages', 'read') ) );
- // --- end hack ---
- */
-
- //dump($qualifying_roles);
- //dump($objscope_objects);
-
- foreach ( array_keys($qualifying_roles) as $role_handle ) {
- //dump($role_handle);
-
- if ( $otype_use_object_roles && empty($require_blog_and_obj_role) ) {
- if ( ! empty($objscope_objects['restrictions'][$role_handle]) ) {
- $objscope_clause = " AND $src_table.{$src->cols->id} NOT IN ('" . implode("', '", array_keys($objscope_objects['restrictions'][$role_handle])) . "')";
- }
- elseif ( isset($objscope_objects['unrestrictions'][$role_handle]) ) {
- if ( ! empty($objscope_objects['unrestrictions'][$role_handle]) )
- $objscope_clause = " AND $src_table.{$src->cols->id} IN ('" . implode("', '", array_keys($objscope_objects['unrestrictions'][$role_handle])) . "')";
- else
- $objscope_clause = " AND 1=2"; // role is default-restricted for this object type, but objects are unrestrictions are set
- } else
- $objscope_clause = '';
- } else
- $objscope_clause = '';
-
- //dump($objscope_clause);
-
- $all_terms_qualified = array();
- $all_taxonomies_qualified = array();
-
- if ( $_taxonomies ) {
- $args['return_id_type'] = COL_TAXONOMY_ID_RS;
-
- $strict_taxonomies = array();
-
- foreach ($_taxonomies as $taxonomy)
- if ( $this->scoper->taxonomies->member_property($taxonomy, 'requires_term') )
- $strict_taxonomies[$taxonomy] = true;
-
- foreach ($_taxonomies as $taxonomy) {
- // we only need a separate clause for each role if considering object roles (and therefore considering that some objects might require some roles to be object-assigned)
- if ( ! $otype_use_object_roles )
- $role_handle_arg = $qualifying_roles;
- else
- $role_handle_arg = array( $role_handle => 1 );
-
- // If a taxonomy does not require objects to have a term, its term role assignments
- // will be purely supplemental; there is no basis for ignoring blogrole assignments.
- //
- // So if none of the taxonomies require each object to have a term
- // AND the user has a qualifying role via blog assignment, we can skip the taxonomies clause altogether.
- // Otherwise, will consider current user's termroles
- if ( ! $strict_taxonomies ) {
- if ( array_intersect_key($role_handle_arg, $user->blog_roles[ANY_CONTENT_DATE_RS]) ) {
- // User has a qualifying role by blog assignment, so term_id clause is not required
- $all_taxonomies_qualified[ANY_CONTENT_DATE_RS] = true;
- break;
- }
- }
-
- // qualify_terms returns:
- // terms for which current user has a qualifying role
- // - AND -
- // which are non-restricted (i.e. blend in blog assignments) for a qualifying role which the user has blog-wide
- //
- // note: $reqd_caps function arg is used; qualify_terms will ignore reqd_caps element in args array
- if ( $user_terms = $this->scoper->qualify_terms_daterange($reqd_caps, $taxonomy, $role_handle_arg, $args) ) {
- if ( ! isset($term_count[$taxonomy]) )
- $term_count[$taxonomy] = $this->scoper->get_terms($taxonomy, UNFILTERED_RS, COL_COUNT_RS);
-
- foreach ( array_keys($user_terms) as $date_key ) {
- if ( count($user_terms[$date_key]) ) {
- // don't bother applying term requirements if user has cap for all terms in this taxonomy
- if ( (count($user_terms[$date_key]) >= $term_count[$taxonomy]) && $this->scoper->taxonomies->member_property($taxonomy, 'requires_term') ) {
- // User is qualified for all terms in this taxonomy; no need for any term_id clauses
- $all_terms_qualified[$date_key][$taxonomy] = true;
- } else {
- $where[$date_key][$objscope_clause][TERM_SCOPE_RS][$taxonomy] = ( isset($where[$date_key][$objscope_clause][TERM_SCOPE_RS][$taxonomy]) ) ? array_unique( array_merge($where[$date_key][$objscope_clause][TERM_SCOPE_RS][$taxonomy], $user_terms[$date_key]) ) : $user_terms[$date_key];
- }
- }
-
- $all_taxonomies_qualified[$date_key] = ! empty( $all_terms_qualified[$date_key] ) && ( count($all_terms_qualified[$date_key]) == count($strict_taxonomies) );
- }
- }
- } // end foreach taxonomy
- }
-
- foreach ( array_keys($user_blog_roles) as $date_key ) {
- if ( ! empty($all_taxonomies_qualified[$date_key]) || ( ! $_taxonomies && ! empty($user_blog_roles[$date_key][$role_handle]) ) ) {
- if ( $date_key || $objscope_clause || ! empty($require_blog_and_obj_role) ) {
- $where[$date_key][$objscope_clause][BLOG_SCOPE_RS] = "1=1";
- } else {
- return "1=1"; // no need to include other clause if user has a qualifying role blog-wide or in all terms, it is not date-limited, and that role does not require object assignment for any objects
- }
- }
- }
-
- // if object roles should be applied, populatate array key to force inclusion of OBJECT_SCOPE_RS query clauses below
- if ( $otype_use_object_roles && isset($qualifying_object_roles[$role_handle]) && $user_qualifies_for_obj_roles ) { // want to apply objscope requirements for anon user, but not apply any obj roles
- if ( $role_spec = scoper_explode_role_handle($role_handle) )
- $where[ANY_CONTENT_DATE_RS][NO_OBJSCOPE_CLAUSE_RS][OBJECT_SCOPE_RS][$role_spec->role_type][$role_spec->role_name] = true;
- }
-
- // we only need a separate clause for each role if considering object roles (and therefore considering that some objects might require some roles to be object-assigned)
- if ( ! $otype_use_object_roles && ! empty($where[ANY_CONTENT_DATE_RS]) )
- break;
- } // end foreach role
-
- // also include object scope clauses for any roles which qualify only for object-assignment
- if ( $otype_use_object_roles && isset( $qualifying_object_roles ) && $user_qualifies_for_obj_roles ) { // want to apply objscope requirements for anon user, but not apply any obj roles
- if ( $obj_only_roles = array_diff_key( $qualifying_object_roles, $qualifying_roles ) ) {
- foreach ( array_keys($obj_only_roles) as $role_handle )
- if ( $role_spec = scoper_explode_role_handle($role_handle) )
- $where[ANY_CONTENT_DATE_RS][NO_OBJSCOPE_CLAUSE_RS][OBJECT_SCOPE_RS][$role_spec->role_type][$role_spec->role_name] = true;
- }
- }
-
- // DB query perf enhancement: if any terms are included regardless of post ID, don't also include those terms in ID-specific clause
- foreach ( array_keys($where) as $date_key ) {
- foreach ( array_keys($where[$date_key]) as $objscope_clause ) {
- if ( $objscope_clause && isset($where[$date_key][$objscope_clause][TERM_SCOPE_RS]) ) {
- foreach ( $where[$date_key][$objscope_clause][TERM_SCOPE_RS] as $taxonomy => $terms ) {
-
- if ( ! empty($terms) && ! empty($where[$date_key][NO_OBJSCOPE_CLAUSE_RS][TERM_SCOPE_RS][$taxonomy]) ) {
- $where[$date_key][$objscope_clause][TERM_SCOPE_RS][$taxonomy] = array_diff( $where[$date_key][$objscope_clause][TERM_SCOPE_RS][$taxonomy], $where[$date_key][NO_OBJSCOPE_CLAUSE_RS][TERM_SCOPE_RS][$taxonomy] );
-
- if ( empty( $where[$date_key][$objscope_clause][TERM_SCOPE_RS][$taxonomy] ) ) {
- unset( $where[$date_key][$objscope_clause][TERM_SCOPE_RS][$taxonomy] );
-
- // if we removed a taxonomy array, don't leave behind a term scope array with no taxonomies
- if ( empty( $where[$date_key][$objscope_clause][TERM_SCOPE_RS] ) ) {
- unset( $where[$date_key][$objscope_clause][TERM_SCOPE_RS] );
-
- // if we removed a term scope array, don't leave behind an objscope array with no scopes
- if ( empty( $where[$date_key][$objscope_clause] ) )
- unset( $where[$date_key][$objscope_clause] );
- }
- }
- }
- }
- }
- }
- }
-
- // since object roles are not pre-loaded prior to this call, role date limits are handled via subselect, within the date_key = '' iteration
- $object_roles_duration_clause = scoper_get_duration_clause();
-
-
- // implode the array of where criteria into a query as concisely as possible
- foreach ( $where as $date_key => $objscope_clauses ) {
-
- foreach ( $objscope_clauses as $objscope_clause => $scope_criteria ) {
-
- foreach ( array_keys($scope_criteria) as $scope ) {
-
- switch ($scope) {
- case BLOG_SCOPE_RS:
- $where[$date_key][$objscope_clause][BLOG_SCOPE_RS] = $where[$date_key][$objscope_clause][BLOG_SCOPE_RS] . " $objscope_clause";
- break;
-
- case TERM_SCOPE_RS:
- $taxonomy_clauses = array();
-
- foreach ( $scope_criteria[TERM_SCOPE_RS] as $taxonomy => $terms ) {
- $is_strict = ! empty( $strict_taxonomies[$taxonomy] );
-
- if ( $objscope_clause )
- // Avoid " term_id IN (5) OR ( term_id IN (5) AND ID NOT IN (100) )
- // Otherwise this redundancy can occur when various qualifying roles require object role assignment for different objects
- if ( ! empty($where[$date_key][NO_OBJSCOPE_CLAUSE_RS][TERM_SCOPE_RS][$taxonomy]) )
- if ( ! $terms = array_diff($terms, $where[$date_key][NO_OBJSCOPE_CLAUSE_RS][TERM_SCOPE_RS][$taxonomy]) ) {
- //unset($scope_criteria[TERM_SCOPE_RS][$taxonomy]); // this doesn't affect anything (removed in v1.1)
- continue;
- }
-
- $terms = array_unique($terms);
- if ( $qvars = $this->scoper->taxonomies->get_terms_query_vars($taxonomy) )
- if ( $terms_query && ! $otype_use_object_roles ) {
- $qtv = $this->scoper->taxonomies->get_terms_query_vars($taxonomy, true);
- $taxonomy_clauses[false] []= "{$qtv->term->alias}.{$qtv->term->col_id} IN ('" . implode("', '", $terms) . "') $objscope_clause";
- } else {
- $this_tx_clause = "{$qvars->term->alias}.{$qvars->term->col_id} IN ('" . implode("', '", $terms) . "')";
-
- // Use a subselect rather than adding our own LEFT JOIN.
- $terms_subselect = "SELECT {$qvars->term->alias}.{$qvars->term->col_obj_id} FROM {$qvars->term->table} {$qvars->term->as} WHERE $this_tx_clause";
-
- if ( defined('RVY_VERSION') && $objrole_revisions_clause )
- $revision_clause = "OR ( $src_table.{$src->cols->type} = 'revision' AND $src_table.{$src->cols->parent} IN ( $terms_subselect ) )";
- else
- $revision_clause = '';
-
- $taxonomy_clauses[$is_strict] []= "( $src_table.{$src->cols->id} IN ( $terms_subselect ) $revision_clause ) $objscope_clause";
- }
- }
-
- if ( $taxonomy_clauses ) {
- // all taxonomy clauses concat: [taxonomy 1 clauses] [OR] [taxonomy 2 clauses] [OR] ...
- //$where[$date_key][$objscope_clause][TERM_SCOPE_RS] = agp_implode(' ) OR ( ', $taxonomy_clauses, ' ( ', ' ) ');
-
- // strict taxonomy clauses (if any are present, they must all be satisfied)
- if ( ! empty( $taxonomy_clauses[true] ) ) {
- $where[$date_key][$objscope_clause][TERM_SCOPE_RS] = agp_implode(' ) AND ( ', $taxonomy_clauses[true], ' ( ', ' ) ');
-
- // non-strict taxonomy clauses
- } elseif ( ! empty( $taxonomy_clauses[false] ) ) {
- $where[$date_key][$objscope_clause][TERM_SCOPE_RS] = agp_implode(' ) OR ( ', $taxonomy_clauses[false], ' ( ', ' ) ');
- } else {
- $where[$date_key][$objscope_clause][TERM_SCOPE_RS] = '1=2';
- }
-
- // all taxonomy clauses concat: ( [strict taxonomy clause 1] [AND] [strict taxonomy clause 2]... ) [OR] [taxonomy 3 clauses] [OR] ...
- //$where[$date_key][$objscope_clause][TERM_SCOPE_RS] = agp_implode(' ) OR ( ', $taxonomy_clauses, ' ( ', ' ) ');
- }
-
- break;
-
- case OBJECT_SCOPE_RS: // should only exist with nullstring objscope_clause
- if ( $user_qualifies_for_obj_roles ) {
-
- global $wpdb;
- $u_g_clause = $user->get_user_clause('uro');
-
- foreach ( array_keys($scope_criteria[OBJECT_SCOPE_RS]) as $role_type ) { //should be only one
- if ( $scope_criteria[OBJECT_SCOPE_RS][$role_type] )
- ksort( $scope_criteria[OBJECT_SCOPE_RS][$role_type] ); // sort array for efficient membuffering of query results
-
- // Combine all qualifying (and applied) object roles into a single OR clause
- $role_in = "'" . implode("', '", array_keys($scope_criteria[OBJECT_SCOPE_RS][$role_type])) . "'";
-
- static $cache_obj_ids = array();
-
- if ( 'post.php' == $GLOBALS['pagenow'] && ! empty($_REQUEST['action']) || did_action( 'save_post' ) || ! empty($_GET['doaction']) )
- $force_refresh = true;
-
- $objrole_subselect = "SELECT DISTINCT uro.obj_or_term_id FROM $wpdb->user2role2object_rs AS uro WHERE uro.role_type = '$role_spec->role_type' AND uro.scope = 'object' AND uro.assign_for IN ('entity', 'both') AND uro.role_name IN ($role_in) AND uro.src_or_tx_name = '$src_name' $object_roles_duration_clause $u_g_clause ";
-
- if ( ! isset( $cache_obj_ids[$objrole_subselect] ) || ! empty($force_refresh) )
- $cache_obj_ids[$objrole_subselect] = scoper_get_col( $objrole_subselect );
-
- if ( $cache_obj_ids[$objrole_subselect] ) {
- $where[$date_key][$objscope_clause][OBJECT_SCOPE_RS] = "$src_table.{$src->cols->id} IN ( '" . implode( "','", $cache_obj_ids[$objrole_subselect] ) . "' )";
- } else
- $where[$date_key][$objscope_clause][OBJECT_SCOPE_RS] = "1=2";
-
- if ( defined('RVY_VERSION') && $objrole_revisions_clause )
- $where[$date_key][$objscope_clause][OBJECT_SCOPE_RS] = "( {$where[$date_key][$objscope_clause]['object']} OR ( $src_table.{$src->cols->type} = 'revision' AND $src_table.{$src->cols->parent} IN ( '" . implode( "','", $cache_obj_ids[$objrole_subselect] ) . "' ) ) )";
- }
- }
-
- break;
- } // end scope switch
- } // end foreach scope
-
- /*
- // --- optional hack to require read_private cap via blog role AND object role
- if ( ! empty($require_blog_and_obj_role) ) {
- if ( ! isset($where[$date_key][''][BLOG_SCOPE_RS]) )
- $where[$date_key][''][BLOG_SCOPE_RS] = '1=2';
-
- if ( ! isset($where[$date_key][''][TERM_SCOPE_RS]) )
- $where[$date_key][''][TERM_SCOPE_RS] = '1=2';
-
- if ( ! isset($where[$date_key][''][OBJECT_SCOPE_RS]) )
- $where[$date_key][''][OBJECT_SCOPE_RS] = '1=2';
-
- $where[$date_key][''] = "( ( {$where[$date_key]['']['blog']} ) OR ( {$where[$date_key]['']['term']} ) ) AND ( {$where[$date_key]['']['object']} )";
- }
- else
- // --- end hack
- */
- // all scope clauses concat: [object roles] OR [term ids] OR [blogrole1 clause] [OR] [blogrole2 clause] [OR] ...
- // Collapse the array to a string even if it's empty
- $where[$date_key][$objscope_clause] = agp_implode(' ) OR ( ', $where[$date_key][$objscope_clause], ' ( ', ' ) ');
- } // end foreach objscope clause
-
- $date_clause = '';
-
- if ( $date_key && is_serialized($date_key) ) {
- $content_date_limits = unserialize($date_key);
-
- if ( $content_date_limits->content_min_date_gmt )
- $date_clause .= " AND $src_table.{$src->cols->date} >= '" . $content_date_limits->content_min_date_gmt . "'";
-
- if ( $content_date_limits->content_max_date_gmt )
- $date_clause .= " AND $src_table.{$src->cols->date} <= '" . $content_date_limits->content_max_date_gmt . "'";
- }
-
- foreach ( array_keys($where[$date_key]) as $objscope_clause )
- if ( empty ($where[$date_key][$objscope_clause]) )
- unset($where[$date_key][$objscope_clause]);
-
- // all objscope clauses concat: [clauses w/o objscope] [OR] [objscope 1 clauses] [OR] [objscope 2 clauses]
- $where[$date_key] = agp_implode(' ) OR ( ', $where[$date_key], ' ( ', ' ) ');
-
- if ( $date_clause && $where[$date_key] )
- $where[$date_key] = "( $where[$date_key]{$date_clause} )";
-
- } // end foreach datekey (set of content date limits for which role(s) apply)
-
-
- foreach ( array_keys($where) as $date_key )
- if ( empty ($where[$date_key]) )
- unset($where[$date_key]);
-
- // all date clauses concat: [clauses w/o content date limits] [OR] [content date range 1 clauses] [OR] [content date range 2 clauses]
- $where = agp_implode(' ) OR ( ', $where, ' ( ', ' ) ');
-
- if ( empty($where) )
- $where = '1=2';
-
- return $where;
- }
-
- function flt_objects_results($results, $src_name, $object_types, $args = array()) {
- if ( ! $object_types || ( is_array($object_types) && count($object_types) > 1 ) )
- $object_type = cr_find_post_type();
- else
- $object_type = strval( $object_types );
-
- if ( ( 'edit.php' == $GLOBALS['pagenow'] ) && ! is_content_administrator_rs() ) {
- $post_type_obj = get_post_type_object( $object_type );
-
- if ( ! empty($post_type_obj->hierarchical) ) {
- // ScoperAncestry class is loaded by hardway_rs.php
- $ancestors = ScoperAncestry::get_page_ancestors(); // array of all ancestor IDs for keyed page_id, with direct parent first
-
- $args = array( 'remap_parents' => false );
- ScoperHardway::remap_tree( $results, $ancestors, 'ID', 'post_parent', $args );
- }
- }
-
- if ( $this->scoper->is_front() && empty($this->skip_teaser) ) {
- if ( $tease_otypes = $this->_get_teaser_object_types($src_name, $object_types, $args) ) {
- require_once( dirname(__FILE__).'/teaser_rs.php');
-
- $args['force_teaser'] = true;
- return ScoperTeaser::posts_teaser_prep_results( $results, $tease_otypes, $args );
- }
-
- // won't do anything unless teaser is enabled for object type(s)
- //$results = apply_filters('objects_teaser_pre_results_rs', $results, 'post', $object_type, array('force_teaser' => true));
- }
-
- return $results;
- }
-
- // currently only used to conditionally launch teaser filtering
- function flt_the_posts( $results, $query_obj ) {
- if ( empty($this->skip_teaser) ) {
- //$object_type = cr_find_post_type( '', false); // object type detection is problematic due to insertion of posts query into page templates on some installations
- $object_type = '';
-
- // won't do anything unless teaser is enabled for object type(s)
- $results = apply_filters( 'objects_teaser_rs', $results, 'post', $object_type, array('force_teaser' => true) );
- }
-
- return $results;
- }
-
- function flt_objects_teaser($results, $src_name, $object_types = '', $args = array()) {
- $defaults = array('user' => '', 'use_object_roles' => -1, 'use_term_roles' => -1, 'request' => '', 'force_teaser' => false);
- $args = array_merge( $defaults, (array) $args );
- extract($args);
-
- global $wpdb;
-
- if ( 'post' != $src_name )
- return $results;
-
- if ( is_admin() || defined('XMLRPC_REQUEST') )
- return $results;
-
- $object_types = $this->_get_object_types($src_name, $object_types);
- $tease_otypes = $this->_get_teaser_object_types($src_name, $object_types, $args);
-
- if ( empty($tease_otypes) || ( empty($force_teaser) && ! array_intersect($object_types, $tease_otypes) ) )
- return $results;
-
- require_once( dirname(__FILE__).'/teaser_rs.php');
- return ScoperTeaser::posts_teaser($results, $tease_otypes, $args);
- }
-
- } // end class
-
-
- function agp_parse_after_WHERE_11( $request, &$pos_where, &$pos_suffix ) {
- $request_u = strtoupper($request);
- $pos_where = strpos( $request_u, ' WHERE 1=1');
-
- if ( ! $pos_where ) {
- if ( $pos_suffix = agp_get_suffix_pos($request) )
- $where = substr($request, $pos_suffix);
- } else {
- // note: this will still also contain any orderby/limit/groupby clauses ( okay since we won't append anything to the end )
- $where = substr($request, $pos_where + strlen(' WHERE 1=1 '));
- }
-
- return $where;
- }
-
- function agp_get_suffix_pos( $request ) {
- $request_u = strtoupper($request);
-
- $pos_suffix = strlen($request) + 1;
- foreach ( array(' ORDER BY ', ' GROUP BY ', ' LIMIT ') as $suffix_term )
- if ( $pos = strrpos($request_u, $suffix_term) )
- if ( $pos < $pos_suffix )
- $pos_suffix = $pos;
-
- return $pos_suffix;
- }
- ?>