PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.11.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.11.0
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.0, at vendor/codeinwp/themeisle-sdk/src/Modules/Dashboard_widget.php

508 lines 14.1 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://www.codeinwp.com/blog/feed',
86 'https://wpshout.com/feed',
87 ]
88 );
89 add_action( 'wp_dashboard_setup', array( &$this, 'add_widget' ) );
90 add_action( 'wp_network_dashboard_setup', array( &$this, 'add_widget' ) );
91 add_filter( 'themeisle_sdk_recommend_plugin_or_theme', array( &$this, 'recommend_plugin_or_theme' ) );
92
93 return $this;
94 }
95
96
97 /**
98 * Add widget to the dashboard
99 *
100 * @return string|void
101 */
102 public function add_widget() {
103 global $wp_meta_boxes;
104 if ( isset( $wp_meta_boxes['dashboard']['normal']['core']['themeisle'] ) ) {
105 return;
106 }
107 wp_add_dashboard_widget(
108 'themeisle',
109 $this->dashboard_name,
110 [
111 $this,
112 'render_dashboard_widget',
113 ]
114 );
115 }
116
117 /**
118 * Render widget content
119 */
120 public function render_dashboard_widget() {
121 $this->setup_feeds();
122 if ( empty( $this->items ) || ! is_array( $this->items ) ) {
123 return;
124 }
125 ?>
126 <style type="text/css">
127 #themeisle ul li.ti-dw-recommend-item {
128 padding-left: 7px;
129 border-top: 1px solid #eee;
130 margin-bottom: 0px;
131 padding-top: 6px;
132 }
133
134 #themeisle h2.hndle {
135 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=');
136 background-repeat: no-repeat;
137 background-position: 2% 50%;
138 background-size: 25px;
139 padding-left: 39px;
140 }
141
142 #themeisle .inside {
143 padding: 0;
144 }
145
146 .ti-feed-list {
147 padding: 0 12px 5px;
148 margin-bottom: 10px;
149 border-bottom: 1px solid #eee;
150 }
151
152 .ti-dw-feed-item a {
153 display: flex;
154 align-items: center;
155 margin-bottom: 5px;
156 padding: 5px;
157 transition: .2s ease;
158 border-radius: 3px;
159 }
160
161 .ti-dw-feed-item a:hover {
162 background-color: #f8f8f8;
163 }
164
165 .ti-dw-feed-item a:hover .ti-dw-date-container {
166 opacity: .9;
167 }
168
169 .ti-dw-feed-item .ti-dw-month-container {
170 margin-top: -5px;
171 text-transform: uppercase;
172 font-size: 10px;
173 letter-spacing: 1px;
174 font-weight: 700;
175 }
176
177 .ti-dw-feed-item .ti-dw-date-container {
178 border-radius: 3px;
179 transition: .2s ease;
180 min-height: 35px;
181 margin-right: 5px;
182 min-width: 35px;
183 text-align: center;
184 border: 1px solid #2a6f97;
185 color: #fff;
186 background: #2ea2cc;
187 display: flex;
188 flex-direction: column;
189 justify-content: center;
190 }
191
192 .ti-dw-footer {
193 padding: 0 12px 5px;
194 text-align: center;
195 }
196
197 .ti-dw-recommend-item {
198 display: block;
199 }
200
201 .ti-dw-recommend-item span {
202 color: #72777c;
203 }
204
205 .ti-dw-powered-by {
206 font-size: 11px;
207 margin-top: 3px;
208 display: block;
209 color: #72777c;
210 }
211
212 .ti-dw-powered-by span {
213 font-weight: 600;
214 }
215
216 </style>
217 <?php do_action( 'themeisle_sdk_dashboard_widget_before', $this->product ); ?>
218
219 <ul class="ti-feed-list">
220 <?php
221
222 foreach ( $this->items as $item ) {
223 ?>
224 <li class="ti-dw-feed-item">
225 <a href="
226 <?php
227 echo esc_url(
228 add_query_arg(
229 array(
230 'utm_source' => 'wpadmin',
231 'utm_campaign' => 'feed',
232 'utm_medium' => 'dashboard_widget',
233 ),
234 $item['link']
235 )
236 );
237 ?>
238 " target="_blank">
239 <span class="ti-dw-date-container"><span
240 class="ti-dw-day-container"><?php echo esc_attr( gmdate( 'd', $item['date'] ) ); ?></span> <span
241 class="ti-dw-month-container"><?php echo esc_attr( substr( gmdate( 'M', $item['date'] ), 0, 3 ) ); ?></span></span><?php echo esc_attr( $item['title'] ); ?>
242 </a>
243 </li>
244 <?php
245 }
246 ?>
247 </ul>
248 <?php
249 $recommend = apply_filters( 'themeisle_sdk_recommend_plugin_or_theme', array() );
250 if ( ! is_array( $recommend ) || empty( $recommend ) ) {
251 return;
252 }
253
254 $type = $recommend['type'];
255
256 if ( ( 'theme' === $type && ! current_user_can( 'install_themes' ) ) ) {
257 return;
258 }
259 if ( ( 'plugin' === $type && ! current_user_can( 'install_plugins' ) ) ) {
260 return;
261 }
262
263 add_thickbox();
264 $url = add_query_arg(
265 [
266 'theme' => $recommend['slug'],
267 ],
268 network_admin_url( 'theme-install.php' )
269 );
270
271 if ( 'plugin' === $type ) {
272
273 $url = add_query_arg(
274 array(
275 'tab' => 'plugin-information',
276 'plugin' => $recommend['slug'],
277 ),
278 network_admin_url( 'plugin-install.php' )
279 );
280 }
281 ?>
282 <div class="ti-dw-footer">
283 <span class="ti-dw-recommend-item ">
284 <span class="ti-dw-recommend"><?php echo esc_attr( apply_filters( 'themeisle_sdk_dashboard_popular_label', sprintf( Loader::$labels['dashboard_widget']['popular'], ucwords( $type ) ) ) ); ?>
285 : </span>
286 <?php
287 echo esc_attr(
288 trim(
289 str_replace(
290 array(
291 'lite',
292 'Lite',
293 '(Lite)',
294 '(lite)',
295 ),
296 '',
297 $recommend['name']
298 )
299 )
300 );
301 ?>
302 (<a class="thickbox open-plugin-details-modal"
303 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>)
304 </span>
305 <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>
306 </div>
307
308 <?php
309
310 }
311
312 /**
313 * Setup feed items.
314 */
315 private function setup_feeds() {
316 if ( false === ( $items_normalized = get_transient( 'themeisle_sdk_feed_items' ) ) ) { //phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
317 // Do not force the feed for the items in the sdk feeds list.
318 // this prevents showing notices if another plugin will force all SimplePie feeds to load, instead it will
319 // use the regular SimplePie validation and abort early if the feed is not valid.
320 $sdk_feeds = $this->feeds;
321 add_action(
322 'wp_feed_options',
323 function ( $feed, $url ) use ( $sdk_feeds ) {
324 if ( defined( 'TI_SDK_PHPUNIT' ) && true === TI_SDK_PHPUNIT ) {
325 return;
326 }
327
328 if ( ! is_string( $url ) && in_array( $url, $sdk_feeds, true ) ) {
329 $feed->force_feed( false );
330
331 return;
332 }
333 if ( is_array( $url ) ) {
334 foreach ( $url as $feed_url ) {
335 if ( in_array( $feed_url, $sdk_feeds, true ) ) {
336 $feed->force_feed( false );
337
338 return;
339 }
340 }
341 }
342 },
343 PHP_INT_MAX,
344 2
345 );
346 // Load SimplePie Instance.
347 $feed = fetch_feed( $sdk_feeds );
348 // TODO report error when is an error loading the feed.
349 if ( is_wp_error( $feed ) ) {
350 return;
351 }
352
353 $items = $feed->get_items( 0, 5 );
354 $items = is_array( $items ) ? $items : [];
355
356 $items_normalized = [];
357
358 foreach ( $items as $item ) {
359 $items_normalized[] = array(
360 'title' => $item->get_title(),
361 'date' => $item->get_date( 'U' ),
362 'link' => $item->get_permalink(),
363 );
364 }
365 set_transient( 'themeisle_sdk_feed_items', $items_normalized, 48 * HOUR_IN_SECONDS );
366 }
367 $this->items = $items_normalized;
368 }
369
370 /**
371 * Either the current product is installed or not.
372 *
373 * @param array $val The current recommended product.
374 *
375 * @return bool Either we should exclude the plugin or not.
376 */
377 public function remove_current_products( $val ) {
378 if ( 'theme' === $val['type'] ) {
379 $exist = wp_get_theme( $val['slug'] );
380
381 return ! $exist->exists();
382 } else {
383 $all_plugins = array_keys( get_plugins() );
384 foreach ( $all_plugins as $slug ) {
385 if ( strpos( $slug, $val['slug'] ) !== false ) {
386 return false;
387 }
388 }
389
390 return true;
391 }
392 }
393
394 /**
395 * Contact the API and fetch the recommended plugins/themes
396 */
397 public function recommend_plugin_or_theme() {
398 $products = $this->get_product_from_api();
399 if ( ! is_array( $products ) ) {
400 $products = array();
401 }
402 $products = array_filter( $products, array( $this, 'remove_current_products' ) );
403 $products = array_merge( $products );
404 if ( count( $products ) > 1 ) {
405 shuffle( $products );
406 $products = array_slice( $products, 0, 1 );
407 }
408 $to_recommend = isset( $products[0] ) ? $products[0] : $products;
409
410 return $to_recommend;
411 }
412
413 /**
414 * Fetch products from the recomended section.
415 *
416 * @return array|mixed The list of products to use in recomended section.
417 */
418 public function get_product_from_api() {
419 if ( false === ( $products = get_transient( 'themeisle_sdk_products' ) ) ) { //phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
420 $products = array();
421 $all_themes = $this->get_themes_from_wporg( 'themeisle' );
422 $all_plugins = $this->get_plugins_from_wporg( 'themeisle' );
423 static $allowed_products = [
424 'hestia' => true,
425 'neve' => true,
426 'visualizer' => true,
427 'feedzy-rss-feeds' => true,
428 'wp-product-review' => true,
429 'otter-blocks' => true,
430 'themeisle-companion' => true,
431 ];
432 foreach ( $all_themes as $theme ) {
433 if ( $theme->active_installs < 4999 ) {
434 continue;
435 }
436 if ( ! isset( $allowed_products[ $theme->slug ] ) ) {
437 continue;
438 }
439 $products[] = array(
440 'name' => $theme->name,
441 'type' => 'theme',
442 'slug' => $theme->slug,
443 'installs' => $theme->active_installs,
444 );
445 }
446 foreach ( $all_plugins as $plugin ) {
447 if ( $plugin->active_installs < 4999 ) {
448 continue;
449 }
450 if ( ! isset( $allowed_products[ $plugin->slug ] ) ) {
451 continue;
452 }
453 $products[] = array(
454 'name' => $plugin->name,
455 'type' => 'plugin',
456 'slug' => $plugin->slug,
457 'installs' => $plugin->active_installs,
458 );
459 }
460 set_transient( 'themeisle_sdk_products', $products, 6 * HOUR_IN_SECONDS );
461 }
462
463 return $products;
464 }
465
466 /**
467 * Fetch themes from wporg api.
468 *
469 * @param string $author The author name.
470 *
471 * @return array The list of themes.
472 */
473 public function get_themes_from_wporg( $author ) {
474 $products = $this->safe_get(
475 'https://api.wordpress.org/themes/info/1.1/?action=query_themes&request[author]=' . $author . '&request[per_page]=30&request[fields][active_installs]=true'
476 );
477 $products = json_decode( wp_remote_retrieve_body( $products ) );
478 if ( is_object( $products ) ) {
479 $products = isset( $products->themes ) ? $products->themes : array();
480 } else {
481 $products = array();
482 }
483
484 return (array) $products;
485 }
486
487 /**
488 * Fetch plugin from wporg api.
489 *
490 * @param string $author The author slug.
491 *
492 * @return array The list of plugins for the selected author.
493 */
494 public function get_plugins_from_wporg( $author ) {
495 $products = $this->safe_get(
496 'https://api.wordpress.org/plugins/info/1.1/?action=query_plugins&request[author]=' . $author . '&request[per_page]=40&request[fields][active_installs]=true'
497 );
498 $products = json_decode( wp_remote_retrieve_body( $products ) );
499 if ( is_object( $products ) ) {
500 $products = isset( $products->plugins ) ? $products->plugins : array();
501 } else {
502 $products = array();
503 }
504
505 return (array) $products;
506 }
507 }
508