', 'manage_aiopod_options', 'aio-podcast-studio-separator-3', '__return_null' ); } /** * Display page content. * * @since 1.0.0 */ public function display_page_content() { require_once AIOPOD_PLUGIN_DIR . 'admin/partials/settings/settings.php'; } /** * Initiate settings. * * @since 1.0.0 */ public function admin_init() { $this->tabs = $this->get_tabs(); $this->sections = $this->get_sections(); $this->fields = $this->get_fields(); // Initialize settings $this->initialize_settings(); } /** * Get settings tabs. * * @since 1.0.0 * @return array $tabs Setting tabs array. */ public function get_tabs() { $tabs = array( 'general' => __( 'General', 'aio-podcast-studio' ), 'display' => __( 'Display', 'aio-podcast-studio' ), 'seo' => __( 'SEO & Social', 'aio-podcast-studio' ), 'privacy' => __( 'Privacy', 'aio-podcast-studio' ) ); return apply_filters( 'aiopod_settings_tabs', $tabs ); } /** * Get settings sections. * * @since 1.0.0 * @return array $sections Setting sections array. */ public function get_sections() { $sections = array( array( 'id' => 'aiopod_appearance_settings', 'title' => __( 'Appearance', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'general', 'page' => 'aiopod_appearance_settings' ), array( 'id' => 'aiopod_pages_settings', 'title' => __( 'Pages & Archives', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'general', 'page' => 'aiopod_appearance_settings' ), array( 'id' => 'aiopod_taxonomies_settings', 'title' => __( 'WordPress Categories & Tags', 'aio-podcast-studio' ), 'description' => __( 'This section allows you to add the standard WordPress Categories and Tags boxes to podcasts and episodes, and to list them in your site’s regular category and tag archives, rendered by your theme. They do not replace the plugin’s own Podcast Categories and Episode Tags — those remain what the plugin itself uses throughout, including the categories your RSS feed publishes to Apple Podcasts and Spotify. WordPress categories and tags are an additional way to group your podcast content alongside the rest of your site.', 'aio-podcast-studio' ), 'tab' => 'general', 'page' => 'aiopod_appearance_settings' ), array( 'id' => 'aiopod_performance_settings', 'title' => __( 'Performance & Compatibility', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'general', 'page' => 'aiopod_appearance_settings' ), array( 'id' => 'aiopod_formatting_settings', 'title' => __( 'Formatting', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'general', 'page' => 'aiopod_appearance_settings' ), array( 'id' => 'aiopod_pagination_settings', 'title' => __( 'Pagination', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'general', 'page' => 'aiopod_appearance_settings' ), array( 'id' => 'aiopod_cleanup_settings', 'title' => __( 'Data & Cleanup', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'general', 'page' => 'aiopod_appearance_settings' ), array( 'id' => 'aiopod_player_settings', 'title' => __( 'Player', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_player_settings' ), array( 'id' => 'aiopod_podcasts_settings', 'title' => __( 'Podcasts List', 'aio-podcast-studio' ), 'menu_title' => __( 'Podcasts', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_podcasts_settings' ), array( 'id' => 'aiopod_podcast_settings', 'title' => __( 'Single Podcast Page', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_podcasts_settings' ), array( 'id' => 'aiopod_episodes_settings', 'title' => __( 'Episodes List', 'aio-podcast-studio' ), 'menu_title' => __( 'Episodes', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_episodes_settings' ), array( 'id' => 'aiopod_filters_settings', 'title' => __( 'Episodes Filters', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_episodes_settings' ), array( 'id' => 'aiopod_episode_settings', 'title' => __( 'Single Episode Page', 'aio-podcast-studio' ), 'description' => sprintf( /* translators: 1: URL to Player settings page, 2: "Player" link label */ __( 'Episode details on the single episode page are rendered by the player. Configure them under %2$s.', 'aio-podcast-studio' ), esc_url( admin_url( 'admin.php?page=aiopod_settings&tab=display§ion=aiopod_player_settings' ) ), esc_html__( 'Player', 'aio-podcast-studio' ) ), 'tab' => 'display', 'page' => 'aiopod_episodes_settings' ), array( 'id' => 'aiopod_related_episodes_settings', 'title' => __( 'Single Episode — Related Episodes', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_episodes_settings' ), array( 'id' => 'aiopod_categories_settings', 'title' => __( 'Categories List', 'aio-podcast-studio' ), 'menu_title' => __( 'Categories', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_categories_settings' ), array( 'id' => 'aiopod_category_settings', 'title' => __( 'Single Category Page', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_categories_settings' ), array( 'id' => 'aiopod_tags_settings', 'title' => __( 'Tags List', 'aio-podcast-studio' ), 'menu_title' => __( 'Tags', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_tags_settings' ), array( 'id' => 'aiopod_tag_settings', 'title' => __( 'Single Tag Page', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_tags_settings' ), array( 'id' => 'aiopod_participants_settings', 'title' => __( 'Participants List', 'aio-podcast-studio' ), 'menu_title' => __( 'Participants', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_participants_settings' ), array( 'id' => 'aiopod_participant_settings', 'title' => __( 'Single Participant Page', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'display', 'page' => 'aiopod_participants_settings' ), array( 'id' => 'aiopod_seo_settings', 'title' => __( 'SEO', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'seo', 'page' => 'aiopod_seo_settings' ), array( 'id' => 'aiopod_share_buttons_settings', 'title' => __( 'Share Buttons', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'seo', 'page' => 'aiopod_share_buttons_settings' ), array( 'id' => 'aiopod_privacy_settings', 'title' => __( 'Privacy', 'aio-podcast-studio' ), 'description' => '', 'tab' => 'privacy', 'page' => 'aiopod_privacy_settings' ) ); return apply_filters( 'aiopod_settings_sections', $sections ); } /** * Get settings fields. * * @since 1.0.0 * @return array $fields Setting fields array. */ public function get_fields() { $fields = array( 'aiopod_appearance_settings' => array( array( 'name' => 'primary_color', 'label' => __( 'Primary Color', 'aio-podcast-studio' ), 'description' => __( 'Used to style key UI elements such as the player, progress bar, tabs, and sliders.', 'aio-podcast-studio' ), 'type' => 'color', 'sanitize_callback' => 'sanitize_text_field' ), array( 'name' => 'enable_featured_images', 'label' => __( 'Enable Featured Images', 'aio-podcast-studio' ), 'description' => __( 'Enable featured images for podcasts and episodes.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'download_external_images', 'label' => __( 'Download External Images', 'aio-podcast-studio' ), 'description' => __( 'Download externally hosted images when importing podcasts from RSS feeds to store them locally. Has no effect unless Enable Featured Images is turned on.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'image_size', 'label' => __( 'Image File Size', 'aio-podcast-studio' ), 'description' => __( 'Select the image size used across the plugin. Smaller sizes improve performance, while larger sizes provide better image quality.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'thumbnail' => __( 'Thumbnail', 'aio-podcast-studio' ), 'medium' => __( 'Medium', 'aio-podcast-studio' ), 'large' => __( 'Large', 'aio-podcast-studio' ), 'full' => __( 'Full Size', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'fallback_podcast_image', 'label' => __( 'Use Podcast Image as Fallback', 'aio-podcast-studio' ), 'description' => __( 'Use the podcast image when an episode does not have its own image. Applies to episode listings and RSS feeds.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'hide_on_single_post_pages', 'label' => __( 'Hide Featured Images on Single Post Pages', 'aio-podcast-studio' ), 'description' => __( 'Hide featured images on single podcast and episode pages if your theme displays them automatically.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ) ), 'aiopod_pages_settings' => array( array( 'name' => 'category', 'label' => __( 'Single Category Page', 'aio-podcast-studio' ), 'description' => __( 'Select the page where podcasts for a specific category are displayed. Add the [aiopod_category] shortcode to this page.', 'aio-podcast-studio' ), 'type' => 'pages', 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'tag', 'label' => __( 'Single Tag Page', 'aio-podcast-studio' ), 'description' => __( 'Select the page where episodes for a specific tag are displayed. Add the [aiopod_tag] shortcode to this page.', 'aio-podcast-studio' ), 'type' => 'pages', 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'participant', 'label' => __( 'Single Participant Page', 'aio-podcast-studio' ), 'description' => __( 'Select the page where podcasts and episodes for a specific participant are displayed. Add the [aiopod_participant] shortcode to this page.', 'aio-podcast-studio' ), 'type' => 'pages', 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'podcast_archive_page', 'label' => __( 'Podcast Archive Page', 'aio-podcast-studio' ), 'description' => __( 'Select a page to use as the custom podcast archive. Requests to the default archive will be redirected here. Add the [aiopod_podcasts] shortcode to this page.', 'aio-podcast-studio' ), 'type' => 'pages', 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'episode_archive_page', 'label' => __( 'Episode Archive Page', 'aio-podcast-studio' ), 'description' => __( 'Select a page to use as the custom episode archive. Requests to the default archive will be redirected here. Add the [aiopod_episodes] shortcode to this page.', 'aio-podcast-studio' ), 'type' => 'pages', 'sanitize_callback' => 'sanitize_key' ) ), 'aiopod_taxonomies_settings' => array( array( 'name' => 'wp_taxonomies', 'label' => __( 'Enable For Podcasts & Episodes', 'aio-podcast-studio' ), 'description' => '', 'type' => 'multicheck', 'options' => array( 'categories' => __( 'WordPress Categories', 'aio-podcast-studio' ), 'tags' => __( 'WordPress Tags', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'include_in_core_archives', 'label' => __( 'Include in WordPress Category & Tag Archives', 'aio-podcast-studio' ), 'description' => __( 'Only applies when WordPress Categories or Tags are enabled above. Adds your podcasts and episodes to your site’s category and tag archives, alongside your posts.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ) ), 'aiopod_performance_settings' => array( array( 'name' => 'lazyloading', 'label' => __( 'Lazyload Images', 'aio-podcast-studio' ), 'description' => __( 'Load images only when they enter the viewport to improve page speed and performance. Disable this option if you notice display issues.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'force_load_assets', 'label' => __( 'Force Load Plugin Assets', 'aio-podcast-studio' ), 'description' => __( 'Force load the plugin’s CSS and/or JavaScript files on the front end. Enable this option if layouts or players do not render correctly.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'css' => __( 'Force load CSS files', 'aio-podcast-studio' ), 'js' => __( 'Force load JavaScript files', 'aio-podcast-studio' ), ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'maybe_flush_rewrite_rules', 'label' => __( 'Auto Flush Rewrite Rules', 'aio-podcast-studio' ), 'description' => __( 'Automatically detect and refresh missing permalink rules when necessary. This is usually not required, as rewrite rules are refreshed when relevant settings or assigned pages change. Disable this option if you experience frequent 404, 500, or performance issues.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'episode_file_url_format', 'label' => __( 'Episode File URL Format', 'aio-podcast-studio' ), 'description' => sprintf( '%1$s

%2$s
%3$s
%4$s
%5$s', __( 'Select the URL format for episode downloads and RSS feed links. If your server handles media file extensions itself instead of passing them to WordPress, listeners are sent to your homepage and podcast apps report the file as invalid or unplayable. If this occurs, switch to a different format.', 'aio-podcast-studio' ), __( 'Examples:', 'aio-podcast-studio' ), '/episodes/my-episode/file/episode.mp3', '/episodes/my-episode/file/', '/?aiopod_episode=my-episode&aiopod_download=1' ), 'type' => 'select', 'options' => array( 'extension' => __( 'With file extension', 'aio-podcast-studio' ), 'no_extension' => __( 'Without file extension', 'aio-podcast-studio' ), 'query' => __( 'Query string', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ) ), 'aiopod_formatting_settings' => array( array( 'name' => 'datetime_format', 'label' => __( 'DateTime Format', 'aio-podcast-studio' ), 'description' => sprintf( '%s %s
%s', __( 'Enter the PHP date format used to display dates on the front end.', 'aio-podcast-studio' ), __( 'Learn more about formatting.', 'aio-podcast-studio' ), __( 'Leave empty to display relative time (e.g., "2 hours ago").', 'aio-podcast-studio' ) ), 'placeholder' => 'F j, Y', 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ), array( 'name' => 'number_format', 'label' => __( 'Number Format', 'aio-podcast-studio' ), 'description' => __( 'Choose how large numbers (e.g., plays or downloads) are displayed.', 'aio-podcast-studio' ), 'type' => 'radio', 'options' => array( 'full' => __( 'Full Format (e.g., 1,200, 3,400,000)', 'aio-podcast-studio' ), 'short' => __( 'Short Format (e.g., 1.2K, 3.4M)', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_text_field' ), ), 'aiopod_pagination_settings' => array( array( 'name' => 'layout', 'label' => __( 'Pagination Type', 'aio-podcast-studio' ), 'description' => __( 'Choose the default pagination style: Numeric or More Button (Ajax).', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'numeric' => __( 'Numeric Pagination', 'aio-podcast-studio' ), 'loadmore' => __( 'More Button (Ajax)', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'page_range', 'label' => __( 'Page Range', 'aio-podcast-studio' ), 'description' => __( 'Set how many page numbers to display on either side of the current page when using numeric pagination. Default is 2.', 'aio-podcast-studio' ), 'type' => 'number', 'min' => 1, 'step' => 1, 'sanitize_callback' => 'aiopod_sanitize_int' ), array( 'name' => 'more_button_label', 'label' => __( 'More Button Label', 'aio-podcast-studio' ), 'description' => __( 'Enter the text displayed on the More Button in Ajax pagination.', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ) ), 'aiopod_cleanup_settings' => array( array( 'name' => 'delete_plugin_data', 'label' => __( 'Remove Data on Uninstall', 'aio-podcast-studio' ), 'description' => __( 'Delete all plugin data from the database when uninstalling the plugin.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'delete_media_files', 'label' => __( 'Delete Media Files', 'aio-podcast-studio' ), 'description' => __( 'Delete associated media files when a podcast, episode, participant, or category is deleted.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'delete_episodes_with_podcast', 'label' => __( 'Delete Episodes with Podcast', 'aio-podcast-studio' ), 'description' => __( 'Automatically delete all episodes associated with a podcast when the podcast is deleted. Disable this option to keep episodes.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'stats_log_retention', 'label' => __( 'Statistics Log Retention', 'aio-podcast-studio' ), 'description' => __( 'How many days to keep detailed play and download history. Older history is cleaned up automatically each day. Your statistics charts and totals are always kept, no matter what. Leave empty to keep all history forever.', 'aio-podcast-studio' ), 'placeholder' => __( 'e.g. 365', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'aiopod_sanitize_int' ) ), 'aiopod_player_settings' => array( array( 'name' => 'autoplay', 'label' => __( 'Autoplay', 'aio-podcast-studio' ), 'description' => __( 'Automatically start playback when the player is ready.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'autoadvance', 'label' => __( 'Autoplay Next Episode', 'aio-podcast-studio' ), 'description' => __( 'Automatically play the next episode in the list when the current episode ends.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'loop', 'label' => __( 'Loop', 'aio-podcast-studio' ), 'description' => __( 'Continuously loop the media playback.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'muted', 'label' => __( 'Muted', 'aio-podcast-studio' ), 'description' => __( 'Mute audio by default when playback starts.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'preload', 'label' => __( 'Preload', 'aio-podcast-studio' ), 'description' => __( 'Choose how media should load: Auto (load entire media), Metadata (load metadata only), or None (do not preload).', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'auto' => __( 'Auto', 'aio-podcast-studio' ), 'metadata' => __( 'Metadata', 'aio-podcast-studio' ), 'none' => __( 'None', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'playsinline', 'label' => __( 'Plays Inline on Mobile', 'aio-podcast-studio' ), 'description' => __( 'Prevent fullscreen mode on mobile devices during playback.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'controls', 'label' => __( 'Player Controls', 'aio-podcast-studio' ), 'description' => __( 'Select which controls to display on the player.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'rewind' => __( 'Rewind Button', 'aio-podcast-studio' ), 'play' => __( 'Play Button', 'aio-podcast-studio' ), 'fastforward' => __( 'Forward Button', 'aio-podcast-studio' ), 'progress' => __( 'Progress Bar', 'aio-podcast-studio' ), 'currenttime' => __( 'Current Time', 'aio-podcast-studio' ), 'duration' => __( 'Duration', 'aio-podcast-studio' ), 'volume' => __( 'Volume Button', 'aio-podcast-studio' ), 'speed' => __( 'Speed Control', 'aio-podcast-studio' ), 'chapters' => __( 'Chapters', 'aio-podcast-studio' ), 'pip' => __( 'Picture-in-Picture Button', 'aio-podcast-studio' ), 'download' => __( 'Download Button', 'aio-podcast-studio' ), 'fullscreen' => __( 'Fullscreen Button', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'episode_details', 'label' => __( 'Episode Details', 'aio-podcast-studio' ), 'description' => __( 'Select which episode details to display on the player.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'episode_title' => __( 'Episode Title', 'aio-podcast-studio' ), 'episode_excerpt' => __( 'Episode Description (Excerpt)', 'aio-podcast-studio' ), 'episode_date' => __( 'Episode Date', 'aio-podcast-studio' ), 'podcast_title' => __( 'Podcast Title', 'aio-podcast-studio' ), 'episode_tags' => __( 'Episode Tags', 'aio-podcast-studio' ), 'episode_type' => __( 'Episode Type (Trailer / Bonus)', 'aio-podcast-studio' ), 'season_number' => __( 'Season Number', 'aio-podcast-studio' ), 'episode_number' => __( 'Episode Number', 'aio-podcast-studio' ), 'episode_file_size' => __( 'Episode File Size', 'aio-podcast-studio' ), 'episode_duration' => __( 'Episode Duration', 'aio-podcast-studio' ), 'explicit_badge' => __( 'Explicit Badge', 'aio-podcast-studio' ), 'downloads_count' => __( 'Downloads Count', 'aio-podcast-studio' ), 'plays_count' => __( 'Plays Count', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'excerpt_length', 'label' => __( 'Excerpt Length', 'aio-podcast-studio' ), 'description' => __( 'Set the maximum number of characters for the episode description on the player. Enter 0 to display the full description.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'social_buttons', 'label' => __( 'Social Media Buttons', 'aio-podcast-studio' ), 'description' => sprintf( __( 'Select which social buttons to display on the player. Configure Share Buttons.', 'aio-podcast-studio' ), esc_url( admin_url( 'admin.php?page=aiopod_settings&tab=seo§ion=aiopod_share_buttons_settings' ) ) ), 'type' => 'multicheck', 'options' => array( 'subscribe_buttons' => __( 'Subscribe Buttons', 'aio-podcast-studio' ), 'follow_buttons' => __( 'Follow Us Buttons', 'aio-podcast-studio' ), 'share_buttons' => __( 'Share Buttons', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'hotkeys', 'label' => __( 'Keyboard Hotkeys', 'aio-podcast-studio' ), 'description' => sprintf( '%s
', __( 'Enable keyboard shortcuts to control the player.', 'aio-podcast-studio' ), __( 'Spacebar', 'aio-podcast-studio' ), __( 'Toggle play/pause.', 'aio-podcast-studio' ), __( 'Left Arrow', 'aio-podcast-studio' ), __( 'Rewind the episode.', 'aio-podcast-studio' ), __( 'Right Arrow', 'aio-podcast-studio' ), __( 'Forward the episode.', 'aio-podcast-studio' ), __( 'Up Arrow', 'aio-podcast-studio' ), __( 'Increase the volume.', 'aio-podcast-studio' ), __( 'Down Arrow', 'aio-podcast-studio' ), __( 'Decrease the volume.', 'aio-podcast-studio' ), __( 'F Key', 'aio-podcast-studio' ), __( 'Toggle fullscreen mode.', 'aio-podcast-studio' ), __( 'M Key', 'aio-podcast-studio' ), __( 'Toggle mute.', 'aio-podcast-studio' ) ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ) ), 'aiopod_podcasts_settings' => array( array( 'name' => 'show_count', 'label' => __( 'Show Total Podcasts', 'aio-podcast-studio' ), 'description' => __( 'Show the total number of podcasts above the list.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'columns', 'label' => __( 'Columns', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of columns to display in the list.', 'aio-podcast-studio' ), 'type' => 'number', 'min' => 1, 'max' => 12, 'step' => 1, 'sanitize_callback' => 'intval' ), array( 'name' => 'limit', 'label' => __( 'Limit (per page)', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of podcasts to display per page. Leave blank for the default value (100).', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'orderby', 'label' => __( 'Order By', 'aio-podcast-studio' ), 'description' => __( 'Select how podcasts are sorted.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'title' => __( 'Title', 'aio-podcast-studio' ), 'date' => __( 'Date Added', 'aio-podcast-studio' ), 'popularity' => __( 'Popularity (Plays + Downloads)', 'aio-podcast-studio' ), 'downloads' => __( 'Downloads', 'aio-podcast-studio' ), 'plays' => __( 'Plays', 'aio-podcast-studio' ), 'rand' => __( 'Random', 'aio-podcast-studio' ), 'menu_order' => __( 'Menu Order', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'order', 'label' => __( 'Order Direction', 'aio-podcast-studio' ), 'description' => __( 'Choose ascending or descending order.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'asc' => __( 'Ascending', 'aio-podcast-studio' ), 'desc' => __( 'Descending', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'display_options', 'label' => __( 'Podcast Details', 'aio-podcast-studio' ), 'description' => __( 'Select which details to display for each podcast in the list.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'podcast_title' => __( 'Podcast Title', 'aio-podcast-studio' ), 'podcast_excerpt' => __( 'Podcast Description (Excerpt)', 'aio-podcast-studio' ), 'podcast_categories' => __( 'Podcast Categories', 'aio-podcast-studio' ), 'podcast_date' => __( 'Podcast Date', 'aio-podcast-studio' ), 'episodes_count' => __( 'Episodes Count', 'aio-podcast-studio' ), 'explicit_badge' => __( 'Explicit Badge', 'aio-podcast-studio' ), 'downloads_count' => __( 'Downloads Count', 'aio-podcast-studio' ), 'plays_count' => __( 'Plays Count', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'excerpt_length', 'label' => __( 'Excerpt Length', 'aio-podcast-studio' ), 'description' => __( 'Set the maximum number of characters for podcast descriptions. Enter 0 to display the full description.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'pagination', 'label' => __( 'Pagination Type', 'aio-podcast-studio' ), 'description' => __( 'Choose the pagination style: None, Numeric, or More Button (Ajax).', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( '' => '— ' . __( 'Use Global Setting', 'aio-podcast-studio' ) . ' —' , 'none' => __( 'None', 'aio-podcast-studio' ), 'numeric' => __( 'Numeric Pagination', 'aio-podcast-studio' ), 'loadmore' => __( 'More Button (Ajax)', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ) ), 'aiopod_podcast_settings' => array( array( 'name' => 'display_metadata', 'label' => __( 'Podcast Metadata', 'aio-podcast-studio' ), 'description' => __( 'Select which podcast details to display in the header area.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'categories' => __( 'Podcast Categories', 'aio-podcast-studio' ), 'date' => __( 'Podcast Date', 'aio-podcast-studio' ), 'episodes_count' => __( 'Episodes Count', 'aio-podcast-studio' ), 'explicit_badge' => __( 'Explicit Badge', 'aio-podcast-studio' ), 'downloads_count' => __( 'Downloads Count', 'aio-podcast-studio' ), 'plays_count' => __( 'Plays Count', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'social_buttons', 'label' => __( 'Social Media Buttons', 'aio-podcast-studio' ), 'description' => sprintf( __( 'Select which social buttons to display on the single podcast page. Configure Share Buttons.', 'aio-podcast-studio' ), esc_url( admin_url( 'admin.php?page=aiopod_settings&tab=seo§ion=aiopod_share_buttons_settings' ) ) ), 'type' => 'multicheck', 'options' => array( 'subscribe_buttons' => __( 'Subscribe Buttons', 'aio-podcast-studio' ), 'follow_buttons' => __( 'Follow Us Buttons', 'aio-podcast-studio' ), 'share_buttons' => __( 'Share Buttons', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'show_episodes', 'label' => __( 'Show Episodes', 'aio-podcast-studio' ), 'description' => sprintf( __( 'Show episodes associated with this podcast on the single podcast page. When Trailer or Bonus sections are enabled, this section displays only full episodes; otherwise it also includes trailer and bonus episodes. Episode layout and ordering are managed in Episodes Settings → Episodes List.', 'aio-podcast-studio' ), esc_url( admin_url( 'admin.php?page=aiopod_settings&tab=display§ion=aiopod_episodes_settings' ) ) ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'episodes_title', 'label' => __( 'Episodes Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the episodes section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Latest Episodes', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ), array( 'name' => 'show_trailer_episodes', 'label' => __( 'Show Trailer Episodes', 'aio-podcast-studio' ), 'description' => __( 'Show trailer episodes in a separate section on the single podcast page.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'trailer_episodes_title', 'label' => __( 'Trailer Episodes Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the trailer episodes section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Trailers & More', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ), array( 'name' => 'show_bonus_episodes', 'label' => __( 'Show Bonus Episodes', 'aio-podcast-studio' ), 'description' => __( 'Show bonus episodes in a separate section on the single podcast page.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'bonus_episodes_title', 'label' => __( 'Bonus Episodes Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the bonus episodes section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Bonus Episodes', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ), array( 'name' => 'slides_per_view', 'label' => __( 'Slides Per View', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of trailer and bonus episode slides visible at the same time.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'space_between', 'label' => __( 'Space Between', 'aio-podcast-studio' ), 'description' => __( 'Enter the space between trailer and bonus episode slides (in pixels).', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_dots', 'label' => __( 'Show Dots', 'aio-podcast-studio' ), 'description' => __( 'Show pagination dots below the trailer and bonus episode sliders.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_arrows', 'label' => __( 'Show Arrows', 'aio-podcast-studio' ), 'description' => __( 'Show previous and next navigation arrows on the trailer and bonus episode sliders.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_participants', 'label' => __( 'Show Participants', 'aio-podcast-studio' ), 'description' => __( 'Show participants associated with this podcast on the single podcast page.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'participants_title', 'label' => __( 'Participants Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the participants section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Creators and Guests', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ) ), 'aiopod_episodes_settings' => array( array( 'name' => 'show_count', 'label' => __( 'Show Total Episodes', 'aio-podcast-studio' ), 'description' => __( 'Show the total number of episodes above the list.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'layout', 'label' => __( 'Select Layout', 'aio-podcast-studio' ), 'description' => __( 'Choose a layout for displaying episodes.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'grid' => __( 'Grid', 'aio-podcast-studio' ), 'list' => __( 'List', 'aio-podcast-studio' ), 'compact' => __( 'Compact', 'aio-podcast-studio' ), 'slider' => __( 'Slider', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'columns', 'label' => __( 'Columns', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of columns to display in the list.', 'aio-podcast-studio' ), 'type' => 'number', 'min' => 1, 'max' => 12, 'step' => 1, 'sanitize_callback' => 'intval' ), array( 'name' => 'slides_per_view', 'label' => __( 'Slides Per View', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of slides visible at the same time.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'space_between', 'label' => __( 'Space Between', 'aio-podcast-studio' ), 'description' => __( 'Enter the space between slides (in pixels).', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_dots', 'label' => __( 'Show Dots', 'aio-podcast-studio' ), 'description' => __( 'Show pagination dots below the slider.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_arrows', 'label' => __( 'Show Arrows', 'aio-podcast-studio' ), 'description' => __( 'Show previous and next navigation arrows.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'limit', 'label' => __( 'Limit (per page)', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of episodes to display per page. Leave blank for the default value (100).', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'orderby', 'label' => __( 'Order By', 'aio-podcast-studio' ), 'description' => __( 'Select how episodes are sorted.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'title' => __( 'Title', 'aio-podcast-studio' ), 'date' => __( 'Date Added', 'aio-podcast-studio' ), 'popularity' => __( 'Popularity (Plays + Downloads)', 'aio-podcast-studio' ), 'downloads' => __( 'Downloads', 'aio-podcast-studio' ), 'plays' => __( 'Plays', 'aio-podcast-studio' ), 'rand' => __( 'Random', 'aio-podcast-studio' ), 'menu_order' => __( 'Menu Order', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'order', 'label' => __( 'Order Direction', 'aio-podcast-studio' ), 'description' => __( 'Choose ascending or descending order.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'asc' => __( 'Ascending', 'aio-podcast-studio' ), 'desc' => __( 'Descending', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'display_options', 'label' => __( 'Episode Details', 'aio-podcast-studio' ), 'description' => __( 'Select which details to display for each episode in the list.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'episode_title' => __( 'Episode Title', 'aio-podcast-studio' ), 'episode_excerpt' => __( 'Episode Description (Excerpt)', 'aio-podcast-studio' ), 'episode_date' => __( 'Episode Date', 'aio-podcast-studio' ), 'podcast_title' => __( 'Podcast Title', 'aio-podcast-studio' ), 'episode_tags' => __( 'Episode Tags', 'aio-podcast-studio' ), 'episode_type' => __( 'Episode Type (Trailer / Bonus)', 'aio-podcast-studio' ), 'season_number' => __( 'Season Number', 'aio-podcast-studio' ), 'episode_number' => __( 'Episode Number', 'aio-podcast-studio' ), 'episode_file_size' => __( 'Episode File Size', 'aio-podcast-studio' ), 'episode_duration' => __( 'Episode Duration', 'aio-podcast-studio' ), 'explicit_badge' => __( 'Explicit Badge', 'aio-podcast-studio' ), 'downloads_count' => __( 'Downloads Count', 'aio-podcast-studio' ), 'plays_count' => __( 'Plays Count', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'excerpt_length', 'label' => __( 'Excerpt Length', 'aio-podcast-studio' ), 'description' => __( 'Set the maximum number of characters for episode descriptions. Enter 0 to display the full description.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'max_height', 'label' => __( 'Maximum List Height', 'aio-podcast-studio' ), 'description' => __( 'Set the maximum height (in pixels) for the episode list container. If the content exceeds this height, a scrollbar will appear. Leave empty to display the full content.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'enable_player', 'label' => __( 'Enable Player', 'aio-podcast-studio' ), 'description' => sprintf( __( 'Enable direct playback on episode lists. Otherwise, episodes link to their single episode page. Configure player settings under Player. The player is always enabled for the Compact layout.', 'aio-podcast-studio' ), esc_url( admin_url( 'admin.php?page=aiopod_settings&tab=display§ion=aiopod_player_settings' ) ) ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'enable_filters', 'label' => __( 'Enable Filters', 'aio-podcast-studio' ), 'description' => __( 'Show episode filters on episode lists. Configure filter settings under "Episodes Filters".', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'scroll_offset', 'label' => __( 'Page Scroll Top Offset', 'aio-podcast-studio' ), 'description' => __( 'Set the top offset (in pixels) for scrolling to the player after selecting an episode. Requires "Enable Player" to be enabled. Leave empty to disable automatic scrolling.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'pagination', 'label' => __( 'Pagination Type', 'aio-podcast-studio' ), 'description' => __( 'Choose the pagination style: None, Numeric, or More Button (Ajax).', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( '' => '— ' . __( 'Use Global Setting', 'aio-podcast-studio' ) . ' —' , 'none' => __( 'None', 'aio-podcast-studio' ), 'numeric' => __( 'Numeric Pagination', 'aio-podcast-studio' ), 'loadmore' => __( 'More Button (Ajax)', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ) ), 'aiopod_filters_settings' => array( array( 'name' => 'display_options', 'label' => __( 'Filter Options', 'aio-podcast-studio' ), 'description' => __( 'Select which filter options should be enabled in the episodes list.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'keyword' => __( 'Filter by Episode Title & Description', 'aio-podcast-studio' ), 'tags' => __( 'Filter by Tags', 'aio-podcast-studio' ), 'season' => __( 'Filter by Season Number', 'aio-podcast-studio' ), 'sort' => __( 'Enable Sort Dropdown', 'aio-podcast-studio' ), 'reset' => __( 'Show Reset Button', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'layout', 'label' => __( 'Filters Layout', 'aio-podcast-studio' ), 'description' => __( 'Choose how filters are displayed: vertically (stacked) or horizontally (inline).', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'vertical' => __( 'Vertical', 'aio-podcast-studio' ), 'horizontal' => __( 'Horizontal', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'mode', 'label' => __( 'Filters Behavior', 'aio-podcast-studio' ), 'description' => __( 'Choose how filters behave when visitors interact with them.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'live' => __( 'Live - Update instantly', 'aio-podcast-studio' ), 'ajax' => __( 'Ajax - Update instantly without page reload', 'aio-podcast-studio' ), 'search' => __( 'Search - Update on button click', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ) ), 'aiopod_episode_settings' => array( array( 'name' => 'show_related_episodes', 'label' => __( 'Show Related Episodes', 'aio-podcast-studio' ), 'description' => __( 'Show related episodes on the single episode page.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'related_episodes_title', 'label' => __( 'Related Episodes Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the related episodes section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Related Episodes', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ), array( 'name' => 'show_participants', 'label' => __( 'Show Participants', 'aio-podcast-studio' ), 'description' => __( 'Show participants associated with this episode on the single episode page.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'participants_title', 'label' => __( 'Participants Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the participants section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Creators and Guests', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ), array( 'name' => 'comments', 'label' => __( 'Comments', 'aio-podcast-studio' ), 'description' => __( 'Choose how comments are handled on episode pages.', 'aio-podcast-studio' ), 'type' => 'radio', 'options' => array( 'inherit' => __( 'Use episode-level comment settings', 'aio-podcast-studio' ), 'open' => __( 'Enable comments on all episode pages', 'aio-podcast-studio' ), 'closed' => __( 'Disable comments on all episode pages', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ) ), 'aiopod_related_episodes_settings' => array( array( 'name' => 'columns', 'label' => __( 'Columns', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of columns to display in the related episodes list.', 'aio-podcast-studio' ), 'type' => 'number', 'min' => 1, 'max' => 12, 'step' => 1, 'sanitize_callback' => 'intval' ), array( 'name' => 'limit', 'label' => __( 'Limit (per page)', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of related episodes to display per page. Leave blank for the default value (100).', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'orderby', 'label' => __( 'Order By', 'aio-podcast-studio' ), 'description' => __( 'Select how related episodes are sorted.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'title' => __( 'Title', 'aio-podcast-studio' ), 'date' => __( 'Date Added', 'aio-podcast-studio' ), 'popularity' => __( 'Popularity (Plays + Downloads)', 'aio-podcast-studio' ), 'downloads' => __( 'Downloads', 'aio-podcast-studio' ), 'plays' => __( 'Plays', 'aio-podcast-studio' ), 'rand' => __( 'Random', 'aio-podcast-studio' ), 'menu_order' => __( 'Menu Order', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'order', 'label' => __( 'Order Direction', 'aio-podcast-studio' ), 'description' => __( 'Choose ascending or descending order.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'asc' => __( 'Ascending', 'aio-podcast-studio' ), 'desc' => __( 'Descending', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'display_options', 'label' => __( 'Episode Details', 'aio-podcast-studio' ), 'description' => __( 'Select which details to display for each related episode.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'episode_title' => __( 'Episode Title', 'aio-podcast-studio' ), 'episode_excerpt' => __( 'Episode Description (Excerpt)', 'aio-podcast-studio' ), 'episode_date' => __( 'Episode Date', 'aio-podcast-studio' ), 'podcast_title' => __( 'Podcast Title', 'aio-podcast-studio' ), 'episode_tags' => __( 'Episode Tags', 'aio-podcast-studio' ), 'episode_type' => __( 'Episode Type (Trailer / Bonus)', 'aio-podcast-studio' ), 'season_number' => __( 'Season Number', 'aio-podcast-studio' ), 'episode_number' => __( 'Episode Number', 'aio-podcast-studio' ), 'episode_file_size' => __( 'Episode File Size', 'aio-podcast-studio' ), 'episode_duration' => __( 'Episode Duration', 'aio-podcast-studio' ), 'explicit_badge' => __( 'Explicit Badge', 'aio-podcast-studio' ), 'downloads_count' => __( 'Downloads Count', 'aio-podcast-studio' ), 'plays_count' => __( 'Plays Count', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'excerpt_length', 'label' => __( 'Excerpt Length', 'aio-podcast-studio' ), 'description' => __( 'Set the maximum number of characters for related episode descriptions. Enter 0 to display the full description.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'enable_filters', 'label' => __( 'Enable Filters', 'aio-podcast-studio' ), 'description' => __( 'Show episode filters on related episode lists. Configure filter settings under "Episodes Filters".', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'pagination', 'label' => __( 'Pagination Type', 'aio-podcast-studio' ), 'description' => __( 'Choose the pagination style: None, Numeric, or More Button (Ajax).', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( '' => '— ' . __( 'Use Global Setting', 'aio-podcast-studio' ) . ' —' , 'none' => __( 'None', 'aio-podcast-studio' ), 'numeric' => __( 'Numeric Pagination', 'aio-podcast-studio' ), 'loadmore' => __( 'More Button (Ajax)', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ) ), 'aiopod_categories_settings' => array( array( 'name' => 'layout', 'label' => __( 'Select Layout', 'aio-podcast-studio' ), 'description' => __( 'Choose a layout to display categories.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'grid' => __( 'Grid', 'aio-podcast-studio' ), 'list' => __( 'List', 'aio-podcast-studio' ), 'dropdown' => __( 'Dropdown', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'columns', 'label' => __( 'Columns', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of columns to display in the list.', 'aio-podcast-studio' ), 'type' => 'number', 'min' => 1, 'max' => 12, 'step' => 1, 'sanitize_callback' => 'intval' ), array( 'name' => 'limit', 'label' => __( 'Limit (per page)', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of categories to display per page. Leave blank to show all.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'orderby', 'label' => __( 'Order By', 'aio-podcast-studio' ), 'description' => __( 'Select how categories are sorted.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'id' => __( 'ID', 'aio-podcast-studio' ), 'count' => __( 'Count', 'aio-podcast-studio' ), 'name' => __( 'Name', 'aio-podcast-studio' ), 'slug' => __( 'Slug', 'aio-podcast-studio' ), 'menu_order' => __( 'Menu Order', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'order', 'label' => __( 'Order Direction', 'aio-podcast-studio' ), 'description' => __( 'Choose ascending or descending order.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'asc' => __( 'Ascending', 'aio-podcast-studio' ), 'desc' => __( 'Descending', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'hierarchical', 'label' => __( 'Show Hierarchy', 'aio-podcast-studio' ), 'description' => __( 'Show subcategories under their parent categories.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_name', 'label' => __( 'Show Name', 'aio-podcast-studio' ), 'description' => __( 'Show category name.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_description', 'label' => __( 'Show Description', 'aio-podcast-studio' ), 'description' => __( 'Show category descriptions.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_count', 'label' => __( 'Show Podcasts Count', 'aio-podcast-studio' ), 'description' => __( 'Show the number of podcasts in each category.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'hide_empty', 'label' => __( 'Hide Empty Categories', 'aio-podcast-studio' ), 'description' => __( 'Hide categories that do not contain any podcasts.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'pagination', 'label' => __( 'Pagination Type', 'aio-podcast-studio' ), 'description' => __( 'Choose the pagination style: None, Numeric, or More Button (Ajax).', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( '' => '— ' . __( 'Use Global Setting', 'aio-podcast-studio' ) . ' —' , 'none' => __( 'None', 'aio-podcast-studio' ), 'numeric' => __( 'Numeric Pagination', 'aio-podcast-studio' ), 'loadmore' => __( 'More Button (Ajax)', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ) ), 'aiopod_category_settings' => array( array( 'name' => 'show_breadcrumbs', 'label' => __( 'Show Breadcrumbs', 'aio-podcast-studio' ), 'description' => __( 'Show breadcrumb navigation on the single category page.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_subcategories', 'label' => __( 'Show Subcategories', 'aio-podcast-studio' ), 'description' => __( 'Show subcategories on the single category page.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'subcategories_title', 'label' => __( 'Subcategories Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the subcategories section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Subcategories', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ), array( 'name' => 'subcategories_position', 'label' => __( 'Subcategories Position', 'aio-podcast-studio' ), 'description' => __( 'Choose whether subcategories are displayed before or after the podcasts list on the single category page.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'before_podcasts' => __( 'Before Podcasts', 'aio-podcast-studio' ), 'after_podcasts' => __( 'After Podcasts', 'aio-podcast-studio' ), ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'show_podcasts', 'label' => __( 'Show Podcasts', 'aio-podcast-studio' ), 'description' => sprintf( __( 'Show podcasts associated with this category on the single category page. Podcast layout and ordering are managed in Podcasts Settings → Podcasts List.', 'aio-podcast-studio' ), esc_url( admin_url( 'admin.php?page=aiopod_settings&tab=display§ion=aiopod_podcasts_settings' ) ) ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'podcasts_title', 'label' => __( 'Podcasts Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the podcasts section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Podcasts', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ) ), 'aiopod_tags_settings' => array( array( 'name' => 'layout', 'label' => __( 'Select Layout', 'aio-podcast-studio' ), 'description' => __( 'Choose a layout to display tags.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'cloud' => __( 'Tag Cloud', 'aio-podcast-studio' ), 'list' => __( 'List', 'aio-podcast-studio' ), 'dropdown' => __( 'Dropdown', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'orderby', 'label' => __( 'Order By', 'aio-podcast-studio' ), 'description' => __( 'Select how tags are sorted.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'id' => __( 'ID', 'aio-podcast-studio' ), 'count' => __( 'Count', 'aio-podcast-studio' ), 'name' => __( 'Name', 'aio-podcast-studio' ), 'slug' => __( 'Slug', 'aio-podcast-studio' ), 'menu_order' => __( 'Menu Order', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'order', 'label' => __( 'Order Direction', 'aio-podcast-studio' ), 'description' => __( 'Choose ascending or descending order.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'asc' => __( 'Ascending', 'aio-podcast-studio' ), 'desc' => __( 'Descending', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'show_count', 'label' => __( 'Show Episodes Count', 'aio-podcast-studio' ), 'description' => __( 'Tag counts use WordPress defaults and may include trailers and bonus episodes. Episode listings display only full episodes. Disable counts if you tag trailers or bonus episodes.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'hide_empty', 'label' => __( 'Hide Empty Tags', 'aio-podcast-studio' ), 'description' => __( 'Hide tags that do not contain any episodes.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ) ), 'aiopod_tag_settings' => array( array( 'name' => 'show_breadcrumbs', 'label' => __( 'Show Breadcrumbs', 'aio-podcast-studio' ), 'description' => __( 'Show breadcrumb navigation on the single tag page.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_episodes', 'label' => __( 'Show Episodes', 'aio-podcast-studio' ), 'description' => sprintf( __( 'Show episodes associated with this tag on the single tag page. Episode layout and ordering are managed in Episodes Settings → Episodes List.', 'aio-podcast-studio' ), esc_url( admin_url( 'admin.php?page=aiopod_settings&tab=display§ion=aiopod_episodes_settings' ) ) ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'episodes_title', 'label' => __( 'Episodes Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the episodes section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Episodes', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ) ), 'aiopod_participants_settings' => array( array( 'name' => 'show_count', 'label' => __( 'Show Total Participants', 'aio-podcast-studio' ), 'description' => __( 'Show the total number of participants above the list.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'columns', 'label' => __( 'Columns', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of columns to display in the list.', 'aio-podcast-studio' ), 'type' => 'number', 'min' => 1, 'max' => 12, 'step' => 1, 'sanitize_callback' => 'intval' ), array( 'name' => 'limit', 'label' => __( 'Limit (per page)', 'aio-podcast-studio' ), 'description' => __( 'Enter the number of participants to display per page. Leave blank to show all.', 'aio-podcast-studio' ), 'type' => 'number', 'sanitize_callback' => 'intval' ), array( 'name' => 'orderby', 'label' => __( 'Order By', 'aio-podcast-studio' ), 'description' => __( 'Select how participants are sorted.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'id' => __( 'ID', 'aio-podcast-studio' ), 'count' => __( 'Count', 'aio-podcast-studio' ), 'name' => __( 'Name', 'aio-podcast-studio' ), 'slug' => __( 'Slug', 'aio-podcast-studio' ), 'menu_order' => __( 'Menu Order', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'order', 'label' => __( 'Order Direction', 'aio-podcast-studio' ), 'description' => __( 'Choose ascending or descending order.', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( 'asc' => __( 'Ascending', 'aio-podcast-studio' ), 'desc' => __( 'Descending', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ), array( 'name' => 'display_options', 'label' => __( 'Participant Details', 'aio-podcast-studio' ), 'description' => __( 'Select which details to display for each participant.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'name' => __( 'Participant Name', 'aio-podcast-studio' ), 'description' => __( 'Description (Biography)', 'aio-podcast-studio' ), 'job_title' => __( 'Job Title', 'aio-podcast-studio' ), 'company_name' => __( 'Company Name', 'aio-podcast-studio' ), 'website_url' => __( 'Website URL', 'aio-podcast-studio' ), 'podcasts_count' => __( 'Podcasts Count', 'aio-podcast-studio' ), 'episodes_count' => __( 'Episodes Count', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'pagination', 'label' => __( 'Pagination Type', 'aio-podcast-studio' ), 'description' => __( 'Choose the pagination style: None, Numeric, or More Button (Ajax).', 'aio-podcast-studio' ), 'type' => 'select', 'options' => array( '' => '— ' . __( 'Use Global Setting', 'aio-podcast-studio' ) . ' —' , 'none' => __( 'None', 'aio-podcast-studio' ), 'numeric' => __( 'Numeric Pagination', 'aio-podcast-studio' ), 'loadmore' => __( 'More Button (Ajax)', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'sanitize_key' ) ), 'aiopod_participant_settings' => array( array( 'name' => 'show_breadcrumbs', 'label' => __( 'Show Breadcrumbs', 'aio-podcast-studio' ), 'description' => __( 'Show breadcrumb navigation on the single participant page.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'display_metadata', 'label' => __( 'Participant Metadata', 'aio-podcast-studio' ), 'description' => __( 'Select which participant details to display in the header area.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'job_title' => __( 'Job Title', 'aio-podcast-studio' ), 'company_name' => __( 'Company Name', 'aio-podcast-studio' ), 'website_url' => __( 'Website URL', 'aio-podcast-studio' ), 'podcasts_count' => __( 'Podcasts Count', 'aio-podcast-studio' ), 'episodes_count' => __( 'Episodes Count', 'aio-podcast-studio' ), ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'show_follow_buttons', 'label' => __( 'Show Follow Us Buttons', 'aio-podcast-studio' ), 'description' => __( 'Show social follow buttons for the participant.', 'aio-podcast-studio' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'show_podcasts', 'label' => __( 'Show Podcasts', 'aio-podcast-studio' ), 'description' => sprintf( __( 'Show podcasts associated with this participant on the single participant page. Podcast layout and ordering are managed in Podcasts Settings → Podcasts List.', 'aio-podcast-studio' ), esc_url( admin_url( 'admin.php?page=aiopod_settings&tab=display§ion=aiopod_podcasts_settings' ) ) ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'podcasts_title', 'label' => __( 'Podcasts Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the podcasts section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Podcasts', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ), array( 'name' => 'show_episodes', 'label' => __( 'Show Episodes', 'aio-podcast-studio' ), 'description' => sprintf( __( 'Show episodes associated with this participant on the single participant page. Episode layout and ordering are managed in Episodes Settings → Episodes List.', 'aio-podcast-studio' ), esc_url( admin_url( 'admin.php?page=aiopod_settings&tab=display§ion=aiopod_episodes_settings' ) ) ), 'type' => 'checkbox', 'sanitize_callback' => 'intval' ), array( 'name' => 'episodes_title', 'label' => __( 'Episodes Title', 'aio-podcast-studio' ), 'description' => __( 'Enter the title displayed above the episodes section.', 'aio-podcast-studio' ), 'placeholder' => __( 'Episodes', 'aio-podcast-studio' ), 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ) ), 'aiopod_seo_settings' => array( array( 'name' => 'open_graph_tags', 'label' => __( 'Open Graph Tags', 'aio-podcast-studio' ), 'description' => __( 'Enable Open Graph meta tags and Twitter Cards on the selected pages.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'podcast' => __( 'Single Podcast Page', 'aio-podcast-studio' ), 'episode' => __( 'Single Episode Page', 'aio-podcast-studio' ), 'category' => __( 'Single Category Page', 'aio-podcast-studio' ), 'tag' => __( 'Single Tag Page', 'aio-podcast-studio' ), 'participant' => __( 'Single Participant Page', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ), array( 'name' => 'twitter_username', 'label' => __( 'Twitter / X Username', 'aio-podcast-studio' ), 'description' => __( 'Enter the Twitter / X @username to associate with shared content. Required for Twitter / X Card attribution.', 'aio-podcast-studio' ), 'placeholder' => '@username', 'type' => 'text', 'sanitize_callback' => 'sanitize_text_field' ) ), 'aiopod_share_buttons_settings' => array( array( 'name' => 'buttons', 'label' => __( 'Show Buttons', 'aio-podcast-studio' ), 'description' => __( 'Select the social platforms to display as share buttons for podcasts and episodes.', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'facebook' => __( 'Facebook', 'aio-podcast-studio' ), 'twitter' => __( 'Twitter / X', 'aio-podcast-studio' ), 'linkedin' => __( 'LinkedIn', 'aio-podcast-studio' ), 'pinterest' => __( 'Pinterest', 'aio-podcast-studio' ), 'tumblr' => __( 'Tumblr', 'aio-podcast-studio' ), 'whatsapp' => __( 'WhatsApp', 'aio-podcast-studio' ), 'email' => __( 'Email', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ) ), 'aiopod_privacy_settings' => array( array( 'name' => 'disable_cookies', 'label' => __( 'Disable Plugin Cookies', 'aio-podcast-studio' ), 'type' => 'multicheck', 'options' => array( 'aiopod_rand_seed' => __( 'aiopod_rand_seed - Used to maintain consistent random sorting when pagination is enabled.', 'aio-podcast-studio' ) ), 'sanitize_callback' => 'aiopod_sanitize_array' ) ) ); return apply_filters( 'aiopod_settings_fields', $fields ); } /** * Initialize and registers the settings sections and fields to WordPress. * * @since 1.0.0 */ public function initialize_settings() { // Register settings sections & fields foreach ( $this->sections as $section ) { $page_hook = isset( $section['page'] ) ? $section['page'] : $section['id']; // Sections if ( false === get_option( $section['id'] ) ) { add_option( $section['id'] ); } if ( isset( $section['description'] ) && ! empty( $section['description'] ) ) { $callback = array( $this, 'settings_section_callback' ); } elseif ( isset( $section['callback'] ) ) { $callback = $section['callback']; } else { $callback = null; } add_settings_section( $section['id'], $section['title'], $callback, $page_hook ); // Fields $fields = $this->fields[ $section['id'] ]; foreach ( $fields as $option ) { $name = $option['name']; $type = isset( $option['type'] ) ? $option['type'] : 'text'; $label = isset( $option['label'] ) ? $option['label'] : ''; $callback = isset( $option['callback'] ) ? $option['callback'] : array( $this, 'callback_' . $type ); $args = array( 'id' => $name, 'class' => isset( $option['class'] ) ? $option['class'] : $name, 'label_for' => "{$section['id']}[{$name}]", 'description' => isset( $option['description'] ) ? $option['description'] : '', 'name' => $label, 'section' => $section['id'], 'size' => isset( $option['size'] ) ? $option['size'] : null, 'options' => isset( $option['options'] ) ? $option['options'] : '', 'sanitize_callback' => isset( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : '', 'type' => $type, 'placeholder' => isset( $option['placeholder'] ) ? $option['placeholder'] : '', 'min' => isset( $option['min'] ) ? $option['min'] : '', 'max' => isset( $option['max'] ) ? $option['max'] : '', 'step' => isset( $option['step'] ) ? $option['step'] : '' ); add_settings_field( "{$section['id']}[{$name}]", $label, $callback, $page_hook, $section['id'], $args ); } // Creates our settings in the options table register_setting( $page_hook, $section['id'], array( $this, 'sanitize_options' ) ); } } /** * Displays a section description. * * @since 1.0.0 * @param array $args Settings section args. */ public function settings_section_callback( $args ) { foreach ( $this->sections as $section ) { if ( $section['id'] == $args['id'] ) { printf( '
%s
', $section['description'] ); break; } } } /** * Displays a text field for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_text( $args ) { $value = esc_attr( $this->get_option( $args['id'], $args['section'], '' ) ); $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; $type = isset( $args['type'] ) ? $args['type'] : 'text'; $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . esc_attr( $args['placeholder'] ) . '"'; $html = sprintf( '', esc_attr( $type ), esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), $value, $placeholder ); $html .= $this->get_field_description( $args ); echo $html; } /** * Displays a url field for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_url( $args ) { $this->callback_text( $args ); } /** * Displays a number field for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_number( $args ) { $value = esc_attr( $this->get_option( $args['id'], $args['section'], 0 ) ); $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; $type = isset( $args['type'] ) ? $args['type'] : 'number'; $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . esc_attr( $args['placeholder'] ) . '"'; $min = empty( $args['min'] ) ? '' : ' min="' . esc_attr( $args['min'] ) . '"'; $max = empty( $args['max'] ) ? '' : ' max="' . esc_attr( $args['max'] ) . '"'; $step = empty( $args['max'] ) ? '' : ' step="' . esc_attr( $args['step'] ) . '"'; $html = sprintf( '', esc_attr( $type ), esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), $value, $placeholder, $min, $max, $step ); $html .= $this->get_field_description( $args ); echo $html; } /** * Displays a checkbox for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_checkbox( $args ) { $value = esc_attr( $this->get_option( $args['id'], $args['section'], 0 ) ); $html = '
'; $html .= sprintf( '', wp_kses_post( $args['description'] ) ); $html .= '
'; echo $html; } /** * Displays a multicheckbox for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_multicheck( $args ) { $value = $this->get_option( $args['id'], $args['section'], array() ); $html = '
'; $html .= sprintf( '', esc_attr( $args['section'] ), esc_attr( $args['id'] ) ); foreach ( $args['options'] as $key => $label ) { $checked = in_array( $key, $value ) ? 'checked="checked"' : ''; $html .= sprintf( '
', wp_kses( $label, array( 'em' => array(), 'strong' => array(), 'code' => array() ) ) ); } $html .= '
'; $html .= $this->get_field_description( $args ); echo $html; } /** * Displays a radio button for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_radio( $args ) { $value = $this->get_option( $args['id'], $args['section'], '' ); $html = '
'; foreach ( $args['options'] as $key => $label ) { $html .= sprintf( '
', wp_kses( $label, array( 'em' => array(), 'strong' => array(), 'code' => array() ) ) ); } $html .= $this->get_field_description( $args ); $html .= '
'; echo $html; } /** * Displays a selectbox for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_select( $args ) { $value = esc_attr( $this->get_option( $args['id'], $args['section'], '' ) ); $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; $html = sprintf( '' ); $html .= $this->get_field_description( $args ); echo $html; } /** * Displays a textarea for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_textarea( $args ) { $value = esc_textarea( $this->get_option( $args['id'], $args['section'], '' ) ); $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; $placeholder = empty( $args['placeholder'] ) ? '' : ' placeholder="' . esc_attr( $args['placeholder'] ) . '"'; $html = sprintf( '', esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), $placeholder, $value ); $html .= $this->get_field_description( $args ); echo $html; } /** * Displays the html for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_html( $args ) { echo $this->get_field_description( $args ); } /** * Displays a rich text textarea for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_wysiwyg( $args ) { $value = $this->get_option( $args['id'], $args['section'], '' ); $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : '500px'; echo '
'; $editor_settings = array( 'teeny' => true, 'textarea_name' => $args['section'] . '[' . $args['id'] . ']', 'textarea_rows' => 10 ); if ( isset( $args['options'] ) && is_array( $args['options'] ) ) { $editor_settings = array_merge( $editor_settings, $args['options'] ); } wp_editor( $value, $args['section'] . '-' . $args['id'], $editor_settings ); echo '
'; echo $this->get_field_description( $args ); } /** * Displays a file upload field for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_file( $args ) { $value = esc_attr( $this->get_option( $args['id'], $args['section'], '' ) ); $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; $id = $args['section'] . '[' . $args['id'] . ']'; $label = isset( $args['options']['button_label'] ) ? $args['options']['button_label'] : __( 'Choose File', 'aio-podcast-studio' ); $html = '
'; $html .= sprintf( '', esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), $value ); $html .= ''; $html .= '
'; $html .= $this->get_field_description( $args ); echo $html; } /** * Displays a password field for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_password( $args ) { $value = esc_attr( $this->get_option( $args['id'], $args['section'], '' ) ); $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; $html = sprintf( '', esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), $value ); $html .= $this->get_field_description( $args ); echo $html; } /** * Displays a color picker field for a settings field. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_color( $args ) { $value = esc_attr( $this->get_option( $args['id'], $args['section'], '#ffffff' ) ); $size = isset( $args['size'] ) && ! is_null( $args['size'] ) ? $args['size'] : 'regular'; $html = sprintf( '', esc_attr( $size ), esc_attr( $args['section'] ), esc_attr( $args['id'] ), $value, '#ffffff' ); $html .= $this->get_field_description( $args ); echo $html; } /** * Displays a select box for creating the pages select box. * * @since 1.0.0 * @param array $args Settings field args. */ public function callback_pages( $args ) { $dropdown_args = array( 'show_option_none' => '— ' . __( 'Select a page', 'aio-podcast-studio' ) . ' —', 'option_none_value' => 0, 'selected' => esc_attr( $this->get_option( $args['id'], $args['section'], -1 ) ), 'name' => $args['section'] . '[' . $args['id'] . ']', 'id' => $args['section'] . '[' . $args['id'] . ']', 'echo' => 0 ); $html = wp_dropdown_pages( $dropdown_args ); $html .= $this->get_field_description( $args ); echo $html; } /** * Get field description for display. * * @since 1.0.0 * @param array $args Settings field args. */ public function get_field_description( $args ) { if ( ! empty( $args['description'] ) ) { $description = sprintf( '

%s

', wp_kses_post( $args['description'] ) ); } else { $description = ''; } return $description; } /** * Sanitize callback for Settings API. * * @since 1.0.0 * @param array $options The unsanitized collection of options. * @return The collection of sanitized values. */ public function sanitize_options( $options ) { if ( ! $options ) { return $options; } foreach ( $options as $option_slug => $option_value ) { $sanitize_callback = $this->get_sanitize_callback( $option_slug ); // If callback is set, call it if ( $sanitize_callback ) { $options[ $option_slug ] = call_user_func( $sanitize_callback, $option_value ); continue; } } return $options; } /** * Get sanitization callback for given option slug. * * @since 1.0.0 * @param string $slug Option slug. * @return mixed String or bool false. */ public function get_sanitize_callback( $slug = '' ) { if ( empty( $slug ) ) { return false; } // Iterate over registered fields and see if we can find proper callback foreach ( $this->fields as $section => $options ) { foreach ( $options as $option ) { if ( $option['name'] != $slug ) { continue; } // Return the callback name return isset( $option['sanitize_callback'] ) && is_callable( $option['sanitize_callback'] ) ? $option['sanitize_callback'] : false; } } return false; } /** * Get the value of a settings field. * * @since 1.0.0 * @param string $option Settings field name. * @param string $section The section name this field belongs to. * @param string $default Default text if it's not found. * @return string */ public function get_option( $option, $section, $default = '' ) { $options = get_option( $section ); if ( ! empty( $options[ $option ] ) ) { return $options[ $option ]; } return $default; } }