PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.11.10
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.11.10
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / vendor / codeinwp / themeisle-sdk / src / Modules / Dashboard_widget.php

Dashboard_widget.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.11.10, at vendor/codeinwp/themeisle-sdk/src/Modules/Dashboard_widget.php

507 lines 14.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The blog dashboard model class for ThemeIsle SDK
4 *
5 * @package ThemeIsleSDK
6 * @subpackage Modules
7 * @copyright Copyright (c) 2017, Marius Cristea
8 * @license http://opensource.org/licenses/gpl-3.0.php GNU Public License
9 * @since 1.0.0
10 */
11
12 namespace ThemeisleSDK\Modules;
13
14 use ThemeisleSDK\Common\Abstract_Module;
15 use ThemeisleSDK\Loader;
16 use ThemeisleSDK\Product;
17
18 // Exit if accessed directly.
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 /**
24 * Blog dashboard widget module for ThemeIsle SDK.
25 */
26 class Dashboard_Widget extends Abstract_Module {
27
28 /**
29 * Fetched feeds items.
30 *
31 * @var array Feed items.
32 */
33 private $items = array();
34
35 /**
36 * Dashboard widget title.
37 *
38 * @var string $dashboard_name Dashboard name.
39 */
40 private $dashboard_name = '';
41
42 /**
43 * Dashboard widget feed sources.
44 *
45 * @var array $feeds Feed url.
46 */
47 private $feeds = [];
48
49 /**
50 * Should we load this module.
51 *
52 * @param Product $product Product object.
53 *
54 * @return bool
55 */
56 public function can_load( $product ) {
57 if ( $this->is_from_partner( $product ) ) {
58 return false;
59 }
60
61 if ( ! apply_filters( $product->get_slug() . '_load_dashboard_widget', true ) ) {
62 return false;
63 }
64
65 return true;
66 }
67
68 /**
69 * Registers the hooks.
70 *
71 * @param Product $product Product to load.
72 *
73 * @return Dashboard_Widget Module instance.
74 */
75 public function load( $product ) {
76 if ( apply_filters( 'themeisle_sdk_hide_dashboard_widget', false ) ) {
77 return;
78 }
79 $this->product = $product;
80 $this->dashboard_name = apply_filters( 'themeisle_sdk_dashboard_widget_name', Loader::$labels['dashboard_widget']['title'] );
81 $this->feeds = apply_filters(
82 'themeisle_sdk_dashboard_widget_feeds',
83 [
84 'https://themeisle.com/blog/feed',
85 'https://wpshout.com/feed',
86 ]
87 );
88 add_action( 'wp_dashboard_setup', array( &$this, 'add_widget' ) );
89 add_action( 'wp_network_dashboard_setup', array( &$this, 'add_widget' ) );
90 add_filter( 'themeisle_sdk_recommend_plugin_or_theme', array( &$this, 'recommend_plugin_or_theme' ) );
91
92 return $this;
93 }
94
95
96 /**
97 * Add widget to the dashboard
98 *
99 * @return string|void
100 */
101 public function add_widget() {
102 global $wp_meta_boxes;
103 if ( isset( $wp_meta_boxes['dashboard']['normal']['core']['themeisle'] ) ) {
104 return;
105 }
106 wp_add_dashboard_widget(
107 'themeisle',
108 $this->dashboard_name,
109 [
110 $this,
111 'render_dashboard_widget',
112 ]
113 );
114 }
115
116 /**
117 * Render widget content
118 */
119 public function render_dashboard_widget() {
120 $this->setup_feeds();
121 if ( empty( $this->items ) || ! is_array( $this->items ) ) {
122 return;
123 }
124 ?>
125 <style type="text/css">
126 #themeisle ul li.ti-dw-recommend-item {
127 padding-left: 7px;
128 border-top: 1px solid #eee;
129 margin-bottom: 0px;
130 padding-top: 6px;
131 }
132
133 #themeisle h2.hndle {
134 background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABbCAMAAADncTNAAAAAtFBMVEVHcEyAgIB/f3+xsbGgoaGBgYGCgoKKioqAgIC1tbW5ubnFx8iAgIDU1taBgYGCgoKAgIC0tLXW19jW2NiAgIC3uLiBgYHLzMy4uLhycnLW19d/f3/T1NW0tLTX19mVlZWvr6+BgYHl5eWKiottbW5JSUnW2Nm5ubnh4eHT1NWVlZVjY2N4eHh9fX6pqqq+v79PT0/39/fu7u7Nzc7Z2ttYWFgBAQHDw8P////JysoZGRk0NTZqJc/sAAAAIXRSTlMA0FL7/oEnEPL6eibivm9gwJya76/enFq2CXI+2lFAyM8GATmPAAADj0lEQVR4Xu2YaW/iOhSGAwRCWDosnXa6znjJvm8svf//f12TuARyhiR2pfnUR6gSEnr0+uT4xK7yRb755pvhHePli5K7Bfpkuhoq8ozRJdMH+WWha6Z3sqYparCSLRJqspjImVbANJU03cNMMpofAwQZCGsmpQYyFvVM0Q00OQ9koMl5IPcCoro+RA1Dt2Ea9n9eZ0+YHJLkgIlkDywQx00wCTyaReiKH8LbNU9ybJOdkchV6QFxyCFLbVvdfaREqgUWg/tx2UbqIcK2Hex2TdGLwFTjIj3XP3YfCZFsb23KRZn/3263oymSFI0/a5S4PqUBjoBIJBDjeEhCN0wxQSRybIxtJ3K5SGzuE/vAwIQc8ZmMMJFAIM4oikZItfEFtorGgoE43FObwqHU68OtPCnOz8KZ2Jbl5LgkSW0Tc7YyIz/EFWmS4jMbiZU5mJOmKRaJpKGGyLZtDJh3iyaNUu/3+xyKnrtFL71EG+FTiMpENhQtxUQ8kSOXCIr2tnCNhg/gTX0SHYFp0t7TCwQZ7U841yoHrW6rtGroUwTWVnLMssxx+H4bgZcSOFf5MYx0Ae8FghomMDyC2EBNImBywPkNTDNqGLQpIg2TjUNU8tBy9DQMo0DAZF16rAi7vJAtFTIYFAHUc6hIRW6OuOhJgaCSwmDEAYK4oa7ro+qIEyJU/US7KTJKPNSFT9tFgVFBu0SF1y7yjX4masRA9Da7EFGj28R/BkQz6xGIOurkx38T/bKs9Uk8aIiMwm/Jw0VP1yLrJwt13xAxvABBgsK4KWLov35DkRF7ZaqgzuZ7MQ8MOntmVYyAqKTwaICKqvSUFnVccMN5sziEP/5+xGDTahbH5Q3ZB76zr8fI+nJtvUUU3t3ml5GKviK/npCg3CGodnuJ4JVkfRFJYGVDBZrqKnn9RLf+CzDTS5PaN5J38+auzX4ykU4Qoj0rdKfcYs5ijfo9OL/uRUgZyQr7NCWtWwiUSLc4arfJa7lpszTA1OJZAQ8w8dXFrR5YHzCWSnS3pZ18tOi4Ps4vl/c7i/6qomjRecN+UubrPyPGn/VEMU3T0UFHkaPzpgjxmJsnjmrtionlMDZiog0TsY/DPtn8SXtlBvbtxKtwopy7lqW3smQO+yoGE1Uu55GJ3pmI8ygoejZNnqj0vnIRCyTKfLstRdtStGQi09myUsvwvlkuzSUXbV+Xz5ryBebV33fln/A/moud69FZiEYAAAAASUVORK5CYII=');
135 background-repeat: no-repeat;
136 background-position: 2% 50%;
137 background-size: 25px;
138 padding-left: 39px;
139 }
140
141 #themeisle .inside {
142 padding: 0;
143 }
144
145 .ti-feed-list {
146 padding: 0 12px 5px;
147 margin-bottom: 10px;
148 border-bottom: 1px solid #eee;
149 }
150
151 .ti-dw-feed-item a {
152 display: flex;
153 align-items: center;
154 margin-bottom: 5px;
155 padding: 5px;
156 transition: .2s ease;
157 border-radius: 3px;
158 }
159
160 .ti-dw-feed-item a:hover {
161 background-color: #f8f8f8;
162 }
163
164 .ti-dw-feed-item a:hover .ti-dw-date-container {
165 opacity: .9;
166 }
167
168 .ti-dw-feed-item .ti-dw-month-container {
169 margin-top: -5px;
170 text-transform: uppercase;
171 font-size: 10px;
172 letter-spacing: 1px;
173 font-weight: 700;
174 }
175
176 .ti-dw-feed-item .ti-dw-date-container {
177 border-radius: 3px;
178 transition: .2s ease;
179 min-height: 35px;
180 margin-right: 5px;
181 min-width: 35px;
182 text-align: center;
183 border: 1px solid #2a6f97;
184 color: #fff;
185 background: #2ea2cc;
186 display: flex;
187 flex-direction: column;
188 justify-content: center;
189 }
190
191 .ti-dw-footer {
192 padding: 0 12px 5px;
193 text-align: center;
194 }
195
196 .ti-dw-recommend-item {
197 display: block;
198 }
199
200 .ti-dw-recommend-item span {
201 color: #72777c;
202 }
203
204 .ti-dw-powered-by {
205 font-size: 11px;
206 margin-top: 3px;
207 display: block;
208 color: #72777c;
209 }
210
211 .ti-dw-powered-by span {
212 font-weight: 600;
213 }
214
215 </style>
216 <?php do_action( 'themeisle_sdk_dashboard_widget_before', $this->product ); ?>
217
218 <ul class="ti-feed-list">
219 <?php
220
221 foreach ( $this->items as $item ) {
222 ?>
223 <li class="ti-dw-feed-item">
224 <a href="
225 <?php
226 echo esc_url(
227 add_query_arg(
228 array(
229 'utm_source' => 'wpadmin',
230 'utm_campaign' => 'feed',
231 'utm_medium' => 'dashboard_widget',
232 ),
233 $item['link']
234 )
235 );
236 ?>
237 " target="_blank">
238 <span class="ti-dw-date-container"><span
239 class="ti-dw-day-container"><?php echo esc_attr( gmdate( 'd', $item['date'] ) ); ?></span> <span
240 class="ti-dw-month-container"><?php echo esc_attr( substr( gmdate( 'M', $item['date'] ), 0, 3 ) ); ?></span></span><?php echo esc_attr( $item['title'] ); ?>
241 </a>
242 </li>
243 <?php
244 }
245 ?>
246 </ul>
247 <?php
248 $recommend = apply_filters( 'themeisle_sdk_recommend_plugin_or_theme', array() );
249 if ( ! is_array( $recommend ) || empty( $recommend ) ) {
250 return;
251 }
252
253 $type = $recommend['type'];
254
255 if ( ( 'theme' === $type && ! current_user_can( 'install_themes' ) ) ) {
256 return;
257 }
258 if ( ( 'plugin' === $type && ! current_user_can( 'install_plugins' ) ) ) {
259 return;
260 }
261
262 add_thickbox();
263 $url = add_query_arg(
264 [
265 'theme' => $recommend['slug'],
266 ],
267 network_admin_url( 'theme-install.php' )
268 );
269
270 if ( 'plugin' === $type ) {
271
272 $url = add_query_arg(
273 array(
274 'tab' => 'plugin-information',
275 'plugin' => $recommend['slug'],
276 ),
277 network_admin_url( 'plugin-install.php' )
278 );
279 }
280 ?>
281 <div class="ti-dw-footer">
282 <span class="ti-dw-recommend-item ">
283 <span class="ti-dw-recommend"><?php echo esc_attr( apply_filters( 'themeisle_sdk_dashboard_popular_label', sprintf( Loader::$labels['dashboard_widget']['popular'], ucwords( $type ) ) ) ); ?>
284 : </span>
285 <?php
286 echo esc_attr(
287 trim(
288 str_replace(
289 array(
290 'lite',
291 'Lite',
292 '(Lite)',
293 '(lite)',
294 ),
295 '',
296 $recommend['name']
297 )
298 )
299 );
300 ?>
301 (<a class="thickbox open-plugin-details-modal"
302 href="<?php echo esc_url( $url . '&TB_iframe=true&width=600&height=500' ); ?>"><?php echo esc_attr( apply_filters( 'themeisle_sdk_dashboard_install_label', Loader::$labels['dashboard_widget']['install'] ) ); ?></a>)
303 </span>
304 <span class="ti-dw-powered-by"><span><?php echo esc_attr( apply_filters( 'themeisle_sdk_dashboard_widget_powered_by', sprintf( Loader::$labels['dashboard_widget']['powered'], $this->product->get_friendly_name() ) ) ); ?></span></span>
305 </div>
306
307 <?php
308
309 }
310
311 /**
312 * Setup feed items.
313 */
314 private function setup_feeds() {
315 if ( false === ( $items_normalized = get_transient( 'themeisle_sdk_feed_items' ) ) ) { //phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
316 // Do not force the feed for the items in the sdk feeds list.
317 // this prevents showing notices if another plugin will force all SimplePie feeds to load, instead it will
318 // use the regular SimplePie validation and abort early if the feed is not valid.
319 $sdk_feeds = $this->feeds;
320 add_action(
321 'wp_feed_options',
322 function ( $feed, $url ) use ( $sdk_feeds ) {
323 if ( defined( 'TI_SDK_PHPUNIT' ) && true === TI_SDK_PHPUNIT ) {
324 return;
325 }
326
327 if ( ! is_string( $url ) && in_array( $url, $sdk_feeds, true ) ) {
328 $feed->force_feed( false );
329
330 return;
331 }
332 if ( is_array( $url ) ) {
333 foreach ( $url as $feed_url ) {
334 if ( in_array( $feed_url, $sdk_feeds, true ) ) {
335 $feed->force_feed( false );
336
337 return;
338 }
339 }
340 }
341 },
342 PHP_INT_MAX,
343 2
344 );
345 // Load SimplePie Instance.
346 $feed = fetch_feed( $sdk_feeds );
347 // TODO report error when is an error loading the feed.
348 if ( is_wp_error( $feed ) ) {
349 return;
350 }
351
352 $items = $feed->get_items( 0, 5 );
353 $items = is_array( $items ) ? $items : [];
354
355 $items_normalized = [];
356
357 foreach ( $items as $item ) {
358 $items_normalized[] = array(
359 'title' => $item->get_title(),
360 'date' => $item->get_date( 'U' ),
361 'link' => $item->get_permalink(),
362 );
363 }
364 set_transient( 'themeisle_sdk_feed_items', $items_normalized, 48 * HOUR_IN_SECONDS );
365 }
366 $this->items = $items_normalized;
367 }
368
369 /**
370 * Either the current product is installed or not.
371 *
372 * @param array $val The current recommended product.
373 *
374 * @return bool Either we should exclude the plugin or not.
375 */
376 public function remove_current_products( $val ) {
377 if ( 'theme' === $val['type'] ) {
378 $exist = wp_get_theme( $val['slug'] );
379
380 return ! $exist->exists();
381 } else {
382 $all_plugins = array_keys( get_plugins() );
383 foreach ( $all_plugins as $slug ) {
384 if ( strpos( $slug, $val['slug'] ) !== false ) {
385 return false;
386 }
387 }
388
389 return true;
390 }
391 }
392
393 /**
394 * Contact the API and fetch the recommended plugins/themes
395 */
396 public function recommend_plugin_or_theme() {
397 $products = $this->get_product_from_api();
398 if ( ! is_array( $products ) ) {
399 $products = array();
400 }
401 $products = array_filter( $products, array( $this, 'remove_current_products' ) );
402 $products = array_merge( $products );
403 if ( count( $products ) > 1 ) {
404 shuffle( $products );
405 $products = array_slice( $products, 0, 1 );
406 }
407 $to_recommend = isset( $products[0] ) ? $products[0] : $products;
408
409 return $to_recommend;
410 }
411
412 /**
413 * Fetch products from the recomended section.
414 *
415 * @return array|mixed The list of products to use in recomended section.
416 */
417 public function get_product_from_api() {
418 if ( false === ( $products = get_transient( 'themeisle_sdk_products' ) ) ) { //phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
419 $products = array();
420 $all_themes = $this->get_themes_from_wporg( 'themeisle' );
421 $all_plugins = $this->get_plugins_from_wporg( 'themeisle' );
422 static $allowed_products = [
423 'hestia' => true,
424 'neve' => true,
425 'visualizer' => true,
426 'feedzy-rss-feeds' => true,
427 'wp-product-review' => true,
428 'otter-blocks' => true,
429 'themeisle-companion' => true,
430 ];
431 foreach ( $all_themes as $theme ) {
432 if ( $theme->active_installs < 4999 ) {
433 continue;
434 }
435 if ( ! isset( $allowed_products[ $theme->slug ] ) ) {
436 continue;
437 }
438 $products[] = array(
439 'name' => $theme->name,
440 'type' => 'theme',
441 'slug' => $theme->slug,
442 'installs' => $theme->active_installs,
443 );
444 }
445 foreach ( $all_plugins as $plugin ) {
446 if ( $plugin->active_installs < 4999 ) {
447 continue;
448 }
449 if ( ! isset( $allowed_products[ $plugin->slug ] ) ) {
450 continue;
451 }
452 $products[] = array(
453 'name' => $plugin->name,
454 'type' => 'plugin',
455 'slug' => $plugin->slug,
456 'installs' => $plugin->active_installs,
457 );
458 }
459 set_transient( 'themeisle_sdk_products', $products, 6 * HOUR_IN_SECONDS );
460 }
461
462 return $products;
463 }
464
465 /**
466 * Fetch themes from wporg api.
467 *
468 * @param string $author The author name.
469 *
470 * @return array The list of themes.
471 */
472 public function get_themes_from_wporg( $author ) {
473 $products = $this->safe_get(
474 'https://api.wordpress.org/themes/info/1.1/?action=query_themes&request[author]=' . $author . '&request[per_page]=30&request[fields][active_installs]=true'
475 );
476 $products = json_decode( wp_remote_retrieve_body( $products ) );
477 if ( is_object( $products ) ) {
478 $products = isset( $products->themes ) ? $products->themes : array();
479 } else {
480 $products = array();
481 }
482
483 return (array) $products;
484 }
485
486 /**
487 * Fetch plugin from wporg api.
488 *
489 * @param string $author The author slug.
490 *
491 * @return array The list of plugins for the selected author.
492 */
493 public function get_plugins_from_wporg( $author ) {
494 $products = $this->safe_get(
495 'https://api.wordpress.org/plugins/info/1.1/?action=query_plugins&request[author]=' . $author . '&request[per_page]=40&request[fields][active_installs]=true'
496 );
497 $products = json_decode( wp_remote_retrieve_body( $products ) );
498 if ( is_object( $products ) ) {
499 $products = isset( $products->plugins ) ? $products->plugins : array();
500 } else {
501 $products = array();
502 }
503
504 return (array) $products;
505 }
506 }
507