PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.10.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.10.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 3.10.4 All 148 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.10.8, at vendor/codeinwp/themeisle-sdk/src/Modules/Dashboard_widget.php

505 lines 13.9 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\Product;
16
17 // Exit if accessed directly.
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 /**
23 * Blog dashboard widget module for ThemeIsle SDK.
24 */
25 class Dashboard_Widget extends Abstract_Module {
26
27 /**
28 * Fetched feeds items.
29 *
30 * @var array Feed items.
31 */
32 private $items = array();
33
34 /**
35 * Dashboard widget title.
36 *
37 * @var string $dashboard_name Dashboard name.
38 */
39 private $dashboard_name = '';
40
41 /**
42 * Dashboard widget feed sources.
43 *
44 * @var array $feeds Feed url.
45 */
46 private $feeds = [];
47
48 /**
49 * Should we load this module.
50 *
51 * @param Product $product Product object.
52 *
53 * @return bool
54 */
55 public function can_load( $product ) {
56 if ( $this->is_from_partner( $product ) ) {
57 return false;
58 }
59
60 if ( ! apply_filters( $product->get_slug() . '_load_dashboard_widget', true ) ) {
61 return false;
62 }
63
64 return true;
65 }
66
67 /**
68 * Registers the hooks.
69 *
70 * @param Product $product Product to load.
71 *
72 * @return Dashboard_Widget Module instance.
73 */
74 public function load( $product ) {
75 if ( apply_filters( 'themeisle_sdk_hide_dashboard_widget', false ) ) {
76 return;
77 }
78 $this->product = $product;
79 $this->dashboard_name = apply_filters( 'themeisle_sdk_dashboard_widget_name', 'WordPress Guides/Tutorials' );
80 $this->feeds = apply_filters(
81 'themeisle_sdk_dashboard_widget_feeds',
82 [
83 'https://themeisle.com/blog/feed',
84 'https://www.codeinwp.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( 'Popular %s', 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', '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( 'Powered by %s', $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 return;
330 }
331 if ( is_array( $url ) ) {
332 foreach ( $url as $feed_url ) {
333 if ( in_array( $feed_url, $sdk_feeds, true ) ) {
334 $feed->force_feed( false );
335 return;
336 }
337 }
338 }
339 },
340 PHP_INT_MAX,
341 2
342 );
343 // Load SimplePie Instance.
344 $feed = fetch_feed( $sdk_feeds );
345 // TODO report error when is an error loading the feed.
346 if ( is_wp_error( $feed ) ) {
347 return;
348 }
349
350 $items = $feed->get_items( 0, 5 );
351 $items = is_array( $items ) ? $items : [];
352
353 $items_normalized = [];
354
355 foreach ( $items as $item ) {
356 $items_normalized[] = array(
357 'title' => $item->get_title(),
358 'date' => $item->get_date( 'U' ),
359 'link' => $item->get_permalink(),
360 );
361 }
362 set_transient( 'themeisle_sdk_feed_items', $items_normalized, 48 * HOUR_IN_SECONDS );
363 }
364 $this->items = $items_normalized;
365 }
366
367 /**
368 * Either the current product is installed or not.
369 *
370 * @param array $val The current recommended product.
371 *
372 * @return bool Either we should exclude the plugin or not.
373 */
374 public function remove_current_products( $val ) {
375 if ( 'theme' === $val['type'] ) {
376 $exist = wp_get_theme( $val['slug'] );
377
378 return ! $exist->exists();
379 } else {
380 $all_plugins = array_keys( get_plugins() );
381 foreach ( $all_plugins as $slug ) {
382 if ( strpos( $slug, $val['slug'] ) !== false ) {
383 return false;
384 }
385 }
386
387 return true;
388 }
389 }
390
391 /**
392 * Contact the API and fetch the recommended plugins/themes
393 */
394 public function recommend_plugin_or_theme() {
395 $products = $this->get_product_from_api();
396 if ( ! is_array( $products ) ) {
397 $products = array();
398 }
399 $products = array_filter( $products, array( $this, 'remove_current_products' ) );
400 $products = array_merge( $products );
401 if ( count( $products ) > 1 ) {
402 shuffle( $products );
403 $products = array_slice( $products, 0, 1 );
404 }
405 $to_recommend = isset( $products[0] ) ? $products[0] : $products;
406
407 return $to_recommend;
408 }
409
410 /**
411 * Fetch products from the recomended section.
412 *
413 * @return array|mixed The list of products to use in recomended section.
414 */
415 public function get_product_from_api() {
416 if ( false === ( $products = get_transient( 'themeisle_sdk_products' ) ) ) { //phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
417 $products = array();
418 $all_themes = $this->get_themes_from_wporg( 'themeisle' );
419 $all_plugins = $this->get_plugins_from_wporg( 'themeisle' );
420 static $allowed_products = [
421 'hestia' => true,
422 'neve' => true,
423 'visualizer' => true,
424 'feedzy-rss-feeds' => true,
425 'wp-product-review' => true,
426 'otter-blocks' => true,
427 'themeisle-companion' => true,
428 ];
429 foreach ( $all_themes as $theme ) {
430 if ( $theme->active_installs < 4999 ) {
431 continue;
432 }
433 if ( ! isset( $allowed_products[ $theme->slug ] ) ) {
434 continue;
435 }
436 $products[] = array(
437 'name' => $theme->name,
438 'type' => 'theme',
439 'slug' => $theme->slug,
440 'installs' => $theme->active_installs,
441 );
442 }
443 foreach ( $all_plugins as $plugin ) {
444 if ( $plugin->active_installs < 4999 ) {
445 continue;
446 }
447 if ( ! isset( $allowed_products[ $plugin->slug ] ) ) {
448 continue;
449 }
450 $products[] = array(
451 'name' => $plugin->name,
452 'type' => 'plugin',
453 'slug' => $plugin->slug,
454 'installs' => $plugin->active_installs,
455 );
456 }
457 set_transient( 'themeisle_sdk_products', $products, 6 * HOUR_IN_SECONDS );
458 }
459
460 return $products;
461 }
462
463 /**
464 * Fetch themes from wporg api.
465 *
466 * @param string $author The author name.
467 *
468 * @return array The list of themes.
469 */
470 public function get_themes_from_wporg( $author ) {
471 $products = $this->safe_get(
472 'https://api.wordpress.org/themes/info/1.1/?action=query_themes&request[author]=' . $author . '&request[per_page]=30&request[fields][active_installs]=true'
473 );
474 $products = json_decode( wp_remote_retrieve_body( $products ) );
475 if ( is_object( $products ) ) {
476 $products = isset( $products->themes ) ? $products->themes : array();
477 } else {
478 $products = array();
479 }
480
481 return (array) $products;
482 }
483
484 /**
485 * Fetch plugin from wporg api.
486 *
487 * @param string $author The author slug.
488 *
489 * @return array The list of plugins for the selected author.
490 */
491 public function get_plugins_from_wporg( $author ) {
492 $products = $this->safe_get(
493 'https://api.wordpress.org/plugins/info/1.1/?action=query_plugins&request[author]=' . $author . '&request[per_page]=40&request[fields][active_installs]=true'
494 );
495 $products = json_decode( wp_remote_retrieve_body( $products ) );
496 if ( is_object( $products ) ) {
497 $products = isset( $products->plugins ) ? $products->plugins : array();
498 } else {
499 $products = array();
500 }
501
502 return (array) $products;
503 }
504 }
505