PluginProbe
ElasticPress / 5.3.5
ElasticPress v5.3.5
5.3.5 5.3.4 3.6.5 3.6.6 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 5.0.0 5.0.1 5.0.2 All 108 releases
elasticpress / includes / classes / Feature / RelatedPosts / RelatedPosts.php

RelatedPosts.php in ElasticPress 5.3.5, at includes/classes/Feature/RelatedPosts/RelatedPosts.php

289 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ElasticPress related posts feature
4 *
5 * @since 2.1
6 * @package elasticpress
7 */
8
9 namespace ElasticPress\Feature\RelatedPosts;
10
11 use WP_Query;
12 use ElasticPress\Elasticsearch;
13 use ElasticPress\Feature;
14 use ElasticPress\REST;
15 use ElasticPress\Utils;
16
17 /**
18 * Related posts feature class
19 */
20 class RelatedPosts extends Feature {
21 /**
22 * Initialize feature setting it's config
23 *
24 * @since 3.0
25 */
26 public function __construct() {
27 $this->slug = 'related_posts';
28
29 $this->group = 'core-search';
30
31 $this->requires_install_reindex = false;
32
33 parent::__construct();
34 }
35
36 /**
37 * Sets i18n strings.
38 *
39 * @return void
40 * @since 5.2.0
41 */
42 public function set_i18n_strings(): void {
43 $this->title = esc_html__( 'Related Posts', 'elasticpress' );
44
45 $this->summary = '<p>' . __( 'Instantly deliver engaging and precise related content with no impact on site performance. Output related content using our block or directly in your theme using our <a href="https://www.elasticpress.io/resources/articles/related-posts-api/">API functions</a>.', 'elasticpress' ) . '</p>';
46
47 $this->docs_url = __( 'https://www.elasticpress.io/resources/articles/configuring-elasticpress-via-the-plugin-dashboard/#related-posts', 'elasticpress' );
48 }
49
50 /**
51 * Format args for related posts
52 *
53 * @param array $formatted_args Formatted ES args
54 * @param array $args WP_Query args
55 * @return array
56 */
57 public function formatted_args( $formatted_args, $args ) {
58 if ( ! empty( $args['more_like'] ) ) {
59 // lets compare ES version to see if new MLT structure applies
60 $new_mlt = version_compare( (string) Elasticsearch::factory()->get_elasticsearch_version(), 6.0, '>=' );
61
62 if ( $new_mlt && is_array( $args['more_like'] ) ) {
63 foreach ( $args['more_like'] as $id ) {
64 $ids[] = array( '_id' => $id );
65 }
66 } elseif ( $new_mlt && ! is_array( $args['more_like'] ) ) {
67 $ids = array( '_id' => $args['more_like'] );
68 } else {
69 $ids = is_array( $args['more_like'] ) ? $args['more_like'] : array( $args['more_like'] );
70 }
71
72 $mlt_key = ( $new_mlt ) ? 'like' : 'ids';
73
74 $formatted_args['query'] = array(
75 'more_like_this' => array(
76 $mlt_key => $ids,
77 /**
78 * Filter fields used to determine related posts
79 *
80 * @hook ep_related_posts_fields
81 * @param {array} $fields Related post fields
82 * @return {array} New fields
83 */
84 'fields' => apply_filters(
85 'ep_related_posts_fields',
86 array(
87 'post_title',
88 'post_content',
89 'terms.post_tag.name',
90 )
91 ),
92 /**
93 * Filter related posts minimum term frequency
94 *
95 * @hook ep_related_posts_min_term_freq
96 * @param {int} $minimum Minimum term frequency
97 * @return {array} New value
98 */
99 'min_term_freq' => apply_filters( 'ep_related_posts_min_term_freq', 1 ),
100 /**
101 * Filter related posts maximum query terms
102 *
103 * @hook ep_related_posts_max_query_terms
104 * @param {int} $maximum Maximum query terms
105 * @return {array} New value
106 */
107 'max_query_terms' => apply_filters( 'ep_related_posts_max_query_terms', 12 ),
108 /**
109 * Filter related posts minimum document frequency
110 *
111 * @hook ep_related_posts_min_doc_freq
112 * @param {int} $minimum Minimum document frequency
113 * @return {array} New value
114 */
115 'min_doc_freq' => apply_filters( 'ep_related_posts_min_doc_freq', 1 ),
116 ),
117 );
118 }
119
120 return $formatted_args;
121 }
122
123 /**
124 * Search Elasticsearch for related content
125 *
126 * @param int $post_id Post ID
127 * @param int $post_return Number of posts to return
128 * @since 4.1.0
129 * @return WP_Query
130 */
131 public function get_related_query( $post_id, $post_return = 5 ) {
132 $args = array(
133 'more_like' => $post_id,
134 'posts_per_page' => $post_return,
135 'ep_integrate' => true,
136 'ignore_sticky_posts' => true,
137 );
138
139 /**
140 * Filter WP Query related post arguments
141 *
142 * @hook ep_find_related_args
143 * @param {array} $args WP Query arguments
144 * @since 2.1
145 * @return {array} New arguments
146 */
147 return new WP_Query( apply_filters( 'ep_find_related_args', $args ) );
148 }
149
150 /**
151 * Search Elasticsearch for related content
152 *
153 * @param int $post_id Post ID
154 * @param int $post_return Number of posts to return
155 *
156 * @since 2.1
157 * @uses get_related_query
158 *
159 * @return array|bool
160 */
161 public function find_related( $post_id, $post_return = 5 ) {
162 $query = $this->get_related_query( $post_id, $post_return );
163
164 if ( ! $query->have_posts() ) {
165 return false;
166 }
167 return $query->posts;
168 }
169
170 /**
171 * Setup all feature filters
172 *
173 * @since 2.1
174 */
175 public function setup() {
176 add_action( 'widgets_init', [ $this, 'register_widget' ] );
177 add_filter( 'widget_types_to_hide_from_legacy_widget_block', [ $this, 'hide_legacy_widget' ] );
178 add_filter( 'ep_formatted_args', [ $this, 'formatted_args' ], 10, 2 );
179 add_action( 'init', [ $this, 'register_block' ] );
180 add_action( 'rest_api_init', [ $this, 'setup_endpoint' ] );
181 }
182
183 /**
184 * Setup REST endpoints
185 *
186 * @since 3.2
187 */
188 public function setup_endpoint() {
189 $controller = new REST\RelatedPosts();
190 $controller->register_routes();
191 }
192
193 /**
194 * Register gutenberg block
195 *
196 * @since 3.2
197 */
198 public function register_block() {
199 /**
200 * Registering it here so translation works
201 *
202 * @see https://core.trac.wordpress.org/ticket/54797#comment:20
203 */
204 wp_register_script(
205 'ep-related-posts-block-script',
206 EP_URL . 'dist/js/related-posts-block-script.js',
207 Utils\get_asset_info( 'related-posts-block-script.js', 'dependencies' ),
208 Utils\get_asset_info( 'related-posts-block-script.js', 'version' ),
209 true
210 );
211
212 wp_set_script_translations( 'ep-related-posts-block-script', 'elasticpress' );
213
214 register_block_type_from_metadata(
215 EP_PATH . 'assets/js/blocks/related-posts',
216 [
217 'render_callback' => [ $this, 'render_block' ],
218 ]
219 );
220 }
221
222 /**
223 * Render Gutenberg block
224 *
225 * @param array $attributes Block attributes
226 * @since 3.2
227 * @return string
228 */
229 public function render_block( $attributes ) {
230 $posts = $this->find_related( get_the_ID(), $attributes['number'] );
231
232 if ( empty( $posts ) ) {
233 return '';
234 }
235
236 $class = 'wp-block-elasticpress-related-posts';
237
238 if ( ! empty( $attributes['align'] ) ) {
239 $class .= ' align' . $attributes['align'];
240 }
241
242 ob_start();
243
244 $wrapper_attributes = get_block_wrapper_attributes( [ 'class' => $class ] );
245 ?>
246 <section <?php echo wp_kses_data( $wrapper_attributes ); ?>">
247 <ul>
248 <?php foreach ( $posts as $related_post ) : ?>
249 <li>
250 <a href="<?php echo esc_url( get_permalink( $related_post->ID ) ); ?>">
251 <?php echo wp_kses( get_the_title( $related_post->ID ), 'ep-html' ); ?>
252 </a>
253 </li>
254 <?php endforeach; ?>
255 </ul>
256 </section>
257 <?php
258
259 $block_content = ob_get_clean();
260
261 return $block_content;
262 }
263
264 /**
265 * Register related posts widget
266 *
267 * @since 2.2
268 */
269 public function register_widget() {
270 register_widget( __NAMESPACE__ . '\Widget' );
271 }
272
273 /**
274 * Hide the legacy widget.
275 *
276 * Hides the legacy widget in favor of the Block when the block editor
277 * is in use and the legacy widget has not been used.
278 *
279 * @since 4.3
280 * @param array $widgets An array of excluded widget-type IDs.
281 * @return array array of excluded widget-type IDs to hide.
282 */
283 public function hide_legacy_widget( $widgets ) {
284 $widgets[] = 'ep-related-posts';
285
286 return $widgets;
287 }
288 }
289