diff --git a/src/admin/layout/class-engine.php b/src/admin/layout/class-engine.php index a4e20cb..5aa289b 100644 --- a/src/admin/layout/class-engine.php +++ b/src/admin/layout/class-engine.php @@ -99,18 +99,21 @@ abstract class Engine { * * @since 1.5.0 */ - public function register_sections(): void { - foreach ( $this->get_sections() as $section ) { + public function add_settings_sections(): void { + $this->sections[Includes\Settings::instance()->general_settings->get_section_slug()] = Includes\Settings::instance()->general_settings; + + /*foreach ( $this->get_sections() as $section ) { // Append tab to the tab-array. $this->sections[ $section['id'] ] = $section; add_settings_section( $section['id'], '', fn() => $this->description(), - $section['id'] + 'footnotes' ); - $this->register_meta_boxes( $section['id'] ); - } + $this->add_settings_fields(); + //$this->register_meta_boxes( $section['id'] ); + }*/ } // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing /** @@ -120,7 +123,68 @@ abstract class Engine { * @todo Review nonce verification. */ public function display_content(): void { - $this->append_scripts(); + // check user capabilities + if ( ! current_user_can( 'manage_options' ) ) { + return; + } + + $active_section_id = isset( $_GET['t'] ) ? wp_unslash( $_GET['t'] ) : array_key_first( $this->sections ); + $active_section = $this->sections[ $active_section_id ]; + + ?> +
+

+ + +
+ "; + //print_r($wp_settings_sections); + /*$section = (array) $wp_settings_sections['footnotes']; + print_r($section); + print_r($section['title']); + print_r(!isset($wp_settings_fields)); + print_r(!isset($wp_settings_fields[ 'footnotes' ])); + print_r(!isset($wp_settings_fields[ 'footnotes' ][ $section['id'] ]));*/ + echo ""; + + // output setting sections and their fields + // (sections are registered for "footnotes", each field is registered to a specific section) + do_settings_sections( 'footnotes' ); + + //do_meta_boxes( $active_section['id'], 'main', null ); + + // output save settings button + submit_button( 'Save Settings' ); + ?> +
+
+ append_scripts(); $active_section_id = isset( $_GET['t'] ) ? wp_unslash( $_GET['t'] ) : array_key_first( $this->sections ); $active_section = $this->sections[ $active_section_id ]; @@ -163,16 +227,7 @@ abstract class Engine { submit_button(); } echo ''; - echo ''; - - // Echo JavaScript for the expand/collapse function of the meta boxes. - echo ''; + echo '';*/ } // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing /** @@ -182,7 +237,7 @@ abstract class Engine { * @todo Required? Should be `abstract`? */ public function description(): void { - // Default no description will be displayed. + // Nothing yet. } /** @@ -224,6 +279,9 @@ abstract class Engine { * @since 1.5.0 */ abstract protected function get_meta_boxes(): array; + + + abstract protected function add_settings_fields(): void; /** * Returns an array describing a sub-page section. @@ -368,21 +426,32 @@ abstract class Engine { */ protected function add_text_box( string $setting_name, int $max_length = 999, bool $readonly = false, bool $hidden = false ): string { $style = ''; - // Collect data for given settings field. - $data = $this->load_setting( $setting_name ); if ( $hidden ) { $style .= 'display:none;'; } return sprintf( '', - $data['name'], - $data['id'], + $setting_name, + $setting_name, $max_length, $style, - $data['value'], + get_option($setting_name), $readonly ? 'readonly="readonly"' : '' ); } + public function new_add_text_box( array $args ): void { + extract( $args ); + + echo ( sprintf( + '', + $name, + $name, + $max_length ?? 999, + $style ?? '', + $value, + isset($readonly) ? 'readonly="readonly"' : '' + ) ); + } /** * Constructs the HTML for a checkbox 'input' element. @@ -438,7 +507,32 @@ abstract class Engine { $select_options ); } + public function new_add_select_box( array $args ): void { + $select_options = ''; + $setting_value = ( !isset( $options[$args['name']] ) ) + ? null : $options[$args['name']]; + // Loop through all array keys. + foreach ( $args['options'] as $option_value => $caption ) { + $select_options .= sprintf( + '', + $option_value, + // Only check for equality, not identity, WRT backlink symbol arrows. + // phpcs:disable WordPress.PHP.StrictComparisons.LooseComparison + $option_value == $setting_value ? 'selected' : '', + // phpcs:enable WordPress.PHP.StrictComparisons.LooseComparison + $caption + ); + } + + echo ( sprintf( + '', + $args['name'], + $args['name'], + $select_options + ) ); + } + /** * Constructs the HTML for a 'textarea' element. * diff --git a/src/admin/layout/class-init.php b/src/admin/layout/class-init.php index 6a54e9e..08a0dee 100644 --- a/src/admin/layout/class-init.php +++ b/src/admin/layout/class-init.php @@ -93,7 +93,10 @@ class Init { */ public function initialize_settings(): void { Includes\Settings::instance()->register_settings(); - $this->settings->register_sections(); + + Includes\Settings::instance()->general_settings->add_settings_section(); + $this->settings->add_settings_sections(); + $this->settings->add_settings_fields(); } /** @@ -103,8 +106,7 @@ class Init { * @see http://codex.wordpress.org/Function_Reference/add_menu_page */ public function register_options_submenu(): void { - add_submenu_page( - 'options-general.php', + add_options_page( 'footnotes Settings', \footnotes\includes\Config::PLUGIN_PUBLIC_NAME, 'manage_options', diff --git a/src/admin/layout/class-settings.php b/src/admin/layout/class-settings.php index 61905a1..8b04d95 100644 --- a/src/admin/layout/class-settings.php +++ b/src/admin/layout/class-settings.php @@ -17,6 +17,8 @@ declare(strict_types=1); namespace footnotes\admin\layout; +require_once plugin_dir_path( dirname( __FILE__, 2 ) ) . 'includes/class-settings.php'; + use footnotes\includes as Includes; use footnotes\general as General; @@ -56,6 +58,165 @@ class Settings extends Engine { public function get_priority(): int { return 10; } + + public function add_settings_fields(): void { + $active_section_id = isset( $_GET['t'] ) ? wp_unslash( $_GET['t'] ) : array_key_first( $this->sections ); + $active_section = $this->sections[ $active_section_id ]; + + switch ($active_section->get_section_slug()) { + case 'footnotes-settings': + $this->add_general_settings_fields(); + break; + case 'footnotes-customize': + $this->add_customize_settings_fields(); + break; + case 'footnotes-expert': + $this->add_expert_settings_fields(); + break; + case 'footnotes-customcss': + $this->add_customcss_settings_fields(); + break; + case 'footnotes-how-to': + print_r("Demo goes here"); + break; + default: print_r("ERR: section not found"); + } + } + + public function add_general_settings_fields(): void { + // Options for the label element. + $label_element_options = array( + 'p' => __( 'paragraph', 'footnotes' ), + 'h2' => __( 'heading 2', 'footnotes' ), + 'h3' => __( 'heading 3', 'footnotes' ), + 'h4' => __( 'heading 4', 'footnotes' ), + 'h5' => __( 'heading 5', 'footnotes' ), + 'h6' => __( 'heading 6', 'footnotes' ), + ); + // Options for the positioning of the reference container. + $positions_options = array( + 'post_end' => __( 'at the end of the post', 'footnotes' ), + 'widget' => __( 'in the widget area', 'footnotes' ), + 'footer' => __( 'in the footer', 'footnotes' ), + ); + // Basic responsive page layout options. + $page_layout_options = array( + 'none' => __( 'No', 'footnotes' ), + 'reference-container' => __( 'to the reference container exclusively', 'footnotes' ), + 'entry-content' => __( 'to the div element starting below the post title', 'footnotes' ), + 'main-content' => __( 'to the main element including the post title', 'footnotes' ), + ); + + // Options for the separating punctuation between backlinks. + $separators_options = array( + // Unicode character names are conventionally uppercase. + 'comma' => __( 'COMMA', 'footnotes' ), + 'semicolon' => __( 'SEMICOLON', 'footnotes' ), + 'en_dash' => __( 'EN DASH', 'footnotes' ), + ); + + /* + * Options for the terminating punctuation after backlinks. + * The Unicode name of RIGHT PARENTHESIS was originally more accurate because. + * This character is bidi-mirrored. Let's use the Unicode 1.0 name. + * The wrong names were enforced in spite of Unicode, that subsequently scrambled to correct. + */ + $terminators_options = array( + 'period' => __( 'FULL STOP', 'footnotes' ), + // Unicode 1.0 name of RIGHT PARENTHESIS (represented as a left parenthesis in right-to-left scripts). + 'parenthesis' => __( 'CLOSING PARENTHESIS', 'footnotes' ), + 'colon' => __( 'COLON', 'footnotes' ), + ); + // Options for the first column width (per cent is a ratio, not a unit). + $width_units_options = array( + '%' => __( 'per cent', 'footnotes' ), + 'px' => __( 'pixels', 'footnotes' ), + 'rem' => __( 'root em', 'footnotes' ), + 'em' => __( 'em', 'footnotes' ), + 'vw' => __( 'viewport width', 'footnotes' ), + ); + // Options for reference container script mode. + $script_mode_options = array( + 'jquery' => __( 'jQuery', 'footnotes' ), + 'js' => __( 'plain JavaScript', 'footnotes' ), + ); + // Options for Yes/No select box. + $enabled_options = array( + 'yes' => __( 'Yes', 'footnotes' ), + 'no' => __( 'No', 'footnotes' ), + ); + + Includes\Settings::instance()->general_settings->add_settings_fields($this); + + /* + add_settings_field( + \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_ELEMENT, + __( 'Heading\'s HTML element', 'footnotes' ), + array ($this, 'new_add_select_box'), + 'footnotes', + 'footnotes-settings', + array( + 'name' => \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_ELEMENT, + 'label_for' => \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_ELEMENT, + 'value' => get_option(\footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_ELEMENT), + 'options' => $label_element_options + ) + ); + + add_settings_field( + \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER, + __( 'Border under the heading', 'footnotes' ), + array ($this, 'new_add_select_box'), + 'footnotes', + 'footnotes-settings', + array( + 'name' => \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER, + 'label_for' => \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER, + 'value' => get_option(\footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER), + 'options' => $enabled_options + ) + ); + + add_settings_field( + \footnotes\includes\Settings::REFERENCE_CONTAINER_COLLAPSE, + __( 'Collapse by default', 'footnotes' ), + array ($this, 'new_add_select_box'), + 'footnotes', + 'footnotes-settings', + array( + 'name' => \footnotes\includes\Settings::REFERENCE_CONTAINER_COLLAPSE, + 'label_for' => \footnotes\includes\Settings::REFERENCE_CONTAINER_COLLAPSE, + 'value' => get_option(\footnotes\includes\Settings::REFERENCE_CONTAINER_COLLAPSE), + 'options' => $enabled_options + ) + ); + + add_settings_field( + \footnotes\includes\Settings::FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE, + __( 'Script mode', 'footnotes' ), + array ($this, 'new_add_select_box'), + 'footnotes', + 'footnotes-settings', + array( + 'name' => \footnotes\includes\Settings::FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE, + 'label_for' => \footnotes\includes\Settings::FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE, + 'value' => get_option(\footnotes\includes\Settings::FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE), + 'options' => $script_mode_options, + 'description' => __( 'The plain JavaScript mode will enable hard links with configurable scroll offset', 'footnotes') + ) + );*/ + } + + public function setting_field_callback( array $args ): void { + if (isset($args['type'])) { + switch($args['type']) { + case 'text': + $this->new_add_text_box($args); + return; + default: return; + } + } else return; + } /** * Displays the AMP compatibility mode option. @@ -90,91 +251,17 @@ class Settings extends Engine { * @since 1.5.0 */ public function reference_container(): void { - - // Options for the label element. - $label_element = array( - 'p' => __( 'paragraph', 'footnotes' ), - 'h2' => __( 'heading 2', 'footnotes' ), - 'h3' => __( 'heading 3', 'footnotes' ), - 'h4' => __( 'heading 4', 'footnotes' ), - 'h5' => __( 'heading 5', 'footnotes' ), - 'h6' => __( 'heading 6', 'footnotes' ), - ); - // Options for the positioning of the reference container. - $positions = array( - 'post_end' => __( 'at the end of the post', 'footnotes' ), - 'widget' => __( 'in the widget area', 'footnotes' ), - 'footer' => __( 'in the footer', 'footnotes' ), - ); - // Basic responsive page layout options. - $page_layout_options = array( - 'none' => __( 'No', 'footnotes' ), - 'reference-container' => __( 'to the reference container exclusively', 'footnotes' ), - 'entry-content' => __( 'to the div element starting below the post title', 'footnotes' ), - 'main-content' => __( 'to the main element including the post title', 'footnotes' ), - ); - // Options for the separating punctuation between backlinks. - $separators = array( - // Unicode character names are conventionally uppercase. - 'comma' => __( 'COMMA', 'footnotes' ), - 'semicolon' => __( 'SEMICOLON', 'footnotes' ), - 'en_dash' => __( 'EN DASH', 'footnotes' ), - ); - - /* - * Options for the terminating punctuation after backlinks. - * The Unicode name of RIGHT PARENTHESIS was originally more accurate because. - * This character is bidi-mirrored. Let's use the Unicode 1.0 name. - * The wrong names were enforced in spite of Unicode, that subsequently scrambled to correct. - */ - $terminators = array( - 'period' => __( 'FULL STOP', 'footnotes' ), - // Unicode 1.0 name of RIGHT PARENTHESIS (represented as a left parenthesis in right-to-left scripts). - 'parenthesis' => __( 'CLOSING PARENTHESIS', 'footnotes' ), - 'colon' => __( 'COLON', 'footnotes' ), - ); - // Options for the first column width (per cent is a ratio, not a unit). - $width_units = array( - '%' => __( 'per cent', 'footnotes' ), - 'px' => __( 'pixels', 'footnotes' ), - 'rem' => __( 'root em', 'footnotes' ), - 'em' => __( 'em', 'footnotes' ), - 'vw' => __( 'viewport width', 'footnotes' ), - ); - // Options for reference container script mode. - $script_mode = array( - 'jquery' => __( 'jQuery', 'footnotes' ), - 'js' => __( 'plain JavaScript', 'footnotes' ), - ); - // Options for Yes/No select box. - $enabled = array( - 'yes' => __( 'Yes', 'footnotes' ), - 'no' => __( 'No', 'footnotes' ), - ); - + + + + // Load template file. $template = new Includes\Template( \footnotes\includes\Template::DASHBOARD, 'settings-reference-container' ); // Replace all placeholders. $template->replace( array( - 'label-name' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_NAME, __( 'Heading:', 'footnotes' ) ), - 'name' => $this->add_text_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_NAME ), - - 'label-element' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_ELEMENT, __( 'Heading\'s HTML element:', 'footnotes' ) ), - 'element' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_ELEMENT, $label_element ), - - 'label-border' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER, __( 'Border under the heading:', 'footnotes' ) ), - 'border' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER, $enabled ), - - 'label-collapse' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_COLLAPSE, __( 'Collapse by default:', 'footnotes' ) ), - 'collapse' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_COLLAPSE, $enabled ), - - 'label-script' => $this->add_label( \footnotes\includes\Settings::FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE, __( 'Script mode:', 'footnotes' ) ), - 'script' => $this->add_select_box( \footnotes\includes\Settings::FOOTNOTES_REFERENCE_CONTAINER_SCRIPT_MODE, $script_mode ), - 'notice-script' => __( 'The plain JavaScript mode will enable hard links with configurable scroll offset.', 'footnotes' ), - 'label-position' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_POSITION, __( 'Default position:', 'footnotes' ) ), - 'position' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_POSITION, $positions ), + 'position' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_POSITION, $positions_options ), // Translators: %s: at the end of the post. 'notice-position' => sprintf( __( 'To use the position or section shortcode, please set the position to: %s', 'footnotes' ), '' . __( 'at the end of the post', 'footnotes' ) . '' ), @@ -187,7 +274,7 @@ class Settings extends Engine { 'notice-section' => __( 'If present in the content, any shortcode in this text box will delimit a section terminated by a reference container.', 'footnotes' ), 'label-startpage' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_START_PAGE_ENABLE, __( 'Display on start page too:', 'footnotes' ) ), - 'startpage' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_START_PAGE_ENABLE, $enabled ), + 'startpage' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_START_PAGE_ENABLE, $enabled_options ), 'label-margin-top' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_TOP_MARGIN, __( 'Top margin:', 'footnotes' ) ), 'margin-top' => $this->add_num_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_TOP_MARGIN, -500, 500 ), @@ -202,53 +289,53 @@ class Settings extends Engine { 'notice-page-layout' => __( 'Most themes don\'t need this fix.', 'footnotes' ), 'label-url-wrap' => $this->add_label( \footnotes\includes\Settings::FOOTNOTE_URL_WRAP_ENABLED, __( 'Allow URLs to line-wrap anywhere:', 'footnotes' ) ), - 'url-wrap' => $this->add_select_box( \footnotes\includes\Settings::FOOTNOTE_URL_WRAP_ENABLED, $enabled ), + 'url-wrap' => $this->add_select_box( \footnotes\includes\Settings::FOOTNOTE_URL_WRAP_ENABLED, $enabled_options ), 'notice-url-wrap' => __( 'Unicode-conformant browsers don\'t need this fix.', 'footnotes' ), 'label-symbol' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_BACKLINK_SYMBOL_ENABLE, __( 'Display a backlink symbol:', 'footnotes' ) ), - 'symbol-enable' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_BACKLINK_SYMBOL_ENABLE, $enabled ), + 'symbol-enable' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_BACKLINK_SYMBOL_ENABLE, $enabled_options ), 'notice-symbol' => __( 'Please choose or input the symbol at the top of the next dashboard tab.', 'footnotes' ), 'label-switch' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH, __( 'Symbol appended, not prepended:', 'footnotes' ) ), - 'switch' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH, $enabled ), + 'switch' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_BACKLINK_SYMBOL_SWITCH, $enabled_options ), 'label-3column' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_3COLUMN_LAYOUT_ENABLE, __( 'Backlink symbol in an extra column:', 'footnotes' ) ), - '3column' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_3COLUMN_LAYOUT_ENABLE, $enabled ), + '3column' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_3COLUMN_LAYOUT_ENABLE, $enabled_options ), 'notice-3column' => __( 'This legacy layout is available if identical footnotes are not combined.', 'footnotes' ), 'label-row-borders' => $this->add_label( \footnotes\includes\Settings::REFERENCE_CONTAINER_ROW_BORDERS_ENABLE, __( 'Borders around the table rows:', 'footnotes' ) ), - 'row-borders' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_ROW_BORDERS_ENABLE, $enabled ), + 'row-borders' => $this->add_select_box( \footnotes\includes\Settings::REFERENCE_CONTAINER_ROW_BORDERS_ENABLE, $enabled_options ), 'label-separator' => $this->add_label( \footnotes\includes\Settings::BACKLINKS_SEPARATOR_ENABLED, __( 'Add a separator when enumerating backlinks:', 'footnotes' ) ), - 'separator-enable' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_SEPARATOR_ENABLED, $enabled ), - 'separator-options' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_SEPARATOR_OPTION, $separators ), + 'separator-enable' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_SEPARATOR_ENABLED, $enabled_options ), + 'separator-options' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_SEPARATOR_OPTION, $separators_options ), 'separator-custom' => $this->add_text_box( \footnotes\includes\Settings::BACKLINKS_SEPARATOR_CUSTOM ), 'notice-separator' => __( 'Your input overrides the selection.', 'footnotes' ), 'label-terminator' => $this->add_label( \footnotes\includes\Settings::BACKLINKS_TERMINATOR_ENABLED, __( 'Add a terminal punctuation to backlinks:', 'footnotes' ) ), - 'terminator-enable' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_TERMINATOR_ENABLED, $enabled ), - 'terminator-options' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_TERMINATOR_OPTION, $terminators ), + 'terminator-enable' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_TERMINATOR_ENABLED, $enabled_options ), + 'terminator-options' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_TERMINATOR_OPTION, $terminators_options ), 'terminator-custom' => $this->add_text_box( \footnotes\includes\Settings::BACKLINKS_TERMINATOR_CUSTOM ), 'notice-terminator' => __( 'Your input overrides the selection.', 'footnotes' ), 'label-width' => $this->add_label( \footnotes\includes\Settings::BACKLINKS_COLUMN_WIDTH_ENABLED, __( 'Set backlinks column width:', 'footnotes' ) ), - 'width-enable' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_WIDTH_ENABLED, $enabled ), + 'width-enable' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_WIDTH_ENABLED, $enabled_options ), 'width-scalar' => $this->add_num_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_WIDTH_SCALAR, 0, 500, true ), - 'width-unit' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_WIDTH_UNIT, $width_units ), + 'width-unit' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_WIDTH_UNIT, $width_units_options ), 'notice-width' => __( 'Absolute width in pixels doesn\'t need to be accurate to the tenth, but relative width in rem or em may.', 'footnotes' ), 'label-max-width' => $this->add_label( \footnotes\includes\Settings::BACKLINKS_COLUMN_MAX_WIDTH_ENABLED, __( 'Set backlinks column maximum width:', 'footnotes' ) ), - 'max-width-enable' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_MAX_WIDTH_ENABLED, $enabled ), + 'max-width-enable' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_MAX_WIDTH_ENABLED, $enabled_options ), 'max-width-scalar' => $this->add_num_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_MAX_WIDTH_SCALAR, 0, 500, true ), - 'max-width-unit' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_MAX_WIDTH_UNIT, $width_units ), + 'max-width-unit' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_COLUMN_MAX_WIDTH_UNIT, $width_units_options ), 'notice-max-width' => __( 'Absolute width in pixels doesn\'t need to be accurate to the tenth, but relative width in rem or em may.', 'footnotes' ), 'label-line-break' => $this->add_label( \footnotes\includes\Settings::BACKLINKS_LINE_BREAKS_ENABLED, __( 'Stack backlinks when enumerating:', 'footnotes' ) ), - 'line-break' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_LINE_BREAKS_ENABLED, $enabled ), + 'line-break' => $this->add_select_box( \footnotes\includes\Settings::BACKLINKS_LINE_BREAKS_ENABLED, $enabled_options ), 'notice-line-break' => __( 'This option adds a line break before each added backlink when identical footnotes are combined.', 'footnotes' ), 'label-link' => $this->add_label( \footnotes\includes\Settings::LINK_ELEMENT_ENABLED, __( 'Use the link element for referrers and backlinks:', 'footnotes' ) ), - 'link' => $this->add_select_box( \footnotes\includes\Settings::LINK_ELEMENT_ENABLED, $enabled ), + 'link' => $this->add_select_box( \footnotes\includes\Settings::LINK_ELEMENT_ENABLED, $enabled_options ), 'notice-link' => __( 'The link element is needed to apply the theme\'s link color.', 'footnotes' ), 'description-link' => __( 'If the link element is not desired for styling, a simple span is used instead when the above is set to No.', 'footnotes' ), ) diff --git a/src/includes/class-core.php b/src/includes/class-core.php index 048b547..2c1ed31 100644 --- a/src/includes/class-core.php +++ b/src/includes/class-core.php @@ -157,6 +157,7 @@ class Core { * @return void */ private function load_dependencies() { + require_once plugin_dir_path( __DIR__ ) . 'includes/class-settings.php'; /** * The class responsible for orchestrating the actions and filters of the @@ -175,7 +176,6 @@ class Core { */ require_once plugin_dir_path( __DIR__ ) . 'includes/class-config.php'; require_once plugin_dir_path( __DIR__ ) . 'includes/class-convert.php'; - require_once plugin_dir_path( __DIR__ ) . 'includes/class-settings.php'; require_once plugin_dir_path( __DIR__ ) . 'includes/class-template.php'; /** diff --git a/src/includes/class-settings.php b/src/includes/class-settings.php index 42fff9f..587597a 100644 --- a/src/includes/class-settings.php +++ b/src/includes/class-settings.php @@ -1,6 +1,6 @@ array( @@ -1164,7 +1167,21 @@ class Settings { self::FOOTNOTES_BACKLINK_TOOLTIP_TEXT => 'Alt+ ←', // Reference container. - self::REFERENCE_CONTAINER_NAME => 'References', + self::REFERENCE_CONTAINER_NAME => array( + 'title' => 'Reference container title', + 'setting_args' => array ( + 'type' => 'string', + 'description' => 'The title of the reference container', + 'default' => 'References', + ), + 'field_args' => array ( + 'name' => self::REFERENCE_CONTAINER_NAME, + 'label_for' => self::REFERENCE_CONTAINER_NAME, + 'type' => 'text', + 'value' => 'References', + 'description' => 'The title of the reference container', + ), + ), self::REFERENCE_CONTAINER_LABEL_ELEMENT => 'p', self::REFERENCE_CONTAINER_LABEL_BOTTOM_BORDER => 'yes', self::REFERENCE_CONTAINER_COLLAPSE => 'no', @@ -1281,7 +1298,7 @@ class Settings { 'footnotes_storage_expert' => array( // WordPress hooks with priority level. - self::EXPERT_LOOKUP_THE_TITLE => '', + self::EXPERT_LOOKUP_THE_TITLE => "", self::EXPERT_LOOKUP_THE_TITLE_PRIORITY_LEVEL => PHP_INT_MAX, self::EXPERT_LOOKUP_THE_CONTENT => 'checked', @@ -1319,7 +1336,10 @@ class Settings { * @since 1.5.0 * @todo Create `PreferencesSet` class. */ - private array $settings = array(); + public array $settings = array(); + + public GeneralSettingsSection $general_settings; + /********************************************************************** * SETTINGS STORAGE. **********************************************************************/ @@ -1336,7 +1356,11 @@ class Settings { * @since 1.5.0 */ private function __construct() { - $this->load_all(); + $this->load_options(); + + require_once plugin_dir_path( __DIR__ ) . 'includes/settings/class-general-settings-section.php'; + + $this->general_settings = new GeneralSettingsSection('footnotes_storage', 'footnotes-settings', 'General Settings'); } /** @@ -1348,7 +1372,7 @@ class Settings { * @since 1.5.0 */ public function get_container( int $index ): string { - return $this->container[ $index ]; + return $this->option_groups[ $index ]; } /** @@ -1360,7 +1384,7 @@ class Settings { * @since 1.5.6 */ public function get_defaults( int $index ): array { - return $this->default[ $this->container[ $index ] ]; + return $this->default[ $this->option_groups[ $index ] ]; } /** @@ -1398,14 +1422,21 @@ class Settings { * The Settings Container label will be the same as the Settings Container name. * * @since 1.5.0 + * @todo Only register current tab? */ public function register_settings(): void { - // Register all settings. - $num_settings = count( $this->container ); - for ( $i = 0; $i < $num_settings; $i++ ) { - register_setting( $this->get_container( $i ), $this->get_container( $i ) ); + // Register all settings. + foreach ($this->default_settings as $option_groups_name => $option_groups_values) { + foreach ($option_groups_values as $setting_name => $setting_value) { + if (!is_array($setting_value)) { + register_setting( $option_groups_name, $setting_name ); + } else { + register_setting( $option_groups_name, $setting_name, $setting_value['setting_args']); + } + } } } + /** * Returns a singleton of this class. * @@ -1421,46 +1452,46 @@ class Settings { return self::$instance; } /** - * Loads all Settings from each Settings container. + * Loads all settings from each option group. * * @since 1.5.0 + * @since 2.8.0 Renamed from `load_all()` to `load_options()`. */ - private function load_all(): void { + private function load_options(): void { // Clear current settings. $this->settings = array(); - $num_settings = count( $this->container ); - for ( $i = 0; $i < $num_settings; $i++ ) { - // Load settings. - $this->settings = array_merge( $this->settings, $this->load( $i ) ); + + foreach ($this->option_groups as $option_group) { + $this->settings[$option_group] = $this->load_option( $option_group ); } } + /** - * Loads all settings from specified Settings Containers. + * Loads all settings from a given option group. * - * @param int $index Settings container index. - * @return (string|int)[] Loaded settings (or defaults if specified container is empty). + * @param string $option_group Option group slug. + * @return (string|int)[] Loaded settings (or defaults if specified option group is empty). * * @since 1.5.0 + * @since 2.8.0 Renamed from `load()` to `load_option()`. */ - private function load( int $index ): array { - // Load all settings from container. - $options = get_option( $this->get_container( $index ) ); - // Load all default settings. - $default = $this->default[ $this->get_container( $index ) ]; - + private function load_option(string $option_group): array { + // Load all settings from option group. + $options = get_option( $option_group ); + // No settings found, set them to their default value. if ( empty( $options ) ) { - return $default; + return $this->default_settings[$option_group]; } - // Iterate through all available settings ( = default values). - foreach ( $default as $key => $value ) { - // Available setting not found in the container. - if ( ! array_key_exists( $key, $options ) ) { + + foreach ( $this->default_settings[$option_group] as $setting_name => $setting_value ) { + // Available setting not found in the option group. + if ( ! array_key_exists( $setting_name, $options ) ) { // Define the setting with its default value. - $options[ $key ] = $value; + $options[ $setting_name ] = $setting_value; } } - // Return settings loaded from Container. + // Return settings loaded from option group. return $options; } } diff --git a/src/includes/settings/class-general-settings-section.php b/src/includes/settings/class-general-settings-section.php new file mode 100644 index 0000000..cc7fc14 --- /dev/null +++ b/src/includes/settings/class-general-settings-section.php @@ -0,0 +1,56 @@ +options_group_slug = $options_group_slug; + $this->section_slug = $section_slug; + $this->title = $title; + + $this->load_dependencies(); + + $this->add_settings_groups(get_option( $this->options_group_slug )); + } + + protected function load_dependencies(): void { + require_once plugin_dir_path( __DIR__ ) . 'settings/general/class-reference-container-settings-group.php'; + } + + protected function add_settings_groups(): void { + $this->settings_groups = array ( + ReferenceContainerSettingsGroup::GROUP_ID => new ReferenceContainerSettingsGroup($this->options_group_slug, $this->section_slug), + ); + } +} diff --git a/src/includes/settings/class-setting.php b/src/includes/settings/class-setting.php new file mode 100644 index 0000000..0ca69f0 --- /dev/null +++ b/src/includes/settings/class-setting.php @@ -0,0 +1,137 @@ +options_group_slug, $this->key, $this->get_setting_args()); + } + + public function get_setting_args(): array { + return array ( + 'type' => $this->type, + 'description' => $this->description, + 'default' => $this->default_value, + ); + } + + public function get_setting_field_args(): array { + return array ( + 'name' => $this->key, + 'label_for' => $this->key, + 'type' => $this->input_type, + 'value' => $this->value, + 'description' => $this->description, + ); + } + + public function get_options_group_slug(): string { + return $this->options_group_slug; + } + + public function get_section_slug(): string { + return $this->section_slug; + } +} diff --git a/src/includes/settings/class-settings-group.php b/src/includes/settings/class-settings-group.php new file mode 100644 index 0000000..ceb7191 --- /dev/null +++ b/src/includes/settings/class-settings-group.php @@ -0,0 +1,71 @@ +section_slug, + $this->title, + array($this, 'setting_section_callback'), + 'footnotes' + ); + } + + public function add_settings_fields($component): void { + foreach($this->settings_groups as $settings_group) { + $settings_group->add_settings_fields($component); + } + } + + public function setting_section_callback(): void { + echo "
"; + } + + protected abstract function add_settings_groups(): void; + + public function get_options_group_slug(): string { + return $this->options_group_slug; + } + + public function get_section_slug(): string { + return $this->section_slug; + } + + public function get_title(): string { + return $this->title; + } + + public function get_settings_group(string $group_id) { + return $this->settings_groups[$group_id]; + } +} diff --git a/src/includes/settings/general/class-reference-container-settings-group.php b/src/includes/settings/general/class-reference-container-settings-group.php new file mode 100644 index 0000000..5580b9c --- /dev/null +++ b/src/includes/settings/general/class-reference-container-settings-group.php @@ -0,0 +1,122 @@ + 'footnote_inputfield_references_label', + 'name' => 'Reference Container Name', + 'description' => 'The title of the reference container.', + 'default_value' => 'Reference', + 'type' => 'string', + 'input_type' => 'text' + ); + + /** + * The general settings. + * + * @var Setting[] + * + * @since 2.8.0 + */ + protected array $settings; + + public function __construct( + /** + * Setting options group slug. + * + * @var string + * + * @since 2.8.0 + */ + protected string $options_group_slug, + + /** + * Setting section slug. + * + * @var string + * + * @since 2.8.0 + */ + protected string $section_slug + ) { + $this->load_dependencies(); + + $this->add_settings(get_option( $this->options_group_slug )); + } + + protected function load_dependencies(): void { + require_once plugin_dir_path( __DIR__ ) . 'class-setting.php'; + } + + protected function add_settings(array $options): void { + $this->settings = array( + self::REFERENCE_CONTAINER_NAME['key'] => $this->add_setting(self::REFERENCE_CONTAINER_NAME) + ); + } + + private function add_setting(array $setting): Setting { + extract( $setting ); + + return new Setting( + self::GROUP_ID, + $this->options_group_slug, + $this->section_slug, + $key, + $name, + $description, + $default_value, + $type, + $input_type + ); + } + + public function add_settings_fields($component): void { + foreach ($this->settings as $setting) { + add_settings_field( + $setting->key, + __( $setting->name, 'footnotes' ), + array ($component, 'setting_field_callback'), + 'footnotes', + $setting->get_section_slug(), + $setting->get_setting_field_args() + ); + } + } +} diff --git a/src/includes/settings/general/reference-container/class-reference-container-name-setting.php b/src/includes/settings/general/reference-container/class-reference-container-name-setting.php new file mode 100644 index 0000000..8794351 --- /dev/null +++ b/src/includes/settings/general/reference-container/class-reference-container-name-setting.php @@ -0,0 +1,106 @@ +options_group_slug, self::NAME, $this->get_setting_args()); + } +}