'', 'use_object_roles' => -1, 'use_term_roles' => -1, 'request' => '', 'object_type' => '' ); $args = array_merge( $defaults, (array) $args ); extract($args); global $wpdb, $scoper, $wp_query; global $query_interceptor; if ( did_action('wp_meta') && ! did_action('wp_head') ) return $results; if ( empty($request) ) { // TODO: teaser logs last_request itself global $query_interceptor; if ( empty ($query_interceptor->last_request['post']) ) { // try to get it from wpdb instead if ( ! empty($wpdb->last_query) ) $request = $wpdb->last_query; else { // don't risk exposing hidden content if something goes wrong with query logging return array(); } } else $request = $query_interceptor->last_request['post']; } // Pagination could be broken by subsequent query for filtered ids, so buffer current paging parameters // ( this code mimics WP_Query::get_posts() ) if ( ! empty( $wp_query->query_vars['posts_per_page'] ) ) { $found_posts_query = apply_filters( 'found_posts_query', 'SELECT FOUND_ROWS()' ); $buffer_found_posts = $wpdb->get_var( $found_posts_query ); if ( $buffer_found_posts >= $wp_query->query_vars['posts_per_page'] ) { $restore_pagination = true; $buffer_found_posts = apply_filters( 'found_posts', $buffer_found_posts ); } } $list_private = array(); if ( awp_ver( '3.0' ) ) $private_stati = get_post_stati( array( 'private' => true ) ); else $private_stati = array( 'private' ); if ( is_single() || is_page() ) { $maybe_fudge_private = true; $maybe_strip_private = false; } else { $maybe_strip_private = true; $maybe_fudge_private = false; } if ( ! is_object($user) ) { global $current_user; $user = $current_user; } // don't risk exposing hidden content if there is a problem with query parsing if ( ! $pos = strpos(strtoupper($request), " FROM") ) return array(); $distinct = ( stripos( $request, " DISTINCT " ) ) ? 'DISTINCT' : ''; // RS does not add any joins, but if DISTINCT clause exists in query, retain it $request = "SELECT $distinct {$wpdb->posts}.ID " . substr($request, $pos); if ( $limitpos = strpos($request, ' LIMIT ') ) $request = substr($request, 0, $limitpos); $args['skip_teaser'] = true; $filtered_request = $query_interceptor->flt_objects_request($request, 'post', $object_type, $args); global $scoper_teaser_filtered_ids; $scoper_teaser_filtered_ids = scoper_get_col($filtered_request); if ( ! isset($scoper->teaser_ids) ) $scoper->teaser_ids = array(); $hide_ungranted_private = array(); foreach ( $tease_otypes as $object_type ) { $hide_ungranted_private[$object_type] = scoper_get_otype_option('teaser_hide_private', 'post', $object_type); } foreach ( array_keys($results) as $key ) { if ( is_array($results[$key]) ) $id = $results[$key]['ID']; else $id = $results[$key]->ID; if ( ! $scoper_teaser_filtered_ids || ! in_array($id, $scoper_teaser_filtered_ids) ) { if ( isset($results[$key]->post_type) ) $object_type = $results[$key]->post_type; else $object_type = $scoper->data_sources->get_from_db('type', 'post', $id); if ( ! in_array($object_type, $tease_otypes) ) continue; // Defeat a WP core secondary safeguard so we can apply the teaser message rather than 404 if ( in_array( $results[$key]->post_status, $private_stati ) ) { // don't want the teaser message (or presence in category archive listing) if we're hiding a page from listing $type_obj = get_post_type_object( $object_type ); if ( $type_obj && $type_obj->hierarchical ) { // TODO: review implementation of this option with custom types if ( ! isset($list_private[$object_type]) ) $list_private[$object_type] = scoper_get_otype_option( 'private_items_listable', 'post', 'page' ); } else $list_private[$object_type] = true; if ( $hide_ungranted_private[$object_type] || ( $maybe_strip_private && ! $list_private[$object_type] ) ) { $need_reindex = true; unset ( $results[$key] ); // Actually, don't do this because the current method of removing private items from the paged result set will not move items from one result page to another //$buffer_found_posts--; // since we're removing this item from the teased results, decrement the paging total continue; } elseif ( ! empty( $maybe_fudge_private ) && $list_private[$object_type] ) { $results[$key]->post_status = 'publish'; } } } } if ( ! empty($need_reindex) ) // re-index the array so paging isn't confused $results = array_values($results); // pagination could be broken by the filtered ids query performed in this function, so original paging parameters were buffered if ( ! empty($restore_pagination) ) { // WP query will apply found_posts filter shortly after this function returns. Feed it the buffered value from original unfiltered results. // Static flag in created function ensures it is only applied once. $func_name = create_function( '$a', 'static $been_here; if ( ! empty($been_here) ) return $a; else {$been_here = true; ' . "return $buffer_found_posts;}" ); add_filter( 'found_posts', $func_name, 1); } return $results; } // apply teaser modifications to the recordset. Note: this is applied later than function posts_teaser($results, $tease_otypes, $args = '') { $defaults = array('user' => '', 'use_object_roles' => -1, 'use_term_roles' => -1, 'request' => '' ); $args = array_merge( $defaults, (array) $args ); extract($args); global $wpdb, $scoper, $wp_query; if ( did_action('wp_meta') && ! did_action('wp_head') ) return $results; if ( ! is_object($user) ) { global $current_user; $user = $current_user; } $teaser_replace = array(); $teaser_prepend = array(); $teaser_append = array(); foreach ( $tease_otypes as $object_type ) { $teaser_replace[$object_type]['post_content'] = ScoperTeaser::get_teaser_text( 'replace', 'content', 'post', $object_type, $user ); $teaser_prepend[$object_type]['post_content'] = ScoperTeaser::get_teaser_text( 'prepend', 'content', 'post', $object_type, $user ); $teaser_append[$object_type]['post_content'] = ScoperTeaser::get_teaser_text( 'append', 'content', 'post', $object_type, $user ); $teaser_replace[$object_type]['post_excerpt'] = ScoperTeaser::get_teaser_text( 'replace', 'excerpt', 'post', $object_type, $user ); $teaser_prepend[$object_type]['post_excerpt'] = ScoperTeaser::get_teaser_text( 'prepend', 'excerpt', 'post', $object_type, $user ); $teaser_append[$object_type]['post_excerpt'] = ScoperTeaser::get_teaser_text( 'append', 'excerpt', 'post', $object_type, $user ); $teaser_prepend[$object_type]['post_title'] = ScoperTeaser::get_teaser_text( 'prepend', 'name', 'post', $object_type, $user ); $teaser_append[$object_type]['post_title'] = ScoperTeaser::get_teaser_text( 'append', 'name', 'post', $object_type, $user ); } global $scoper_teaser_filtered_ids; if ( ! isset($scoper->teaser_ids) ) $scoper->teaser_ids = array(); $excerpt_teaser = array(); $more_teaser = array(); $x_chars_teaser = array(); foreach ( $tease_otypes as $object_type ) { $teaser_type = scoper_get_otype_option( 'use_teaser', 'post', $object_type ); if ( 'excerpt' == $teaser_type ) $excerpt_teaser[$object_type] = true; elseif ( 'more' == $teaser_type ) { $excerpt_teaser[$object_type] = true; $more_teaser[$object_type] = true; } elseif ( 'x_chars' == $teaser_type ) { $excerpt_teaser[$object_type] = true; $more_teaser[$object_type] = true; $x_chars_teaser[$object_type] = true; } } // strip content from all $results rows not in $items $args = array( 'teaser_prepend' => $teaser_prepend, 'teaser_append' => $teaser_append, 'teaser_replace' => $teaser_replace, 'excerpt_teaser' => $excerpt_teaser, 'more_teaser' => $more_teaser, 'x_chars_teaser' => $x_chars_teaser ); foreach ( array_keys($results) as $key ) { if ( is_array($results[$key]) ) $id = $results[$key]['ID']; else $id = $results[$key]->ID; if ( ! $scoper_teaser_filtered_ids || ! in_array($id, $scoper_teaser_filtered_ids) ) { if ( isset($results[$key]->post_type) ) $object_type = $results[$key]->post_type; else $object_type = $scoper->data_sources->get_from_db('type', 'post', $id); if ( ! in_array($object_type, $tease_otypes) ) continue; ScoperTeaser::apply_teaser( $results[$key], 'post', $object_type, $args ); } } return $results; } function get_teaser_text( $teaser_operation, $variable, $src_name, $object_type, $user = '' ) { if ( ! is_object($user) ) { global $current_user; $user = $current_user; } $anon = ( $user->ID == 0 ) ? '_anon' : ''; if ( $msg = scoper_get_otype_option( "teaser_{$teaser_operation}_{$variable}{$anon}", 'post', $object_type, CURRENT_ACCESS_NAME_RS) ) { if ( defined('SCOPER_TRANSLATE_TEASER') ) { scoper_load_textdomain(); // otherwise this is only loaded for wp-admin $msg = translate( $msg, 'scoper'); if ( ! empty($msg) && ! is_null($msg) && is_string($msg) ) $msg = htmlspecialchars_decode( $msg ); } return $msg; } } function apply_teaser( &$object, $src_name, $object_type, $args = '' ) { $defaults = array( 'col_excerpt' => '', 'col_content' => '', 'excerpt_teaser' => '', 'col_id' => '', 'teaser_prepend' => '', 'teaser_append' => '', 'teaser_replace' => '', 'more_teaser' => '', 'x_chars_teaser' => '' ); $args = array_merge( $defaults, (array) $args ); extract($args); global $scoper; if ( is_array($object) ) $id = $object['ID']; else $id = $object->ID; $object->scoper_teaser = true; $scoper->teaser_ids['post'][$id] = true; if ( ! empty( $object->post_password ) ) { $excerpt_teaser[$object_type] = false; $more_teaser[$object_type] = false; $x_chars_teaser[$object_type] = false; } if ( ! empty($x_chars_teaser[$object_type]) ) $num_chars = ( defined('SCOPER_TEASER_NUM_CHARS') ) ? SCOPER_TEASER_NUM_CHARS : 50; // Content replacement mode is applied in the following preference order: // 1. Custom excerpt, if available and if selected teaser mode is "excerpt", "excerpt or more", or "excerpt, pre-more or first x chars" // 2. Pre-more content, if applicable and if selected teaser mode is "excerpt or more", or "excerpt, pre-more or first x chars" // 3. First X Characters (defined by SCOPER_TEASER_NUM_CHARS), if total content is longer than that and selected teaser mode is "excerpt, pre-more or first x chars" $teaser_set = false; $use_excerpt_suffix = true; // optionally, use post excerpt as the hidden content teaser instead of a fixed replacement if ( ! empty($excerpt_teaser[$object_type]) && ! empty($object->post_excerpt) ) { $object->post_content = $object->post_excerpt; } elseif ( ! empty($more_teaser[$object_type]) && ( $more_pos = strpos($object->post_content, '') ) ) { $object->post_content = substr( $object->post_content, 0, $more_pos + 11 ); $object->post_excerpt = $object->post_content; if ( is_single() || is_page() ) $object->post_content .= '

' . $teaser_replace[$object_type]['post_content'] . '

'; // since no custom excerpt or more tag is stored, use first X characters as teaser - but only if the total length is more than that } elseif ( ! empty($x_chars_teaser[$object_type]) && ! empty($object->post_content) && ( strlen( strip_tags($object->post_content) ) > $num_chars ) ) { scoper_load_textdomain(); // otherwise this is only loaded for wp-admin // since we are stripping out img tag, also strip out image caption applied by WP $object->post_content = preg_replace( "/\[caption.*\]/", '', $object->post_content ); $object->post_content = str_replace( "[/caption]", '', $object->post_content ); $object->post_content = sprintf(_x('%s...', 'teaser suffix', 'scoper'), substr( strip_tags($object->post_content), 0, $num_chars ) ); $object->post_excerpt = $object->post_content; if ( is_single() || is_page() ) $object->post_content .= '

' . $teaser_replace[$object_type]['post_content'] . '

'; } else { if ( isset($teaser_replace[$object_type]['post_content']) ) $object->post_content = $teaser_replace[$object_type]['post_content']; else $object->post_content = ''; // Replace excerpt with a user-specified fixed teaser message, // but only if since no custom excerpt exists or teaser options aren't set to some variation of "use excerpt as teaser" if ( ! empty($teaser_replace[$object_type]['post_excerpt']) ) $object->post_excerpt = $teaser_replace[$object_type]['post_excerpt']; // If SCOPER_FORCE_EXCERPT_SUFFIX is defined, use the "content" prefix and suffix only when fully replacing content with a fixed teaser $use_excerpt_suffix = false; } // Deal with ambiguity in teaser settings. Previously, content prefix/suffix was applied even if RS substitutes the excerpt as displayed content. // To avoid confusion with existing installations, only use excerpt prefix/suffix if a value is set or constant is defined. if ( $use_excerpt_suffix && defined( 'SCOPER_FORCE_EXCERPT_SUFFIX' ) ) { $teaser_prepend[$object_type]['post_content'] = $teaser_prepend[$object_type]['post_excerpt']; $teaser_append[$object_type]['post_content'] = $teaser_append[$object_type]['post_excerpt']; } foreach ( $teaser_prepend[$object_type] as $col => $entry ) if ( isset($object->$col) ) $object->$col = $entry . $object->$col; foreach ( $teaser_append[$object_type] as $col => $entry ) if ( isset($object->$col) ) { if ( ( $col == 'post_content' ) && ! empty( $more_pos ) ) { // WP will strip off anything after the more comment $object->$col = str_replace( '', "$entry", $object->$col ); } else $object->$col .= $entry; } // no need to display password form if we're blocking content anyway if ( ! empty( $object->post_password ) ) $object->post_password = ''; } } // end class ?>