[ $this, 'sanitize' ] ] ); // Section 1: Modules & Navigation add_settings_section( 'senti-modules-section', __( 'Modules & Navigation', 'senti-feedback' ), [ $this, 'modules_section_desc' ], 'senti-settings' ); add_settings_field( 'senti-modules', __( 'Active modules', 'senti-feedback' ), [ $this, 'modules_field' ], 'senti-settings', 'senti-modules-section' ); add_settings_field( 'senti-landing-mode', __( 'Landing page', 'senti-feedback' ), [ $this, 'landing_mode_field' ], 'senti-settings', 'senti-modules-section' ); // Section 2: Feedback & Submissions add_settings_section( 'senti-feedback-section', __( 'Feedback & Submissions', 'senti-feedback' ), '__return_empty_string', 'senti-settings' ); add_settings_field( 'senti-submission-access', __( 'Submission access', 'senti-feedback' ), [ $this, 'submission_access_field' ], 'senti-settings', 'senti-feedback-section' ); add_settings_field( 'senti-submission-moderation', __( 'Moderation', 'senti-feedback' ), [ $this, 'submission_moderation_field' ], 'senti-settings', 'senti-feedback-section' ); add_settings_field( 'senti-allowed-types', __( 'Allowed request types', 'senti-feedback' ), [ $this, 'allowed_types_field' ], 'senti-settings', 'senti-feedback-section' ); // Section 3: Discussion & Voting add_settings_section( 'senti-discussion-voting-section', __( 'Discussion & Voting', 'senti-feedback' ), '__return_empty_string', 'senti-settings' ); add_settings_field( 'senti-comments-mode', __( 'Feedback discussion', 'senti-feedback' ), [ $this, 'comments_mode_field' ], 'senti-settings', 'senti-discussion-voting-section' ); add_settings_field( 'senti-voting-access', __( 'Voting access', 'senti-feedback' ), [ $this, 'voting_access_field' ], 'senti-settings', 'senti-discussion-voting-section' ); // Section 4: Portal Page Assignments add_settings_section( 'senti-pages-section', __( 'Page Assignments', 'senti-feedback' ), '__return_empty_string', 'senti-settings' ); foreach ( $this->page_labels() as $section => $label ) { add_settings_field( 'senti-page-' . $section, $label, [ $this, 'page_field' ], 'senti-settings', 'senti-pages-section', [ 'section' => $section ] ); } } /** * @internal * @param mixed $value * @return array{ * modules: array{feedback: bool, roadmap: bool, changelog: bool}, * submission_access: 'anyone'|'logged_in', * submission_moderation: bool, * allowed_types: list, * comments_mode: 'open'|'logged_in'|'closed', * voting_access: 'anyone'|'logged_in', * landing_mode: string * } */ public function sanitize( mixed $value ): array { $data = is_array( $value ) ? $value : []; $modules = $this->sanitize_modules( $data ); $submission_access = ( $data['submission_access'] ?? '' ) === Settings::ACCESS_LOGGED_IN ? Settings::ACCESS_LOGGED_IN : Settings::ACCESS_ANYONE; $submission_moderation = ! empty( $data['submission_moderation'] ); $comments_mode = match ( $data['comments_mode'] ?? '' ) { Settings::COMMENTS_LOGGED_IN => Settings::COMMENTS_LOGGED_IN, Settings::COMMENTS_CLOSED => Settings::COMMENTS_CLOSED, default => Settings::COMMENTS_OPEN, }; $voting_access = ( $data['voting_access'] ?? '' ) === Settings::ACCESS_LOGGED_IN ? Settings::ACCESS_LOGGED_IN : Settings::ACCESS_ANYONE; $this->sanitize_page_assignments( $data ); return [ 'modules' => $modules, 'submission_access' => $submission_access, 'submission_moderation' => $submission_moderation, 'allowed_types' => $this->sanitize_allowed_types( $data ), 'comments_mode' => $comments_mode, 'voting_access' => $voting_access, 'landing_mode' => $this->sanitize_landing_mode( $data, $modules ), ]; } /** * @param array $data * @return array{feedback: bool, roadmap: bool, changelog: bool} */ private function sanitize_modules( array $data ): array { $modules_raw = isset( $data['modules'] ) && is_array( $data['modules'] ) ? $data['modules'] : []; $feedback = ! empty( $modules_raw[ Settings::MODULE_FEEDBACK ] ); $roadmap = ! empty( $modules_raw[ Settings::MODULE_ROADMAP ] ); $changelog = ! empty( $modules_raw[ Settings::MODULE_CHANGELOG ] ); if ( ! isset( $data['modules'] ) ) { $current_modules = $this->get_settings()->active_modules(); $feedback = $current_modules[ Settings::MODULE_FEEDBACK ]; $roadmap = $current_modules[ Settings::MODULE_ROADMAP ]; $changelog = $current_modules[ Settings::MODULE_CHANGELOG ]; } if ( ! $feedback && ! $roadmap && ! $changelog ) { $feedback = true; } return [ Settings::MODULE_FEEDBACK => $feedback, Settings::MODULE_ROADMAP => $roadmap, Settings::MODULE_CHANGELOG => $changelog, ]; } /** * @param array $data * @return list */ private function sanitize_allowed_types( array $data ): array { $allowed_types = []; if ( isset( $data['allowed_types'] ) && is_array( $data['allowed_types'] ) ) { foreach ( $data['allowed_types'] as $type_slug ) { if ( is_string( $type_slug ) && term_exists( $type_slug, Identifiers::TAXONOMY_REQUEST_TYPE ) ) { $allowed_types[] = sanitize_title( $type_slug ); } } } return $allowed_types !== [] ? $allowed_types : RequestType::values(); } /** * @param array $data * @param array{feedback: bool, roadmap: bool, changelog: bool} $modules */ private function sanitize_landing_mode( array $data, array $modules ): string { $landing_mode = isset( $data['landing_mode'] ) && is_string( $data['landing_mode'] ) ? sanitize_key( $data['landing_mode'] ) : PortalPages::PORTAL; $allowed_landing = array_keys( $this->landing_mode_labels( $modules ) ); return in_array( $landing_mode, $allowed_landing, true ) ? $landing_mode : PortalPages::PORTAL; } /** * @param array $data */ private function sanitize_page_assignments( array $data ): void { $assigned = $this->pages->all(); $changed = false; foreach ( array_keys( $this->page_labels() ) as $section ) { $page_id = isset( $data[ 'page_' . $section ] ) ? absint( $data[ 'page_' . $section ] ) : 0; if ( $page_id > 0 && get_post_type( $page_id ) === 'page' && ( $assigned[ $section ] ?? 0 ) !== $page_id ) { $assigned[ $section ] = $page_id; $changed = true; } } if ( $changed ) { update_option( PortalPages::OPTION_NAME, $assigned, false ); $this->rewrites->flush(); } } /** * @internal */ public function render(): void { if ( ! current_user_can( Capabilities::MANAGE_SETTINGS ) ) { wp_die( esc_html__( 'You are not allowed to manage Senti settings.', 'senti-feedback' ) ); } require dirname( __DIR__, 2 ) . '/templates/admin/settings.php'; } /** * @internal */ public function modules_section_desc(): void { ?>

