*/ private static $snippets = array(); /** * Registers hooks. */ public static function init() { add_filter( 'posts_pre_query', array( __CLASS__, 'pre_query' ), 10, 2 ); add_filter( 'get_the_excerpt', array( __CLASS__, 'excerpt' ), 20, 2 ); } /** * Whether the search box upgrade is on. * * @return bool */ public static function enabled() { return '1' === (string) get_option( self::OPTION_ENABLED, '1' ) && Keys::is_connected(); } /** * Asks AskMyPages for one page of results. * * @param string $query Search terms. * @param int $page Page number. * @param int $per_page Results per page. * @return array|\WP_Error */ public static function fetch( $query, $page, $per_page ) { return Api::signed( 'POST', '/v1/plugin/search', wp_json_encode( array( 'q' => $query, 'page' => $page, 'perPage' => $per_page, // Who is searching: members-only items come back only for allowed roles. 'viewer' => Access::viewer(), ) ), self::TIMEOUT ); } /** * Supplies results for the main search query. * * @param array|null $posts Posts, or null to let WordPress query. * @param WP_Query $query The query. * @return array|null */ public static function pre_query( $posts, $query ) { if ( null !== $posts || is_admin() || ! $query instanceof WP_Query || ! $query->is_main_query() || ! $query->is_search() ) { return $posts; } $terms = (string) $query->get( 's' ); if ( '' === trim( $terms ) || ! self::enabled() || ! Access::allowed( 'search' ) ) { return $posts; } $per_page = (int) $query->get( 'posts_per_page' ); $per_page = $per_page > 0 ? min( $per_page, 50 ) : (int) get_option( 'posts_per_page', 10 ); $page = max( 1, (int) $query->get( 'paged' ) ); $result = self::fetch( $terms, $page, $per_page ); if ( is_wp_error( $result ) || ! isset( $result['results'], $result['total'] ) ) { // Fall back to native search and tell the admin why, once in a while. set_transient( 'askmypages_search_fallback', is_wp_error( $result ) ? $result->get_error_message() : 'unexpected response', HOUR_IN_SECONDS ); return $posts; } $ids = array(); foreach ( (array) $result['results'] as $hit ) { $id = isset( $hit['externalId'] ) ? absint( $hit['externalId'] ) : 0; if ( $id ) { $ids[] = $id; self::$snippets[ $id ] = isset( $hit['snippet'] ) ? (string) $hit['snippet'] : ''; } } $found = array(); if ( $ids ) { $found = get_posts( array( 'post__in' => $ids, 'orderby' => 'post__in', 'post_type' => 'any', // PDFs are attachments, whose status is "inherit"; private // items only come back for viewers the service allowed. 'post_status' => array( 'publish', 'private', 'inherit' ), 'posts_per_page' => count( $ids ), ) ); $found = array_values( array_filter( $found, static function ( $post ) { return 'attachment' !== $post->post_type || Sync::is_eligible_pdf( $post ); } ) ); } $query->found_posts = (int) $result['total']; $query->max_num_pages = (int) ceil( $query->found_posts / $per_page ); return $found; } /** * Uses the AskMyPages snippet as the excerpt on search results. Only the * tag survives; the service escapes everything else. * * @param string $excerpt Excerpt. * @param \WP_Post $post Post. * @return string */ public static function excerpt( $excerpt, $post = null ) { if ( $post && isset( self::$snippets[ $post->ID ] ) && '' !== self::$snippets[ $post->ID ] ) { return wp_kses( self::$snippets[ $post->ID ], array( 'mark' => array() ) ); } return $excerpt; } }