'SPF Framework by SP', 'framework_class' => '', // menu settings. 'menu_title' => '', 'menu_slug' => '', 'menu_type' => 'menu', // 'menu_capability' => 'manage_options', It's implemented in add_admin_menu() 'menu_icon' => null, 'menu_position' => null, 'menu_hidden' => false, 'menu_parent' => '', // menu extras. 'show_bar_menu' => true, 'show_sub_menu' => true, 'show_network_menu' => true, 'show_in_customizer' => false, 'show_search' => true, 'show_reset_all' => true, 'show_reset_section' => true, 'show_footer' => true, 'show_all_options' => true, 'sticky_header' => true, 'save_defaults' => true, 'ajax_save' => true, // admin bar menu settings. 'admin_bar_menu_icon' => '', 'admin_bar_menu_priority' => 80, // footer. 'footer_text' => '', 'footer_after' => '', 'footer_credit' => '', // database model. 'database' => '', // options, transient, theme_mod, network. 'transient_time' => 0, // contextual help. 'contextual_help' => array(), 'contextual_help_sidebar' => '', // typography options. 'enqueue_webfont' => true, 'async_webfont' => false, // others. 'output_css' => true, // theme. 'theme' => 'dark', 'class' => '', // external default values. 'defaults' => array(), ); /** * Run framework construct. * * @param string $key The filter unique key. * @param array $params The parameters. */ public function __construct( $key, $params = array() ) { $this->unique = $key; $this->args = apply_filters( "spf_{$this->unique}_args", wp_parse_args( $params['args'], $this->args ), $this ); $this->sections = apply_filters( "spf_{$this->unique}_sections", $params['sections'], $this ); // run only is admin panel options, avoid performance loss. $this->pre_tabs = $this->pre_tabs( $this->sections ); $this->pre_fields = $this->pre_fields( $this->sections ); $this->pre_sections = $this->pre_sections( $this->sections ); $this->get_options(); $this->set_options(); $this->save_defaults(); add_action( 'admin_menu', array( &$this, 'add_admin_menu' ) ); add_action( 'admin_bar_menu', array( &$this, 'add_admin_bar_menu' ), $this->args['admin_bar_menu_priority'] ); add_action( 'wp_ajax_spf_' . $this->unique . '_ajax_save', array( &$this, 'ajax_save' ) ); if ( ! empty( $this->args['show_network_menu'] ) ) { add_action( 'network_admin_menu', array( &$this, 'add_admin_menu' ) ); } // wp enqeueu for typography and output css. parent::__construct(); } /** * Instance. * * @param object $key The instance key. * @param array $params All the parameters. * @return mixed */ public static function instance( $key, $params = array() ) { return new self( $key, $params ); } /** * Pre tabs. * * @param array $sections All the sections. * @return mixed */ public function pre_tabs( $sections ) { $result = array(); $parents = array(); $count = 100; foreach ( $sections as $key => $section ) { if ( ! empty( $section['parent'] ) ) { $section['priority'] = ( isset( $section['priority'] ) ) ? $section['priority'] : $count; $parents[ $section['parent'] ][] = $section; unset( $sections[ $key ] ); } ++$count; } foreach ( $sections as $key => $section ) { $section['priority'] = ( isset( $section['priority'] ) ) ? $section['priority'] : $count; if ( ! empty( $section['id'] ) && ! empty( $parents[ $section['id'] ] ) ) { $section['subs'] = wp_list_sort( $parents[ $section['id'] ], array( 'priority' => 'ASC' ), 'ASC', true ); } $result[] = $section; ++$count; } return wp_list_sort( $result, array( 'priority' => 'ASC' ), 'ASC', true ); } /** * Pre fields method. * * @param array $sections The sections. * @return $result */ public function pre_fields( $sections ) { $result = array(); foreach ( $sections as $key => $section ) { if ( ! empty( $section['fields'] ) ) { foreach ( $section['fields'] as $field ) { $result[] = $field; } } } return $result; } /** * The pre sections. * * @param array $sections The sections. * @return mixed */ public function pre_sections( $sections ) { $result = array(); foreach ( $this->pre_tabs as $tab ) { if ( ! empty( $tab['subs'] ) ) { foreach ( $tab['subs'] as $sub ) { $result[] = $sub; } } if ( empty( $tab['subs'] ) ) { $result[] = $tab; } } return $result; } /** * Add admin bar menu. * * @param object $wp_admin_bar The admin bar. * @return void */ public function add_admin_bar_menu( $wp_admin_bar ) { if ( ! empty( $this->args['show_bar_menu'] ) && empty( $this->args['menu_hidden'] ) ) { global $submenu; $menu_slug = $this->args['menu_slug']; $menu_icon = ( ! empty( $this->args['admin_bar_menu_icon'] ) ) ? '' : ''; $wp_admin_bar->add_node( array( 'id' => $menu_slug, 'title' => $menu_icon . $this->args['menu_title'], 'href' => ( is_network_admin() ) ? network_admin_url( 'admin.php?page=' . $menu_slug ) : admin_url( 'admin.php?page=' . $menu_slug ), ) ); if ( ! empty( $submenu[ $menu_slug ] ) ) { foreach ( $submenu[ $menu_slug ] as $key => $menu ) { $wp_admin_bar->add_node( array( 'parent' => $menu_slug, 'id' => $menu_slug . '-' . $key, 'title' => $menu[0], 'href' => ( is_network_admin() ) ? network_admin_url( 'admin.php?page=' . $menu[2] ) : admin_url( 'admin.php?page=' . $menu[2] ), ) ); } } if ( ! empty( $this->args['show_network_menu'] ) ) { $wp_admin_bar->add_node( array( 'parent' => 'network-admin', 'id' => $menu_slug . '-network-admin', 'title' => $menu_icon . $this->args['menu_title'], 'href' => network_admin_url( 'admin.php?page=' . $menu_slug ), ) ); } } } /** * Ajax save method. * * @return void */ public function ajax_save() { $result = $this->set_options( true ); if ( ! $result ) { wp_send_json_error( array( 'success' => false, 'error' => esc_html__( 'Error while saving.', 'post-carousel' ), ) ); } else { wp_send_json_success( array( 'success' => true, 'notice' => $this->notice, 'errors' => $this->errors, ) ); } } /** * Get default value. * * @param array $field The field array. * @param array $options The options array. * @return mixed */ public function get_default( $field, $options = array() ) { $default = ( isset( $this->args['defaults'][ $field['id'] ] ) ) ? $this->args['defaults'][ $field['id'] ] : ''; $default = ( isset( $field['default'] ) ) ? $field['default'] : $default; $default = ( isset( $options[ $field['id'] ] ) ) ? $options[ $field['id'] ] : $default; return $default; } /** * Save defaults and set new fields value to main options. * * @return void */ public function save_defaults() { $tmp_options = $this->options; foreach ( $this->pre_fields as $field ) { if ( ! empty( $field['id'] ) ) { $this->options[ $field['id'] ] = $this->get_default( $field, $this->options ); } } if ( $this->args['save_defaults'] && empty( $tmp_options ) ) { $this->save_options( $this->options ); } } /** * Sanitize Smart Post Show plugin options. * * @param array $options Raw options array. * @return array Sanitized options array. */ public function sanitize_options( $options ) { if ( ! is_array( $options ) ) { return array(); } $sanitized = array(); foreach ( $options as $key => $value ) { switch ( $key ) { case 'spf_transient': // Handle nested array. $sanitized['spf_transient'] = array(); if ( is_array( $value ) ) { foreach ( $value as $sub_key => $sub_val ) { switch ( $sub_key ) { case 'section': $sanitized['spf_transient']['section'] = sanitize_text_field( $sub_val ); break; default: $sanitized['spf_transient'][ $sub_key ] = sanitize_text_field( $sub_val ); break; } } } break; case 'spf_options_noncesp_post_carousel_settings': case '_wp_http_referer': $sanitized[ $key ] = sanitize_text_field( $value ); break; case 'sp_post_carousel_settings': $sanitized['sp_post_carousel_settings'] = array(); if ( is_array( $value ) ) { foreach ( $value as $sub_key => $sub_val ) { switch ( $sub_key ) { case 'pcp_delete_all_data': case 'pcp_swiper_js': case 'pcp_swiper_css': case 'pcp_fontawesome_css': case 'accessibility': // These should be boolean-like (0/1). $sanitized['sp_post_carousel_settings'][ $sub_key ] = (int) $sub_val; break; case 'prev_slide_message': case 'next_slide_message': case 'first_slide_message': case 'last_slide_message': case 'pagination_bullet_message': $sanitized['sp_post_carousel_settings'][ $sub_key ] = sanitize_text_field( $sub_val ); break; case 'pcp_custom_css': $sanitized['sp_post_carousel_settings'][ $sub_key ] = wp_strip_all_tags( $sub_val ); break; case 'pcp_custom_js': $sanitized['sp_post_carousel_settings'][ $sub_key ] = wp_kses_post( $sub_val ); break; default: $sanitized['sp_post_carousel_settings'][ $sub_key ] = sanitize_text_field( $sub_val ); break; } } } break; default: // Fallback sanitization. $sanitized[ $key ] = is_scalar( $value ) ? wp_kses_post( $value ) : ''; break; } } return $sanitized; } /** * Set options. * * @param boolean $ajax The ajax save. * * @return mixed */ public function set_options( $ajax = false ) { // Check nonce. $nonce = $ajax && ( ! empty( $_POST['nonce'] ) ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : ( ( ! empty( $_POST[ 'spf_options_nonce' . $this->unique ] ) ) ? sanitize_text_field( wp_unslash( $_POST[ 'spf_options_nonce' . $this->unique ] ) ) : '' ); if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'spf_options_nonce' ) ) { return false; } // XSS ok. // No worries, This "POST" requests is sanitizing in the below. $response = ( $ajax && ! empty( $_POST['data'] ) ) ? json_decode( wp_unslash( trim( $_POST['data'] ) ), true ) : wp_unslash( $_POST ); // phpcs:ignore -- Sanitized below. $response = $this->sanitize_options( $response ); // Sanitize json response. // Set variables. $data = array(); $options = ( ! empty( $response[ $this->unique ] ) ) ? $response[ $this->unique ] : array(); $transient = ( ! empty( $response['spf_transient'] ) ) ? $response['spf_transient'] : array(); $importing = false; $section_id = ( ! empty( $transient['section'] ) ) ? $transient['section'] : ''; if ( ! empty( $transient['reset'] ) ) { foreach ( $this->pre_fields as $field ) { if ( ! empty( $field['id'] ) ) { $data[ $field['id'] ] = $this->get_default( $field ); } } $this->notice = esc_html__( 'Default options restored.', 'post-carousel' ); } elseif ( ! empty( $transient['reset_section'] ) && ! empty( $section_id ) ) { if ( ! empty( $this->pre_sections[ $section_id - 1 ]['fields'] ) ) { foreach ( $this->pre_sections[ $section_id - 1 ]['fields'] as $field ) { if ( ! empty( $field['id'] ) ) { $data[ $field['id'] ] = $this->get_default( $field ); } } } $data = wp_parse_args( $data, $this->options ); $this->notice = esc_html__( 'Default options restored for only this section.', 'post-carousel' ); } else { // Sanitize and validate. foreach ( $this->pre_fields as $field ) { if ( ! empty( $field['id'] ) ) { $field_id = $field['id']; $field_value = isset( $options[ $field_id ] ) ? $options[ $field_id ] : ''; // Ajax and Importing doing wp_unslash already. if ( ! $ajax && ! $importing ) { $field_value = wp_unslash( $field_value ); } // sanitize. if ( ! isset( $field['sanitize'] ) ) { if ( is_array( $field_value ) ) { $data[ $field_id ] = wp_kses_post_deep( $field_value ); } else { $data[ $field_id ] = wp_kses_post( $field_value ); } } elseif ( isset( $field['sanitize'] ) && is_callable( $field['sanitize'] ) ) { $data[ $field_id ] = call_user_func( $field['sanitize'], $field_value ); } else { $data[ $field_id ] = wp_kses_post( $field_value ); } // Validate "post" request of field. if ( isset( $field['validate'] ) && is_callable( $field['validate'] ) ) { $has_validated = call_user_func( $field['validate'], $field_value ); if ( ! empty( $has_validated ) ) { $data[ $field_id ] = ( isset( $this->options[ $field_id ] ) ) ? $this->options[ $field_id ] : ''; $this->errors[ $field_id ] = $has_validated; } } } } } $data = apply_filters( "spf_{$this->unique}_save", $data, $this ); do_action( "spf_{$this->unique}_save_before", $data, $this ); $this->options = $data; $this->save_options( $data ); do_action( "spf_{$this->unique}_save_after", $data, $this ); if ( empty( $this->notice ) ) { $this->notice = esc_html__( 'Settings saved.', 'post-carousel' ); } return true; } /** * Save options database. * * @param array $data The options values. * @return void */ public function save_options( $data ) { if ( 'transient' === $this->args['database'] ) { set_transient( $this->unique, $data, $this->args['transient_time'] ); } elseif ( 'theme_mod' === $this->args['database'] ) { set_theme_mod( $this->unique, $data ); } elseif ( 'network' === $this->args['database'] ) { update_site_option( $this->unique, $data ); } else { update_option( $this->unique, $data ); } do_action( "spf_{$this->unique}_saved", $data, $this ); } /** * Get options from database. * * @return mixed */ public function get_options() { if ( 'transient' === $this->args['database'] ) { $this->options = get_transient( $this->unique ); } elseif ( 'theme_mod' === $this->args['database'] ) { $this->options = get_theme_mod( $this->unique ); } elseif ( 'network' === $this->args['database'] ) { $this->options = get_site_option( $this->unique ); } else { $this->options = get_option( $this->unique ); } if ( empty( $this->options ) ) { $this->options = array(); } return $this->options; } /** * WP api – admin menu. */ public function add_admin_menu() { // Show plugin setting menu as per user role. – ShapedPlugin // Use the hook 'sp_pc_dashboard_capability' to change user capability. $menu_capability = apply_filters( 'sp_pc_dashboard_capability', 'manage_options' ); extract( $this->args ); // phpcs:ignore if ( 'submenu' === $menu_type ) { $menu_page = call_user_func( 'add_submenu_page', $menu_parent, $menu_title, $menu_title, $menu_capability, $menu_slug, array( &$this, 'add_options_html' ) ); } else { $menu_page = call_user_func( 'add_menu_page', $menu_title, $menu_title, $menu_capability, $menu_slug, array( &$this, 'add_options_html' ), $menu_icon, $menu_position ); if ( ! empty( $this->args['show_sub_menu'] ) && count( $this->pre_tabs ) > 1 ) { // create submenus. $tab_key = 1; foreach ( $this->pre_tabs as $section ) { call_user_func( 'add_submenu_page', $menu_slug, $section['title'], $section['title'], $menu_capability, $menu_slug . '#tab=' . $tab_key, '__return_null' ); if ( ! empty( $section['subs'] ) ) { $tab_key += ( count( $section['subs'] ) - 1 ); } ++$tab_key; } remove_submenu_page( $menu_slug, $menu_slug ); } if ( ! empty( $menu_hidden ) ) { remove_menu_page( $menu_slug ); } } add_action( 'load-' . $menu_page, array( &$this, 'add_page_on_load' ) ); } /** * Add page on load. */ public function add_page_on_load() { if ( ! empty( $this->args['contextual_help'] ) ) { $screen = get_current_screen(); foreach ( $this->args['contextual_help'] as $tab ) { $screen->add_help_tab( $tab ); } if ( ! empty( $this->args['contextual_help_sidebar'] ) ) { $screen->set_help_sidebar( $this->args['contextual_help_sidebar'] ); } } } /** * Error check function. */ /** * Error Check function * * @param mixed $sections The section. * @param string $err The error. * @return statement */ public function error_check( $sections, $err = '' ) { if ( ! $this->args['ajax_save'] ) { if ( ! empty( $sections['fields'] ) ) { foreach ( $sections['fields'] as $field ) { if ( ! empty( $field['id'] ) ) { if ( array_key_exists( $field['id'], $this->errors ) ) { $err = '!'; } } } } if ( ! empty( $sections['subs'] ) ) { foreach ( $sections['subs'] as $sub ) { $err = $this->error_check( $sub, $err ); } } if ( ! empty( $sections['id'] ) && array_key_exists( $sections['id'], $this->errors ) ) { $err = $this->errors[ $sections['id'] ]; } } return $err; } /** * Option page html output. * * @return void */ public function add_options_html() { $has_nav = ( count( $this->pre_tabs ) > 1 ) ? true : false; $show_all = ( ! $has_nav ) ? ' spf-show-all' : ''; $show_buttons = isset( $this->args['show_buttons'] ) ? $this->args['show_buttons'] : true; $menu_slug = isset( $this->args['menu_slug'] ) ? $this->args['menu_slug'] : ''; $ajax_class = ( $this->args['ajax_save'] ) ? ' spf-save-ajax' : ''; $sticky_class = ( $this->args['sticky_header'] ) ? ' spf-sticky-header' : ''; $wrapper_class = ( $this->args['framework_class'] ) ? ' ' . $this->args['framework_class'] : ''; $theme = ( $this->args['theme'] ) ? ' spf-theme-' . $this->args['theme'] : ''; $class = ( $this->args['class'] ) ? ' ' . $this->args['class'] : ''; if ( 'pcp_replace_layout' === $menu_slug ) { echo '

