slug = 'related_posts'; $this->title = esc_html__( 'Related Posts', 'elasticpress' ); $this->summary = __( 'ElasticPress understands data in real time, so it can instantly deliver engaging and precise related content with no impact on site performance.', 'elasticpress' ); $this->docs_url = __( 'https://elasticpress.zendesk.com/hc/en-us/articles/360050447492-Configuring-ElasticPress-via-the-Plugin-Dashboard#related-posts', 'elasticpress' ); $this->requires_install_reindex = false; parent::__construct(); } /** * Format args for related posts * * @param array $formatted_args Formatted ES args * @param array $args WP_Query args * @return array */ public function formatted_args( $formatted_args, $args ) { if ( ! empty( $args['more_like'] ) ) { // lets compare ES version to see if new MLT structure applies $new_mlt = version_compare( Elasticsearch::factory()->get_elasticsearch_version(), 6.0, '>=' ); if ( $new_mlt && is_array( $args['more_like'] ) ) { foreach ( $args['more_like'] as $id ) { $ids[] = array( '_id' => $id ); } } elseif ( $new_mlt && ! is_array( $args['more_like'] ) ) { $ids = array( '_id' => $args['more_like'] ); } else { $ids = is_array( $args['more_like'] ) ? $args['more_like'] : array( $args['more_like'] ); } $mlt_key = ( $new_mlt ) ? 'like' : 'ids'; $formatted_args['query'] = array( 'more_like_this' => array( $mlt_key => $ids, /** * Filter fields used to determine related posts * * @hook ep_related_posts_fields * @param {array} $fields Related post fields * @return {array} New fields */ 'fields' => apply_filters( 'ep_related_posts_fields', array( 'post_title', 'post_content', 'terms.post_tag.name', ) ), /** * Filter related posts minimum term frequency * * @hook ep_related_posts_min_term_freq * @param {int} $minimum Minimum term frequency * @return {array} New value */ 'min_term_freq' => apply_filters( 'ep_related_posts_min_term_freq', 1 ), /** * Filter related posts maximum query terms * * @hook ep_related_posts_max_query_terms * @param {int} $maximum Maximum query terms * @return {array} New value */ 'max_query_terms' => apply_filters( 'ep_related_posts_max_query_terms', 12 ), /** * Filter related posts minimum document frequency * * @hook ep_related_posts_min_doc_freq * @param {int} $minimum Minimum document frequency * @return {array} New value */ 'min_doc_freq' => apply_filters( 'ep_related_posts_min_doc_freq', 1 ), ), ); } return $formatted_args; } /** * Search Elasticsearch for related content * * @param int $post_id Post ID * @param int $return Return code * @since 4.1.0 * @return WP_Query */ public function get_related_query( $post_id, $return = 5 ) { $args = array( 'more_like' => $post_id, 'posts_per_page' => $return, 'ep_integrate' => true, 'ignore_sticky_posts' => true, ); /** * Filter WP Query related post arguments * * @hook ep_find_related_args * @param {array} $args WP Query arguments * @since 2.1 * @return {array} New arguments */ return new WP_Query( apply_filters( 'ep_find_related_args', $args ) ); } /** * Search Elasticsearch for related content * * @param int $post_id Post ID * @param int $return Return code * * @since 2.1 * @uses get_related_query * * @return array|bool */ public function find_related( $post_id, $return = 5 ) { $query = $this->get_related_query( $post_id, $return ); if ( ! $query->have_posts() ) { return false; } return $query->posts; } /** * Setup all feature filters * * @since 2.1 */ public function setup() { add_action( 'widgets_init', [ $this, 'register_widget' ] ); add_filter( 'widget_types_to_hide_from_legacy_widget_block', [ $this, 'hide_legacy_widget' ] ); add_filter( 'ep_formatted_args', [ $this, 'formatted_args' ], 10, 2 ); add_action( 'init', [ $this, 'register_block' ] ); add_action( 'rest_api_init', [ $this, 'setup_endpoint' ] ); } /** * Setup REST endpoints * * @since 3.2 */ public function setup_endpoint() { register_rest_route( 'wp/v2', '/posts/(?P[0-9]+)/related', [ 'methods' => 'GET', 'callback' => [ $this, 'output_endpoint' ], 'permission_callback' => '__return_true', 'args' => [ 'id' => [ 'description' => 'Post ID.', 'type' => 'numeric', ], 'number' => [ 'description' => 'Number of posts', 'type' => 'numeric', 'default' => 5, ], ], ] ); } /** * Output related posts endpoint * * @param \WP_REST_Request $request REST request * @since 3.2 * @return \WP_REST_Response */ public function output_endpoint( $request ) { $id = $request['id']; $posts = $this->find_related( $id, (int) $request['number'] ); $prepared_posts = []; if ( ! empty( $posts ) ) { foreach ( $posts as $post ) { $prepared_post = []; $prepared_post['id'] = $post->ID; $prepared_post['link'] = get_permalink( $post->ID ); $prepared_post['status'] = $post->post_status; $prepared_post['title'] = [ 'raw' => $post->post_title, 'rendered' => get_the_title( $post->ID ), ]; $prepared_post['author'] = (int) $post->post_author; $prepared_post['parent'] = (int) $post->post_parent; $prepared_post['menu_order'] = (int) $post->menu_order; $prepared_post['content'] = [ 'rendered' => post_password_required( $post ) ? '' : apply_filters( 'the_content', $post->post_content ), ]; $prepared_post['date'] = $post->post_date; $prepared_post['date_gmt'] = $post->post_date_gmt; $prepared_post['modified'] = $post->post_modified; $prepared_post['modified_gmt'] = $post->post_modified_gmt; $prepared_posts[] = $prepared_post; } } $response = new \WP_REST_Response(); $response->set_data( $prepared_posts ); return $response; } /** * Register gutenberg block * * @since 3.2 */ public function register_block() { /** * Registering it here so translation works * * @see https://core.trac.wordpress.org/ticket/54797#comment:20 */ wp_register_script( 'ep-related-posts-block-script', EP_URL . 'dist/js/related-posts-block-script.js', Utils\get_asset_info( 'related-posts-block-script.js', 'dependencies' ), Utils\get_asset_info( 'related-posts-block-script.js', 'version' ), true ); wp_set_script_translations( 'ep-related-posts-block-script', 'elasticpress' ); register_block_type_from_metadata( EP_PATH . 'assets/js/blocks/related-posts', [ 'render_callback' => [ $this, 'render_block' ], ] ); } /** * Render Gutenberg block * * @param array $attributes Block attributes * @since 3.2 * @return string */ public function render_block( $attributes ) { $posts = $this->find_related( get_the_ID(), $attributes['number'] ); if ( empty( $posts ) ) { return ''; } $class = 'wp-block-elasticpress-related-posts'; if ( ! empty( $attributes['align'] ) ) { $class .= ' align' . $attributes['align']; } if ( ! empty( $attributes['className'] ) ) { $class .= ' ' . $attributes['className']; } ob_start(); ?>

API functions.', 'elasticpress' ) ); ?>