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

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