plugin_path . 'vendors/class-settings-api.php'; /** * Visual Portfolio Settings Class */ class Visual_Portfolio_Settings { /** * Settings API instance * * @var object */ public static $settings_api; /** * Cached settings fields. We call settings fields method a lot of times to get default values. * So, for performance reasons we need to cache the output. * * @var object */ public static $cached_settings_fields; /** * Visual_Portfolio_Settings constructor. */ public function __construct() { self::init_actions(); } /** * Get Option Value * * @param string $option - option name. * @param string $section - section name. * @param string $deprecated_default - default option value. * * @return bool|string */ // phpcs:ignore public static function get_option( $option, $section, $deprecated_default = '' ) { $options = get_option( $section ); $result = ''; if ( isset( $options[ $option ] ) ) { $result = $options[ $option ]; } else { // find default. $fields = self::get_settings_fields(); if ( isset( $fields[ $section ] ) && is_array( $fields[ $section ] ) ) { foreach ( $fields[ $section ] as $field_data ) { if ( $option === $field_data['name'] && isset( $field_data['default'] ) ) { $result = $field_data['default']; } } } } return 'off' === $result ? false : ( 'on' === $result ? true : $result ); } /** * Update Option Value * * @param string $option - option name. * @param string $section - section name. * @param string $value - new option value. */ public static function update_option( $option, $section, $value ) { $options = get_option( $section ); if ( ! is_array( $options ) ) { $options = array(); } $options[ $option ] = $value; update_option( $section, $options ); } /** * Init actions */ public static function init_actions() { self::$settings_api = new Visual_Portfolio_Settings_API(); add_action( 'admin_init', array( __CLASS__, 'admin_init' ) ); add_action( 'admin_menu', array( __CLASS__, 'admin_menu' ), 11 ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'admin_enqueue_scripts' ) ); add_action( 'wp_ajax_vp_get_pages_list', array( __CLASS__, 'get_posts_ajax_callback' ) ); } /** * Initialize the settings * * @return void */ public static function admin_init() { self::redirect_if_toggle_unregistered_portfolio_post_type(); // set the settings. self::$settings_api->set_sections( self::get_settings_sections() ); self::$settings_api->set_fields( self::get_settings_fields() ); // initialize settings. self::$settings_api->admin_init(); } /** * Register the admin settings menu * * @return void */ public static function admin_menu() { remove_submenu_page( 'visual-portfolio-settings', 'visual-portfolio-settings' ); add_submenu_page( Visual_Portfolio_Custom_Post_Type::get_menu_slug(), esc_html__( 'Settings', 'visual-portfolio' ), esc_html__( 'Settings', 'visual-portfolio' ), 'manage_options', 'visual-portfolio-settings', array( __CLASS__, 'print_settings_page' ) ); } /** * Redirect to actual admin page if unregistered portfolio post type. * * @return void */ public static function redirect_if_toggle_unregistered_portfolio_post_type() { global $pagenow; $register_portfolio_post_type = Visual_Portfolio_Custom_Post_Type::portfolio_post_type_is_registered(); // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( $register_portfolio_post_type && 'admin.php' === $pagenow && isset( $_GET['page'] ) && 'visual-portfolio-settings' === $_GET['page'] ) { wp_safe_redirect( admin_url( '/edit.php?post_type=portfolio&page=visual-portfolio-settings' ) ); exit; } if ( ! $register_portfolio_post_type && 'edit.php' === $pagenow && isset( $_GET['page'] ) && 'visual-portfolio-settings' === $_GET['page'] && isset( $_GET['post_type'] ) && 'portfolio' === $_GET['post_type'] ) { wp_safe_redirect( admin_url( '/admin.php?page=visual-portfolio-settings' ) ); exit; } // phpcs:enable WordPress.Security.NonceVerification.Recommended } /** * Enqueue archive select2 ajax script. * * @param string $page - Current admin page. * @return void */ public static function admin_enqueue_scripts( $page ) { if ( 'portfolio_page_visual-portfolio-settings' === $page || 'toplevel_page_visual-portfolio-settings' === $page ) { $data_init = array( 'nonce' => wp_create_nonce( 'vp-ajax-nonce' ), ); Visual_Portfolio_Assets::enqueue_script( 'visual-portfolio-archive-page-selector', 'build/assets/admin/js/archive-page-selector', array( 'select2' ) ); wp_localize_script( 'visual-portfolio-archive-page-selector', 'VPAdminVariables', $data_init ); } } /** * Plugin settings sections * * @return array */ public static function get_settings_sections() { $sections = array( array( 'id' => 'vp_general', 'title' => esc_html__( 'General', 'visual-portfolio' ), 'icon' => '', ), array( 'id' => 'vp_images', 'title' => esc_html__( 'Images', 'visual-portfolio' ), 'icon' => '', ), array( 'id' => 'vp_popup_gallery', 'title' => esc_html__( 'Popup & Lightbox', 'visual-portfolio' ), 'icon' => '', ), array( 'id' => 'vp_watermarks', 'title' => esc_html__( 'Watermarks', 'visual-portfolio' ), 'icon' => '', ), array( 'id' => 'vp_social_integrations', 'title' => esc_html__( 'Social Feeds', 'visual-portfolio' ), 'icon' => '', ), array( 'id' => 'vp_white_label', 'title' => esc_html__( 'White Label', 'visual-portfolio' ), 'icon' => '', ), ); return apply_filters( 'vpf_settings_sections', $sections ); } /** * Returns all the settings fields * * @return array settings fields */ public static function get_settings_fields() { if ( ! empty( self::$cached_settings_fields ) ) { return self::$cached_settings_fields; } $default_breakpoints = Visual_Portfolio_Breakpoints::get_default_breakpoints(); $go_pro_links = array( 'watermarks' => Visual_Portfolio_Admin::get_plugin_site_url( array( 'utm_medium' => 'settings_page', 'utm_campaign' => 'watermarks', ) ), 'social' => Visual_Portfolio_Admin::get_plugin_site_url( array( 'utm_medium' => 'settings_page', 'utm_campaign' => 'social_feeds', ) ), 'white_label' => Visual_Portfolio_Admin::get_plugin_site_url( array( 'utm_medium' => 'settings_page', 'utm_campaign' => 'white_label', ) ), ); $settings_fields = array( 'vp_general' => array( array( 'name' => 'register_portfolio_post_type', 'label' => esc_html__( 'Register Portfolio Post Type', 'visual-portfolio' ), 'desc' => esc_html__( 'Add custom post type `portfolio` to showcase your works.', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', ), array( 'name' => 'portfolio_archive_page', 'label' => esc_html__( 'Archive Page', 'visual-portfolio' ), 'desc' => esc_html__( 'Base page of your portfolio, where will be placed your works archive.', 'visual-portfolio' ), 'type' => 'select', 'options' => self::get_pages_list(), 'sanitize_callback' => array( 'Visual_Portfolio_Archive_Mapping', 'save_archive_page_option' ), 'condition' => array( array( 'control' => '[type="checkbox"][name="vp_general[register_portfolio_post_type]"]', ), ), ), array( 'name' => 'archive_page_items_per_page', 'label' => esc_html__( 'Archive Page Items Per Page', 'visual-portfolio' ), 'type' => 'number', 'min' => -1, 'max' => 9999, 'default' => 6, 'condition' => array( array( 'control' => '[type="checkbox"][name="vp_general[register_portfolio_post_type]"]', ), ), ), array( 'name' => 'filter_taxonomies', 'label' => esc_html__( 'Filter Taxonomies', 'visual-portfolio' ), 'desc' => esc_html__( 'You can show custom taxonomies in the portfolio Filter. Enter some taxonomies by "," separating values. Example: "product_cat,product_tag"', 'visual-portfolio' ), 'type' => 'text', 'default' => '', ), array( 'name' => 'no_image', 'label' => esc_html__( 'Placeholder Image', 'visual-portfolio' ), 'desc' => esc_html__( 'This image used on items in layouts where image is not specified.', 'visual-portfolio' ), 'type' => 'image', 'default' => '', 'options' => array( 'button_label' => esc_html__( 'Choose image', 'visual-portfolio' ), ), ), // AJAX Caching and Preloading. array( 'name' => 'ajax_caching', 'label' => esc_html__( 'AJAX Cache and Preload', 'visual-portfolio' ), 'desc' => esc_html__( 'Reduce AJAX calls request time.', 'visual-portfolio' ), 'type' => 'toggle', 'default' => class_exists( 'Visual_Portfolio_Pro' ) ? 'on' : 'off', 'is_pro' => true, ), // Breakpoints. array( 'name' => 'breakpoints_title', 'label' => esc_html__( 'Responsive Breakpoints', 'visual-portfolio' ), 'type' => 'section_title', 'is_pro' => true, ), array( 'name' => 'breakpoint_xl', 'label' => esc_html__( 'Extra Large', 'visual-portfolio' ), 'type' => 'number', 'min' => (float) $default_breakpoints['lg'] + 1, 'max' => 3840, 'placeholder' => (string) $default_breakpoints['xl'], 'default' => (float) $default_breakpoints['xl'], // translators: %1$s - default breakpoint. 'desc' => sprintf( esc_html__( 'Sets the breakpoint on extra large screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['xl'] ), 'is_pro' => true, ), array( 'name' => 'breakpoint_lg', 'label' => esc_html__( 'Large', 'visual-portfolio' ), 'type' => 'number', 'min' => (float) $default_breakpoints['md'] + 1, 'max' => (float) $default_breakpoints['xl'] - 1, 'placeholder' => (string) $default_breakpoints['lg'], 'default' => (float) $default_breakpoints['lg'], // translators: %1$s - default breakpoint. 'desc' => sprintf( esc_html__( 'Sets the breakpoint on large screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['lg'] ), 'is_pro' => true, ), array( 'name' => 'breakpoint_md', 'label' => esc_html__( 'Medium', 'visual-portfolio' ), 'type' => 'number', 'min' => (float) $default_breakpoints['sm'] + 1, 'max' => (float) $default_breakpoints['lg'] - 1, 'placeholder' => (string) $default_breakpoints['md'], 'default' => (float) $default_breakpoints['md'], // translators: %1$s - default breakpoint. 'desc' => sprintf( esc_html__( 'Sets the breakpoint on medium screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['md'] ), 'is_pro' => true, ), array( 'name' => 'breakpoint_sm', 'label' => esc_html__( 'Small', 'visual-portfolio' ), 'type' => 'number', 'min' => (float) $default_breakpoints['xs'] + 1, 'max' => (float) $default_breakpoints['md'] - 1, 'placeholder' => (string) $default_breakpoints['sm'], 'default' => (float) $default_breakpoints['sm'], // translators: %1$s - default breakpoint. 'desc' => sprintf( esc_html__( 'Sets the breakpoint on small screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['sm'] ), 'is_pro' => true, ), array( 'name' => 'breakpoint_xs', 'label' => esc_html__( 'Extra Small', 'visual-portfolio' ), 'type' => 'number', 'min' => 1, 'max' => (float) $default_breakpoints['sm'] - 1, 'placeholder' => (string) $default_breakpoints['xs'], 'default' => (float) $default_breakpoints['xs'], // translators: %1$s - default breakpoint. 'desc' => sprintf( esc_html__( 'Sets the breakpoint on extra small screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['xs'] ), 'is_pro' => true, ), ), 'vp_images' => array( array( 'name' => 'lazy_loading', 'label' => esc_html__( 'Lazy Loading', 'visual-portfolio' ), // translators: %s - plugin brand name. 'desc' => sprintf( esc_html__( 'Enable lazy loading for %s layouts only or for the whole website.', 'visual-portfolio' ), visual_portfolio()->plugin_name ), 'type' => 'select', 'default' => 'vp', 'options' => array( '' => esc_html__( 'Disabled', 'visual-portfolio' ), // translators: %s - plugin brand name. 'vp' => sprintf( esc_html__( '%s Only', 'visual-portfolio' ), visual_portfolio()->plugin_name ), 'full' => esc_html__( 'All images', 'visual-portfolio' ), ), ), array( 'name' => 'lazy_loading_excludes', 'label' => esc_html__( 'Lazy Loading Excludes', 'visual-portfolio' ), // translators: %s - doc url. // translators: %s - link text. 'desc' => sprintf( __( 'Listed images will not be lazy loaded. Both full URLs and partial strings can be used. One per line. %2$s', 'visual-portfolio' ), 'https://visualportfolio.co/docs/settings/images/', esc_html__( 'More info', 'visual-portfolio' ) ), 'type' => 'textarea', 'placeholder' => "image-example.webp\nslider-image-classname", 'condition' => array( array( 'control' => '[name="vp_images[lazy_loading]"]', ), ), ), array( 'name' => 'images_layouts_title', 'label' => esc_html__( 'Layouts Image Sizes', 'visual-portfolio' ), 'desc' => __( 'Image sizes used in portfolio layouts.', 'visual-portfolio' ), 'type' => 'section_title', ), array( 'name' => 'sm', 'label' => esc_html__( 'Small', 'visual-portfolio' ), 'type' => 'number', 'placeholder' => '500', 'default' => 500, ), array( 'name' => 'md', 'label' => esc_html__( 'Medium', 'visual-portfolio' ), 'type' => 'number', 'placeholder' => '800', 'default' => 800, ), array( 'name' => 'lg', 'label' => esc_html__( 'Large', 'visual-portfolio' ), 'type' => 'number', 'placeholder' => '1280', 'default' => 1280, ), array( 'name' => 'xl', 'label' => esc_html__( 'Extra Large', 'visual-portfolio' ), 'type' => 'number', 'placeholder' => '1920', 'default' => 1920, ), array( 'name' => 'images_popup_title', 'label' => esc_html__( 'Lightbox Image Sizes', 'visual-portfolio' ), 'desc' => __( 'Image sizes used in lightbox images.', 'visual-portfolio' ), 'type' => 'section_title', ), array( 'name' => 'sm_popup', 'label' => esc_html__( 'Small', 'visual-portfolio' ), 'type' => 'number', 'placeholder' => '500', 'default' => 500, ), array( 'name' => 'md_popup', 'label' => esc_html__( 'Medium', 'visual-portfolio' ), 'type' => 'number', 'placeholder' => '800', 'default' => 800, ), array( 'name' => 'xl_popup', 'label' => esc_html__( 'Large', 'visual-portfolio' ), 'type' => 'number', 'placeholder' => '1920', 'default' => 1920, ), array( 'name' => 'images_sizes_note', // translators: %s: regenerate thumbnails url. 'desc' => sprintf( __( 'After publishing your changes, new image sizes may not be shown until you Regenerate Thumbnails.', 'visual-portfolio' ), 'https://wordpress.org/plugins/regenerate-thumbnails/' ), 'type' => 'html', ), ), 'vp_popup_gallery' => array( // Vendor. array( 'name' => 'vendor', 'label' => esc_html__( 'Vendor Script', 'visual-portfolio' ), 'type' => 'select', 'options' => array( 'fancybox' => esc_html__( 'Fancybox', 'visual-portfolio' ), 'photoswipe' => esc_html__( 'PhotoSwipe', 'visual-portfolio' ), ), 'default' => 'fancybox', ), // Default WordPress Images. array( 'name' => 'enable_on_wordpress_images', 'label' => esc_html__( 'Lightbox for WordPress Images', 'visual-portfolio' ), 'desc' => esc_html__( 'Enable lightbox for WordPress native galleries and images.', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'off', ), // Section divider. array( 'name' => 'popup_general_divider_title', 'type' => 'section_title', ), // Deeplinking. array( 'name' => 'deep_linking', 'label' => esc_html__( 'Deep Linking', 'visual-portfolio' ), 'desc' => esc_html__( 'Makes URL automatically change to reflect the current opened popup, and you can easily link directly to that image or video.', 'visual-portfolio' ), 'type' => 'toggle', 'default' => class_exists( 'Visual_Portfolio_Pro' ) ? 'on' : 'off', 'is_pro' => true, ), array( 'name' => 'deep_linking_url_to_share_images', 'label' => esc_html__( 'Use Deep Linking URL to Share Images', 'visual-portfolio' ), 'desc' => esc_html__( 'Check to share Deep Linking URLs when sharing images. When disabled, all galleries will share direct links to image files.', 'visual-portfolio' ), 'type' => 'toggle', 'default' => class_exists( 'Visual_Portfolio_Pro' ) ? 'on' : 'off', 'is_pro' => true, ), // Loop. array( 'name' => 'loop', 'label' => esc_html__( 'Loop', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', 'is_pro' => true, ), // Click to Zoom. array( 'name' => 'click_to_zoom', 'label' => esc_html__( 'Click to Zoom', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', ), // Restore Focus. array( 'name' => 'restore_focus', 'label' => esc_html__( 'Restore Focus', 'visual-portfolio' ), 'desc' => esc_html__( 'Restore focus on the last active item after Popup is closed.', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', ), // UI Elements. array( 'name' => 'popup_ui_elements_title', 'label' => esc_html__( 'UI Elements', 'visual-portfolio' ), 'type' => 'section_title', ), array( 'name' => 'show_arrows', 'label' => esc_html__( 'Display Arrows', 'visual-portfolio' ), 'desc' => esc_html__( 'Arrows to navigate between images.', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', ), array( 'name' => 'show_counter', 'label' => esc_html__( 'Display Images Counter', 'visual-portfolio' ), 'desc' => esc_html__( 'On the top left corner will be showed images counter.', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', ), array( 'name' => 'show_zoom_button', 'label' => esc_html__( 'Display Zoom Button', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', ), array( 'name' => 'show_fullscreen_button', 'label' => esc_html__( 'Display Fullscreen Button', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', ), array( 'name' => 'show_share_button', 'label' => esc_html__( 'Display Share Button', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', ), array( 'name' => 'show_close_button', 'label' => esc_html__( 'Display Close Button', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', ), // Fancybox Popup Settings. array( 'name' => 'show_thumbs', 'label' => esc_html__( 'Display Thumbnails', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', 'condition' => array( array( 'control' => '[name="vp_popup_gallery[vendor]"]', 'operator' => '===', 'value' => 'fancybox', ), ), ), array( 'name' => 'thumbs_auto_start', 'label' => esc_html__( 'Thumbnails Opened At Startup', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'off', 'is_pro' => true, 'condition' => array( array( 'control' => '[type="checkbox"][name="vp_popup_gallery[show_thumbs]"]', ), array( 'control' => '[name="vp_popup_gallery[vendor]"]', 'operator' => '===', 'value' => 'fancybox', ), ), ), array( 'name' => 'thumbs_position', 'label' => esc_html__( 'Thumbnails Position', 'visual-portfolio' ), 'type' => 'select', 'default' => 'vertical', 'options' => array( 'vertical' => esc_html__( 'Vertical', 'visual-portfolio' ), 'horizontal' => esc_html__( 'Horizontal', 'visual-portfolio' ), ), 'is_pro' => true, 'condition' => array( array( 'control' => '[type="checkbox"][name="vp_popup_gallery[show_thumbs]"]', ), array( 'control' => '[name="vp_popup_gallery[vendor]"]', 'operator' => '===', 'value' => 'fancybox', ), ), ), array( 'name' => 'show_download_button', 'label' => esc_html__( 'Display Download Button', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'off', 'condition' => array( array( 'control' => '[name="vp_popup_gallery[vendor]"]', 'operator' => '===', 'value' => 'fancybox', ), ), ), array( 'name' => 'show_slideshow', 'label' => esc_html__( 'Display Slideshow', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'off', 'condition' => array( array( 'control' => '[name="vp_popup_gallery[vendor]"]', 'operator' => '===', 'value' => 'fancybox', ), ), ), // Quick View settings. array( 'name' => 'popup_quick_view_title', 'label' => esc_html__( 'Quick View', 'visual-portfolio' ), 'type' => 'section_title', ), array( 'name' => 'popup_quick_view_show_url_button', 'label' => esc_html__( 'Display URL Button', 'visual-portfolio' ), 'desc' => esc_html__( 'Button with page URL will be placed in the popup toolbar.', 'visual-portfolio' ), 'type' => 'toggle', 'default' => 'on', 'is_pro' => true, ), array( 'name' => 'popup_quick_view_internal_links_target', 'label' => esc_html__( 'Internal Links', 'visual-portfolio' ), 'type' => 'select', 'default' => '_blank', 'options' => array( '_blank' => esc_html__( 'Open in New Tab', 'visual-portfolio' ), '_top' => esc_html__( 'Open in Current Tab', 'visual-portfolio' ), '_self' => esc_html__( 'Open in Frame (not recommended)', 'visual-portfolio' ), 'prevent-click' => esc_html__( 'Prevent Click', 'visual-portfolio' ), ), 'is_pro' => true, ), array( 'name' => 'popup_quick_view_external_links_target', 'label' => esc_html__( 'External Links', 'visual-portfolio' ), 'type' => 'select', 'default' => '_blank', 'options' => array( '_blank' => esc_html__( 'Open in New Tab', 'visual-portfolio' ), '_top' => esc_html__( 'Open in Current Tab', 'visual-portfolio' ), '_self' => esc_html__( 'Open in Frame (not recommended)', 'visual-portfolio' ), 'prevent-click' => esc_html__( 'Prevent Click', 'visual-portfolio' ), ), 'is_pro' => true, ), array( 'name' => 'pages_iframe_custom_css', 'label' => esc_html__( 'Custom CSS', 'visual-portfolio' ), 'desc' => esc_html__( 'When you display posts and pages in popup iframe, you may not need some page elements like header and footer. Hide it using custom CSS with classname `.vp-popup-iframe`.', 'visual-portfolio' ), 'type' => 'textarea', 'default' => ! class_exists( 'Visual_Portfolio_Pro' ) ? '' : ' /* Hide header and footer in standard themes */ .vp-popup-iframe #site-header, .vp-popup-iframe #masthead, .vp-popup-iframe #site-footer, .vp-popup-iframe #colophon { display: none; } /* Hide header and footer in Twenty Twenty-Two theme (Full Site Editing) */ .vp-popup-iframe .wp-site-blocks > header.wp-block-template-part, .vp-popup-iframe .wp-site-blocks > footer.wp-block-template-part { display: none; }', 'is_pro' => true, ), // Misc settings. array( 'name' => 'popup_misc_title', 'label' => esc_html__( 'Misc', 'visual-portfolio' ), 'type' => 'section_title', ), array( 'name' => 'background_color', 'label' => esc_html__( 'Background Color', 'visual-portfolio' ), 'type' => 'color', 'default' => '#1e1e1e', ), ), 'vp_watermarks' => array( array( 'name' => 'pro_info', 'desc' => '
' . esc_html__( 'Protect your works using watermarks', 'visual-portfolio' ) . '
' . esc_html__( 'Go Pro', 'visual-portfolio' ) . '' . esc_html__( 'Social feeds such as Instagram, Youtube, Flickr, Twitter, etc...', 'visual-portfolio' ) . '
' . esc_html__( 'Go Pro', 'visual-portfolio' ) . '' . esc_html__( 'Remove our plugin brand and logos from Front and Admin areas', 'visual-portfolio' ) . '
' . esc_html__( 'Go Pro', 'visual-portfolio' ) . '