'Withdraw from contract here', 'legal_confirm_text' => 'Confirm withdrawal', ); /** * Messages of the last save, field => message; read once per request. * * @var array|null */ private static $errors = null; /** * Hooks the section, the rows and the save. * * @return void */ public static function init() { add_filter( Admin::SECTIONS_FILTER, array( __CLASS__, 'sections' ) ); add_filter( Admin::FIELDS_FILTER, array( __CLASS__, 'fields' ), 10, 2 ); add_filter( Admin::SAVE_FILTER, array( __CLASS__, 'save' ), 10, 4 ); } /** * Adds Legal wording right after Portal, while the statutory withdrawal is * offered: the two texts belong to it. The values stay stored while it is not. * * @param array $sections Sections of the screen. * @return array */ public static function sections( $sections ) { $sections = (array) $sections; if ( ! Routes::offered( 'withdrawal', new Settings() ) ) { return $sections; } $sections[ self::SECTION ] = array( 'tab' => 'portal', 'label' => __( 'Legal wording', 'careback' ), 'position' => 15, 'render' => array( __CLASS__, 'render_legal' ), ); return $sections; } /** * Adds the returns policy page to Portal and the consent to Voluntary return. * * @param array $fields Rows of the section. * @param string $section Section key. * @return array */ public static function fields( $fields, $section = '' ) { $fields = (array) $fields; if ( 'portal' === $section ) { $fields['returns_policy_page'] = array( 'position' => 30, 'render' => array( __CLASS__, 'render_policy_page' ), ); } elseif ( 'route-return' === $section ) { $fields['policy_consent'] = array( 'position' => 20, 'render' => array( __CLASS__, 'render_consent' ), ); } return $fields; } /** * Legal wording: the two texts, each with its limit and our default as its * placeholder. * * @param array $s Stored settings. * @param string $screen Screen id. * @param Settings $settings The screen's settings. * @return void */ public static function render_legal( array $s, $screen = '', $settings = null ) { unset( $screen, $settings ); $link = isset( $s['legal_link_text'] ) ? (string) $s['legal_link_text'] : ''; $confirm = isset( $s['legal_confirm_text'] ) ? (string) $s['legal_confirm_text'] : ''; ?>

/>

'page', 'post_status' => array( 'publish', 'draft' ), 'posts_per_page' => 500, // phpcs:ignore WordPress.WP.PostsPerPage.posts_per_page_posts_per_page -- a bounded list of the site's pages for one select, read on the settings screen only. 'orderby' => 'title', 'order' => 'ASC', 'no_found_rows' => true, ) ); if ( $chosen && ! in_array( (int) $chosen->ID, wp_list_pluck( $pages, 'ID' ), true ) ) { $pages[] = $chosen; } $selected = $chosen ? (int) $chosen->ID : 0; ?> ID ) ) : ?>

ID ); switch ( $page->post_status ) { case 'publish': return $title; case 'draft': /* translators: %s: page title. */ return sprintf( __( '%s (draft)', 'careback' ), $title ); case 'private': /* translators: %s: page title. */ return sprintf( __( '%s (private)', 'careback' ), $title ); default: /* translators: %s: page title. */ return sprintf( __( '%s (not published)', 'careback' ), $title ); } } /** * What the screen says about the chosen page when the form cannot link it, * or when it asks for a password. * * @param \WP_Post|null $page The chosen page. * @return void */ private static function page_state_note( $page ) { if ( ! $page instanceof \WP_Post ) { return; } $note = ''; if ( 'draft' === $page->post_status ) { $note = __( 'This page is a draft, so the form does not show the link yet. Publish it, or choose another page.', 'careback' ); } elseif ( 'private' === $page->post_status ) { $note = __( 'This page is private, so the form does not show the link. Publish it, or choose another page.', 'careback' ); } elseif ( 'publish' !== $page->post_status ) { $note = __( 'This page is not published, so the form does not show the link yet. Publish it, or choose another page.', 'careback' ); } elseif ( post_password_required( $page ) || '' !== (string) $page->post_password ) { $note = __( 'This page asks for a password.', 'careback' ); } if ( '' !== $note ) { echo '

' . esc_html( $note ) . '

'; } } /** * Voluntary return → Returns policy: the consent switch, naming the page it * uses and its state. * * @param array $s Stored settings. * @param string $screen Screen id. * @param Settings $settings The screen's settings. * @return void */ public static function render_consent( array $s, $screen = '', $settings = null ) { unset( $screen ); $settings = $settings instanceof Settings ? $settings : new Settings( $s ); $page = Returns_Policy::page( $settings ); $on = ! empty( $s[ Returns_Policy::CONSENT ] ); $error = self::error( Returns_Policy::CONSENT ); if ( $page ) { $uses = sprintf( /* translators: 1: title of the returns policy page, 2: its state, such as "published" or "draft". */ __( 'Uses the page set under Portal and form → Returns policy page: “%1$s” (%2$s). Never asked on a statutory withdrawal.', 'careback' ), trim( wp_strip_all_tags( get_the_title( $page ) ) ), self::state_word( (string) $page->post_status ) ); } else { $uses = __( 'Uses the page set under Portal and form → Returns policy page; none is chosen yet. Never asked on a statutory withdrawal.', 'careback' ); } ?>

$max ) { if ( ! isset( $posted[ $key ] ) || ! is_scalar( $posted[ $key ] ) ) { continue; } $text = trim( sanitize_text_field( $posted[ $key ] ) ); if ( mb_strlen( $text ) > $max ) { /* translators: %d: the most characters the field takes. */ $errors[ $key ] = sprintf( _n( 'Use up to %d character.', 'Use up to %d characters.', $max, 'careback' ), $max ); continue; } $own = Texts::defaults(); $word = (string) array_search( $key, Texts::LEGAL, true ); if ( self::LEGAL_ENGLISH[ $key ] === $text || ( isset( $own[ $word ] ) && $own[ $word ] === $text ) ) { $text = ''; } $values[ $key ] = $text; } // The returns policy page: a page of the site, or none. $page = null; if ( isset( $posted[ Returns_Policy::PAGE ] ) && is_scalar( $posted[ Returns_Policy::PAGE ] ) ) { $id = absint( $posted[ Returns_Policy::PAGE ] ); $post = $id ? get_post( $id ) : null; $id = $post instanceof \WP_Post && 'page' === $post->post_type && 'trash' !== $post->post_status ? $id : 0; $page = $id ? get_post( $id ) : false; $values[ Returns_Policy::PAGE ] = $id; } // The consent: only with a published page to agree to. if ( isset( $posted['careback_policy_consent_shown'] ) ) { $on = ! empty( $posted[ Returns_Policy::CONSENT ] ); if ( $on ) { if ( null === $page ) { $page = Returns_Policy::page( new Settings() ); } if ( ! $page instanceof \WP_Post || 'publish' !== $page->post_status ) { $on = false; $errors[ Returns_Policy::CONSENT ] = __( 'Choose a published returns policy page first (Portal and form → Returns policy page).', 'careback' ); } } $values[ Returns_Policy::CONSENT ] = $on ? 1 : 0; } self::keep_errors( $errors ); return $values; } /** * Keeps the messages of this save for the screen the save returns to. * * @param array $errors Field => message. * @return void */ private static function keep_errors( array $errors ) { $user = get_current_user_id(); if ( ! $user ) { return; } if ( $errors ) { set_transient( self::ERRORS . $user, $errors, 5 * MINUTE_IN_SECONDS ); } else { delete_transient( self::ERRORS . $user ); } self::$errors = null; } /** * The message the last save left for a field, or ''. The messages are read * once and then cleared, so they show on the screen right after the save. * * @param string $field Settings key. * @return string */ public static function error( $field ) { if ( null === self::$errors ) { $user = get_current_user_id(); $stored = $user ? get_transient( self::ERRORS . $user ) : false; self::$errors = is_array( $stored ) ? $stored : array(); if ( $user && false !== $stored ) { delete_transient( self::ERRORS . $user ); } } return isset( self::$errors[ $field ] ) ? (string) self::$errors[ $field ] : ''; } }