*/ private static array $anchors = array(); /** * Render a form. * * @param array{list?: string, view?: string, name?: bool, title?: string, button?: string} $args List key (empty * for the first list), * view, name field, * heading and button * text. */ public static function render( array $args ): string { $key = sanitize_key( (string) ( $args['list'] ?? '' ) ); $mailing_list = Settings::get( $key ); if ( null === $mailing_list ) { return self::editor_hint( '' === $key ? __( 'GruVer Subscribe: no mailing list has been set up yet.', 'gruver-subscribe' ) /* translators: %s: key of the list */ : sprintf( __( 'GruVer Subscribe: there is no mailing list with the key ā%sā.', 'gruver-subscribe' ), $key ) ); } wp_enqueue_style( self::STYLE ); $key = $mailing_list->key; $view = self::view( (string) ( $args['view'] ?? '' ) ); $failed = Handler::current( $key ); $outcome = null !== $failed ? $failed->outcome : self::outcome( $key ); $typed = array( 'email' => null !== $failed ? $failed->email : '', 'name' => null !== $failed ? $failed->name : '', ); $id = wp_unique_id( 'gruver-subscribe-' ); $title = trim( (string) ( $args['title'] ?? '' ) ); $button = trim( (string) ( $args['button'] ?? '' ) ); $anchor = self::anchor( $key ); if ( isset( self::$anchors[ $anchor ] ) ) { $anchor = $id; } self::$anchors[ $anchor ] = true; $html = '
' . esc_html( $title ) . '
'; } if ( '' !== $outcome ) { self::no_cache(); $html .= ''; } if ( Handler::SENT === $outcome ) { return $html . '' . '' . '' . '
'; } $fields .= '' . '' . '' . '
' . Honeypot::html( $id . '-website' ); $consent = ''; $submit = ''; // The form goes back to this page; after an error the browser lands on the form again. return $html . ''; } /** * A known view, the large form otherwise. * * @param string $view Requested view. */ public static function view( string $view ): string { return in_array( $view, self::VIEWS, true ) ? $view : self::VIEW_FORM; } /** * Id of the form of a list, also the fragment of the redirect. * * @param string $key List key. */ public static function anchor( string $key ): string { return '' === $key ? 'gruver-subscribe' : 'gruver-subscribe-' . $key; } /** * Text for an outcome of the handler. * * @param string $outcome One of Handler::OUTCOMES. */ public static function message( string $outcome ): string { return match ( $outcome ) { Handler::SENT => __( 'Almost done ā please confirm the email we have just sent to your inbox.', 'gruver-subscribe' ), Handler::INVALID => __( 'Please check the email address.', 'gruver-subscribe' ), Handler::CONSENT => __( 'Please tick the box to agree.', 'gruver-subscribe' ), Handler::CONSENT_CHANGED => __( 'The consent text has changed. Please read it and tick the box again.', 'gruver-subscribe' ), Handler::TOO_FAST => __( 'That was very quick. Please wait a moment and send the form again.', 'gruver-subscribe' ), Handler::LIMITED => __( 'Too many attempts. Please try again in a few minutes.', 'gruver-subscribe' ), Handler::EXPIRED => __( 'The form has expired. Please send it again.', 'gruver-subscribe' ), default => __( 'Signing up is not possible right now. Please try again later.', 'gruver-subscribe' ), }; } /** * Outcome from the redirect after a success, if it belongs to this list. * * @param string $key List key. */ private static function outcome( string $key ): string { // Only the success arrives by redirect; errors are shown from the POST itself. return self::query( Handler::QUERY_LIST ) === $key && Handler::SENT === self::query( Handler::QUERY_STATUS ) ? Handler::SENT : ''; } /** * A page with a message depends on the visitor; page caches must not keep it. DONOTCACHEPAGE is the constant the * common cache plugins check before they store a page. */ private static function no_cache(): void { if ( ! defined( 'DONOTCACHEPAGE' ) ) { define( 'DONOTCACHEPAGE', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound -- constant of the cache plugins, not of this plugin. } } /** * A value from the query string. * * @param string $name Parameter. */ private static function query( string $name ): string { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only selects which message to show after the redirect. return isset( $_GET[ $name ] ) && is_string( $_GET[ $name ] ) ? sanitize_key( wp_unslash( $_GET[ $name ] ) ) : ''; } /** * Path and query of the current page, without the parameters of an earlier redirect. */ private static function current_path(): string { $uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '/'; return remove_query_arg( array( Handler::QUERY_STATUS, Handler::QUERY_LIST ), '' !== $uri ? $uri : '/' ); } /** * A hidden field. * * @param string $name Name. * @param string $value Value. */ private static function hidden( string $name, string $value ): string { return ''; } /** * A hint for people who edit the website; visitors see nothing. * * @param string $message Message. */ private static function editor_hint( string $message ): string { if ( ! current_user_can( 'edit_posts' ) ) { return ''; } $link = current_user_can( 'manage_options' ) ? ' ' . esc_html__( 'Open settings', 'gruver-subscribe' ) . '' : ''; return '' . esc_html( $message ) . $link . '
'; } }