*/ abstract public function forms(); /** * The fields of one form, for the mapping screen. Leave out anything a person does not type * (submit buttons, captchas, honeypots, HTML blocks, page breaks, file uploads, passwords). * * @param string $form_id The form's ID in this plugin. * @return array `name` is the key * {@see Integration::values()} uses for the same field. */ abstract public function fields( $form_id ); /** * Hook into the plugin's "submission accepted" action. The callback builds the values and calls * {@see Integration::send()}. Runs on every request, so it must only add hooks. * * @return void */ abstract public function register(); /** * Hand one accepted submission to the relay. Every adapter's hook ends here, and nothing thrown * below it reaches the form plugin or the visitor. * * @param string $form_id The form's ID in this plugin. * @param string $form_title The form's title in this plugin. * @param array $values Same `name`s as {@see Integration::fields()}. * @return void */ protected function send( $form_id, $form_title, array $values ) { try { Relay::capture( $this->slug(), (string) $form_id, (string) $form_title, $values ); } catch ( \Throwable $e ) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( 'LaunchList: ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } } } /** * Whether this form's submissions go to LaunchList right now. Ask before writing anything to the * form plugin's own data (an entry marker), so forms that are not sent are left untouched. * * @param string $form_id The form's ID in this plugin. * @return bool */ protected function routed( $form_id ) { return Relay::routed( $this->slug(), (string) $form_id ); } /** @var array Keys each adapter has claimed in this request. */ private static $claimed = array(); /** * Claim a key once per request: true the first time this adapter claims it, false after. Adapters * claim `hooks` in register() so a second call adds nothing, and one key per submission so a hook * that fires twice relays once. * * @param string $key What is being claimed, e.g. `hooks` or `entry:42`. * @return bool */ protected function claim( $key ) { $key = $this->slug() . ':' . $key; if ( isset( self::$claimed[ $key ] ) ) { return false; } self::$claimed[ $key ] = true; return true; } /** * Plain text: tags stripped, entities decoded, trimmed. Anything that is not a scalar is empty. * * @param mixed $value A submitted value or a label. * @return string */ protected static function plain( $value ) { if ( ! is_scalar( $value ) ) { return ''; } return trim( html_entity_decode( wp_strip_all_tags( (string) $value ), ENT_QUOTES, 'UTF-8' ) ); } /** * The label of one part of a field, e.g. "Name (First)". Never translated: a submitted label names * the field in LaunchList when it is not mapped, so it must not change with the visitor's locale. * * @param string $label The field's label. * @param string $part The part's label. * @return string */ protected static function part_label( $label, $part ) { return sprintf( '%1$s (%2$s)', $label, $part ); } /** * Add one answer to the values handed to the relay, unless it is empty. * * @param array $values The values so far. * @param string $name The field's name, as in fields(). * @param string $label The field's label, untranslated. * @param string $type One of Integration::TYPES. * @param mixed $value A string, or a list for a multiple choice. * @return void */ protected static function push( array &$values, $name, $label, $type, $value ) { if ( is_array( $value ) ) { $list = array(); foreach ( $value as $item ) { $item = self::plain( $item ); if ( '' !== $item ) { $list[] = $item; } } if ( ! $list ) { return; } $value = $list; } else { $value = self::plain( $value ); if ( '' === $value ) { return; } } $values[] = array( 'name' => (string) $name, 'label' => self::plain( $label ), 'type' => $type, 'value' => $value, ); } /** * Log an error from an adapter's own code while debugging, and never rethrow it. * * @param \Throwable $e The error. * @return void */ protected function fail( \Throwable $e ) { if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { error_log( 'LaunchList (' . $this->name() . '): ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log } } }