To unlock the Replace Layout on The Default Blog, WooCommerce Shop, Category, Tag, Taxonomy, Search, Author, Date... Pages, and Post Types, Upgrade To Pro

'; } echo '
'; if ( 'pcp_replace_layout' === $menu_slug ) { echo '
Upgrade to Pro!
'; } $notice_class = ( ! empty( $this->notice ) ) ? ' spf-form-show' : ''; $notice_text = ( ! empty( $this->notice ) ) ? $this->notice : ''; $error_class = ( ! empty( $this->errors ) ) ? ' spf-form-show' : ''; echo '
'; if ( ! empty( $this->errors ) ) { foreach ( $this->errors as $error ) { echo '! ' . esc_html( $error ) . '
'; } } echo '
'; echo '
'; echo '
'; echo ''; wp_nonce_field( 'spf_options_nonce', 'spf_options_nonce' . $this->unique ); echo '
'; echo '
'; echo '
'; if ( 'pcp_replace_layout' === $menu_slug ) { echo '

' . esc_html__( 'Replace Layout (Pro)', 'post-carousel' ) . '

'; } elseif ( $show_buttons ) { echo '

' . esc_html__( 'Settings', 'post-carousel' ) . '

'; } else { echo '

' . esc_html( $this->args['framework_title'] ) . '

