PluginProbe
Ever Compare – Products Compare Plugin for WooCommerce / trunk
Ever Compare – Products Compare Plugin for WooCommerce vtrunk
1.3.7 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 trunk 1.0.0 1.0.1 1.0.2 All 31 releases
← All changes | includes/classes/Admin/Recommended_Plugins.php +105 -52 1.2.5 → trunk View file →
@@ -1,6 +1,8 @@
1 1 <?php
2 2 namespace EverCompare\Admin;
3 +
4 +defined( 'ABSPATH' ) || exit;
3 5 /**
4 6 * Recommended Plugins handlers class
5 7 */
6 8 class Recommended_Plugins {
@@ -65,15 +67,15 @@
65 67
66 68 // Initialize properties
67 69 $this->text_domain = !empty( $args['text_domain'] ) ? $args['text_domain'] : 'htrp';
68 70 $this->parent_menu_slug = !empty( $args['parent_menu_slug'] ) ? $args['parent_menu_slug'] : 'plugins.php';
69 - $this->menu_label = !empty( $args['menu_label'] ) ? $args['menu_label'] : esc_html__( 'Recommendations', $this->text_domain );
71 + $this->menu_label = !empty( $args['menu_label'] ) ? $args['menu_label'] : esc_html__( 'Recommendations', 'ever-compare' );
70 72 $this->menu_capability = !empty( $args['menu_capability'] ) ? $args['menu_capability'] : 'manage_options';
71 73 $this->menu_page_slug = !empty( $args['menu_page_slug'] ) ? $args['menu_page_slug'] : $this->text_domain . '_extensions';
72 74 $this->priority = !empty( $args['priority'] ) ? $args['priority'] : 100;
73 75 $this->hook_suffix = !empty( $args['hook_suffix'] ) ? $args['hook_suffix'] : '';
74 76 $this->assets_url = !empty( $args['assets_url'] ) ? $args['assets_url'] : plugins_url( '', __FILE__ );
75 - $this->tab_list = !empty( $args['tab_list'] ) ? $args['assets_url'] : [];
77 + $this->tab_list = !empty( $args['tab_list'] ) ? $args['tab_list'] : [];
76 78
77 79
78 80 add_action( 'admin_menu', [ $this, 'admin_menu' ], $this->priority );
79 81 add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
@@ -123,13 +125,13 @@
123 125 $localize_vars['ajaxurl'] = admin_url('admin-ajax.php');
124 126 $localize_vars['text_domain'] = sanitize_title_with_dashes( $this->text_domain );
125 127 $localize_vars['nonce'] = wp_create_nonce('htrp_nonce');
126 128 $localize_vars['buttontxt'] = array(
127 - 'buynow' => esc_html__( 'Buy Now', $this->text_domain ),
128 - 'preview' => esc_html__( 'Preview', $this->text_domain ),
129 - 'installing' => esc_html__( 'Installing..', $this->text_domain ),
130 - 'activating' => esc_html__( 'Activating..', $this->text_domain ),
131 - 'active' => esc_html__( 'Activated', $this->text_domain ),
129 + 'buynow' => esc_html__( 'Buy Now', 'ever-compare' ),
130 + 'preview' => esc_html__( 'Preview', 'ever-compare' ),
131 + 'installing' => esc_html__( 'Installing..', 'ever-compare' ),
132 + 'activating' => esc_html__( 'Activating..', 'ever-compare' ),
133 + 'active' => esc_html__( 'Activated', 'ever-compare' ),
132 134 );
133 135 wp_localize_script( 'htrp-plugin-install-manager', 'htrp_params', $localize_vars );
134 136
135 137 }
@@ -148,28 +150,40 @@
148 150 */
149 151 public function render_html(){
150 152 if ( ! function_exists('plugins_api') ){ include_once( ABSPATH . 'wp-admin/includes/plugin-install.php' ); }
151 153
152 - $htplugins_plugin_list = $this->get_plugins();
153 - $palscode_plugin_list = $this->get_plugins( 'palscode' );
154 -
155 - $plugin_list = array_merge( $htplugins_plugin_list, $palscode_plugin_list );
156 -
157 - $prepare_plugin = array();
158 - foreach ( $plugin_list as $plugin_key => $plugin ) {
159 - $prepare_plugin[$plugin['slug']] = $plugin;
154 + $requested_slugs = array();
155 + foreach ( $this->tab_list as $tab ) {
156 + if ( empty( $tab['plugins'] ) ) { continue; }
157 + foreach ( $tab['plugins'] as $plugin ) {
158 + if ( ! empty( $plugin['slug'] ) ) { $requested_slugs[] = $plugin['slug']; }
159 + }
160 160 }
161 + $prepare_plugin = $this->get_plugins_info( $requested_slugs );
161 162
162 163 ?>
163 164 <div class="wrap">
164 - <h2><?php echo get_admin_page_title(); ?></h2>
165 + <h2><?php echo esc_html(get_admin_page_title()); ?></h2>
165 166 <style>
166 167 .htrp-admin-tab-pane{
167 168 display: none;
168 169 }
170 + /* Grid layout is normally provided by core's .plugin-install-php #the-list rule,
171 + which is scoped to WP's own Add Plugins screen and never matches this page -
172 + define it ourselves so the cards don't just stack in a single column. */
169 173 .htrp-admin-tab-pane.htrp-active{
170 - display: block;
174 + display: flex;
175 + flex-wrap: wrap;
176 + gap: 16px;
171 177 }
178 + .plugin-card{
179 + display: flex;
180 + flex-direction: column;
181 + justify-content: space-between;
182 + }
183 + .plugin-card h3 a{
184 + text-decoration: none;
185 + }
172 186 .htrp-extension-admin-tab-area .filter-links li>a:focus, .htrp-extension-admin-tab-area .filter-links li>a:hover {
173 187 color: inherit;
174 188 box-shadow: none;
175 189 }
@@ -213,27 +227,28 @@
213 227 'slug' => isset( $plugin['slug'] ) ? $plugin['slug'] : '',
214 228 'location' => isset( $plugin['location'] ) ? $plugin['slug'].'/'.$plugin['location'] : '',
215 229 'name' => isset( $plugin['name'] ) ? $plugin['name'] : '',
216 230 );
217 - $title = wp_kses( $plugin['name'], $this->plugins_allowedtags );
218 -
219 231 if( array_key_exists( $plugin['slug'], $prepare_plugin ) ){
220 232 $plugins_type = 'free';
233 + $title = $data['name'] ? $data['name'] : $prepare_plugin[$plugin['slug']]['name'];
234 + $title = wp_kses( $title, $this->plugins_allowedtags );
221 235 $image_url = $this->plugin_icon( $plugins_type, $prepare_plugin[$data['slug']]['icons'] );
222 - $description = strip_tags( $prepare_plugin[$data['slug']]['description'] );
236 + $description = wp_strip_all_tags( $prepare_plugin[$data['slug']]['description'] );
223 237 $author_name = wp_kses( $prepare_plugin[$data['slug']]['author'], $this->plugins_allowedtags );
224 238 $details_link = self_admin_url('plugin-install.php?tab=plugin-information&amp;plugin=' . $plugin['slug'] .'&amp;TB_iframe=true&amp;width=772&amp;height=577');
225 239 $target = '_self';
226 - $modal_class = 'class="thickbox open-plugin-details-modal"';
240 + $modal_class = 'thickbox open-plugin-details-modal';
227 241
228 242 }else{
229 243 $plugins_type = 'pro';
244 + $title = wp_kses( $plugin['name'], $this->plugins_allowedtags );
230 245 $image_url = $this->plugin_icon( $plugins_type, $plugin['slug'] );
231 246 $description = isset( $plugin['description'] ) ? $plugin['description'] : '';
232 - $author_name = esc_html__( 'HasTheme', $this->text_domain );
247 + $author_name = esc_html__( 'HasTheme', 'ever-compare' );
233 248 $author_link = isset( $plugin['author_link'] ) ? $plugin['author_link'] : '';
234 249 $details_link = isset( $plugin['link'] ) ? $plugin['link'] : '';
235 - $button_text = esc_html__('Buy Now', $this->text_domain );
250 + $button_text = esc_html__('Buy Now', 'ever-compare' );
236 251 $button_classes = 'button button-primary';
237 252 $target = '_blank';
238 253 $modal_class = '';
239 254 }
@@ -243,20 +258,20 @@
243 258 // Installed but Inactive.
244 259 if ( file_exists( WP_PLUGIN_DIR . '/' . $data['location'] ) && is_plugin_inactive( $data['location'] ) ) {
245 260
246 261 $button_classes = 'button htrp-activate-now button-primary';
247 - $button_text = esc_html__( 'Activate', $this->text_domain );
262 + $button_text = esc_html__( 'Activate', 'ever-compare' );
248 263
249 264 // Not Installed.
250 265 } elseif ( ! file_exists( WP_PLUGIN_DIR . '/' . $data['location'] ) ) {
251 266
252 267 $button_classes = 'button htrp-install-now';
253 - $button_text = esc_html__( 'Install Now', $this->text_domain );
268 + $button_text = esc_html__( 'Install Now', 'ever-compare' );
254 269
255 270 // Active.
256 271 } else {
257 272 $button_classes = 'button disabled';
258 - $button_text = esc_html__( 'Activated', $this->text_domain );
273 + $button_text = esc_html__( 'Activated', 'ever-compare' );
259 274 }
260 275
261 276 ?>
262 277 <div class="plugin-card htrp-plugin-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
@@ -262,9 +277,9 @@
262 277 <div class="plugin-card htrp-plugin-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
263 278 <div class="plugin-card-top">
264 279 <div class="name column-name" style="margin-right: 0;">
265 280 <h3>
266 - <a href="<?php echo esc_url( $details_link ) ?>" target="<?php echo esc_attr( $target ) ?>" <?php echo $modal_class; ?>>
281 + <a href="<?php echo esc_url( $details_link ) ?>" target="<?php echo esc_attr( $target ) ?>" class="<?php echo esc_attr($modal_class); ?>" >
267 282 <?php echo esc_html( $title ) ?>
268 283 <img src="<?php echo esc_url( $image_url ) ?>" class="plugin-icon" alt="<?php echo esc_attr( $title ) ?>">
269 284 </a>
270 285 </h3>
@@ -269,15 +284,15 @@
269 284 </a>
270 285 </h3>
271 286 </div>
272 287 <div class="desc column-description" style="margin-right: 0;">
273 - <p><?php echo wp_trim_words( $description, 23, '....'); ?></p>
288 + <p><?php echo esc_html(wp_trim_words( $description, 23, '....')); ?></p>
274 289 <p class="authors">
275 - <cite><?php echo esc_html__( 'By ', $this->text_domain ); ?>
290 + <cite><?php echo esc_html__( 'By ', 'ever-compare' ); ?>
276 291 <?php if( $plugins_type == 'free' ): ?>
277 - <?php echo $author_name; ?>
292 + <?php echo wp_kses_post( $author_name); ?>
278 293 <?php else: ?>
279 - <a href="<?php echo esc_url( $author_link ); ?>" target="_blank" ><?php echo $author_name; ?></a>
294 + <a href="<?php echo esc_url( $author_link ); ?>" target="_blank" ><?php echo esc_html($author_name); ?></a>
280 295 <?php endif; ?>
281 296 </cite>
282 297 </p>
283 298 </div>
@@ -285,22 +300,22 @@
285 300 <div class="plugin-card-bottom">
286 301 <div class="column-updated">
287 302 <?php
288 303 if (! file_exists( WP_PLUGIN_DIR . '/' . $data['location'] ) && $plugins_type == 'pro' ) {
289 - echo '<a class="button button-primary" href="'.esc_url( $details_link ).'" target="'.esc_attr( $target ).'">'.esc_html__( 'Buy Now', $this->text_domain ).'</a>';
304 + echo '<a class="button button-primary" href="'.esc_url( $details_link ).'" target="'.esc_attr( $target ).'">'.esc_html__( 'Buy Now', 'ever-compare' ).'</a>';
290 305 }else{
291 306 ?>
292 - <button class="<?php echo esc_attr($button_classes); ?>" data-pluginopt='<?php echo wp_json_encode( $data ); ?>'><?php echo $button_text; ?></button>
307 + <button class="<?php echo esc_attr($button_classes); ?>" data-pluginopt='<?php echo wp_json_encode( $data ); ?>'><?php echo esc_html($button_text); ?></button>
293 308
294 309 <?php } ?>
295 310 </div>
296 311 <div class="column-downloaded">
297 - <a href="<?php echo esc_url( $details_link ) ?>" target="<?php echo esc_attr( $target ) ?>" <?php echo $modal_class; ?>><?php echo esc_html__('More Details', $this->text_domain) ?></a>
312 + <a href="<?php echo esc_url( $details_link ) ?>" target="<?php echo esc_attr( $target ) ?>" class=" <?php echo esc_attr($modal_class); ?>" ><?php echo esc_html__('More Details', 'ever-compare') ?></a>
298 313 <span class="downloaded-count">
299 314 <?php
300 315 if( $plugins_type == 'free' ){
301 316 /* translators: %s: Number of installations. */
302 - printf( __( '%s Active Installations' ), $this->active_install_count( $prepare_plugin[$data['slug']]['active_installs'] ) );
317 + printf( esc_html__( '%s Active Installations', 'ever-compare' ), esc_html($this->active_install_count( $prepare_plugin[$data['slug']]['active_installs'] )) );
303 318 }
304 319 ?>
305 320 </span>
306 321 </div>
@@ -319,23 +334,61 @@
319 334
320 335 }
321 336
322 337 /**
323 - * [get_plugins] Get plugin from wp.org API
324 - * @param string $username wo.org username
325 - * @return [array] plugin list
338 + * [get_plugins_info] Look up wp.org plugin info by slug (not by author account —
339 + * wp.org's author-query filters by actual SVN repo ownership, which can differ
340 + * from a plugin's displayed "Author:" line and silently miss real plugins).
341 + * @param array $slugs Plugin slugs to look up.
342 + * @return array Associative array keyed by slug; slugs plugins_api() can't
343 + * resolve (pro-only/paid, not on wp.org) are simply absent.
326 344 */
327 - public function get_plugins( $username = 'htplugins' ){
328 - $transient_var = 'htrp_htplugins_list_'.$username;
329 - $org_plugins_list = get_transient( $transient_var );
345 + public function get_plugins_info( $slugs ) {
330 346
331 - if ( false === $org_plugins_list ) {
332 - $plugins_list_by_author = plugins_api( 'query_plugins', array( 'author' => $username, 'per_page' => 100 ) );
333 - set_transient( $transient_var, $plugins_list_by_author->plugins, 1 * WEEK_IN_SECONDS );
334 - $org_plugins_list = $plugins_list_by_author->plugins;
347 + if ( empty( $slugs ) ) {
348 + return array();
335 349 }
336 350
337 - return $org_plugins_list;
351 + $slugs = array_unique( $slugs );
352 + sort( $slugs ); // deterministic cache key regardless of tab iteration order
353 +
354 + $transient_var = 'htrp_htplugins_info_' . md5( implode( ',', $slugs ) );
355 + $plugins_info = get_transient( $transient_var );
356 +
357 + if ( false === $plugins_info ) {
358 +
359 + $plugins_info = array();
360 +
361 + foreach ( $slugs as $slug ) {
362 + $plugin_info = plugins_api( 'plugin_information', array(
363 + 'slug' => $slug,
364 + 'fields' => array(
365 + 'short_description' => true, 'sections' => false, 'icons' => true,
366 + 'active_installs' => true, 'author' => true, 'versions' => false,
367 + 'ratings' => false, 'reviews' => false, 'banners' => false,
368 + 'compatibility' => false, 'homepage' => false, 'donate_link' => false,
369 + 'tags' => false,
370 + ),
371 + ) );
372 +
373 + if ( is_wp_error( $plugin_info ) ) {
374 + continue; // not on wp.org (pro-only / paid slug) — stays in the "pro" render branch
375 + }
376 +
377 + $plugins_info[ $slug ] = array(
378 + 'name' => $plugin_info->name,
379 + 'slug' => $plugin_info->slug,
380 + 'icons' => (array) $plugin_info->icons,
381 + 'description' => $plugin_info->short_description,
382 + 'author' => $plugin_info->author,
383 + 'active_installs' => $plugin_info->active_installs,
384 + );
385 + }
386 +
387 + set_transient( $transient_var, $plugins_info, 1 * WEEK_IN_SECONDS );
388 + }
389 +
390 + return $plugins_info;
338 391 }
339 392
340 393 /**
341 394 * [plugin_icon] Generate plugin icon
@@ -372,13 +425,13 @@
372 425 if ( $active_installs >= 1000000 ) {
373 426 $active_installs_millions = floor( $active_installs / 1000000 );
374 427 $active_installs_text = sprintf(
375 428 /* translators: %s: Number of millions. */
376 - _nx( '%s+ Million', '%s+ Million', $active_installs_millions, 'Active plugin installations' ),
429 + _nx( '%s+ Million', '%s+ Million', $active_installs_millions, 'Active plugin installations', 'ever-compare' ),
377 430 number_format_i18n( $active_installs_millions )
378 431 );
379 432 } elseif ( 0 === $active_installs ) {
380 - $active_installs_text = _x( 'Less Than 10', 'Active plugin installations' );
433 + $active_installs_text = _x( 'Less Than 10', 'Active plugin installations', 'ever-compare' );
381 434 } else {
382 435 $active_installs_text = number_format_i18n( $active_installs ) . '+';
383 436 }
384 437 return $active_installs_text;
@@ -392,18 +445,18 @@
392 445 public function plugin_activation() {
393 446
394 447 check_ajax_referer('htrp_nonce', 'nonce');
395 448
396 - if ( ! current_user_can( 'install_plugins' ) || ! isset( $_POST['location'] ) || ! $_POST['location'] ) {
449 + if ( ! current_user_can( 'install_plugins' ) || empty( sanitize_text_field( wp_unslash($_POST['location']) ) ) ) {
397 450 wp_send_json_error(
398 451 array(
399 452 'success' => false,
400 - 'message' => esc_html__( 'Plugin Not Found', $this->text_domain ),
453 + 'message' => esc_html__( 'Plugin Not Found', 'ever-compare' ),
401 454 )
402 455 );
403 456 }
404 457
405 - $plugin_location = ( isset( $_POST['location'] ) ) ? sanitize_text_field( $_POST['location'] ) : '';
458 + $plugin_location = ! empty( sanitize_text_field(wp_unslash($_POST['location'])) ) ? sanitize_text_field(wp_unslash($_POST['location'])) : '';
406 459 $activate = activate_plugin( $plugin_location, '', false, true );
407 460
408 461 if ( is_wp_error( $activate ) ) {
409 462 wp_send_json_error(
@@ -416,9 +469,9 @@
416 469
417 470 wp_send_json_success(
418 471 array(
419 472 'success' => true,
420 - 'message' => esc_html__( 'Plugin Successfully Activated', $this->text_domain ),
473 + 'message' => esc_html__( 'Plugin Successfully Activated', 'ever-compare' ),
421 474 )
422 475 );
423 476
424 477 }