2020-04-07 13:03:04 +00:00
< ? php
/**
* The blog dashboard model class for ThemeIsle SDK
*
* @ package ThemeIsleSDK
* @ subpackage Modules
* @ copyright Copyright ( c ) 2017 , Marius Cristea
* @ license http :// opensource . org / licenses / gpl - 3.0 . php GNU Public License
* @ since 1.0 . 0
*/
namespace ThemeisleSDK\Modules ;
use ThemeisleSDK\Common\Abstract_Module ;
use ThemeisleSDK\Product ;
// Exit if accessed directly.
if ( ! defined ( 'ABSPATH' ) ) {
exit ;
}
/**
* Blog dashboard widget module for ThemeIsle SDK .
*/
class Dashboard_Widget extends Abstract_Module {
/**
* Fetched feeds items .
*
* @ var array Feed items .
*/
private $items = array ();
/**
* Dashboard widget title .
*
* @ var string $dashboard_name Dashboard name .
*/
private $dashboard_name = '' ;
/**
* Dashboard widget feed sources .
*
* @ var array $feeds Feed url .
*/
private $feeds = [];
/**
* Should we load this module .
*
* @ param Product $product Product object .
*
* @ return bool
*/
public function can_load ( $product ) {
if ( $this -> is_from_partner ( $product ) ) {
return false ;
}
if ( ! apply_filters ( $product -> get_slug () . '_load_dashboard_widget' , true ) ) {
return false ;
}
return true ;
}
/**
* Registers the hooks .
*
* @ param Product $product Product to load .
*
* @ return Dashboard_Widget Module instance .
*/
public function load ( $product ) {
if ( apply_filters ( 'themeisle_sdk_hide_dashboard_widget' , false ) ) {
return ;
}
$this -> product = $product ;
$this -> dashboard_name = apply_filters ( 'themeisle_sdk_dashboard_widget_name' , 'WordPress Guides/Tutorials' );
$this -> feeds = apply_filters (
'themeisle_sdk_dashboard_widget_feeds' ,
[
'https://themeisle.com/blog/feed' ,
2023-03-17 22:34:22 +00:00
'https://www.codeinwp.com/blog/feed' ,
'https://wpshout.com/feed' ,
2020-04-07 13:03:04 +00:00
]
);
add_action ( 'wp_dashboard_setup' , array ( & $this , 'add_widget' ) );
add_action ( 'wp_network_dashboard_setup' , array ( & $this , 'add_widget' ) );
add_filter ( 'themeisle_sdk_recommend_plugin_or_theme' , array ( & $this , 'recommend_plugin_or_theme' ) );
return $this ;
}
/**
* Add widget to the dashboard
*
* @ return string | void
*/
2021-07-25 23:25:06 +00:00
public function add_widget () {
2020-04-07 13:03:04 +00:00
global $wp_meta_boxes ;
if ( isset ( $wp_meta_boxes [ 'dashboard' ][ 'normal' ][ 'core' ][ 'themeisle' ] ) ) {
return ;
}
wp_add_dashboard_widget (
'themeisle' ,
$this -> dashboard_name ,
[
$this ,
'render_dashboard_widget' ,
]
);
}
/**
* Render widget content
*/
2021-07-25 23:25:06 +00:00
public function render_dashboard_widget () {
2020-04-07 13:03:04 +00:00
$this -> setup_feeds ();
if ( empty ( $this -> items ) || ! is_array ( $this -> items ) ) {
return ;
}
?>
< style type = " text/css " >
#themeisle ul li.ti-dw-recommend-item {
padding - left : 7 px ;
border - top : 1 px solid #eee;
margin - bottom : 0 px ;
padding - top : 6 px ;
}
#themeisle h2.hndle {
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=' );
background - repeat : no - repeat ;
2022-11-24 13:40:39 +00:00
background - position : 2 % 50 % ;
2020-04-07 13:03:04 +00:00
background - size : 25 px ;
2022-11-24 13:40:39 +00:00
padding - left : 39 px ;
2020-04-07 13:03:04 +00:00
}
#themeisle .inside {
padding : 0 ;
}
. ti - feed - list {
padding : 0 12 px 5 px ;
margin - bottom : 10 px ;
border - bottom : 1 px solid #eee;
}
. ti - dw - feed - item a {
display : flex ;
align - items : center ;
margin - bottom : 5 px ;
padding : 5 px ;
transition : . 2 s ease ;
border - radius : 3 px ;
}
. ti - dw - feed - item a : hover {
background - color : #f8f8f8;
}
. ti - dw - feed - item a : hover . ti - dw - date - container {
opacity : . 9 ;
}
. ti - dw - feed - item . ti - dw - month - container {
margin - top : - 5 px ;
text - transform : uppercase ;
font - size : 10 px ;
letter - spacing : 1 px ;
font - weight : 700 ;
}
. ti - dw - feed - item . ti - dw - date - container {
border - radius : 3 px ;
transition : . 2 s ease ;
min - height : 35 px ;
margin - right : 5 px ;
min - width : 35 px ;
text - align : center ;
border : 1 px solid #2a6f97;
color : #fff;
background : #2ea2cc;
display : flex ;
flex - direction : column ;
justify - content : center ;
}
. ti - dw - footer {
padding : 0 12 px 5 px ;
text - align : center ;
}
. ti - dw - recommend - item {
display : block ;
}
. ti - dw - recommend - item span {
color : #72777c;
}
. ti - dw - powered - by {
font - size : 11 px ;
margin - top : 3 px ;
display : block ;
color : #72777c;
}
. ti - dw - powered - by span {
font - weight : 600 ;
}
</ style >
< ? php do_action ( 'themeisle_sdk_dashboard_widget_before' , $this -> product ); ?>
< ul class = " ti-feed-list " >
< ? php
foreach ( $this -> items as $item ) {
?>
< li class = " ti-dw-feed-item " >
< a href = "
< ? php
2021-07-25 23:25:06 +00:00
echo esc_url (
add_query_arg (
array (
'utm_source' => 'wpadmin' ,
'utm_campaign' => 'feed' ,
'utm_medium' => 'dashboard_widget' ,
),
$item [ 'link' ]
)
2020-04-07 13:03:04 +00:00
);
?>
" target= " _blank " >
< span class = " ti-dw-date-container " >< span
2021-07-25 23:25:06 +00:00
class = " ti-dw-day-container " >< ? php echo esc_attr ( gmdate ( 'd' , $item [ 'date' ] ) ); ?> </span> <span
class = " ti-dw-month-container " >< ? php echo esc_attr ( substr ( gmdate ( 'M' , $item [ 'date' ] ), 0 , 3 ) ); ?> </span></span><?php echo esc_attr( $item['title'] ); ?>
2020-04-07 13:03:04 +00:00
</ a >
</ li >
< ? php
}
?>
</ ul >
< ? php
$recommend = apply_filters ( 'themeisle_sdk_recommend_plugin_or_theme' , array () );
if ( ! is_array ( $recommend ) || empty ( $recommend ) ) {
return ;
}
$type = $recommend [ 'type' ];
if ( ( 'theme' === $type && ! current_user_can ( 'install_themes' ) ) ) {
return ;
}
if ( ( 'plugin' === $type && ! current_user_can ( 'install_plugins' ) ) ) {
return ;
}
add_thickbox ();
$url = add_query_arg (
[
'theme' => $recommend [ 'slug' ],
],
network_admin_url ( 'theme-install.php' )
);
if ( 'plugin' === $type ) {
$url = add_query_arg (
array (
'tab' => 'plugin-information' ,
'plugin' => $recommend [ 'slug' ],
),
network_admin_url ( 'plugin-install.php' )
);
}
?>
< div class = " ti-dw-footer " >
< span class = " ti-dw-recommend-item " >
2021-07-25 23:25:06 +00:00
< span class = " ti-dw-recommend " >< ? php echo esc_attr ( apply_filters ( 'themeisle_sdk_dashboard_popular_label' , sprintf ( 'Popular %s' , ucwords ( $type ) ) ) ); ?>
2020-04-07 13:03:04 +00:00
: </ span >
< ? php
2021-07-25 23:25:06 +00:00
echo esc_attr (
trim (
str_replace (
array (
'lite' ,
'Lite' ,
'(Lite)' ,
'(lite)' ,
),
'' ,
$recommend [ 'name' ]
)
2020-04-07 13:03:04 +00:00
)
);
?>
( < a class = " thickbox open-plugin-details-modal "
2021-07-25 23:25:06 +00:00
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>)
2020-04-07 13:03:04 +00:00
</ span >
2021-07-25 23:25:06 +00:00
< 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>
2020-04-07 13:03:04 +00:00
</ div >
< ? php
}
/**
* Setup feed items .
*/
private function setup_feeds () {
2021-07-25 23:25:06 +00:00
if ( false === ( $items_normalized = get_transient ( 'themeisle_sdk_feed_items' ) ) ) { //phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
2024-01-03 21:51:15 +00:00
// Do not force the feed for the items in the sdk feeds list.
// this prevents showing notices if another plugin will force all SimplePie feeds to load, instead it will
// use the regular SimplePie validation and abort early if the feed is not valid.
$sdk_feeds = $this -> feeds ;
add_action (
'wp_feed_options' ,
function ( $feed , $url ) use ( $sdk_feeds ) {
if ( defined ( 'TI_SDK_PHPUNIT' ) && true === TI_SDK_PHPUNIT ) {
return ;
}
if ( ! is_string ( $url ) && in_array ( $url , $sdk_feeds , true ) ) {
$feed -> force_feed ( false );
return ;
}
if ( is_array ( $url ) ) {
foreach ( $url as $feed_url ) {
if ( in_array ( $feed_url , $sdk_feeds , true ) ) {
$feed -> force_feed ( false );
return ;
}
}
}
},
PHP_INT_MAX ,
2
);
2020-04-07 13:03:04 +00:00
// Load SimplePie Instance.
2024-01-03 21:51:15 +00:00
$feed = fetch_feed ( $sdk_feeds );
2020-04-07 13:03:04 +00:00
// TODO report error when is an error loading the feed.
if ( is_wp_error ( $feed ) ) {
return ;
}
$items = $feed -> get_items ( 0 , 5 );
2023-03-17 22:34:22 +00:00
$items = is_array ( $items ) ? $items : [];
2024-01-03 21:51:15 +00:00
$items_normalized = [];
2023-03-17 22:34:22 +00:00
foreach ( $items as $item ) {
2020-04-07 13:03:04 +00:00
$items_normalized [] = array (
'title' => $item -> get_title (),
'date' => $item -> get_date ( 'U' ),
'link' => $item -> get_permalink (),
);
}
set_transient ( 'themeisle_sdk_feed_items' , $items_normalized , 48 * HOUR_IN_SECONDS );
}
$this -> items = $items_normalized ;
}
/**
* Either the current product is installed or not .
*
* @ param array $val The current recommended product .
*
* @ return bool Either we should exclude the plugin or not .
*/
public function remove_current_products ( $val ) {
if ( 'theme' === $val [ 'type' ] ) {
$exist = wp_get_theme ( $val [ 'slug' ] );
return ! $exist -> exists ();
} else {
$all_plugins = array_keys ( get_plugins () );
foreach ( $all_plugins as $slug ) {
if ( strpos ( $slug , $val [ 'slug' ] ) !== false ) {
return false ;
}
}
return true ;
}
}
/**
* Contact the API and fetch the recommended plugins / themes
*/
2021-07-25 23:25:06 +00:00
public function recommend_plugin_or_theme () {
2020-04-07 13:03:04 +00:00
$products = $this -> get_product_from_api ();
if ( ! is_array ( $products ) ) {
$products = array ();
}
$products = array_filter ( $products , array ( $this , 'remove_current_products' ) );
$products = array_merge ( $products );
if ( count ( $products ) > 1 ) {
shuffle ( $products );
$products = array_slice ( $products , 0 , 1 );
}
$to_recommend = isset ( $products [ 0 ] ) ? $products [ 0 ] : $products ;
return $to_recommend ;
}
/**
* Fetch products from the recomended section .
*
* @ return array | mixed The list of products to use in recomended section .
*/
2021-07-25 23:25:06 +00:00
public function get_product_from_api () {
if ( false === ( $products = get_transient ( 'themeisle_sdk_products' ) ) ) { //phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.FoundInControlStructure
2020-04-07 13:03:04 +00:00
$products = array ();
$all_themes = $this -> get_themes_from_wporg ( 'themeisle' );
$all_plugins = $this -> get_plugins_from_wporg ( 'themeisle' );
static $allowed_products = [
'hestia' => true ,
'neve' => true ,
'visualizer' => true ,
'feedzy-rss-feeds' => true ,
'wp-product-review' => true ,
'otter-blocks' => true ,
'themeisle-companion' => true ,
];
foreach ( $all_themes as $theme ) {
if ( $theme -> active_installs < 4999 ) {
continue ;
}
if ( ! isset ( $allowed_products [ $theme -> slug ] ) ) {
continue ;
}
$products [] = array (
'name' => $theme -> name ,
'type' => 'theme' ,
'slug' => $theme -> slug ,
'installs' => $theme -> active_installs ,
);
}
foreach ( $all_plugins as $plugin ) {
if ( $plugin -> active_installs < 4999 ) {
continue ;
}
if ( ! isset ( $allowed_products [ $plugin -> slug ] ) ) {
continue ;
}
$products [] = array (
'name' => $plugin -> name ,
'type' => 'plugin' ,
'slug' => $plugin -> slug ,
'installs' => $plugin -> active_installs ,
);
}
set_transient ( 'themeisle_sdk_products' , $products , 6 * HOUR_IN_SECONDS );
}
return $products ;
}
/**
* Fetch themes from wporg api .
*
* @ param string $author The author name .
*
* @ return array The list of themes .
*/
2021-07-25 23:25:06 +00:00
public function get_themes_from_wporg ( $author ) {
$products = $this -> safe_get (
2020-04-07 13:03:04 +00:00
'https://api.wordpress.org/themes/info/1.1/?action=query_themes&request[author]=' . $author . '&request[per_page]=30&request[fields][active_installs]=true'
);
$products = json_decode ( wp_remote_retrieve_body ( $products ) );
if ( is_object ( $products ) ) {
$products = isset ( $products -> themes ) ? $products -> themes : array ();
} else {
$products = array ();
}
return ( array ) $products ;
}
/**
* Fetch plugin from wporg api .
*
* @ param string $author The author slug .
*
* @ return array The list of plugins for the selected author .
*/
2021-07-25 23:25:06 +00:00
public function get_plugins_from_wporg ( $author ) {
$products = $this -> safe_get (
2020-04-07 13:03:04 +00:00
'https://api.wordpress.org/plugins/info/1.1/?action=query_plugins&request[author]=' . $author . '&request[per_page]=40&request[fields][active_installs]=true'
);
$products = json_decode ( wp_remote_retrieve_body ( $products ) );
if ( is_object ( $products ) ) {
$products = isset ( $products -> plugins ) ? $products -> plugins : array ();
} else {
$products = array ();
}
return ( array ) $products ;
}
}