get_settings()->all(); $modules = $settings['modules']; ?>
get_settings()->all(); $current = $settings['landing_mode']; $labels = $this->landing_mode_labels( $settings['modules'] ); ?>

get_settings()->all(); $access = $settings['submission_access']; ?>
get_settings()->all(); $moderation = $settings['submission_moderation']; ?>

get_settings()->all(); $allowed = $settings['allowed_types']; $taxonomy_terms = get_terms( [ 'taxonomy' => Identifiers::TAXONOMY_REQUEST_TYPE, 'hide_empty' => false, ] ); $terms = ! is_wp_error( $taxonomy_terms ) && is_array( $taxonomy_terms ) ? $taxonomy_terms : []; ?>

Feedback > Request types.', 'senti-feedback' ), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped esc_url( admin_url( 'edit-tags.php?taxonomy=' . Identifiers::TAXONOMY_REQUEST_TYPE . '&post_type=' . Identifiers::POST_TYPE_FEEDBACK ) ) ); ?>

get_settings()->all(); $mode = $settings['comments_mode']; ?>
get_settings()->all(); $access = $settings['voting_access']; ?>
self::OPTION_NAME . '[page_' . $section . ']', 'selected' => $this->pages->id( $section ), 'show_option_none' => __( 'Select a page', 'senti-feedback' ), ]; wp_dropdown_pages( $dropdown ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_dropdown_pages escapes its generated select markup. } /** * @param array{feedback?: bool, roadmap?: bool, changelog?: bool}|null $modules * @return array */ private function landing_mode_labels( ?array $modules = null ): array { $modules = $modules ?? $this->get_settings()->active_modules(); $labels = [ PortalPages::PORTAL => __( 'Overview', 'senti-feedback' ), ]; if ( ! empty( $modules[ Settings::MODULE_FEEDBACK ] ) ) { $labels[ PortalPages::FEEDBACK ] = __( 'Feedback', 'senti-feedback' ); } if ( ! empty( $modules[ Settings::MODULE_ROADMAP ] ) ) { $labels[ PortalPages::ROADMAP ] = __( 'Roadmap', 'senti-feedback' ); } if ( ! empty( $modules[ Settings::MODULE_CHANGELOG ] ) ) { $labels[ PortalPages::CHANGELOG ] = __( 'Changelog', 'senti-feedback' ); } return $labels; } /** * @return array */ private function page_labels(): array { return [ PortalPages::PORTAL => __( 'Overview page', 'senti-feedback' ), PortalPages::FEEDBACK => __( 'Feedback page', 'senti-feedback' ), PortalPages::ROADMAP => __( 'Roadmap page', 'senti-feedback' ), PortalPages::CHANGELOG => __( 'Changelog page', 'senti-feedback' ), ]; } private function get_settings(): Settings { return $this->settings ?? new Settings(); } }