| Current Path : /home/ereika83/www/wp-content/plugins/sfwd-lms/includes/ |
| Current File : /home/ereika83/www/wp-content/plugins/sfwd-lms/includes/class-ld-semper-fi-module.php |
<?php
/**
* The module base class; handles settings, options, menus, metaboxes, etc.
*
* @since 2.1.0
*
* @package LearnDash\Semper-Fi
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! function_exists( 'str_getcsv' ) ) {
/**
* Input a text file name of a comma separated file, and parse it, returning the data as an array
*
* @since 2.1.0
*
* @param string $input File name.
* @param string $delimiter Delimiter.
* @param string $enclosure Enclosure.
* @param string $escape Escape.
*
* @return array Array of strings that are parsed as comma separated values
*/
function str_getcsv( $input, $delimiter = ',', $enclosure = '"', $escape = '\\' ) {
$fp = fopen( 'php://memory', 'r+' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen -- I don't think we'll refactor it in the nearest feature.
fputs( $fp, $input );
rewind( $fp );
$data = fgetcsv( $fp, 0, $delimiter, $enclosure ); // $escape only got added in 5.3.0
fclose( $fp ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
return $data;
}
}
/**
* The module base class; handles settings, options, menus, metaboxes, etc.
*/
if ( ! class_exists( 'Semper_Fi_Module' ) ) {
/**
* Abstract base class
*
* @codingStandardsIgnoreStart
*/
abstract class Semper_Fi_Module {
// @codingStandardsIgnoreEnd
/**
* Instance of this class
*
* @var object
*/
public static $instance = null;
/**
* Plugin name
*
* @var string
*/
protected $plugin_name;
/**
* Name
*
* @var string
*/
protected $name;
/**
* Menu name
*
* @var string
*/
protected $menu_name;
/**
* Prefix
*
* @var string
*/
protected $prefix;
/**
* File path
*
* @var string
*/
protected $file;
/**
* Array of options
*
* @var Array
*/
protected $options;
/**
* Option name
*
* @var string
*/
protected $option_name;
/**
* Network options
*
* @var bool
*/
protected $network_options = false;
/**
* Default options
*
* @var null|array
*/
protected $default_options;
/**
* Organize settings into settings pages with a menu items and/or metaboxes on post types edit screen; optional
*
* @var null|array
*/
protected $locations = null;
/**
* Organize settings on a settings page into multiple, separate metaboxes; optional
*
* @var null|array
*/
protected $layout = null;
/**
* Organize layouts on a settings page into multiple, separate tabs; optional
*
* @var null|array
*/
protected $tabs = null;
/**
* Current Tab
*
* @var null|string
*/
protected $current_tab = null;
/**
* The current page hook
*
* @var null|string
*/
protected $pagehook = null; // cspell:disable-line.
/**
* Store option
*
* @var bool
*/
protected $store_option = false;
/**
* Parent option
*
* @var string
*/
protected $parent_option = 'sfwd_cpt_options';
/**
* Meta boxes
*
* @var Array
*/
protected $post_metaboxes = array();
/**
* Post type
*
* @var string
*/
protected $post_type;
/**
* Tabbed metaboxes
*
* @var bool
*/
protected $tabbed_metaboxes = false;
/**
* Used for WP Filesystem
*
* @var string
*/
protected $credentials = false;
/**
* Used for passing data to JavaScript
*
* @var string
*/
protected $script_data = null;
/**
* Plugin path details.
*
* @var array
*/
protected $plugin_path = array();
/**
* Array of pointers
*
* @var Array
*/
protected $pointers = array();
/**
* Handles calls to display_settings_page_{$location}, does error checking.
* The function '$this->display_settings_page' actually returns type void.
*
* @since 2.1.0
*
* @param string $name Method name.
* @param array $arguments Arguments.
*
* @throws InvalidArgumentException When method doesn't exist.
*/
public function __call( $name, $arguments ) {
if ( strpos( $name, 'display_settings_page_' ) === 0 ) {
$location = substr( $name, 22 );
$this->display_settings_page( $location );
}
// translators: placeholder: method name.
throw new InvalidArgumentException( sprintf( esc_html_x( "Method %s doesn't exist", 'placeholder: method name', 'learndash' ), $name ) );
}
/**
* Constructor for the Semper_Fi_Module class
*/
public function __construct() {
if ( empty( $this->file ) ) {
$this->file = __FILE__;
}
$this->plugin_path = array();
$this->plugin_path['dir'] = plugin_dir_path( dirname( $this->file ) );
$this->plugin_path['basename'] = plugin_basename( $this->plugin_path['dir'] . '/sfwd_lms.php' );
$this->plugin_path['dirname'] = dirname( $this->plugin_path['basename'] );
$this->plugin_path['url'] = plugin_dir_url( dirname( $this->file ) );
$this->plugin_path['images_url'] = $this->plugin_path['url'] . 'assets/images';
}
/**
* Adds support for getting network options.
*
* @since 2.1.0
*
* @param string $name Name of the option.
* @param boolean|string|array $default Value to return if the option doesn't exist.
* @param boolean $use_cache Whether to use cache. Default true.
* @return string
*/
public function get_option( $name, $default = false, $use_cache = true ) {
if ( $this->network_options ) {
return get_site_option( $name, $default, $use_cache );
} else {
return get_option( $name, $default );
}
}
/**
* Adds support for updating network options.
*
* @since 2.1.0
*
* @param string $option Option to be changed.
* @param string $new_value Value of new option.
* @return bool
*/
public function update_option( $option, $new_value ) {
if ( $this->network_options ) {
return update_site_option( $option, $new_value );
} else {
return update_option( $option, $new_value );
}
}
/**
* Adds support for deleting network options.
*
* @since 2.1.0
*
* @param string $option Name of option to delete.
* @return bool
*/
public function delete_option( $option ) {
if ( $this->network_options ) {
return delete_site_option( $option );
} else {
return delete_option( $option );
}
}
/**
* Get options for module, stored individually or together.
*
* @since 2.1.0
*
* @return bool|string
*/
public function get_class_option() {
$option_name = $this->get_option_name();
if ( $this->store_option ) {
return $this->get_option( $option_name );
} else {
$option = $this->get_option( $this->parent_option );
if ( isset( $option['modules'] ) && isset( $option['modules'][ $option_name ] ) ) {
return $option['modules'][ $option_name ];
}
}
return false;
}
/**
* Update options for module, stored individually or together.
*
* @since 2.1.0
*
* @param string $option_data Option value.
* @param bool|string $option_name Name of the option to update.
* @return bool
*/
public function update_class_option( $option_data, $option_name = false ) {
if ( false === $option_name ) {
$option_name = $this->get_option_name();
}
if ( $this->store_option ) {
return $this->update_option( $option_name, $option_data );
} else {
$option = $this->get_option( $this->parent_option );
if ( ! isset( $option['modules'] ) ) {
$option['modules'] = array();
}
$option['modules'][ $option_name ] = $option_data;
return $this->update_option( $this->parent_option, $option );
}
}
/**
* Delete options for module, stored individually or together.
*
* @since 2.1.0
*
* @param bool $delete Whether to delete.
* @return bool
*/
public function delete_class_option( $delete = false ) {
$option_name = $this->get_option_name();
if ( $this->store_option || $delete ) {
$this->delete_option( $option_name );
} else {
$option = $this->get_option( $this->parent_option );
if ( isset( $option['modules'] ) && isset( $option['modules'][ $option_name ] ) ) {
unset( $option['modules'][ $option_name ] );
return $this->update_option( $this->parent_option, $option );
}
}
return false;
}
/**
* Get the option name with prefix.
*
* @since 2.1.0
*
* @return string Option Name
*/
public function get_option_name() {
if ( ! isset( $this->option_name ) || empty( $this->option_name ) ) {
$this->option_name = $this->prefix . 'options';
}
return $this->option_name;
}
/**
* Convenience function to see if an option is set.
*
* @since 2.1.0
*
* @param string $option Option for this prefix.
* @param null|string $location $this->locations array index.
* @return bool
*/
public function option_isset( $option, $location = null ) {
$prefix = $this->get_prefix( $location );
$opt = $prefix . $option;
return ( ( isset( $this->options[ $opt ] ) ) && $this->options[ $opt ] );
}
/**
* Displays tabs for tabbed locations on a settings page.
*
* @since 2.1.0
*
* @param null|string $location $this->locations array index.
*/
public function display_tabs( $location ) {
if ( ( null !== $location ) && isset( $this->locations[ $location ]['tabs'] ) ) {
$tabs = $this->locations['location']['tabs'];
} else {
$tabs = $this->tabs;
}
if ( ! empty( $tabs ) ) {
?>
<div class="sfwd_tabs_div">
<label class="sfwd_head_nav">
<?php
foreach ( $tabs as $k => $v ) {
?>
<a class="sfwd_head_nav_tab sfwd_head_nav_
<?php
if ( $this->current_tab != $k ) {
echo 'in';}
?>
active" href="<?php echo esc_url( add_query_arg( 'tab', $k ) ); ?>"><?php echo esc_html( $v['name'] ); ?></a>
<?php
}
?>
</label>
</div>
<?php
}
}
/**
* Handles exporting settings data for a module.
*
* @since 2.1.0
*
* @param string $buf Buffer.
* @return string Saved options line separated
*/
public function settings_export( $buf ) {
global $sfwd_options, $sfp;
$post_types = null;
$has_data = null;
$general_settings = null;
$exporter_choices = esc_attr( $_REQUEST['sfp_importer_exporter_export_choices'] );
if ( ! empty( $exporter_choices ) && is_array( $exporter_choices ) ) {
foreach ( $exporter_choices as $ex ) {
if ( 1 === $ex ) {
$general_settings = true;
}
if ( 2 === $ex ) {
if ( isset( $_REQUEST['sfp_importer_exporter_export_post_types'] ) ) {
$post_types = esc_attr( $_REQUEST['sfp_importer_exporter_export_post_types'] );
}
}
}
}
if ( null !== $post_types ) {
$posts_query = new WP_Query( array( 'post_type' => $post_types ) );
$export_data = array();
if ( ( $this === $sfp ) || ( null !== $this->locations ) ) {
while ( $posts_query->have_posts() ) :
$posts_query->the_post();
global $post;
$guid = $post->guid;
$type = $post->post_type;
$title = $post->post_title;
$date = $post->post_date;
$data = '';
/* Add Module Meta Data */
if ( null !== $this->locations ) {
foreach ( $this->locations as $k => $v ) {
if ( isset( $v['type'] ) && isset( $v['options'] ) && ( 'metabox' === $v['type'] ) ) {
$value = $this->get_prefix( $k ) . $k;
$post_meta = get_post_meta( $post->ID, '_' . $value, true );
if ( $post_meta ) {
$data .= "$value = '" . str_replace( array( "'", "\n", "\r" ), array( "\'", '\n', '\r' ), trim( serialize( $post_meta ) ) ) . "'"; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize -- I don't think we need to touch this.
}
}
}
} else {
/* Add Post Field Data */
$post_custom_fields = get_post_custom( $post->ID );
$has_data = null;
if ( is_array( $post_custom_fields ) ) {
foreach ( $post_custom_fields as $field_name => $field ) {
if ( ( substr( $field_name, 1, 7 ) == 'sfwd' ) && ( $field[0] ) ) {
$has_data = true;
$data .= $field_name . " = '" . $field[0] . "'\n";
}
}
}
}
/* Print post data to file */
if ( null !== $has_data ) {
$post_info = "\n[post_data]\n\n";
$post_info .= "post_title = '" . $title . "'\n";
$post_info .= "post_guid = '" . $guid . "'\n";
$post_info .= "post_date = '" . $date . "'\n";
$post_info .= "post_type = '" . $type . "'\n";
if ( $data ) {
$buf .= $post_info . $data . "\n";
}
}
endwhile;
wp_reset_postdata();
}
}
/* Add all active settings to settings file */
$name = $this->get_option_name();
$options = $this->get_class_option();
if ( ! empty( $options ) && null !== $general_settings ) {
$buf .= "\n[ $name]\n\n";
foreach ( $options as $key => $value ) {
if ( ( $name == $this->parent_option ) && ( 'modules' === $key ) ) {
continue;
}
// Don't re-export all module settings -- pdb.
if ( is_array( $value ) ) {
$value = "'" . str_replace( array( "'", "\n", "\r" ), array( "\'", '\n', '\r' ), trim( serialize( $value ) ) ) . "'"; // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize -- I don't think we need to touch this.
} else {
$value = str_replace( array( "\n", "\r" ), array( '\n', '\r' ), trim( var_export( $value, true ) ) ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export -- I don't think we need to touch this.
}
$buf .= "$key = $value\n";
}
}
return $buf;
}
/**
* Print a basic error message.
*
* @since 2.1.0
*
* @param string $error Error message.
* @return bool
*/
public function output_error( $error ) {
echo wp_kses_post( '<div class="sfwd_module error" style="text-align:center;">' . $error . '</div>' );
return false;
}
/**
* Helper function to convert csv in key/value pair format to an associative array.
*
* @since 2.1.0
*
* @param string $csv Comma separated text string.
* @return array Array representation of comma separated text
*/
public function csv_to_array( $csv ) {
$args = array();
$v = str_getcsv( $csv );
$size = count( $v );
if ( is_array( $v ) && isset( $v[0] ) && $size >= 2 ) {
for ( $i = 0; $i < $size; $i += 2 ) {
$args[ $v[ $i ] ] = $v[ $i + 1 ];
}
}
return $args;
}
/**
* Crude approximation of whether current user is an admin
*
* @since 2.1.0
*
* @return bool
*/
public function is_admin() {
return current_user_can( LEARNDASH_ADMIN_CAPABILITY_CHECK );
}
/**
* Load styles for module.
*
* @since 2.1.0
*/
public function enqueue_styles() {
global $learndash_assets_loaded;
wp_enqueue_style( 'thickbox' );
if ( ! empty( $this->pointers ) ) {
wp_enqueue_style( 'wp-pointer' );
}
wp_enqueue_style(
'sfwd-module-style',
LEARNDASH_LMS_PLUGIN_URL . 'assets/css/sfwd_module' . learndash_min_asset() . '.css',
array(),
LEARNDASH_SCRIPT_VERSION_TOKEN
);
wp_style_add_data( 'sfwd-module-style', 'rtl', 'replace' );
$learndash_assets_loaded['styles']['sfwd-module-style'] = __FUNCTION__;
}
/**
* Load scripts for module, can pass data to module script.
*
* @since 2.1.0
*/
public function enqueue_scripts() {
global $learndash_assets_loaded;
wp_enqueue_script( 'jquery' );
if ( is_admin() ) {
wp_enqueue_script( 'jquery-ui-core' );
wp_enqueue_script( 'jquery-ui-datepicker' );
wp_enqueue_script( 'media-upload' );
wp_enqueue_script( 'thickbox' );
if ( ! empty( $this->pointers ) ) {
wp_enqueue_script( 'wp-pointer', false, array( 'jquery' ), LEARNDASH_SCRIPT_VERSION_TOKEN, false );
$this->script_data['pointers'] = $this->pointers;
}
}
$this->script_data['learndash_categories_lang'] = esc_html__( 'LearnDash Categories', 'learndash' );
$this->script_data['loading_lang'] = esc_html__( 'Loading...', 'learndash' );
// translators: placeholder: Lesson.
$this->script_data['select_a_lesson_lang'] = sprintf( esc_html_x( '-- Select a %s --', 'placeholder: Lesson', 'learndash' ), LearnDash_Custom_Label::get_label( 'lesson' ) );
// translators: placeholders: Lesson, Topic.
$this->script_data['select_a_lesson_or_topic_lang'] = sprintf( esc_html_x( '-- Select a %1$s or %2$s --', 'placeholders: Lesson, Topic', 'learndash' ), LearnDash_Custom_Label::get_label( 'lesson' ), LearnDash_Custom_Label::get_label( 'topic' ) );
$this->script_data['advanced_quiz_preview_link'] = admin_url( 'admin.php?page=ldAdvQuiz&module=preview&id=' );
$this->script_data['valid_recurring_paypal_day_range'] = esc_html__( 'Valid range is 1 to 90 when the Billing Cycle is set to days.', 'learndash' );
$this->script_data['valid_recurring_paypal_week_range'] = esc_html__( 'Valid range is 1 to 52 when the Billing Cycle is set to weeks.', 'learndash' );
$this->script_data['valid_recurring_paypal_month_range'] = esc_html__( 'Valid range is 1 to 24 when the Billing Cycle is set to months.', 'learndash' );
$this->script_data['valid_recurring_paypal_year_range'] = esc_html__( 'Valid range is 1 to 5 when the Billing Cycle is set to years.', 'learndash' );
$this->script_data['valid_recurring_paypal_day_max'] = learndash_billing_cycle_field_frequency_max( 'D' );
$this->script_data['valid_recurring_paypal_week_max'] = learndash_billing_cycle_field_frequency_max( 'W' );
$this->script_data['valid_recurring_paypal_month_max'] = learndash_billing_cycle_field_frequency_max( 'M' );
$this->script_data['valid_recurring_paypal_year_max'] = learndash_billing_cycle_field_frequency_max( 'Y' );
global $post;
if ( ( $post instanceof WP_Post ) && ( 'sfwd-quiz' === $post->post_type ) ) {
$this->script_data['quiz_pro'] = intval( learndash_get_setting( $post->ID, 'quiz_pro' ) );
}
wp_enqueue_script(
'sfwd-module-script',
LEARNDASH_LMS_PLUGIN_URL . 'assets/js/sfwd_module' . learndash_min_asset() . '.js',
array( 'jquery' ),
LEARNDASH_SCRIPT_VERSION_TOKEN,
true
);
$learndash_assets_loaded['scripts']['sfwd-module-script'] = __FUNCTION__;
$data = array();
if ( ! empty( $this->script_data ) ) {
$data = $this->script_data;
}
if ( ! isset( $data['ajaxurl'] ) ) {
$data['ajaxurl'] = admin_url( 'admin-ajax.php' );
}
$data = array( 'json' => wp_json_encode( $data ) );
wp_localize_script( 'sfwd-module-script', 'sfwd_data', $data );
if ( ! isset( $learndash_assets_loaded['scripts']['learndash_template_script_js'] ) ) {
// First check if the theme has the file learndash/learndash_template_script.js or learndash_template_script.js file.
$filepath = SFWD_LMS::get_template( 'learndash_template_script.js', null, null, true );
if ( ! empty( $filepath ) ) {
wp_enqueue_script( 'learndash_template_script_js', learndash_template_url_from_path( $filepath ), array( 'jquery' ), LEARNDASH_SCRIPT_VERSION_TOKEN, true );
$learndash_assets_loaded['scripts']['learndash_template_script_js'] = __FUNCTION__;
}
}
}
/**
* Override this to run code at the beginning of the settings page.
*
* @since 2.1.0
*/
public function settings_page_init() {
}
/**
* Filter out admin pointers that have already been clicked.
*
* @since 2.1.0
*/
public function filter_pointers() {
if ( ! empty( $this->pointers ) ) {
$dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
foreach ( $dismissed as $d ) {
if ( isset( $this->pointers[ $d ] ) ) {
unset( $this->pointers[ $d ] );
}
}
}
}
/**
* Add basic hooks when on the module's page.
*/
public function add_page_hooks() {
$hookname = current_filter();
if ( strpos( $hookname, 'load-' ) === 0 ) {
$this->pagehook = substr( $hookname, 5 ); // cspell:disable-line.
}
$this->filter_pointers();
add_action( 'admin_print_scripts', array( $this, 'enqueue_scripts' ) );
add_action( 'admin_print_styles', array( $this, 'enqueue_styles' ) );
add_action( $this->prefix . 'settings_header', array( $this, 'display_tabs' ) );
}
/**
* Collect metabox data together for tabbed metaboxes.
*
* @since 2.1.0
*
* @param array $args Arguments to merge with metaboxes.
* @return array Merged array
*/
public function filter_return_metaboxes( $args ) {
return array_merge( $args, $this->post_metaboxes );
}
/**
* Add submenu for module, call page hooks, set up metaboxes.
*
* @since 2.1.0
*
* @param string $parent_slug Parent menu slug.
*/
public function add_menu( $parent_slug ) {
if ( empty( $parent_slug ) ) {
$parent_slug = 'options-general.php';
}
if ( ! empty( $this->menu_name ) ) {
$name = $this->menu_name;
} else {
$name = $this->name;
}
$default_options_page = $this->post_type . '-options';
if ( null === $this->locations ) {
$hookname = add_submenu_page( $parent_slug, $name, $name, LEARNDASH_ADMIN_CAPABILITY_CHECK, $default_options_page, array( $this, 'display_settings_page' ) );
add_action( "load-{$hookname}", array( $this, 'add_page_hooks' ) );
return true;
}
foreach ( $this->locations as $k => $v ) {
if ( 'metabox' === $v['type'] ) {
add_action( 'save_post', array( $this, 'save_post_data' ), 10, 3 );
if ( isset( $v['display'] ) && ! empty( $v['display'] ) ) {
foreach ( $v['display'] as $posttype ) {
$v['location'] = $k;
$v['posttype'] = $posttype;
if ( ! isset( $v['context'] ) ) {
$v['context'] = 'normal';
}
if ( ! isset( $v['priority'] ) ) {
$v['priority'] = 'high';
}
if ( $this->tabbed_metaboxes ) {
$this->post_metaboxes[] = array(
'id' => $v['prefix'] . $k,
'title' => $v['name'],
'callback' => array(
$this,
'display_metabox',
),
'post_type' => $posttype,
'context' => $v['context'],
'priority' => $v['priority'],
'callback_args' => $v,
);
add_filter( 'sfwd_add_post_metabox', array( $this, 'filter_return_metaboxes' ) );
} else {
if ( ( isset( $name ) ) && ( ! empty( $name ) ) ) {
$title = $name;
} else {
$title = $v['name'];
if ( $title != $this->plugin_name ) {
$title = $this->plugin_name . ' - ' . $title;
}
}
/**
* Filters whether to show legacy quiz metaboxes or not.
*
* @since 3.0.0
*
* @param boolean $show_legacy_quiz Whether to show legacy quiz metabox or not.
* @param string $post_type Post type slug.
*/
if ( ( 'sfwd-quiz' === $posttype ) && ( apply_filters( 'learndash_settings_metaboxes_legacy_quiz', LEARNDASH_SETTINGS_METABOXES_LEGACY_QUIZ, $posttype ) ) ) {
/**
* Filters semperfi metabox title.
*
* @since 2.1.0
*
* @param string $title Metabox title
* @param string $prefix Title prefix
* @param string $location Metabox location key.
*/
$title = apply_filters( 'semperfi_metabox_title', $title, $v['prefix'] . $k, $k ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Legacy prefix.
add_meta_box( $v['prefix'] . $k, $title, array( $this, 'display_metabox' ), $posttype, $v['context'], $v['priority'], $v );
} // phpcs:ignore Squiz.ControlStructures.ControlSignature.SpaceAfterCloseBrace -- DocBlock for filter follows
/**
* Filters whether to show legacy metaboxes or not.
*
* @param boolean $show_legacy Whether to show legacy metabox or not.
* @param string $post_type Post type slug.
*/
elseif ( apply_filters( 'learndash_settings_metaboxes_legacy', LEARNDASH_SETTINGS_METABOXES_LEGACY, $posttype ) ) {
/** This filter is documented in includes/class-ld-semper-fi-module.php */
$title = apply_filters( 'semperfi_metabox_title', $title, $v['prefix'] . $k ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Legacy prefix.
add_meta_box( $v['prefix'] . $k, $title, array( $this, 'display_metabox' ), $posttype, $v['context'], 'low', $v );
}
}
/**
* Enqueue_scripts action
*
* Adds 'admin_print_scripts-post.php' to the enqueued scripts hook
*
* @since 2.1.0
*
* @param array array( $this, 'enqueue_scripts')
*/
add_action( 'admin_print_scripts-post.php', array( $this, 'enqueue_scripts' ) );
/**
* Enqueue_scripts action
*
* Adds admin_print_scripts-post-new.php to the 'enqueue_scripts' hook
*
* @since 2.1.0
*
* @param array array( $this, 'enqueue_scripts')
*/
add_action( 'admin_print_scripts-post-new.php', array( $this, 'enqueue_scripts' ) );
/**
* Enqueue_styles action
*
* Adds admin_print_styles-post.php to the 'enqueue_styles' hook
*
* @since 2.1.0
*
* @param array array( $this, 'enqueue_styles')
*/
add_action( 'admin_print_styles-post.php', array( $this, 'enqueue_styles' ) );
/**
* Enqueue_scripts action
*
* Adds the filename 'admin_print_styles-post-new.php' to the 'enqueue_styles' hook
*
* @since 2.1.0
*
* @param array array( $this, 'enqueue_styles')
*/
add_action( 'admin_print_styles-post-new.php', array( $this, 'enqueue_styles' ) );
}
}
}
}
}
/**
* Update postmeta for metabox.
*
* @since 2.1.0
*
* @param int $post_id Post ID.
* @param WP_Post $saved_post WP Post object.
* @param bool $update Whether this is an existing post.
*/
public function save_post_data( $post_id = 0, $saved_post = null, $update = null ) {
if ( null !== $this->locations ) {
foreach ( $this->locations as $k => $v ) {
if ( isset( $v['type'] ) && ( 'metabox' === $v['type'] ) ) {
$opts = $this->default_options( $k );
$options = array();
$update = false;
foreach ( $opts as $l => $o ) {
if ( isset( $_POST[ $l ] ) ) {
$options[ $l ] = stripslashes_deep( $_POST[ $l ] );
if ( ! is_array( $options[ $l ] ) ) {
$options[ $l ] = esc_attr( $options[ $l ] );
}
$update = true;
}
}
if ( $update ) {
if ( 'sfwd-courses' === $k ) {
if ( ! isset( $options['sfwd-courses_course_prerequisite_enabled'] ) ) {
$options['sfwd-courses_course_prerequisite_enabled'] = 'off';
}
if ( ! isset( $options['sfwd-courses_course_prerequisite'] ) ) {
$options['sfwd-courses_course_prerequisite'] = array();
}
// IF prerequisites not enabled then clear out the courses array.
if ( 'on' !== $options['sfwd-courses_course_prerequisite_enabled'] ) {
$options['sfwd-courses_course_prerequisite'] = array();
} else {
if ( ( isset( $options['sfwd-courses_course_prerequisite'] ) ) && ( ! empty( $options['sfwd-courses_course_prerequisite'] ) ) ) {
foreach ( $options['sfwd-courses_course_prerequisite'] as $c_idx => $c_id ) {
$c_id = intval( $c_id );
if ( empty( $c_id ) ) {
unset( $options['sfwd-courses_course_prerequisite'][ $c_idx ] );
}
}
}
}
// Or the other way if there are no selected prerequisites courses set enable off.
if ( empty( $options['sfwd-courses_course_prerequisite'] ) ) {
$options['sfwd-courses_course_prerequisite_enabled'] = 'off';
} else {
$options['sfwd-courses_course_prerequisite'] = array_values( $options['sfwd-courses_course_prerequisite'] );
}
if ( ( isset( $options['sfwd-courses_course_points_enabled'] ) ) && ( 'on' === $options['sfwd-courses_course_points_enabled'] ) ) {
if ( isset( $options['sfwd-courses_course_points'] ) ) {
$course_points = learndash_format_course_points( $options['sfwd-courses_course_points'] );
} else {
$course_points = 0;
}
if ( ! empty( $course_points ) ) {
update_post_meta( $post_id, 'course_points', $course_points );
} else {
delete_post_meta( $post_id, 'course_points' );
}
} else {
delete_post_meta( $post_id, 'course_points' );
}
if ( isset( $options['sfwd-courses_course_access_list'] ) ) {
$options['sfwd-courses_course_access_list'] = learndash_convert_course_access_list( $options['sfwd-courses_course_access_list'] );
update_post_meta( $post_id, 'course_access_list', $options['sfwd-courses_course_access_list'] );
}
} elseif ( ( 'sfwd-lessons' === $k ) && ( isset( $options[ $k . '_visible_after_specific_date' ] ) ) ) {
$date = $options[ $k . '_visible_after_specific_date' ];
if ( isset( $date['aa'] ) ) {
$date['aa'] = intval( $date['aa'] );
} else {
$date['aa'] = 0;
}
if ( isset( $date['mm'] ) ) {
$date['mm'] = intval( $date['mm'] );
} else {
$date['mm'] = 0;
}
if ( isset( $date['jj'] ) ) {
$date['jj'] = intval( $date['jj'] );
} else {
$date['jj'] = 0;
}
if ( isset( $date['hh'] ) ) {
$date['hh'] = intval( $date['hh'] );
} else {
$date['hh'] = 0;
}
if ( isset( $date['mn'] ) ) {
$date['mn'] = intval( $date['mn'] );
} else {
$date['mn'] = 0;
}
if ( ( ! empty( $date['aa'] ) ) && ( ! empty( $date['mm'] ) ) && ( ! empty( $date['jj'] ) ) ) {
$date_string = sprintf(
'%04d-%02d-%02d %02d:%02d:00',
intval( $date['aa'] ),
intval( $date['mm'] ),
intval( $date['jj'] ),
intval( $date['hh'] ),
intval( $date['mn'] )
);
$date_string_gmt = get_gmt_from_date( $date_string, 'Y-m-d H:i:s' );
$options[ $k . '_visible_after_specific_date' ] = strtotime( $date_string_gmt );
} else {
$options[ $k . '_visible_after_specific_date' ] = 0;
}
} // phpcs:ignore Squiz.ControlStructures.ControlSignature.SpaceAfterCloseBrace -- Explanatory comment
// LEARNDASH-261: We need to reset the reference to the post meta ‘quiz_pro_id’ when the quiz is saved
// in case the ‘Associated Settings’ selector is updated.
elseif ( ( 'sfwd-quiz' === $k ) && ( isset( $options[ $k . '_quiz_pro' ] ) ) ) {
$quiz_pro_id_new = absint( $options['sfwd-quiz_quiz_pro'] );
$quiz_pro_id_org = absint( get_post_meta( $post_id, 'quiz_pro_id', true ) );
if ( $quiz_pro_id_org !== $quiz_pro_id_new ) {
/**
* If this quiz was the primary for all shared settings. We need to
* delete the primary marker then move the primary marker to another
* quiz using the same shared settings.
*/
$quiz_id_primary_org = absint( learndash_get_quiz_primary_shared( $quiz_pro_id_org, false ) );
if ( $quiz_id_primary_org === $post_id ) {
delete_post_meta( $post_id, 'quiz_pro_primary_' . $quiz_pro_id_org );
$quiz_post_ids = learndash_get_quiz_post_ids( $quiz_pro_id_org );
if ( ! empty( $quiz_post_ids ) ) {
foreach ( $quiz_post_ids as $quiz_post_id ) {
if ( $quiz_post_id !== $post_id ) {
update_post_meta( $quiz_post_id, 'quiz_pro_primary_' . $quiz_pro_id_org, $quiz_pro_id_org );
/**
* After we move the primary marker we also need to move the questions.
*/
$ld_quiz_questions_object = LDLMS_Factory_Post::quiz_questions( intval( $post_id ) );
if ( $ld_quiz_questions_object ) {
$questions = $ld_quiz_questions_object->get_questions( 'post_ids' );
$questions = get_post_meta( $post_id, 'ld_quiz_questions', true );
update_post_meta( $quiz_post_id, 'ld_quiz_questions', $questions );
}
break;
}
}
}
}
$quiz_id_primary_new = absint( learndash_get_quiz_primary_shared( $quiz_pro_id_new, false ) );
if ( empty( $quiz_id_primary_new ) ) {
update_post_meta( $post_id, 'quiz_pro_primary_' . $quiz_pro_id_new, $quiz_pro_id_new );
// trigger to cause reloading of the questions.
delete_post_meta( $post_id, 'ld_quiz_questions' );
}
global $wpdb;
$quiz_query_results = $wpdb->query(
$wpdb->prepare( "DELETE FROM {$wpdb->postmeta} WHERE post_id= %d AND meta_key like %s", $post_id, 'quiz_pro_id_%' )
);
update_post_meta( $post_id, 'quiz_pro_id', $quiz_pro_id_new );
update_post_meta( $post_id, 'quiz_pro_id_' . $quiz_pro_id_new, $quiz_pro_id_new );
}
} elseif ( 'sfwd-question' === $k ) {
if ( isset( $options[ $k . '_quiz' ] ) ) {
$quiz_id_new = absint( $options[ $k . '_quiz' ] );
$quiz_id_old = get_post_meta( $post_id, 'quiz_id', true );
$quiz_id_old = absint( $quiz_id_old );
if ( $quiz_id_old !== $quiz_id_new ) {
update_post_meta( $post_id, 'quiz_id', $quiz_id_new );
if ( ! empty( $quiz_id_old ) ) {
learndash_set_quiz_questions_dirty( $quiz_id_old );
}
if ( ! empty( $quiz_id_new ) ) {
learndash_set_quiz_questions_dirty( $quiz_id_new );
}
}
}
}
update_post_meta( $post_id, '_' . $this->get_prefix( $k ) . $k, $options );
// Purge the LD transients when we save any of our post types.
LDLMS_Transients::purge_all();
}
}
}
}
}
/**
* Outputs radio buttons, checkboxes, selects, multiselects, handles groups.
*
* @since 2.1.0
*
* @param array $args Arguments.
* @return string
*/
public function do_multi_input( $args ) {
extract( $args ); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract -- Bad idea, but better keep it for now.
$buf1 = '';
$type = $options['type'];
if ( ( 'radio' === $type ) || ( 'checkbox' === $type ) ) {
$strings = array(
'block' => "%s\n",
'group' => "\t<b>%s</b><br>\n%s\n",
'item' => "\t<label class='sfwd_option_setting_label'><input type='$type' %s name='%s' value='%s' %s> %s</label>\n",
'item_args' => array( 'sel', 'name', 'v', 'attr', 'subopt' ), // cspell:disable-line.
'selected' => 'checked ',
);
} else {
$lazy_load_data = '';
$lazy_load_spinner = '';
if ( ( isset( $args['options']['lazy_load'] ) ) && ( true === $args['options']['lazy_load'] ) ) {
if ( ( isset( $args['options']['lazy_load_data'] ) ) && ( ! empty( $args['options']['lazy_load_data'] ) ) ) {
$args['options']['lazy_load_data']['value'] = $args['value'];
$lazy_load_data = ' learndash_lazy_load_data="' . htmlspecialchars( wp_json_encode( $args['options']['lazy_load_data'] ) ) . '" ';
$lazy_load_spinner = '<br /><span style="display:none;" class="learndash_lazy_loading"><img class="learndash_lazy_load_spinner" alt="' . esc_html__( 'loading', 'learndash' ) . '" src="' . admin_url( '/images/wpspin_light.gif' ) . '" /> ' . esc_html__( 'loading', 'learndash' ) . '</span>';
}
}
$block = '<select ' . $lazy_load_data . ' name="' . $name . '" ' . $attr . '>%s\n</select>';
$show_required = false;
if ( in_array( $args['name'], array( 'sfwd-lessons_course', 'sfwd-topic_course', 'sfwd-topic_lesson' ), true ) === true ) {
if ( ( ! isset( $args['value'] ) ) || ( empty( $args['value'] ) ) ) {
$show_required = true;
}
}
if ( true === $show_required ) {
$block .= '<span class="ld-error dashicons dashicons-warning" title="' . esc_html__( 'Required', 'learndash' ) . '"></span>';
}
$block .= "\n" . $lazy_load_spinner;
$strings = array(
'block' => $block,
'group' => "\t<optgroup label='%s'>\n%s\t</optgroup>\n",
'item' => "\t<option %s value='%s'>%s</option>\n",
'item_args' => array( 'sel', 'v', 'subopt' ), // cspell:disable-line.
'selected' => 'selected ',
);
}
$set_selected = $strings['selected'];
if ( isset( $options['initial_options'] ) && is_array( $options['initial_options'] ) ) {
foreach ( $options['initial_options'] as $l => $option ) {
$is_group = is_array( $option );
if ( ! $is_group ) {
$option = array( $l => $option );
}
$buf2 = '';
foreach ( $option as $v => $subopt ) { // cspell:disable-line.
$sel = '';
$is_arr = is_array( $value );
if ( is_string( $v ) || is_string( $value ) ) {
$cmp = ! strcmp( (string) $v, (string) $value );
} else {
$cmp = ( $value == $v );
}
if ( ( ! $is_arr && $cmp ) || ( $is_arr && in_array( $v, $value, true ) ) ) {
$sel = $set_selected;
}
$item_arr = array();
foreach ( $strings['item_args'] as $arg ) {
$item_arr[] = $$arg;
}
$buf2 .= vsprintf( $strings['item'], $item_arr );
}
if ( $is_group ) {
$buf1 .= sprintf( $strings['group'], $l, $buf2 );
} else {
$buf1 .= $buf2;
}
}
$buf1 = sprintf( $strings['block'], $buf1 );
}
return $buf1;
}
/**
* Outputs a setting item for settings pages and metaboxes.
*
* @since 2.1.0
*
* @param array $args Arguments.
*
* @return string|array
*/
public function get_option_html( $args ) {
global $wp_locale;
static $n = 0;
extract( $args ); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract -- Bad idea, but better keep it for now.
if ( 'custom' === $options['type'] ) {
/**
* Filters the semperfi output option.
*
* The dynamic portion of the hook `$this->prefix` refers to prefix.
*
* @since 2.1.0
*
* @param string $output_option Output option
* @param array $args Option arguments.
*/
return apply_filters( "{$this->prefix}output_option", '', $args ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
}
if ( in_array( $options['type'], array( 'multiselect', 'select', 'multicheckbox', 'radio', 'checkbox', 'textarea', 'text', 'submit', 'hidden' ), true ) ) { // cspell:disable-line.
if ( is_string( $value ) ) {
$value = esc_attr( $value );
}
}
$buf = '';
if ( ! empty( $options['count'] ) ) {
$n++;
$attr .= " onKeyDown='countChars(document.post.$name,document.post.length$n)' onKeyUp='countChars(document.post.$name,document.post.length$n)'";
}
switch ( $options['type'] ) {
case 'multiselect':
$attr .= ' MULTIPLE';
$args['attr'] = $attr;
$name = "{$name}[]";
$args['name'] = $name;
// no break.
case 'select':
$buf .= $this->do_multi_input( $args );
break;
case 'multicheckbox': // cspell:disable-line.
$name = "{$name}[]";
$args['name'] = $name;
$options['type'] = 'checkbox';
$args['options']['type'] = 'checkbox';
// no break.
case 'radio':
$buf .= $this->do_multi_input( $args );
break;
case 'checkbox':
if ( ( isset( $options['checked_value'] ) ) && ( ! empty( $options['checked_value'] ) ) ) {
$attr .= checked( $value, $options['checked_value'], false );
} elseif ( $value ) {
$attr .= ' CHECKED';
}
$buf .= "<input name='$name' type='{$options['type']}' $attr />\n";
break;
case 'textarea':
$buf .= "<textarea name='$name' $attr>$value</textarea>";
break;
case 'image':
$buf .= "<input class='sfwd_upload_image_button' type='button' value='" . esc_html__( 'Upload Image', 'learndash' ) . "' style='float:left;' />" .
"<input class='sfwd_upload_image_label' name='$name' type='text' readonly $attr value='$value' size=57 style='float:left;clear:left;' />\n";
break;
case 'html':
$buf .= $value;
break;
case 'number':
if ( isset( $options['min'] ) ) {
$min = ' min="' . $options['min'] . '" ';
} else {
$min = '';
}
if ( isset( $options['step'] ) ) {
$step = ' step="' . $options['step'] . '" ';
} else {
if ( ! empty( $min ) ) {
$step = ' step="1" ';
} else {
$step = '';
}
}
if ( ( 'sfwd-courses_course_points' === $name ) || ( 'sfwd-courses_course_points_access' === $name ) ) {
$value = learndash_format_course_points( $value );
}
$buf .= "<input name='$name' type='{$options['type']}' $attr $min $step value='$value' />\n";
break;
case 'wp_date_selector':
if ( ! empty( $value ) ) {
if ( ! is_numeric( $value ) ) {
$value = learndash_get_timestamp_from_date_string( $value );
} else {
// If we have a timestamp we assume it is GMT. So we need to convert it to local.
$value_ymd = get_date_from_gmt( date( 'Y-m-d H:i:s', $value ), 'Y-m-d H:i:s' ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
$value = strtotime( $value_ymd );
}
}
if ( ! empty( $value ) ) {
$value_jj = gmdate( 'd', $value );
$value_mm = gmdate( 'm', $value );
$value_aa = gmdate( 'Y', $value );
$value_hh = gmdate( 'H', $value );
$value_mn = gmdate( 'i', $value );
} else {
$value_jj = '';
$value_mm = '';
$value_aa = '';
$value_hh = '';
$value_mn = '';
}
$month_field = '<span class="screen-reader-text">' . esc_html__( 'Month', 'learndash' ) . '</span><select class="ld_date_mm" name="' . $name . '[mm]" ><option value=""></option>';
for ( $i = 1; $i < 13; $i++ ) {
$monthnum = zeroise( $i, 2 );
$monthtext = $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) );
$month_field .= "\t\t\t" . '<option value="' . $monthnum . '" data-text="' . $monthtext . '" ' . selected( $monthnum, $value_mm, false ) . '>';
// translators: placeholder: month number, month text.
$month_field .= sprintf( esc_html_x( '%1$s-%2$s', 'placeholder: month number, month text', 'learndash' ), $monthnum, $monthtext ) . "</option>\n";
}
$month_field .= '</select>';
$day_field = '<span class="screen-reader-text">' . esc_html__( 'Day', 'learndash' ) . '</span><input type="number" placeholder="DD" min="1" max="31" class="ld_date_jj" name="' . $name . '[jj]" value="' . $value_jj . '" size="2" maxlength="2" autocomplete="off" />';
$year_field = '<span class="screen-reader-text">' . esc_html__( 'Year', 'learndash' ) . '</span><input type="number" placeholder="YYYY" min="0000" max="9999" class="ld_date_aa" name="' . $name . '[aa]" value="' . $value_aa . '" size="4" maxlength="4" autocomplete="off" />';
$hour_field = '<span class="screen-reader-text">' . esc_html__( 'Hour', 'learndash' ) . '</span><input type="number" min="0" max="23" placeholder="HH" class="ld_date_hh" name="' . $name . '[hh]" value="' . $value_hh . '" size="2" maxlength="2" autocomplete="off" />';
$minute_field = '<span class="screen-reader-text">' . esc_html__( 'Minute', 'learndash' ) . '</span><input type="number" min="0" max="59" placeholder="MM" class="ld_date_mn" name="' . $name . '[mn]" value="' . $value_mn . '" size="2" maxlength="2" autocomplete="off" />';
$buf .= '<div class="ld_date_selector">' . sprintf(
// translators: placeholders: Month Name, Day number, Year number, Hour number, Minute number.
esc_html__( '%1$s %2$s, %3$s @ %4$s:%5$s', 'learndash' ),
$month_field,
$day_field,
$year_field,
$hour_field,
$minute_field
) . '</div>';
break;
default:
$buf .= "<input name='$name' type='{$options['type']}' $attr value='$value' />\n";
}
if ( ! empty( $options['count'] ) ) {
$size = 60;
if ( isset( $options['size'] ) ) {
$size = $options['size'];
} elseif ( isset( $options['rows'] ) && isset( $options['cols'] ) ) {
$size = $options['rows'] * $options['cols'];
}
$buf .= "<input readonly type='text' name='length$n' size='3' maxlength='3' style='width:53px;height:23px;margin:0px;padding:0px;' value='" . strlen( $value ) . "' />"
// translators: placeholders: Max size, Option Name.
. sprintf( esc_html__( ' characters. Most search engines use a maximum of %1$s chars for the %2$s.', 'learndash' ), $size, strtolower( $options['name'] ) );
}
return $buf;
}
/**
* HTML Help Start anchor tag
*
* @const string
*/
const DISPLAY_HELP_START = '<a class="sfwd_help_text_link" style="cursor:pointer;" title="%s" onclick="toggleVisibility(\'%s_tip\');"><img src="%s/question.png" /><label class="sfwd_label textinput">%s</label></a>';
/**
* HTML Help End anchor label
*
* @const string
*/
const DISPLAY_HELP_END = '<div class="sfwd_help_text_div" style="display:none" id="%s_tip"><label class="sfwd_help_text">%s</label></div>';
/**
* HTML Display label span
*
* @const string
*/
const DISPLAY_LABEL_FORMAT = '<span class="sfwd_option_label" style="text-align:%s;vertical-align:top;">%s</span>';
/**
* HTML Display top label
*
* @const string
*/
const DISPLAY_TOP_LABEL = "</div>\n<div class='sfwd_input sfwd_top_label'>\n";
/**
* The plugin remote update path
*
* @const string
*/
const DISPLAY_ROW_TEMPLATE = '<div class="sfwd_input %s" id="%s">%s<span class="sfwd_option_input"><div class="sfwd_option_div" %s>%s</div>%s</span><p style="clear:left"></p></div>';
/**
* Format a row for an option on a settings page.
*
* @since 2.1.0
*
* @param string $name Name of the option.
* @param array $opts array of options.
* @param array $args Array of arguments.
* @return string
*/
public function get_option_row( $name, $opts, $args ) {
global $post_type;
$label_text = '';
$input_attr = '';
$help_text_2 = '';
$id_attr = '';
if ( 'top' == $opts['label'] ) {
$align = 'left';
} else {
$align = 'right';
}
if ( isset( $opts['id'] ) ) {
$id_attr .= " id=\"{$opts['id']}\" ";
}
if ( 'none' !== $opts['label'] ) {
if ( isset( $opts['help_text'] ) ) {
$help_text = sprintf( self::DISPLAY_HELP_START, esc_html__( 'Click for Help!', 'learndash' ), $name, $this->plugin_path['images_url'], $opts['name'] );
$help_text_2 = sprintf( self::DISPLAY_HELP_END, $name, $opts['help_text'] );
} else {
$help_text = $opts['name'];
}
$label_text = sprintf( self::DISPLAY_LABEL_FORMAT, $align, $help_text );
} else {
$input_attr .= 'sfwd_no_label ';
}
if ( 'top' == $opts['label'] ) {
$label_text .= self::DISPLAY_TOP_LABEL;
}
if ( 'hidden' === $opts['type'] ) {
$input_attr .= 'sfwd_hidden_type';
}
return sprintf( self::DISPLAY_ROW_TEMPLATE, $input_attr, $name, $label_text, $id_attr, $this->get_option_html( $args ), $help_text_2 );
}
/**
* Display options for settings pages and metaboxes, allows for filtering settings, custom display options.
*
* @since 2.1.0
*
* @param null|string $location $this->locations array index.
* @param null|array $meta_args Arguments.
*/
public function display_options( $location = null, $meta_args = null ) {
global $sfwd_lms;
static $location_settings = array();
$defaults = null;
$prefix = $this->get_prefix( $location );
if ( is_array( $meta_args['args'] ) && ! empty( $meta_args['args']['default_options'] ) ) {
$defaults = $meta_args['args']['default_options'];
}
if ( ! isset( $location_settings[ $prefix ] ) ) {
/**
* Filters semperfi display options.
*
* @since 2.1.0
*
* @param array $current_options Current options stored for a location.
* @param null|string $location Location index.
*/
$current_options = apply_filters( "{$this->prefix}display_options", $this->get_current_options( array(), $location, $defaults ), $location ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
/**
* Filters semperfi display settings.
*
* @since 2.1.0
*
* @param array $settings Initial Settings.
* @param null|string $location Location index.
* @param array $current_options Current options stored for a location.
*/
$settings = apply_filters( "{$this->prefix}display_settings", $this->setting_options( $location, $defaults ), $location, $current_options ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
$location_settings[ $prefix ]['current_options'] = $current_options;
$location_settings[ $prefix ]['settings'] = $settings;
} else {
$current_options = $location_settings[ $prefix ]['current_options'];
$settings = $location_settings[ $prefix ]['settings'];
}
$container = "<div class='sfwd sfwd_options {$this->prefix}settings'>";
if ( is_array( $meta_args['args'] ) && ! empty( $meta_args['args']['options'] ) ) {
$args = array();
$arg_keys = array();
foreach ( $meta_args['args']['options'] as $a ) {
if ( ! empty( $location ) ) {
$key = $prefix . $location . '_' . $a;
if ( ! isset( $settings[ $key ] ) ) {
$key = $a;
}
} else {
$key = $prefix . $a;
}
if ( isset( $settings[ $key ] ) ) {
$arg_keys[ $key ] = 1;
}
}
if ( ( is_array( $settings ) ) && ( ! empty( $settings ) ) ) {
$setting_keys = array_keys( $settings );
foreach ( $setting_keys as $s ) {
if ( ! empty( $arg_keys[ $s ] ) ) {
$args[ $s ] = $settings[ $s ];
}
}
}
} else {
$args = $settings;
}
foreach ( $args as $name => $opts ) {
$attr_list = array( 'class', 'style', 'readonly', 'disabled', 'size', 'placeholder' );
if ( 'textarea' === $opts['type'] ) {
$attr_list = array_merge( $attr_list, array( 'rows', 'cols' ) );
}
$attr = '';
foreach ( $attr_list as $a ) {
if ( isset( $opts[ $a ] ) ) {
$attr .= " $a=\"{$opts[ $a]}\" ";
}
}
$opt = '';
if ( isset( $current_options[ $name ] ) ) {
$opt = $current_options[ $name ];
}
if ( 'none' === $opts['label'] && 'submit' === $opts['type'] && false === $opts['save'] ) {
$opt = $opts['name'];
}
if ( 'html' === $opts['type'] && empty( $opt ) && false === $opts['save'] ) {
$opt = $opts['default'];
}
$args = array(
'name' => $name,
'options' => $opts,
'attr' => $attr,
'value' => $opt,
'prefix' => $prefix,
);
if ( ! empty( $opts['nowrap'] ) ) {
echo $this->get_option_html( $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Need to output HTML.
} else {
if ( $container ) {
echo $container; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Need to output HTML.
$container = '';
}
echo $this->get_option_row( $name, $opts, $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Need to output HTML.
}
}
if ( ! $container ) {
echo '</div>';
}
}
/**
* Sanitize options
*
* @param null|string $location $this->locations array index.
*/
public function sanitize_options( $location = null ) {
foreach ( $this->setting_options( $location ) as $k => $v ) {
if ( isset( $this->options[ $k ] ) ) {
if ( ! empty( $v['sanitize'] ) ) {
$type = $v['sanitize'];
} else {
$type = $v['type'];
}
switch ( $type ) {
case 'multiselect':
case 'multicheckbox': // cspell:disable-line.
$this->options[ $k ] = urlencode_deep( $this->options[ $k ] );
break;
case 'textarea':
$this->options[ $k ] = wp_kses_post( $this->options[ $k ] );
$this->options[ $k ] = esc_textarea( $this->options[ $k ] );
break;
case 'filename':
$this->options[ $k ] = sanitize_file_name( $this->options[ $k ] );
break;
case 'text':
$this->options[ $k ] = wp_kses_post( $this->options[ $k ] );
// no break.
case 'checkbox':
case 'radio':
case 'select':
default:
$this->options[ $k ] = esc_attr( $this->options[ $k ] );
}
}
}
}
/**
* Display metaboxes with display_options()
*
* @since 2.1.0
*
* @param object $post Post object.
* @param array $metabox Metabox.
*/
public function display_metabox( $post, $metabox ) {
$this->display_options( $metabox['args']['location'], $metabox );
}
/**
* Handle resetting options to defaults.
*
* @since 2.1.0
*
* @param null|string $location $this->locations array index.
* @param bool $delete delete options flag.
*/
public function reset_options( $location = null, $delete = false ) {
if ( true === $delete ) {
$this->delete_class_option( $delete );
$this->options = array();
}
$default_options = $this->default_options( $location );
foreach ( $default_options as $k => $v ) {
$this->options[ $k ] = $v;
}
$this->update_class_option( $this->options );
}
/**
* Handle option resetting and updating
*
* @since 2.1.0
*
* @param null|string $location $this->locations array index.
*/
public function handle_settings_updates( $location = null ) {
if ( ( isset( $_POST['action'] ) && 'sfp_update_module' === $_POST['action'] && ( isset( $_POST['Submit_Default'] ) || isset( $_POST['Submit_All_Default'] ) || ! empty( $_POST['Submit'] ) ) ) ) {
$nonce = $_POST['nonce-sfwd'];
if ( ! wp_verify_nonce( $nonce, 'sfwd-nonce' ) ) {
die( esc_html__( 'Security Check - If you receive this in error, log out and back in to WordPress', 'learndash' ) );
}
if ( isset( $_POST['Submit_Default'] ) || isset( $_POST['Submit_All_Default'] ) ) {
$message = esc_html__( 'Options Reset.', 'learndash' );
if ( isset( $_POST['Submit_All_Default'] ) ) {
$this->reset_options( $location, true );
/**
* Fires after resetting sfwd options.
*
* @since 2.1.0
*/
do_action( 'sfwd_options_reset' );
} else {
$this->reset_options( $location );
}
}
if ( ! empty( $_POST['Submit'] ) ) {
$message = esc_html__( 'Options Updated.', 'learndash' );
$default_options = $this->default_options( $location );
foreach ( $default_options as $k => $v ) {
if ( isset( $_POST[ $k ] ) ) {
$this->options[ $k ] = stripslashes_deep( $_POST[ $k ] );
} else {
$this->options[ $k ] = '';
}
}
$this->sanitize_options( $location );
/**
* Filters options for a particular prefix.
*
* The dynamic part of the hook `$this->prefix` refers to the semperfi setting prefix.
*
* @since 2.1.0
*
* @param array $options An array of options.
* @param null|string $location Location index.
*/
$this->options = apply_filters( $this->prefix . 'update_options', $this->options, $location ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
$this->update_class_option( $this->options );
wp_cache_flush();
}
/**
* Fires after the settings update for a prefix.
*
* The dynamic part of the hook `$this->prefix` refers to the semperfi setting prefix.
*
* @since 2.1.0
*
* @param array $options An array of options.
* @param null|string $location Location index.
*/
do_action( $this->prefix . 'settings_update', $this->options, $location ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
}
}
/**
* Update / reset settings, printing options, sanitizing, posting back
*
* @since 2.1.0
*
* @param null|string $location $this->locations array index.
*
* @return void
*/
public function display_settings_page( $location = null ) {
// Do nothing.
}
/**
* Get the prefix used for a given location.
*
* @since 2.1.0
*
* @param null|string $location $this->locations array index.
* @return string
*/
public function get_prefix( $location = null ) {
if ( ( null !== $location ) && isset( $this->locations[ $location ]['prefix'] ) ) {
return $this->locations[ $location ]['prefix'];
}
return $this->prefix;
}
/**
* Sets up initial settings
*
* @since 2.1.0
*
* @param null|string $location $this->locations array index.
* @param null|array $defaults Defaults.
* @return array
*/
public function setting_options( $location = null, $defaults = null ) {
if ( null === $defaults ) {
$defaults = $this->default_options;
}
$prefix = $this->get_prefix( $location );
$opts = array();
if ( null === $location || null === $this->locations[ $location ]['options'] ) {
$options = $defaults;
} else {
$options = array();
$prefix = "{$prefix}{$location}_";
if ( ! empty( $this->locations[ $location ]['default_options'] ) ) {
$options = $this->locations[ $location ]['default_options'];
}
foreach ( $this->locations[ $location ]['options'] as $opt ) {
if ( isset( $defaults[ $opt ] ) ) {
$options[ $opt ] = $defaults[ $opt ];
}
}
}
if ( ! $prefix ) {
$prefix = $this->prefix;
}
if ( ! empty( $options ) ) {
foreach ( $options as $k => $v ) {
if ( ! isset( $v['name'] ) ) {
$v['name'] = ucwords( strtr( $k, '_', ' ' ) );
}
if ( ! isset( $v['type'] ) ) {
$v['type'] = 'checkbox';
}
if ( ! isset( $v['default'] ) ) {
$v['default'] = null;
}
if ( ! isset( $v['initial_options'] ) ) {
$v['initial_options'] = $v['default'];
}
if ( 'custom' === $v['type'] && ( ! isset( $v['nowrap'] ) ) ) {
$v['nowrap'] = true;
} elseif ( ! isset( $v['nowrap'] ) ) {
$v['nowrap'] = null;
}
if ( isset( $v['condshow'] ) ) {
if ( ! is_array( $this->script_data ) ) {
$this->script_data = array();
}
if ( ! isset( $this->script_data['condshow'] ) ) {
$this->script_data['condshow'] = array();
}
$this->script_data['condshow'][ $prefix . $k ] = $v['condshow'];
}
if ( 'submit' === $v['type'] ) {
if ( ! isset( $v['save'] ) ) {
$v['save'] = false;
}
if ( ! isset( $v['label'] ) ) {
$v['label'] = 'none';
}
if ( ! isset( $v['prefix'] ) ) {
$v['prefix'] = false;
}
} else {
if ( ! isset( $v['label'] ) ) {
$v['label'] = null;
}
}
if ( 'hidden' === $v['type'] ) {
if ( ! isset( $v['label'] ) ) {
$v['label'] = 'none';
}
if ( ! isset( $v['prefix'] ) ) {
$v['prefix'] = false;
}
}
if ( 'text' === $v['type'] ) {
if ( ! isset( $v['size'] ) ) {
$v['size'] = 57;
}
}
if ( 'textarea' === $v['type'] ) {
if ( ! isset( $v['cols'] ) ) {
$v['cols'] = 57;
}
if ( ! isset( $v['rows'] ) ) {
$v['rows'] = 2;
}
}
if ( ! isset( $v['save'] ) ) {
$v['save'] = true;
}
if ( ! isset( $v['prefix'] ) ) {
$v['prefix'] = true;
}
if ( $v['prefix'] ) {
$opts[ $prefix . $k ] = $v;
} else {
$opts[ $k ] = $v;
}
}
}
return $opts;
}
/**
* Generates just the default option names and values
*
* @since 2.1.0
*
* @param null|string $location $this->locations array index.
* @param null|array $defaults Defaults.
* @return array
*/
public function default_options( $location = null, $defaults = null ) {
$options = $this->setting_options( $location, $defaults );
$opts = array();
foreach ( $options as $k => $v ) {
if ( $v['save'] ) {
$opts[ $k ] = $v['default'];
}
}
return $opts;
}
/**
* Gets the current options stored for a given location.
*
* @since 2.1.0
*
* @param array $opts Array of options.
* @param null|string $location $this->locations array index.
* @param null|array $defaults Defaults.
* @param null|object $post Post object.
* @return array
*/
public function get_current_options( $opts = array(), $location = null, $defaults = null, $post = null ) {
$prefix = $this->get_prefix( $location );
$get_opts = '';
if ( empty( $location ) ) {
$type = 'settings';
} else {
$type = $this->locations[ $location ]['type'];
}
if ( 'settings' === $type ) {
$get_opts = $this->get_class_option();
} elseif ( 'metabox' === $type ) {
if ( null == $post ) {
global $post;
}
if ( isset( $post ) ) {
$get_opts = '_' . $prefix . $location;
$get_opts = get_post_meta( $post->ID, $get_opts, true );
}
}
$defs = $this->default_options( $location, $defaults );
if ( '' == $get_opts ) {
$get_opts = $defs;
} else {
$get_opts = wp_parse_args( $get_opts, $defs );
}
$opts = wp_parse_args( $opts, $get_opts );
return $opts;
}
/**
* Updates the options array in the module; loads saved settings with get_option() or uses defaults
*
* @since 2.1.0
*
* @param array $opts Array of options.
* @param null|string $location $this->locations array index.
* @param null|array $defaults Defaults.
*/
public function update_options( $opts = array(), $location = null, $defaults = null ) {
$type = '';
if ( is_null( $location ) ) {
$type = 'settings';
} else {
$type = $this->locations[ $location ][ $type ];
}
if ( 'settings' === $type ) {
$get_opts = $this->get_class_option();
}
if ( false === $get_opts ) {
$get_opts = $this->default_options( $location, $defaults );
} else {
$this->setting_options( $location, $defaults );
}
// Hack -- make sure this runs anyhow, for now -- pdb.
$this->options = wp_parse_args( $opts, $get_opts );
}
}
}