PluginProbe
Parse.ly / 3.8.4
Parse.ly v3.8.4
3.24.1 3.24.0 3.23.7 3.23.6 3.23.5 3.23.4 3.23.3 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.17.0 3.18.0 3.18.1 3.19.0 3.19.1 3.19.2 3.19.3 3.2.0 3.2.1 3.20.0 3.20.1 3.20.2 3.20.3 All 105 releases
← All changes | src/UI/class-recommended-widget.php +130 -79 3.2.03.8.4 View file →
@@ -1,13 +1,11 @@
1 1 <?php
2 2 /**
3 - * Recommended Widget file
3 + * UI: Recommended Widget class
4 4 *
5 - * This provides a widget to put on a page, will have parsely recommended articles
5 + * Provides a widget with Parse.ly recommended articles.
6 6 *
7 - * @category Components
8 - * @package WordPress
9 - * @subpackage Parse.ly
7 + * @package Parsely
10 8 */
11 9
12 10 declare(strict_types=1);
13 11
@@ -12,20 +10,61 @@
12 10 declare(strict_types=1);
13 11
14 12 namespace Parsely\UI;
15 13
14 +use Parsely\Parsely;
16 15 use WP_Widget;
17 16
17 +use function Parsely\Utils\get_asset_info;
18 +
18 19 use const Parsely\PARSELY_FILE;
19 20
20 21 /**
21 - * This is the class for the recommended widget.
22 + * Provides a widget with Parse.ly recommended articles.
23 + *
24 + * @phpstan-type Widget_Settings array{
25 + * title: string,
26 + * return_limit: int,
27 + * display_direction: string,
28 + * published_within: int,
29 + * sort: string,
30 + * boost: string,
31 + * personalize_results: bool,
32 + * img_src: string,
33 + * display_author: bool,
34 + * }
22 35 */
23 36 final class Recommended_Widget extends WP_Widget {
24 37 /**
25 - * This is the constructor function.
38 + * Instance of Parsely class.
39 + *
40 + * @var Parsely
26 41 */
27 - public function __construct() {
42 + private $parsely;
43 +
44 + /**
45 + * Default values of widget settings
46 + *
47 + * @var Widget_Settings
48 + */
49 + private static $default_widget_settings = array(
50 + 'title' => '',
51 + 'return_limit' => 5,
52 + 'display_direction' => 'vertical',
53 + 'published_within' => 0,
54 + 'sort' => 'score',
55 + 'boost' => 'views',
56 + 'personalize_results' => false,
57 + 'img_src' => 'parsely_thumb',
58 + 'display_author' => false,
59 + );
60 +
61 + /**
62 + * Constructor.
63 + *
64 + * @param Parsely $parsely Instance of Parsely class.
65 + */
66 + public function __construct( Parsely $parsely ) {
28 67 parent::__construct(
29 68 'Parsely_Recommended_Widget',
30 69 __( 'Parse.ly Recommended Widget', 'wp-parsely' ),
31 70 array(
@@ -32,12 +71,14 @@
32 71 'classname' => 'Recommended_Widget parsely-recommended-widget-hidden',
33 72 'description' => __( 'Display a list of post recommendations, personalized for a visitor or the current post.', 'wp-parsely' ),
34 73 )
35 74 );
75 +
76 + $this->parsely = $parsely;
36 77 }
37 78
38 79 /**
39 - * Get the URL for the Recommendations API (GET /related).
80 + * Gets the URL for the Recommendations API (GET /related).
40 81 *
41 82 * @see https://www.parse.ly/help/api/recommendations#get-related
42 83 *
43 84 * @internal While this is a public method now, this should be moved to a new class.
@@ -43,24 +84,24 @@
43 84 * @internal While this is a public method now, this should be moved to a new class.
44 85 *
45 86 * @since 2.5.0
46 87 *
47 - * @param string $api_key Publisher Site ID (API key).
88 + * @param string $site_id Publisher Site ID.
48 89 * @param int|null $published_within Publication filter start date; see https://www.parse.ly/help/api/time for
49 - * formatting details. No restriction by default.
50 - * @param string|null $sort What to sort the results by. There are currently 2 valid options: `score`, which
51 - * will sort articles by overall relevance and `pub_date` which will sort results by
52 - * their publication date. The default is `score`.
90 + * formatting details. No restriction by default.
91 + * @param string|null $sort What to sort the results by. There are currently 2 valid options: `score`,
92 + * which will sort articles by overall relevance and `pub_date` which will sort
93 + * results by their publication date. The default is `score`.
53 94 * @param string|null $boost Available for sort=score only. Sub-sort value to re-rank relevant posts that
54 - * received high e.g. views; default is undefined.
95 + * received high e.g. views; default is undefined.
55 96 * @param int $return_limit Number of records to retrieve; defaults to "10".
56 97 * @return string API URL.
57 98 */
58 - private function get_api_url( string $api_key, ?int $published_within, ?string $sort, ?string $boost, int $return_limit ): string {
59 - $related_api_endpoint = 'https://api.parsely.com/v2/related';
99 + private function get_api_url( string $site_id, ?int $published_within, ?string $sort, ?string $boost, int $return_limit ): string {
100 + $related_api_endpoint = Parsely::PUBLIC_API_BASE_URL . '/related';
60 101
61 102 $query_args = array(
62 - 'apikey' => $api_key,
103 + 'apikey' => $site_id,
63 104 'sort' => $sort,
64 105 'limit' => $return_limit,
65 106 );
66 107
@@ -75,19 +116,19 @@
75 116 return add_query_arg( $query_args, $related_api_endpoint );
76 117 }
77 118
78 119 /**
79 - * This is the widget function
120 + * This is the widget function.
80 121 *
81 - * @param array $args Widget Arguments.
82 - * @param array $instance Values saved to the db.
83 - * @return void
122 + * @param array<string, string> $args Widget Arguments.
123 + * @param array<mixed> $widget_settings Values saved to the db.
84 124 */
85 - public function widget( $args, $instance ): void {
86 - if ( ! $this->api_key_and_secret_are_populated() ) {
125 + public function widget( $args, $widget_settings ): void /* @phpstan-ignore-line */ {
126 + if ( ! $this->site_id_and_secret_are_populated() ) {
87 127 return;
88 128 }
89 129
130 + $instance = $this->get_widget_settings( $widget_settings );
90 131 $removed_title_esc = remove_filter( 'widget_title', 'esc_html' );
91 132
92 133 /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
93 134 $title = apply_filters( 'widget_title', $instance['title'] );
@@ -99,33 +140,32 @@
99 140 $title_html = $args['before_widget'] . $args['before_title'] . $title . $args['after_title'];
100 141 echo wp_kses_post( $title_html );
101 142
102 143 // Set up the variables.
103 - $options = get_option( 'parsely' );
104 144 $api_url = $this->get_api_url(
105 - $options['apikey'],
106 - $instance['published_within'],
145 + $this->parsely->get_site_id(),
146 + (int) $instance['published_within'], // @phpstan-ignore-line
107 147 $instance['sort'],
108 148 $instance['boost'],
109 - (int) $instance['return_limit']
149 + (int) $instance['return_limit'] // @phpstan-ignore-line
110 150 );
111 151
112 - $recommended_widget_script_asset = require plugin_dir_path( PARSELY_FILE ) . 'build/recommended-widget.asset.php';
113 -
114 152 ?>
115 153
116 154 <div class="parsely-recommended-widget"
117 - data-parsely-widget-display-author="<?php echo esc_attr( wp_json_encode( isset( $instance['display_author'] ) && $instance['display_author'] ) ); ?>"
118 - data-parsely-widget-display-direction="<?php echo esc_attr( $instance['display_direction'] ?? '' ); ?>"
155 + data-parsely-widget-display-author="<?php echo esc_attr( (string) wp_json_encode( $instance['display_author'] ) ); ?>"
156 + data-parsely-widget-display-direction="<?php echo esc_attr( $instance['display_direction'] ); ?>"
119 157 data-parsely-widget-api-url="<?php echo esc_url( $api_url ); ?>"
120 - data-parsely-widget-img-display="<?php echo esc_attr( $instance['img_src'] ?? '' ); ?>"
121 - data-parsely-widget-permalink="<?php echo esc_url( get_permalink() ); ?>"
122 - data-parsely-widget-personalized="<?php echo esc_attr( wp_json_encode( isset( $instance['personalize_results'] ) && $instance['personalize_results'] ) ); ?>"
123 - data-parsely-widget-id="<?php echo esc_attr( $this->id ); ?>"
158 + data-parsely-widget-img-display="<?php echo esc_attr( $instance['img_src'] ); ?>"
159 + data-parsely-widget-permalink="<?php echo esc_url( (string) get_permalink() ); ?>"
160 + data-parsely-widget-personalized="<?php echo esc_attr( (string) wp_json_encode( $instance['personalize_results'] ) ); ?>"
161 + data-parsely-widget-id="<?php echo esc_attr( (string) $this->id ); ?>"
124 162 ></div>
125 163
126 164 <?php
127 165
166 + $recommended_widget_script_asset = get_asset_info( 'build/recommended-widget.asset.php' );
167 +
128 168 wp_register_script(
129 169 'wp-parsely-recommended-widget',
130 170 plugin_dir_url( PARSELY_FILE ) . 'build/recommended-widget.js',
131 171 $recommended_widget_script_asset['dependencies'],
@@ -146,14 +186,14 @@
146 186 echo wp_kses_post( $args['after_widget'] );
147 187 }
148 188
149 189 /**
150 - * This is the form function
190 + * This is the form function.
151 191 *
152 - * @param array $instance Values saved to the db.
192 + * @param array<mixed> $current_settings Values saved to the db.
153 193 */
154 - public function form( $instance ): void {
155 - if ( ! $this->api_key_and_secret_are_populated() ) {
194 + public function form( $current_settings ): string {
195 + if ( ! $this->site_id_and_secret_are_populated() ) {
156 196 $settings_page_url = add_query_arg( 'page', 'parsely', get_admin_url() . 'options-general.php' );
157 197
158 198 $message = sprintf(
159 199 /* translators: %s: Plugin settings page URL */
@@ -162,21 +202,23 @@
162 202 );
163 203
164 204 echo '<p>', wp_kses_post( $message ), '</p>';
165 205
166 - return;
206 + return '';
167 207 }
168 208
209 + $instance = $this->get_widget_settings( $current_settings );
210 +
169 211 // editable fields: title.
170 - $title = ! empty( $instance['title'] ) ? $instance['title'] : '';
171 - $return_limit = ! empty( $instance['return_limit'] ) ? (int) $instance['return_limit'] : 5;
172 - $display_direction = ! empty( $instance['display_direction'] ) ? $instance['display_direction'] : 'vertical';
173 - $published_within = ! empty( $instance['published_within'] ) ? $instance['published_within'] : 0;
174 - $sort = ! empty( $instance['sort'] ) ? $instance['sort'] : 'score';
175 - $boost = ! empty( $instance['boost'] ) ? $instance['boost'] : 'views';
176 - $personalize_results = ! empty( $instance['personalize_results'] ) ? $instance['personalize_results'] : false;
177 - $img_src = ! empty( $instance['img_src'] ) ? $instance['img_src'] : 'parsely_thumb';
178 - $display_author = ! empty( $instance['display_author'] ) ? $instance['display_author'] : false;
212 + $title = $instance['title'];
213 + $return_limit = $instance['return_limit'];
214 + $display_direction = $instance['display_direction'];
215 + $published_within = $instance['published_within'];
216 + $sort = $instance['sort'];
217 + $boost = $instance['boost'];
218 + $personalize_results = $instance['personalize_results'];
219 + $img_src = $instance['img_src'];
220 + $display_author = $instance['display_author'];
179 221
180 222 $instance['return_limit'] = $return_limit;
181 223 $instance['display_direction'] = $display_direction;
182 224 $instance['published_within'] = $published_within;
@@ -200,9 +242,9 @@
200 242 <span id="<?php echo esc_attr( $this->get_field_id( 'published_within_unit' ) ); ?>"> <?php esc_html_e( 'days (0 for no limit).', 'wp-parsely' ); ?></span>
201 243 </p>
202 244 <p>
203 245 <label for="<?php echo esc_attr( $this->get_field_id( 'return_limit' ) ); ?>"><?php esc_html_e( 'Number of posts to show (max 20):', 'wp-parsely' ); ?></label>
204 - <input type="number" id="<?php echo esc_attr( $this->get_field_id( 'return_limit' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'return_limit' ) ); ?>" value="<?php echo esc_attr( $instance['return_limit'] ); ?>" min="1" max="20" class="tiny-text" />
246 + <input type="number" id="<?php echo esc_attr( $this->get_field_id( 'return_limit' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'return_limit' ) ); ?>" value="<?php echo esc_attr( (string) $instance['return_limit'] ); ?>" min="1" max="20" class="tiny-text" />
205 247 </p>
206 248 <p>
207 249 <fieldset>
208 250 <legend><?php esc_html_e( 'Display entries:', 'wp-parsely' ); ?></legend>
@@ -249,22 +291,25 @@
249 291 <input type="checkbox" id="<?php echo esc_attr( $this->get_field_id( 'personalize_results' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'personalize_results' ) ); ?>" value="personalize_results"<?php checked( $instance['personalize_results'], 'personalize_results' ); ?> />
250 292 <label for="<?php echo esc_attr( $this->get_field_id( 'personalize_results' ) ); ?>"><?php esc_html_e( 'Personalize recommended results', 'wp-parsely' ); ?></label>
251 293 </p>
252 294 <?php
295 +
296 + return '';
253 297 }
254 298
255 299 /**
256 - * This is the update function
300 + * This is the update function.
257 301 *
258 - * @param array $new_instance The new values for the db.
259 - * @param array $old_instance Values saved to the db.
260 - * @return array
302 + * @param Widget_Settings $new_instance The new values for the db.
303 + * @param Widget_Settings $old_instance Values saved to the db.
304 + *
305 + * @return Widget_Settings
261 306 */
262 - public function update( $new_instance, $old_instance ): array {
307 + public function update( $new_instance, $old_instance ) /* @phpstan-ignore-line */ {
263 308 $instance = $old_instance;
264 309 $instance['title'] = trim( wp_kses_post( $new_instance['title'] ) );
265 - $instance['published_within'] = is_int( $new_instance['published_within'] ) ? $new_instance['published_within'] : (int) trim( $new_instance['published_within'] );
266 - $instance['return_limit'] = (int) $new_instance['return_limit'] <= 20 ? (int) $new_instance['return_limit'] : 20;
310 + $instance['published_within'] = $new_instance['published_within'];
311 + $instance['return_limit'] = $new_instance['return_limit'] <= 20 ? $new_instance['return_limit'] : 20;
267 312 $instance['display_direction'] = trim( $new_instance['display_direction'] );
268 313 $instance['sort'] = trim( $new_instance['sort'] );
269 314 $instance['boost'] = trim( $new_instance['boost'] );
270 315 $instance['display_author'] = $new_instance['display_author'];
@@ -269,13 +314,14 @@
269 314 $instance['boost'] = trim( $new_instance['boost'] );
270 315 $instance['display_author'] = $new_instance['display_author'];
271 316 $instance['personalize_results'] = $new_instance['personalize_results'];
272 317 $instance['img_src'] = trim( $new_instance['img_src'] );
318 +
273 319 return $instance;
274 320 }
275 321
276 322 /**
277 - * Return the list of boost parameters, values and labels.
323 + * Returns the list of boost parameters, values and labels.
278 324 *
279 325 * @since 2.5.0
280 326 *
281 327 * @return array<string, string> Boost parameters values and labels.
@@ -293,9 +339,9 @@
293 339 'engaged_minutes' => __( 'Total engagement time in minutes', 'wp-parsely' ),
294 340 'avg_engaged' => __( 'Engaged minutes spent by total visitors', 'wp-parsely' ),
295 341 'avg_engaged_new' => __( 'Average engaged minutes spent by new visitors', 'wp-parsely' ),
296 342 'avg_engaged_returning' => __( 'Average engaged minutes spent by returning visitors', 'wp-parsely' ),
297 - 'social_interactions' => __( 'Total for Facebook, Twitter, LinkedIn, and Pinterest', 'wp-parsely' ),
343 + 'social_interactions' => __( 'Total social interactions', 'wp-parsely' ),
298 344 'fb_interactions' => __( 'Count of Facebook shares, likes, and comments', 'wp-parsely' ),
299 345 'tw_interactions' => __( 'Count of Twitter tweets and retweets', 'wp-parsely' ),
300 346 'pi_interactions' => __( 'Count of Pinterest pins', 'wp-parsely' ),
301 347 'social_referrals' => __( 'Page views where the referrer was any social network', 'wp-parsely' ),
@@ -305,31 +351,36 @@
305 351 );
306 352 }
307 353
308 354 /**
309 - * Check if both the API key and API secret settings are populated with non-empty values.
355 + * Checks if both the Site ID and API secret settings are populated with
356 + * non-empty values.
310 357 *
311 358 * @since 2.5.0
312 359 *
313 - * @return bool True if apikey and api_secret settings are not empty strings. False otherwise.
360 + * @return bool True if Site ID and API Secret settings are set.
361 + * False otherwise.
314 362 */
315 - private function api_key_and_secret_are_populated(): bool {
316 - $options = get_option( 'parsely' );
363 + private function site_id_and_secret_are_populated(): bool {
364 + return $this->parsely->site_id_is_set() && $this->parsely->api_secret_is_set();
365 + }
317 366
318 - // No options are saved, so API key is not available.
319 - if ( ! is_array( $options ) ) {
320 - return false;
321 - }
367 + /**
368 + * Returns all widget settings by assigning defaults if a setting isn't present
369 + *
370 + * @since 3.7.0
371 + *
372 + * @param array<string, mixed> $settings Widget Options.
373 + *
374 + * @return Widget_Settings
375 + */
376 + public function get_widget_settings( array $settings ) {
377 + /**
378 + * Variable.
379 + *
380 + * @var Widget_Settings
381 + */
382 + $widget_settings = $settings;
322 383
323 - // Parse.ly Site ID settings field is not populated.
324 - if ( ! array_key_exists( 'apikey', $options ) || '' === $options['apikey'] ) {
325 - return false;
326 - }
327 -
328 - // Parse.ly API Secret settings field is not populated.
329 - if ( ! array_key_exists( 'api_secret', $options ) || '' === $options['api_secret'] ) {
330 - return false;
331 - }
332 -
333 - return true;
384 + return array_merge( self::$default_widget_settings, $widget_settings );
334 385 }
335 386 }