'; } echo '
'; echo '
'; echo ( $has_nav && $this->args['show_all_options'] ) ? '
' : ''; echo ( $this->args['show_search'] ) ? '' : ''; if ( $show_buttons ) { echo '
'; echo ''; echo ( $this->args['show_reset_section'] ) ? '' : ''; echo ( $this->args['show_reset_all'] ) ? '' : ''; echo '
'; } echo '
'; echo '
'; echo '
'; echo '
'; echo '
'; if ( $has_nav ) { echo '
'; echo ''; echo '
'; } echo '
'; echo '
'; $section_key = 1; foreach ( $this->pre_sections as $section ) { $onload = ( ! $has_nav ) ? ' spf-onload' : ''; $section_icon = ( ! empty( $section['icon'] ) ) ? '' : ''; echo '
'; echo ( $has_nav ) ? '

' . wp_kses_post( $section_icon ) . esc_html( $section['title'] ) . '

' : ''; echo ( ! empty( $section['description'] ) ) ? '
' . esc_html( $section['description'] ) . '
' : ''; if ( ! empty( $section['fields'] ) ) { foreach ( $section['fields'] as $field ) { $is_field_error = $this->error_check( $field ); if ( ! empty( $is_field_error ) ) { $field['_error'] = $is_field_error; } $value = ( ! empty( $field['id'] ) && isset( $this->options[ $field['id'] ] ) ) ? $this->options[ $field['id'] ] : ''; SP_PC::field( $field, $value, $this->unique, 'options' ); } } else { echo '
' . esc_html__( 'No option provided by developer.', 'post-carousel' ) . '
'; } echo '
'; ++$section_key; } echo '
'; echo '
'; echo '
'; echo '
'; echo '
'; if ( ! empty( $this->args['show_footer'] ) ) { echo ''; } echo '
'; echo '
'; echo '
'; echo ( ! empty( $this->args['footer_after'] ) ) ? wp_kses_post( $this->args['footer_after'] ) : ''; echo '
'; if ( 'pcp_settings' === $menu_slug ) { echo ' Back to Block Settings '; } } } }