includes/admin/class.llms.admin.addons.php
<?php
/**
* LifterLMS Add-On browser
*
* This is where the adds are, if you don't like it that's okay but i don't want to hear your complaints!
*
* @package LifterLMS/Admin/Classes
*
* @since 3.5.0
* @version 7.1.0
*/
defined( 'ABSPATH' ) || exit;
/**
* LLMS_Admin_AddOns class
*
* @since 3.5.0
* @since 3.30.3 Explicitly define undefined properties.
* @since 3.35.0 Sanitize input data.
*/
class LLMS_Admin_AddOns {
/**
* Data from `llms_get_add_ons()`.
*
* @var array
* @since 3.5.0
*/
public $data = array();
/**
* Retrieves the current section from the query string.
*
* @since 3.5.0
* @since 3.22.0 Unknown.
* @since 5.9.0 Stop using deprecated `FILTER_SANITIZE_STRING`.
*
* @return string
*/
private function get_current_section() {
$section = 'all';
if ( isset( $_GET['page'] ) && 'llms-dashboard' === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$section = 'featured';
} elseif ( isset( $_GET['section'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$section = llms_filter_input_sanitize_string( INPUT_GET, 'section' );
}
return apply_filters( 'llms_admin_add_ons_get_current_section', $section );
}
/**
* Retrieve addon data for the current section (tab) based off query string variables
*
* @return array
* @since 3.5.0
* @version 3.22.0
*/
private function get_current_section_content() {
$sec = $this->get_current_section();
$content = apply_filters( 'llms_admin_add_ons_get_current_section_default_content', array(), $sec );
if ( ! $content ) {
if ( 'all' === $sec ) {
$content = $this->get_all();
} elseif ( 'featured' === $sec ) {
$content = $this->get_features();
} else {
$content = $this->get_products_for_cat( $sec );
}
}
return apply_filters( 'llms_admin_add_ons_get_current_section_content', $content, $sec );
}
/**
* Retrieve remote json data.
*
* @since 3.5.0
* @since 3.22.2 Unknown.
* @since 7.1.0 Use strict comparisons for `in_array()`.
*
* @return array|WP_Error
*/
private function get_data() {
$this->data = llms_get_add_ons();
if ( ! is_wp_error( $this->data ) ) {
foreach ( $this->data['items'] as $key => $addon ) {
// Exclude the core plugin and helper plugin.
if ( in_array( $addon['id'], array( 'lifterlms-com-lifterlms', 'lifterlms-com-lifterlms-helper' ), true ) ) {
unset( $this->data['items'][ $key ] );
}
// Exclude uncategorized Add-ons.
if ( array_key_exists( 'uncategorized', $addon['categories'] ) ) {
unset( $this->data['items'][ $key ] );
}
}
}
return $this->data;
}
/**
* Retrieve a list of addons for use on the All section
*
* @return array
* @since 7.5.0
* @version 7.5.0
*/
private function get_all() {
$all = array();
$addons = $this->data['items'];
foreach ( $addons as $addon ) {
// Exclude third-party Addons from the All section.
if ( in_array( 'third-party', array_keys( $addon['categories'] ), true ) ) {
continue;
}
$all[] = $addon;
}
return $all;
}
/**
* Retrieve a list of 'featured' addons for use on the general settings screen
* Excludes already available products from current site's activations
*
* @return array
* @since 3.22.0
* @version 3.22.0
*/
private function get_features() {
$features = array();
// Addons to exclude.
// Helper will filter this based on existing activations.
$exclude = apply_filters( 'llms_admin_addon_features_exclude_ids', array() );
$cats = array(
'e-commerce',
'bundles',
'resources',
'courses',
'courses',
);
foreach ( $cats as $cat ) {
$addon = $this->get_product_from_cat( $cat, $exclude );
if ( $addon ) {
$features[] = $addon;
$exclude[] = $addon['id'];
}
if ( 3 === count( $features ) ) {
return $features;
}
}
return $features;
}
/**
* Get a random product from a category that doesn't exist in the list of excluded product ids.
*
* @since 3.22.0
* @since 7.1.0 Use strict comparisons for `in_array()`.
*
* @param string $cat Category slug.
* @param array $excludes List of product ids to exclude.
* @return array|false
*/
public function get_product_from_cat( $cat, $excludes ) {
$addons = $this->get_products_for_cat( $cat, true );
shuffle( $addons );
foreach ( $addons as $addon ) {
if ( in_array( 'third-party', array_keys( $addon['categories'] ), true ) ) {
continue;
}
if ( ! in_array( $addon['id'], $excludes, true ) ) {
return $addon;
}
}
return false;
}
/**
* Retrieve products for a specific category.
*
* @since 3.22.0
* @since 7.1.0 Use strict comparisons for `in_array()`.
*
* @param string $cat Category slug.
* @return array
*/
private function get_products_for_cat( $cat, $include_bundles = true ) {
$products = array();
foreach ( $this->data['items'] as $item ) {
$cats = array_keys( $item['categories'] );
// Exclude bundles if bundles are not being included or requested.
if ( 'bundles' !== $cat && ! $include_bundles && in_array( 'bundles', $cats, true ) ) {
continue;
}
if ( in_array( $cat, $cats, true ) ) {
$products[] = $item;
}
}
return $products;
}
/**
* Handle form submissions for managing license keys
*
* @return void
* @since 3.22.0
* @version 3.22.0
*/
public function handle_actions() {
// Activate & deactivate addons.
if ( llms_verify_nonce( '_llms_manage_addon_nonce', 'llms_manage_addon' ) ) {
$this->handle_manage_addons();
LLMS_Admin_Notices::output_notices();
}
}
/**
* Handle activation and deactivation of addons
*
* @since 3.22.0
* @since 3.35.0 Sanitize input data.
* @since 5.9.0 Stop using deprecated `FILTER_SANITIZE_STRING`.
*
* @return void
*/
private function handle_manage_addons() {
// phpcs:disable WordPress.Security.NonceVerification.Missing -- nonce is verified in $this->handle_actions() method.
$actions = apply_filters(
'llms_admin_add_ons_manage_actions',
array(
'activate',
'deactivate',
)
);
$errors = array();
$success = array();
foreach ( $actions as $action ) {
if ( empty( $_POST[ 'llms_' . $action ] ) ) {
continue;
}
foreach ( llms_filter_input( INPUT_POST, 'llms_' . $action, FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ) as $id ) {
$addon = llms_get_add_on( $id );
if ( ! method_exists( $addon, $action ) ) {
continue;
}
$ret = call_user_func( array( $addon, $action ) );
if ( is_wp_error( $ret ) ) {
LLMS_Admin_Notices::flash_notice( $ret->get_error_message(), 'error' );
} else {
LLMS_Admin_Notices::flash_notice( $ret );
}
}
}
// phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
* Output HTML for the current screen
*
* @since 3.5.0
* @since 3.28.0 Unknown.
* @since 4.10.1 Use `hr.wp-header-end` in favor of a second (hidden) <h1> to "catch" admin notices.
*
* @return void
*/
public function output() {
if ( is_wp_error( $this->get_data() ) ) {
_e( 'There was an error retrieving add-ons. Please try again.', 'lifterlms' );
return;
}
?>
<div class="wrap lifterlms lifterlms-settings lifterlms-addons">
<div class="llms-subheader">
<h1><?php _e( 'LifterLMS Add-Ons, Courses, and Resources', 'lifterlms' ); ?></h1>
<?php do_action( 'llms_addons_page_after_title' ); ?>
</div>
<div class="llms-inside-wrap">
<?php $this->output_navigation(); ?>
<hr class="wp-header-end">
<form action="" method="POST">
<?php $this->output_content(); ?>
<?php wp_nonce_field( 'llms_manage_addon', '_llms_manage_addon_nonce' ); ?>
<div class="llms-addons-bulk-actions" id="llms-addons-bulk-actions">
<a class="llms-bulk-close" href="#">
<span class="screen-reader-text"><?php _e( 'Close', 'lifterlms' ); ?></span>
<i class="fa fa-times-circle" aria-hidden="true"></i>
</a>
<div class="llms-bulk-desc update">
<i class="fa fa-cloud-download" aria-hidden="true"></i>
<?php _e( 'Update', 'lifterlms' ); ?> <span></span>
</div>
<div class="llms-bulk-desc install">
<i class="fa fa-cloud-download" aria-hidden="true"></i>
<?php _e( 'Install', 'lifterlms' ); ?> <span></span>
</div>
<div class="llms-bulk-desc activate">
<i class="fa fa-plug" aria-hidden="true"></i>
<?php _e( 'Activate', 'lifterlms' ); ?> <span></span>
</div>
<div class="llms-bulk-desc deactivate">
<i class="fa fa-plug" aria-hidden="true"></i>
<?php _e( 'Deactivate', 'lifterlms' ); ?> <span></span>
</div>
<button class="llms-button-primary" name="llms_bulk_actions_submit" value="" type="submit"><?php _e( 'Apply', 'lifterlms' ); ?></button>
</div>
</form>
</div>
</div>
<?php
}
/**
* Output HTML for a single addon
*
* @param array $addon associative array of add-on data
* @return void
* @since 3.5.0
* @version 3.22.0
*/
private function output_addon( $addon ) {
$current_tab = $this->get_current_section();
include 'views/addons/addon-item.php';
}
/**
* Output the addon list for the current section
*
* @return void
* @since 3.5.0
* @version 3.22.0
*/
private function output_content() {
?>
<ul class="llms-addons-wrap section--<?php echo esc_attr( $this->get_current_section() ); ?>">
<?php do_action( 'lifterlms_before_addons' ); ?>
<?php
foreach ( $this->get_current_section_content() as $addon ) {
$addon = llms_get_add_on( $addon );
$this->output_addon( $addon );
}
?>
<?php do_action( 'lifterlms_after_addons' ); ?>
</ul>
<?php
}
/**
* Outputs most popular resources
* used on general settings screen
*
* @return void
* @since 3.7.6
* @version 3.7.6
*/
public function output_for_settings() {
if ( is_wp_error( $this->get_data() ) ) {
_e( 'There was an error retrieving add-ons. Please try again.', 'lifterlms' );
return;
}
$this->output_content();
}
/**
* Output the navigation bar
*
* @return void
* @since 3.5.0
* @version 3.22.0
*/
private function output_navigation() {
$curr_section = $this->get_current_section();
?>
<nav class="llms-nav-tab-wrapper llms-nav-secondary">
<ul class="llms-nav-items">
<?php do_action( 'lifterlms_before_addons_nav', $curr_section ); ?>
<?php
foreach ( $this->data['categories'] as $name => $title ) :
$name = sanitize_title( $name );
$title = sanitize_text_field( $title );
$active = ( $this->get_current_section() === $name ) ? ' llms-active' : '';
?>
<li class="llms-nav-item<?php echo $active; ?>"><a class="llms-nav-link" href="<?php echo esc_url( admin_url( 'admin.php?page=llms-add-ons§ion=' . $name ) ); ?>"><?php echo $title; ?></a></li>
<?php endforeach; ?>
<li class="llms-nav-item<?php echo ( 'all' === $curr_section ) ? ' llms-active' : ''; ?>"><a class="llms-nav-link" href="<?php echo esc_url( admin_url( 'admin.php?page=llms-add-ons§ion=all' ) ); ?>"><?php _e( 'All', 'lifterlms' ); ?></a></li>
<?php do_action( 'lifterlms_after_addons_nav', $curr_section ); ?>
</ul>
</nav>
<?php
}
}