From 0804d03746c17b30f180087fc2e26dffba723da3 Mon Sep 17 00:00:00 2001 From: prismiwi2015 Date: Sun, 23 Aug 2026 16:40:15 +0200 Subject: [PATCH 1/2] The reviewer asks, and every name grows to four letters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WordPress.org's plugin review asked for five things, and this is all of them. The prefix. `atf_` was three letters and the directory requires four, so every collision surface now wears `alltfo_` — the reviewer's own suggestion. Functions, constants, hooks, post types, statuses, capabilities, meta keys, transients, nonce actions, the `wp/v2` rest bases and the shell's entity kind all moved; CSS classes, custom properties and `data-atf-*` attributes stay, because a class name collides with nothing and the stylesheets are the contract the themes were tested against. The style tags. The preview page's document CSS becomes a real enqueued stylesheet (`assets/css/preview.css`), and the front-end renderer stops printing a ` +
``` @@ -136,7 +136,7 @@ id**, inline, so two forms wearing two different themes can sit on the same page ## Adding a token in code ```php -add_filter( 'atf_theme_tokens', function ( $tokens ) { +add_filter( 'alltfo_theme_tokens', function ( $tokens ) { $tokens['field-icon-color'] = 'currentColor'; return $tokens; @@ -161,8 +161,8 @@ the other and the build fails. For a theme that ships inside another plugin, rather than one a user made: ```php -add_action( 'atf_loaded', function () { - atf_register_theme( 'sunset', array( +add_action( 'alltfo_loaded', function () { + alltfo_register_theme( 'sunset', array( 'label' => __( 'Sunset', 'my-plugin' ), 'description' => __( 'Warm gradients, soft corners.', 'my-plugin' ), // Marks the theme as dark so the form gets `atf-is-dark`, which the @@ -187,16 +187,16 @@ Tokens are sanitised at registration rather than at use, so a typo in a token name is dropped once and reported nowhere, instead of being carried around and silently ignored by every reader. -`atf_unregister_theme( 'sunset' )` removes it again. Forms using it fall back to +`alltfo_unregister_theme( 'sunset' )` removes it again. Forms using it fall back to Clean the next time they render, which is recoverable where rewriting every form that referenced it is not. Themes resolve from three sources, each beating the one before: ``` -atf_builtin_themes() the ten that ship +alltfo_builtin_themes() the ten that ship ↓ -atf_register_theme() registered in code by a plugin +alltfo_register_theme() registered in code by a plugin ↓ saved themes (posts) made in the Studio ``` @@ -208,11 +208,11 @@ theme, and get it back by deleting theirs. ## The security boundary -Token values land inside a `
@@ -210,7 +149,7 @@ function atf_maybe_render_preview() { // `preview => true` is what makes this honest: the submission runs the // whole pipeline, including validation, and then stops short of storing // an entry or sending an email. - echo atf_render_form( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Assembled and escaped by the renderer. + echo alltfo_render_form( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Assembled and escaped by the renderer. $form_id, array( 'theme' => $theme, diff --git a/includes/privacy.php b/includes/privacy.php index 256c600..24c9f29 100644 --- a/includes/privacy.php +++ b/includes/privacy.php @@ -17,9 +17,9 @@ defined( 'ABSPATH' ) || exit; -add_filter( 'wp_privacy_personal_data_exporters', 'atf_register_exporter' ); -add_filter( 'wp_privacy_personal_data_erasers', 'atf_register_eraser' ); -add_action( 'admin_init', 'atf_register_privacy_policy_text' ); +add_filter( 'wp_privacy_personal_data_exporters', 'alltfo_register_exporter' ); +add_filter( 'wp_privacy_personal_data_erasers', 'alltfo_register_eraser' ); +add_action( 'admin_init', 'alltfo_register_privacy_policy_text' ); /** * Registers the entries exporter. @@ -29,10 +29,10 @@ * @param array $exporters Registered exporters. * @return array */ -function atf_register_exporter( $exporters ) { +function alltfo_register_exporter( $exporters ) { $exporters['allterrain-forms'] = array( 'exporter_friendly_name' => __( 'Form submissions', 'allterrain-forms' ), - 'callback' => 'atf_export_personal_data', + 'callback' => 'alltfo_export_personal_data', ); return $exporters; @@ -46,10 +46,10 @@ function atf_register_exporter( $exporters ) { * @param array $erasers Registered erasers. * @return array */ -function atf_register_eraser( $erasers ) { +function alltfo_register_eraser( $erasers ) { $erasers['allterrain-forms'] = array( 'eraser_friendly_name' => __( 'Form submissions', 'allterrain-forms' ), - 'callback' => 'atf_erase_personal_data', + 'callback' => 'alltfo_erase_personal_data', ); return $erasers; @@ -69,16 +69,16 @@ function atf_register_eraser( $erasers ) { * @param int $page One-based page. * @return array { entries: WP_Post[], done: bool } */ -function atf_find_entries_for_email( $email, $page = 1 ) { +function alltfo_find_entries_for_email( $email, $page = 1 ) { $per_page = 50; $user = get_user_by( 'email', $email ); $args = array( - 'post_type' => ATF_ENTRY_TYPE, + 'post_type' => ALLTFO_ENTRY_TYPE, // Named, not `'any'`: entry statuses are all `exclude_from_search`, which // `'any'` skips. An export that returns nothing and an erasure that erases // nothing both look like success. - 'post_status' => atf_entry_statuses(), + 'post_status' => alltfo_entry_statuses(), 'posts_per_page' => $per_page, 'paged' => max( 1, (int) $page ), 'orderby' => 'ID', @@ -90,7 +90,7 @@ function atf_find_entries_for_email( $email, $page = 1 ) { // request is rare and runs in the background. $meta = array( array( - 'key' => ATF_META_VALUES, + 'key' => ALLTFO_META_VALUES, 'value' => $email, 'compare' => 'LIKE', ), @@ -99,7 +99,7 @@ function atf_find_entries_for_email( $email, $page = 1 ) { if ( $user ) { $meta['relation'] = 'OR'; $meta[] = array( - 'key' => ATF_META_CONTEXT, + 'key' => ALLTFO_META_CONTEXT, 'value' => '"userId":' . $user->ID . ',', 'compare' => 'LIKE', ); @@ -124,15 +124,15 @@ function atf_find_entries_for_email( $email, $page = 1 ) { * @param int $page One-based page. * @return array The exporter's response. */ -function atf_export_personal_data( $email, $page = 1 ) { - $found = atf_find_entries_for_email( $email, $page ); +function alltfo_export_personal_data( $email, $page = 1 ) { + $found = alltfo_find_entries_for_email( $email, $page ); $items = array(); foreach ( $found['entries'] as $post ) { - $form_id = (int) get_post_meta( $post->ID, ATF_META_FORM, true ); - $schema = atf_get_form_schema( $form_id ); - $values = json_decode( (string) get_post_meta( $post->ID, ATF_META_VALUES, true ), true ); - $context = json_decode( (string) get_post_meta( $post->ID, ATF_META_CONTEXT, true ), true ); + $form_id = (int) get_post_meta( $post->ID, ALLTFO_META_FORM, true ); + $schema = alltfo_get_form_schema( $form_id ); + $values = json_decode( (string) get_post_meta( $post->ID, ALLTFO_META_VALUES, true ), true ); + $context = json_decode( (string) get_post_meta( $post->ID, ALLTFO_META_CONTEXT, true ), true ); $values = is_array( $values ) ? $values : array(); $context = is_array( $context ) ? $context : array(); @@ -148,13 +148,13 @@ function atf_export_personal_data( $email, $page = 1 ) { ), ); - foreach ( atf_input_fields( $schema ) as $field ) { + foreach ( alltfo_input_fields( $schema ) as $field ) { if ( 'password' === $field['type'] ) { continue; } $value = isset( $values[ $field['id'] ] ) ? $values[ $field['id'] ] : ''; - $text = atf_format_field_value( $value, $field, 'email' ); + $text = alltfo_format_field_value( $value, $field, 'email' ); if ( '' === trim( $text ) ) { continue; @@ -202,14 +202,14 @@ function atf_export_personal_data( $email, $page = 1 ) { * @param int $page One-based page. * @return array The eraser's response. */ -function atf_erase_personal_data( $email, $page = 1 ) { +function alltfo_erase_personal_data( $email, $page = 1 ) { // Always page 1: each pass deletes what it finds, so the next pass finds the // next batch at the same offset. Paging forward would skip half of them. - $found = atf_find_entries_for_email( $email, 1 ); + $found = alltfo_find_entries_for_email( $email, 1 ); $removed = 0; foreach ( $found['entries'] as $post ) { - atf_delete_entry_completely( $post->ID ); + alltfo_delete_entry_completely( $post->ID ); ++$removed; } @@ -232,7 +232,7 @@ function atf_erase_personal_data( $email, $page = 1 ) { * * @return void */ -function atf_register_privacy_policy_text() { +function alltfo_register_privacy_policy_text() { if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { return; } diff --git a/includes/render-controls.php b/includes/render-controls.php index d53193f..b68efcc 100644 --- a/includes/render-controls.php +++ b/includes/render-controls.php @@ -25,66 +25,66 @@ * * @param array $field The field. * @param mixed $value Its current value. - * @param array $context The render context from `atf_render_field()`. + * @param array $context The render context from `alltfo_render_field()`. * @return string */ -function atf_render_field_control( $field, $value, $context ) { +function alltfo_render_field_control( $field, $value, $context ) { switch ( $field['type'] ) { case 'textarea': - return atf_render_label( $field, $context['id'] ) . sprintf( + return alltfo_render_label( $field, $context['id'] ) . sprintf( '', - atf_control_attributes( $field, $context ), + alltfo_control_attributes( $field, $context ), isset( $field['rows'] ) ? absint( $field['rows'] ) : 5, esc_textarea( (string) $value ) ); case 'select': - return atf_render_select( $field, $value, $context ); + return alltfo_render_select( $field, $value, $context ); case 'multiselect': - return atf_render_multiselect( $field, $value, $context ); + return alltfo_render_multiselect( $field, $value, $context ); case 'radio': case 'quiz': - return atf_render_choice_group( $field, $value, $context, 'radio' ); + return alltfo_render_choice_group( $field, $value, $context, 'radio' ); case 'checkboxes': - return atf_render_choice_group( $field, $value, $context, 'checkbox' ); + return alltfo_render_choice_group( $field, $value, $context, 'checkbox' ); case 'image_choice': - return atf_render_image_choice( $field, $value, $context ); + return alltfo_render_image_choice( $field, $value, $context ); case 'switch': case 'consent': - return atf_render_single_checkbox( $field, $value, $context ); + return alltfo_render_single_checkbox( $field, $value, $context ); case 'rating': - return atf_render_rating( $field, $value, $context ); + return alltfo_render_rating( $field, $value, $context ); case 'scale': - return atf_render_scale( $field, $value, $context ); + return alltfo_render_scale( $field, $value, $context ); case 'likert': - return atf_render_likert( $field, $value, $context ); + return alltfo_render_likert( $field, $value, $context ); case 'range': - return atf_render_range( $field, $value, $context ); + return alltfo_render_range( $field, $value, $context ); case 'file': - return atf_render_file( $field, $value, $context ); + return alltfo_render_file( $field, $value, $context ); case 'signature': - return atf_render_signature( $field, $value, $context ); + return alltfo_render_signature( $field, $value, $context ); case 'name': - return atf_render_composite( $field, $value, $context, atf_name_parts() ); + return alltfo_render_composite( $field, $value, $context, alltfo_name_parts() ); case 'address': - return atf_render_composite( $field, $value, $context, atf_address_parts() ); + return alltfo_render_composite( $field, $value, $context, alltfo_address_parts() ); case 'date_range': - return atf_render_composite( + return alltfo_render_composite( $field, $value, $context, @@ -101,13 +101,13 @@ function atf_render_field_control( $field, $value, $context ) { ); case 'country': - return atf_render_country( $field, $value, $context ); + return alltfo_render_country( $field, $value, $context ); case 'repeater': - return atf_render_repeater( $field, $value, $context ); + return alltfo_render_repeater( $field, $value, $context ); case 'total': - return atf_render_total( $field, $value, $context ); + return alltfo_render_total( $field, $value, $context ); case 'hidden': return sprintf( @@ -143,7 +143,7 @@ function atf_render_field_control( $field, $value, $context ) { ); case 'page_break': - // Consumed by `atf_schema_pages()` before rendering ever reaches a + // Consumed by `alltfo_schema_pages()` before rendering ever reaches a // break, so arriving here means a break inside a repeater or some // other nesting that cannot paginate. Rendering nothing is right. return ''; @@ -159,7 +159,7 @@ function atf_render_field_control( $field, $value, $context ) { case 'color': case 'text': default: - return atf_render_text_input( $field, $value, $context ); + return alltfo_render_text_input( $field, $value, $context ); } } @@ -173,7 +173,7 @@ function atf_render_field_control( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_text_input( $field, $value, $context ) { +function alltfo_render_text_input( $field, $value, $context ) { $types = array( 'email' => 'email', 'url' => 'url', @@ -187,7 +187,7 @@ function atf_render_text_input( $field, $value, $context ) { ); $type = isset( $types[ $field['type'] ] ) ? $types[ $field['type'] ] : 'text'; - $attributes = atf_control_attributes( $field, $context ); + $attributes = alltfo_control_attributes( $field, $context ); // The date bounds are `min`/`max` in HTML but named `minDate`/`maxDate` in // the schema, because a date field also has a numeric `min` in the shared @@ -203,7 +203,7 @@ function atf_render_text_input( $field, $value, $context ) { } } - return atf_render_label( $field, $context['id'] ) . sprintf( + return alltfo_render_label( $field, $context['id'] ) . sprintf( '', esc_attr( $type ), $attributes, @@ -221,7 +221,7 @@ function atf_render_text_input( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_select( $field, $value, $context ) { +function alltfo_render_select( $field, $value, $context ) { $options = ''; // A placeholder option is `value=""` and `disabled` only when the field is @@ -244,9 +244,9 @@ function atf_render_select( $field, $value, $context ) { ); } - return atf_render_label( $field, $context['id'] ) . sprintf( + return alltfo_render_label( $field, $context['id'] ) . sprintf( '', - atf_control_attributes( $field, $context ), + alltfo_control_attributes( $field, $context ), $options ); } @@ -261,7 +261,7 @@ function atf_render_select( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_multiselect( $field, $value, $context ) { +function alltfo_render_multiselect( $field, $value, $context ) { $selected = array_map( 'strval', (array) $value ); $options = ''; @@ -279,10 +279,10 @@ function atf_render_multiselect( $field, $value, $context ) { $attributes = str_replace( sprintf( 'name="%s"', esc_attr( 'atf[' . $field['id'] . ']' ) ), sprintf( 'name="%s"', esc_attr( 'atf[' . $field['id'] . '][]' ) ), - atf_control_attributes( $field, $context ) + alltfo_control_attributes( $field, $context ) ); - return atf_render_label( $field, $context['id'] ) . sprintf( + return alltfo_render_label( $field, $context['id'] ) . sprintf( '', $attributes, $options @@ -300,7 +300,7 @@ function atf_render_multiselect( $field, $value, $context ) { * @param string $type `radio` or `checkbox`. * @return string */ -function atf_render_choice_group( $field, $value, $context, $type ) { +function alltfo_render_choice_group( $field, $value, $context, $type ) { $multiple = 'checkbox' === $type; $selected = array_map( 'strval', (array) $value ); $name = 'atf[' . $field['id'] . ']' . ( $multiple ? '[]' : '' ); @@ -316,7 +316,7 @@ function atf_render_choice_group( $field, $value, $context, $type ) { $described ); - $out .= atf_render_label( $field, $context['id'], 'legend' ); + $out .= alltfo_render_label( $field, $context['id'], 'legend' ); $out .= '
'; foreach ( $field['choices'] as $index => $choice ) { @@ -352,7 +352,7 @@ function atf_render_choice_group( $field, $value, $context, $type ) { esc_attr( $other_id ), esc_attr( $name ), esc_html__( 'Other', 'allterrain-forms' ), - esc_attr( 'atf_other[' . $field['id'] . ']' ), + esc_attr( 'alltfo_other[' . $field['id'] . ']' ), esc_attr__( 'Please specify', 'allterrain-forms' ) ); } @@ -370,7 +370,7 @@ function atf_render_choice_group( $field, $value, $context, $type ) { * @param array $context The render context. * @return string */ -function atf_render_image_choice( $field, $value, $context ) { +function alltfo_render_image_choice( $field, $value, $context ) { $multiple = ! empty( $field['multiple'] ); $type = $multiple ? 'checkbox' : 'radio'; $selected = array_map( 'strval', (array) $value ); @@ -378,7 +378,7 @@ function atf_render_image_choice( $field, $value, $context ) { $columns = isset( $field['columns'] ) ? max( 1, min( 6, absint( $field['columns'] ) ) ) : 3; $out = sprintf( '
', $columns ); - $out .= atf_render_label( $field, $context['id'], 'legend' ); + $out .= alltfo_render_label( $field, $context['id'], 'legend' ); $out .= '
'; foreach ( $field['choices'] as $index => $choice ) { @@ -419,12 +419,12 @@ function atf_render_image_choice( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_single_checkbox( $field, $value, $context ) { +function alltfo_render_single_checkbox( $field, $value, $context ) { $text = 'consent' === $field['type'] && ! empty( $field['consentText'] ) ? $field['consentText'] : $field['label']; - $attributes = atf_control_attributes( $field, $context ); + $attributes = alltfo_control_attributes( $field, $context ); // A Toggle is drawn as a switch and a Consent as a tick box. They behave // identically — both are one checkbox — but they say different things: a @@ -461,12 +461,12 @@ function atf_render_single_checkbox( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_rating( $field, $value, $context ) { +function alltfo_render_rating( $field, $value, $context ) { $max = isset( $field['max'] ) ? max( 2, min( 10, absint( $field['max'] ) ) ) : 5; $name = 'atf[' . $field['id'] . ']'; $out = '
'; - $out .= atf_render_label( $field, $context['id'], 'legend' ); + $out .= alltfo_render_label( $field, $context['id'], 'legend' ); $out .= '
'; for ( $i = 1; $i <= $max; $i++ ) { @@ -504,7 +504,7 @@ function atf_render_rating( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_scale( $field, $value, $context ) { +function alltfo_render_scale( $field, $value, $context ) { $min = isset( $field['min'] ) ? (int) $field['min'] : 0; $max = isset( $field['max'] ) ? (int) $field['max'] : 10; $name = 'atf[' . $field['id'] . ']'; @@ -518,7 +518,7 @@ function atf_render_scale( $field, $value, $context ) { $max = min( $max, $min + 20 ); $out = '
'; - $out .= atf_render_label( $field, $context['id'], 'legend' ); + $out .= alltfo_render_label( $field, $context['id'], 'legend' ); $out .= '
'; for ( $i = $min; $i <= $max; $i++ ) { @@ -563,17 +563,17 @@ function atf_render_scale( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_likert( $field, $value, $context ) { +function alltfo_render_likert( $field, $value, $context ) { $rows = isset( $field['rows'] ) && is_array( $field['rows'] ) ? $field['rows'] : array(); if ( ! $rows || ! $field['choices'] ) { - return atf_render_label( $field, $context['id'] ); + return alltfo_render_label( $field, $context['id'] ); } $value = is_array( $value ) ? $value : array(); $out = '
'; - $out .= atf_render_label( $field, $context['id'] ); + $out .= alltfo_render_label( $field, $context['id'] ); $out .= sprintf( '', esc_html( $field['label'] ) ); foreach ( $field['choices'] as $choice ) { @@ -620,15 +620,15 @@ function atf_render_likert( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_range( $field, $value, $context ) { +function alltfo_render_range( $field, $value, $context ) { $min = isset( $field['min'] ) ? (float) $field['min'] : 0; $max = isset( $field['max'] ) ? (float) $field['max'] : 100; $current = '' === $value || null === $value ? $min : (float) $value; - return atf_render_label( $field, $context['id'] ) . sprintf( + return alltfo_render_label( $field, $context['id'] ) . sprintf( '
' . '%s
', - atf_control_attributes( $field, $context ), + alltfo_control_attributes( $field, $context ), esc_attr( (string) $current ), esc_attr( $context['id'] ), esc_html( (string) $current ) @@ -645,7 +645,7 @@ function atf_render_range( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_file( $field, $value, $context ) { +function alltfo_render_file( $field, $value, $context ) { $types = isset( $field['filetypes'] ) && is_array( $field['filetypes'] ) ? $field['filetypes'] : array(); $multiple = isset( $field['maxfiles'] ) && absint( $field['maxfiles'] ) > 1; @@ -670,8 +670,8 @@ static function ( $type ) { // The name is the field id without `atf[…]`, because uploads arrive in // `$_FILES` where PHP's nested-array handling is famously awkward. A flat - // name keeps `atf_handle_uploads()` readable. - $name = 'atf_file_' . $field['id'] . ( $multiple ? '[]' : '' ); + // name keeps `alltfo_handle_uploads()` readable. + $name = 'alltfo_file_' . $field['id'] . ( $multiple ? '[]' : '' ); $attributes = sprintf( ' id="%s" name="%s"', @@ -703,7 +703,7 @@ static function ( $type ) { ); } - return atf_render_label( $field, $context['id'] ) . sprintf( + return alltfo_render_label( $field, $context['id'] ) . sprintf( '
%s
', $attributes, $accept, @@ -728,8 +728,8 @@ static function ( $type ) { * @param array $context The render context. * @return string */ -function atf_render_signature( $field, $value, $context ) { - return atf_render_label( $field, $context['id'] ) . sprintf( +function alltfo_render_signature( $field, $value, $context ) { + return alltfo_render_label( $field, $context['id'] ) . sprintf( '
' . '' . '' @@ -743,7 +743,7 @@ function atf_render_signature( $field, $value, $context ) { esc_attr( 'atf[' . $field['id'] . ']' ), esc_attr( (string) $value ), esc_html__( 'Clear', 'allterrain-forms' ), - esc_attr( 'atf_typed[' . $field['id'] . ']' ), + esc_attr( 'alltfo_typed[' . $field['id'] . ']' ), esc_attr__( 'Type your name to sign', 'allterrain-forms' ) ); } @@ -759,12 +759,12 @@ function atf_render_signature( $field, $value, $context ) { * @param array $parts Part key => { label, type, autocomplete }. * @return string */ -function atf_render_composite( $field, $value, $context, $parts ) { +function alltfo_render_composite( $field, $value, $context, $parts ) { $enabled = isset( $field['parts'] ) && is_array( $field['parts'] ) ? $field['parts'] : array_keys( $parts ); $value = is_array( $value ) ? $value : array(); $out = '
'; - $out .= atf_render_label( $field, $context['id'], 'legend' ); + $out .= alltfo_render_label( $field, $context['id'], 'legend' ); $out .= '
'; foreach ( $parts as $key => $part ) { @@ -804,7 +804,7 @@ function atf_render_composite( $field, $value, $context, $parts ) { * * @return array */ -function atf_name_parts() { +function alltfo_name_parts() { /** * Filters the parts offered by the name field. * @@ -813,7 +813,7 @@ function atf_name_parts() { * @param array $parts Part key => { label, autocomplete }. */ return apply_filters( - 'atf_name_parts', + 'alltfo_name_parts', array( 'prefix' => array( 'label' => __( 'Title', 'allterrain-forms' ), @@ -846,7 +846,7 @@ function atf_name_parts() { * * @return array */ -function atf_address_parts() { +function alltfo_address_parts() { /** * Filters the parts offered by the address field. * @@ -855,7 +855,7 @@ function atf_address_parts() { * @param array $parts Part key => { label, autocomplete }. */ return apply_filters( - 'atf_address_parts', + 'alltfo_address_parts', array( 'line1' => array( 'label' => __( 'Address', 'allterrain-forms' ), @@ -895,14 +895,14 @@ function atf_address_parts() { * @param array $context The render context. * @return string */ -function atf_render_country( $field, $value, $context ) { +function alltfo_render_country( $field, $value, $context ) { $options = sprintf( '', $field['required'] ? ' disabled' : '', esc_html( '' !== $field['placeholder'] ? $field['placeholder'] : __( 'Choose a country', 'allterrain-forms' ) ) ); - foreach ( atf_countries() as $code => $name ) { + foreach ( alltfo_countries() as $code => $name ) { $options .= sprintf( '', esc_attr( $code ), @@ -911,9 +911,9 @@ function atf_render_country( $field, $value, $context ) { ); } - return atf_render_label( $field, $context['id'] ) . sprintf( + return alltfo_render_label( $field, $context['id'] ) . sprintf( '', - atf_control_attributes( $field, $context ), + alltfo_control_attributes( $field, $context ), $options ); } @@ -932,7 +932,7 @@ function atf_render_country( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_repeater( $field, $value, $context ) { +function alltfo_render_repeater( $field, $value, $context ) { $sub_fields = isset( $field['fields'] ) && is_array( $field['fields'] ) ? $field['fields'] : array(); $rows = is_array( $value ) && $value ? $value : array( array() ); @@ -941,13 +941,13 @@ function atf_render_repeater( $field, $value, $context ) { esc_attr( $field['id'] ), isset( $field['minRows'] ) ? absint( $field['minRows'] ) : 1, isset( $field['maxRows'] ) ? absint( $field['maxRows'] ) : 10, - esc_attr( atf_repeater_item_label( $field ) ) + esc_attr( alltfo_repeater_item_label( $field ) ) ); - $out .= atf_render_label( $field, $context['id'] ); + $out .= alltfo_render_label( $field, $context['id'] ); $out .= '
'; foreach ( $rows as $index => $row ) { - $out .= atf_render_repeater_row( $field, $sub_fields, is_array( $row ) ? $row : array(), $index, $context ); + $out .= alltfo_render_repeater_row( $field, $sub_fields, is_array( $row ) ? $row : array(), $index, $context ); } $out .= '
'; @@ -964,7 +964,7 @@ function atf_render_repeater( $field, $value, $context ) { // visible to a screen reader until it is cloned into place. $out .= sprintf( '', - atf_render_repeater_row( $field, $sub_fields, array(), '__INDEX__', $context ) + alltfo_render_repeater_row( $field, $sub_fields, array(), '__INDEX__', $context ) ); return $out . '
'; @@ -982,8 +982,8 @@ function atf_render_repeater( $field, $value, $context ) { * @param array $context The render context. * @return string */ -function atf_render_repeater_row( $field, $sub_fields, $row, $index, $context ) { - $item_label = atf_repeater_item_label( $field ); +function alltfo_render_repeater_row( $field, $sub_fields, $row, $index, $context ) { + $item_label = alltfo_repeater_item_label( $field ); // The template row's number is unknowable until it is cloned; the bundle // renumbers every row after each add and remove anyway, so the template @@ -1039,7 +1039,7 @@ function atf_render_repeater_row( $field, $sub_fields, $row, $index, $context ) // then its name rewritten to the nested form. Rendering it specially // instead would mean a second implementation of every control that can // appear inside a repeater, and they would drift. - $control = atf_render_field_control( + $control = alltfo_render_field_control( $sub, isset( $row[ $sub['id'] ] ) ? $row[ $sub['id'] ] : $sub['default'], $sub_context @@ -1051,7 +1051,7 @@ function atf_render_repeater_row( $field, $sub_fields, $row, $index, $context ) // and the composites -- name, address, Likert -- append `[part]`. // Anchoring on the closing quote would leave all of those under the // sub-field's own name, where the rows collide with each other and - // `atf_sanitize_repeater_value()` finds nothing it recognises. + // `alltfo_sanitize_repeater_value()` finds nothing it recognises. $control = str_replace( 'name="' . esc_attr( 'atf[' . $sub['id'] . ']' ), 'name="' . esc_attr( 'atf[' . $field['id'] . '][' . $index . '][' . $sub['id'] . ']' ), @@ -1099,8 +1099,8 @@ function atf_render_repeater_row( $field, $sub_fields, $row, $index, $context ) * @param array $context The render context. * @return string */ -function atf_render_total( $field, $value, $context ) { - return atf_render_label( $field, $context['id'] ) . sprintf( +function alltfo_render_total( $field, $value, $context ) { + return alltfo_render_label( $field, $context['id'] ) . sprintf( '
%s
', ! empty( $field['currency'] ) ? sprintf( '', esc_html( $field['currency'] ) ) : '', @@ -1122,7 +1122,7 @@ function atf_render_total( $field, $value, $context ) { * * @return array Code => name. */ -function atf_countries() { +function alltfo_countries() { $countries = array( 'AF' => 'Afghanistan', 'AL' => 'Albania', @@ -1329,5 +1329,5 @@ function atf_countries() { * * @param array $countries ISO 3166-1 alpha-2 code => name. */ - return apply_filters( 'atf_countries', $countries ); + return apply_filters( 'alltfo_countries', $countries ); } diff --git a/includes/render.php b/includes/render.php index 570095b..77df33d 100644 --- a/includes/render.php +++ b/includes/render.php @@ -46,14 +46,14 @@ * } * @return string The form's HTML. */ -function atf_render_form( $form_id, $args = array() ) { +function alltfo_render_form( $form_id, $args = array() ) { $form_id = absint( $form_id ); $form = $form_id ? get_post( $form_id ) : null; - if ( ! $form || ATF_FORM_TYPE !== $form->post_type ) { + if ( ! $form || ALLTFO_FORM_TYPE !== $form->post_type ) { // Silent for visitors, loud for the person who can fix it. A broken // shortcode id should never print an error into a published page. - if ( atf_can_edit_forms() ) { + if ( alltfo_can_edit_forms() ) { return sprintf( '

%s

', esc_html__( 'AllTerrain Forms: that form does not exist.', 'allterrain-forms' ) @@ -76,17 +76,16 @@ function atf_render_form( $form_id, $args = array() ) { ) ); - $schema = atf_get_form_schema( $form_id ); + $schema = alltfo_get_form_schema( $form_id ); $settings = $schema['settings']; $theme_slug = '' !== $args['theme'] ? $args['theme'] : $settings['theme']; - $tokens = atf_resolve_tokens( $theme_slug, $settings['themeOverrides'] ); + $tokens = alltfo_resolve_tokens( $theme_slug, $settings['themeOverrides'] ); // A unique instance id, not the form id: the same form can legitimately be // on a page twice, and duplicate DOM ids would break every `for` attribute // and every `aria-describedby` on the second copy. - $instance = atf_next_instance_id( $form_id ); - $scope = '#' . $instance; + $instance = alltfo_next_instance_id( $form_id ); $classes = array( 'atf-form', @@ -95,7 +94,7 @@ function atf_render_form( $form_id, $args = array() ) { 'atf-fields-' . sanitize_html_class( $tokens['field-style'] ), ); - if ( ! empty( atf_get_theme( $theme_slug )['dark'] ) ) { + if ( ! empty( alltfo_get_theme( $theme_slug )['dark'] ) ) { $classes[] = 'atf-is-dark'; } @@ -108,34 +107,25 @@ function atf_render_form( $form_id, $args = array() ) { * @param int $form_id The form. * @param array $schema The form schema. */ - $classes = apply_filters( 'atf_form_classes', $classes, $form_id, $schema ); + $classes = apply_filters( 'alltfo_form_classes', $classes, $form_id, $schema ); - $out = sprintf( - '
', - esc_attr( $instance ) - ); - - // Scoped to the wrapper, not to the form. + // The theme's tokens ride the wrapper's own `style` attribute — no `` inside a style - // block is the one mistake that would matter. - $out .= sprintf( '', wp_strip_all_tags( $css ) ); - } + $style = alltfo_tokens_to_declarations( $tokens ); + + $out = sprintf( + '
', + esc_attr( $instance ), + '' !== $style ? sprintf( ' style="%s"', esc_attr( $style ) ) : '' + ); if ( 'show' === $args['title'] ) { $out .= sprintf( '

%s

', esc_html( get_the_title( $form ) ) ); @@ -148,13 +138,13 @@ function atf_render_form( $form_id, $args = array() ) { $out .= sprintf( '
%s
', esc_attr( implode( ' ', $classes ) ), - atf_success_screen_html( $args['message'], isset( $args['success'] ) ? $args['success'] : array() ) + alltfo_success_screen_html( $args['message'], isset( $args['success'] ) ? $args['success'] : array() ) ); return $out; } - $gate = atf_form_availability( $form_id, $schema ); + $gate = alltfo_form_availability( $form_id, $schema ); if ( ! $gate['open'] ) { $out .= sprintf( @@ -167,7 +157,7 @@ function atf_render_form( $form_id, $args = array() ) { } if ( ! $args['preview'] ) { - atf_record_view( $form_id ); + alltfo_record_view( $form_id ); } // A resume link beats the field defaults but loses to anything the caller @@ -175,8 +165,8 @@ function atf_render_form( $form_id, $args = array() ) { // with what was just typed rather than with what was saved yesterday. $resume_token = ''; - if ( isset( $_GET[ ATF_RESUME_QUERY ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The token itself is the credential; it is verified by `atf_resume_values()`. - $resumed = atf_resume_values( sanitize_text_field( wp_unslash( $_GET[ ATF_RESUME_QUERY ] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- As above. + if ( isset( $_GET[ ALLTFO_RESUME_QUERY ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The token itself is the credential; it is verified by `alltfo_resume_values()`. + $resumed = alltfo_resume_values( sanitize_text_field( wp_unslash( $_GET[ ALLTFO_RESUME_QUERY ] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- As above. if ( $resumed && $resumed['form_id'] === $form_id ) { $resume_token = $resumed['token']; @@ -184,27 +174,27 @@ function atf_render_form( $form_id, $args = array() ) { } } - $values = atf_prefill_values( $schema, $args['values'] ); + $values = alltfo_prefill_values( $schema, $args['values'] ); $out .= sprintf( '', esc_attr( implode( ' ', $classes ) ), - esc_url( atf_form_action_url() ), + esc_url( alltfo_form_action_url() ), $form_id, esc_attr( $instance ), $args['preview'] ? ' data-atf-preview="1"' : '', - atf_has_upload_field( $schema ) ? ' enctype="multipart/form-data"' : '' + alltfo_has_upload_field( $schema ) ? ' enctype="multipart/form-data"' : '' ); - $out .= atf_render_hidden_fields( $form_id, $schema, $args['preview'], $instance ); - $out .= atf_render_client_schema( $schema, $instance ); - $out .= atf_render_error_summary( $args['errors'], $schema, $instance ); + $out .= alltfo_render_hidden_fields( $form_id, $schema, $args['preview'], $instance ); + $out .= alltfo_render_client_schema( $schema, $instance ); + $out .= alltfo_render_error_summary( $args['errors'], $schema, $instance ); - $pages = atf_schema_pages( $schema ); + $pages = alltfo_schema_pages( $schema ); $multi = count( $pages ) > 1; if ( $multi ) { - $out .= atf_render_progress( $pages, $settings ); + $out .= alltfo_render_progress( $pages, $settings ); } foreach ( $pages as $index => $page ) { @@ -215,23 +205,23 @@ function atf_render_form( $form_id, $args = array() ) { // same break whose Next brought the visitor here. $arrived_by = $index > 0 && isset( $pages[ $index - 1 ]['break'] ) ? $pages[ $index - 1 ]['break'] : null; - $out .= atf_render_page( $page, $index, count( $pages ), $schema, $values, $args['errors'], $instance, $arrived_by ); + $out .= alltfo_render_page( $page, $index, count( $pages ), $schema, $values, $args['errors'], $instance, $arrived_by ); } // After the last page, so a multi-page form asks its question at the end // rather than making the visitor answer arithmetic before they have seen // what the form is for. - $out .= atf_render_challenge( $schema, $form_id ); + $out .= alltfo_render_challenge( $schema, $form_id ); if ( ! $multi ) { - $out .= atf_render_submit( $settings, true, atf_render_resume_button( $schema, $resume_token ) ); - } elseif ( '' !== atf_render_resume_button( $schema, $resume_token ) ) { + $out .= alltfo_render_submit( $settings, true, alltfo_render_resume_button( $schema, $resume_token ) ); + } elseif ( '' !== alltfo_render_resume_button( $schema, $resume_token ) ) { // On a multi-page form the submit button lives on the last page, but // "save for later" has to be reachable from every one of them -- that is // the whole point of it. So it sits outside the pages entirely. $out .= sprintf( '
%s
', - atf_render_resume_button( $schema, $resume_token ) + alltfo_render_resume_button( $schema, $resume_token ) ); } @@ -246,7 +236,7 @@ function atf_render_form( $form_id, $args = array() ) { * @param int $form_id The form. * @param array $schema The form schema. */ - return apply_filters( 'atf_rendered_form', $out, $form_id, $schema ); + return apply_filters( 'alltfo_rendered_form', $out, $form_id, $schema ); } /** @@ -257,7 +247,7 @@ function atf_render_form( $form_id, $args = array() ) { * @param int $form_id The form. * @return string An id safe for an `id` attribute. */ -function atf_next_instance_id( $form_id ) { +function alltfo_next_instance_id( $form_id ) { static $counts = array(); $counts[ $form_id ] = isset( $counts[ $form_id ] ) ? $counts[ $form_id ] + 1 : 1; @@ -276,7 +266,7 @@ function atf_next_instance_id( $form_id ) { * * @return string */ -function atf_form_action_url() { +function alltfo_form_action_url() { $url = ''; if ( isset( $_SERVER['REQUEST_URI'] ) ) { @@ -291,7 +281,7 @@ function atf_form_action_url() { * * The honeypot is here rather than in the field loop because it must never be a * field: it has no label in the palette, no place in the schema, and no entry - * column. Its name is deliberately plausible (`atf_website`) because bots fill + * column. Its name is deliberately plausible (`alltfo_website`) because bots fill * anything that looks like a real field and skip anything called `honeypot`. * `tabindex="-1"` and `aria-hidden` keep it away from keyboard and screen-reader * users, and it is hidden in CSS rather than with `type="hidden"` -- a hidden @@ -305,25 +295,25 @@ function atf_form_action_url() { * @param string $instance The render's DOM id prefix. * @return string */ -function atf_render_hidden_fields( $form_id, $schema, $preview = false, $instance = '' ) { - $out = sprintf( '', $form_id ); +function alltfo_render_hidden_fields( $form_id, $schema, $preview = false, $instance = '' ) { + $out = sprintf( '', $form_id ); // A nonce on a public front-end form is not CSRF protection -- there is no // session to protect and the form is meant to be submitted by strangers. It // is here because it makes replaying a captured request past the nonce // lifetime fail, which raises the cost of the crudest spam scripts. $out .= sprintf( - '', - esc_attr( wp_create_nonce( 'atf_submit_' . $form_id ) ) + '', + esc_attr( wp_create_nonce( 'alltfo_submit_' . $form_id ) ) ); // Signed rather than raw, so the time trap cannot be defeated by posting an // older timestamp than the one that was served. $issued = time(); - $out .= sprintf( '', $issued ); + $out .= sprintf( '', $issued ); $out .= sprintf( - '', - esc_attr( atf_sign_timestamp( $form_id, $issued ) ) + '', + esc_attr( alltfo_sign_timestamp( $form_id, $issued ) ) ); if ( ! empty( $schema['settings']['spam']['honeypot'] ) ) { @@ -336,12 +326,12 @@ function atf_render_hidden_fields( $form_id, $schema, $preview = false, $instanc . '' - . '' + . '' . '
'; } if ( $preview ) { - $out .= ''; + $out .= ''; } return $out; @@ -356,7 +346,7 @@ function atf_render_hidden_fields( $form_id, $schema, $preview = false, $instanc * @param int $issued Unix timestamp the form was rendered at. * @return string The signature. */ -function atf_sign_timestamp( $form_id, $issued ) { +function alltfo_sign_timestamp( $form_id, $issued ) { return wp_hash( 'atf|' . $form_id . '|' . $issued ); } @@ -382,11 +372,11 @@ function atf_sign_timestamp( $form_id, $issued ) { * @param string $instance The render's DOM id prefix. * @return string A JSON script tag. */ -function atf_render_client_schema( $schema, $instance ) { +function alltfo_render_client_schema( $schema, $instance ) { $fields = array(); foreach ( isset( $schema['fields'] ) ? $schema['fields'] : array() as $field ) { - $fields[] = atf_client_field( $field ); + $fields[] = alltfo_client_field( $field ); } $payload = array( @@ -408,7 +398,7 @@ function atf_render_client_schema( $schema, $instance ) { * @param array $payload The client schema. * @param array $schema The full schema. */ - $payload = apply_filters( 'atf_client_schema', $payload, $schema ); + $payload = apply_filters( 'alltfo_client_schema', $payload, $schema ); return sprintf( '', @@ -432,7 +422,7 @@ function atf_render_client_schema( $schema, $instance ) { * @param array $field A normalised field. * @return array What the front-end bundle needs to know about it. */ -function atf_client_field( $field ) { +function alltfo_client_field( $field ) { $client = array( 'id' => $field['id'], 'type' => $field['type'], @@ -468,7 +458,7 @@ function atf_client_field( $field ) { $client['fields'] = array(); foreach ( $field['fields'] as $sub ) { - $client['fields'][] = atf_client_field( $sub ); + $client['fields'][] = alltfo_client_field( $sub ); } } @@ -490,7 +480,7 @@ function atf_client_field( $field ) { * @param string $instance The render's DOM id prefix. * @return string */ -function atf_render_error_summary( $errors, $schema, $instance ) { +function alltfo_render_error_summary( $errors, $schema, $instance ) { if ( ! $errors ) { // Rendered empty rather than omitted, so the bundle has somewhere to put // client-side errors without building the region at the moment focus @@ -510,7 +500,7 @@ function atf_render_error_summary( $errors, $schema, $instance ) { foreach ( $errors as $field_id => $message ) { $parts = explode( '.', (string) $field_id ); - if ( 3 === count( $parts ) && atf_find_field( $schema, $parts[0] ) ) { + if ( 3 === count( $parts ) && alltfo_find_field( $schema, $parts[0] ) ) { $nested[ $parts[0] ][] = array( 'row' => (int) $parts[1], 'sub' => $parts[2], @@ -526,7 +516,7 @@ function atf_render_error_summary( $errors, $schema, $instance ) { $items = ''; foreach ( $top as $field_id => $message ) { - $field = atf_find_field( $schema, $field_id ); + $field = alltfo_find_field( $schema, $field_id ); $label = $field && '' !== $field['label'] ? $field['label'] : ''; // A repeater with named boxes heads its own indented group: the @@ -550,7 +540,7 @@ function atf_render_error_summary( $errors, $schema, $instance ) { $row_name = sprintf( /* translators: 1: what one row is called, e.g. "Attendee", 2: row number. */ __( '%1$s %2$d', 'allterrain-forms' ), - atf_repeater_item_label( $field ), + alltfo_repeater_item_label( $field ), $entry['row'] + 1 ); @@ -603,7 +593,7 @@ function atf_render_error_summary( $errors, $schema, $instance ) { * @param array $settings The form settings. * @return string */ -function atf_render_progress( $pages, $settings ) { +function alltfo_render_progress( $pages, $settings ) { $style = isset( $settings['progressBar'] ) ? $settings['progressBar'] : 'steps'; if ( 'none' === $style ) { @@ -669,7 +659,7 @@ function atf_render_progress( $pages, $settings ) { * the first page, which has nothing to go back to. * @return string */ -function atf_render_page( $page, $index, $total, $schema, $values, $errors, $instance, $arrived_by = null ) { +function alltfo_render_page( $page, $index, $total, $schema, $values, $errors, $instance, $arrived_by = null ) { $multi = $total > 1; $out = sprintf( @@ -685,7 +675,7 @@ function atf_render_page( $page, $index, $total, $schema, $values, $errors, $ins $out .= '
'; foreach ( $page['fields'] as $field ) { - $out .= atf_render_field( $field, $schema, $values, $errors, $instance ); + $out .= alltfo_render_field( $field, $schema, $values, $errors, $instance ); } $out .= '
'; @@ -714,7 +704,7 @@ function atf_render_page( $page, $index, $total, $schema, $values, $errors, $ins esc_html( $next ) ); } else { - $out .= atf_render_submit( $schema['settings'], false ); + $out .= alltfo_render_submit( $schema['settings'], false ); } $out .= '
'; @@ -733,7 +723,7 @@ function atf_render_page( $page, $index, $total, $schema, $values, $errors, $ins * @param string $extra Markup placed beside the button, inside the row. * @return string */ -function atf_render_submit( $settings, $wrap = true, $extra = '' ) { +function alltfo_render_submit( $settings, $wrap = true, $extra = '' ) { $label = '' !== $settings['submitLabel'] ? $settings['submitLabel'] : __( 'Send', 'allterrain-forms' ); $button = sprintf( @@ -770,8 +760,8 @@ function atf_render_submit( $settings, $wrap = true, $extra = '' ) { * @param string $instance The render's DOM id prefix. * @return string */ -function atf_render_field( $field, $schema, $values, $errors, $instance ) { - $definition = atf_get_field_type( $field['type'] ); +function alltfo_render_field( $field, $schema, $values, $errors, $instance ) { + $definition = alltfo_get_field_type( $field['type'] ); /** * Short-circuits the rendering of one field. @@ -785,7 +775,7 @@ function atf_render_field( $field, $schema, $values, $errors, $instance ) { * @param array $schema The form schema. * @param array $values Current values. */ - $short_circuit = apply_filters( 'atf_pre_render_field', null, $field, $schema, $values ); + $short_circuit = apply_filters( 'alltfo_pre_render_field', null, $field, $schema, $values ); if ( null !== $short_circuit ) { return (string) $short_circuit; @@ -794,7 +784,7 @@ function atf_render_field( $field, $schema, $values, $errors, $instance ) { $id = $instance . '-' . $field['id']; $value = isset( $values[ $field['id'] ] ) ? $values[ $field['id'] ] : $field['default']; $error = isset( $errors[ $field['id'] ] ) ? $errors[ $field['id'] ] : ''; - $visible = atf_field_is_visible( $schema, $field['id'], $values ); + $visible = alltfo_field_is_visible( $schema, $field['id'], $values ); $classes = array( 'atf-field', @@ -858,7 +848,7 @@ function atf_render_field( $field, $schema, $values, $errors, $instance ) { if ( $definition && is_callable( $definition['render'] ) ) { $out .= (string) call_user_func( $definition['render'], $field, $value, $context ); } else { - $out .= atf_render_field_control( $field, $value, $context ); + $out .= alltfo_render_field_control( $field, $value, $context ); } if ( '' !== $field['hint'] ) { @@ -888,7 +878,7 @@ function atf_render_field( $field, $schema, $values, $errors, $instance ) { * @param mixed $value Its current value. * @param array $schema The form schema. */ - return apply_filters( 'atf_rendered_field', $out, $field, $value, $schema ); + return apply_filters( 'alltfo_rendered_field', $out, $field, $value, $schema ); } /** @@ -906,7 +896,7 @@ function atf_render_field( $field, $schema, $values, $errors, $instance ) { * @param string $tag `label` for a real control, `legend` inside a fieldset. * @return string */ -function atf_render_label( $field, $id, $tag = 'label' ) { +function alltfo_render_label( $field, $id, $tag = 'label' ) { if ( '' === $field['label'] ) { return ''; } @@ -936,7 +926,7 @@ function atf_render_label( $field, $id, $tag = 'label' ) { * @param array $context The render context. * @return string */ -function atf_control_attributes( $field, $context ) { +function alltfo_control_attributes( $field, $context ) { $attributes = sprintf( ' id="%s" name="%s"', esc_attr( $context['id'] ), @@ -982,7 +972,7 @@ function atf_control_attributes( $field, $context ) { // An autocomplete token turns a form into one the browser can fill, which is // both a usability win and a WCAG 1.3.5 requirement. - $autocomplete = atf_autocomplete_token( $field ); + $autocomplete = alltfo_autocomplete_token( $field ); if ( '' !== $autocomplete ) { $attributes .= sprintf( ' autocomplete="%s"', esc_attr( $autocomplete ) ); @@ -999,7 +989,7 @@ function atf_control_attributes( $field, $context ) { * @param array $field The field. * @return string A token, or an empty string. */ -function atf_autocomplete_token( $field ) { +function alltfo_autocomplete_token( $field ) { $by_type = array( 'email' => 'email', 'tel' => 'tel', @@ -1020,5 +1010,5 @@ function atf_autocomplete_token( $field ) { * @param string $token The token, or an empty string. * @param array $field The field. */ - return (string) apply_filters( 'atf_autocomplete_token', '', $field ); + return (string) apply_filters( 'alltfo_autocomplete_token', '', $field ); } diff --git a/includes/rest.php b/includes/rest.php index ca56fd2..05060b9 100644 --- a/includes/rest.php +++ b/includes/rest.php @@ -6,7 +6,7 @@ * route here. * * The **builder** routes -- forms, themes, entries, analytics -- require - * `atf_edit_forms` or `atf_read_entries` and are called by an authenticated + * `alltfo_edit_forms` or `alltfo_read_entries` and are called by an authenticated * admin with a nonce. * * The **submit** route is public by definition. It is the only route with @@ -19,7 +19,7 @@ defined( 'ABSPATH' ) || exit; -add_action( 'rest_api_init', 'atf_register_rest_routes' ); +add_action( 'rest_api_init', 'alltfo_register_rest_routes' ); /** * Registers every route. @@ -28,29 +28,29 @@ * * @return void */ -function atf_register_rest_routes() { - $ns = ATF_REST_NAMESPACE; +function alltfo_register_rest_routes() { + $ns = ALLTFO_REST_NAMESPACE; register_rest_route( $ns, '/submit', array( 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_submit', + 'callback' => 'alltfo_rest_submit', // Public on purpose: this is how a stranger sends a form. Every // check that would normally live in a permission callback -- // whether the form is open, whether the visitor may see it, whether // this looks like spam -- happens inside the pipeline, because they // all depend on which form was posted. 'permission_callback' => '__return_true', - // The parameter is `atf_form_id`, because the bundle posts the + // The parameter is `alltfo_form_id`, because the bundle posts the // form's own `FormData` wholesale and that is the name of the hidden // input the renderer emits. Declaring `form_id` here instead makes // WordPress reject every real submission with "Missing parameter(s)" // *before* the callback runs -- a failure no test that calls - // `atf_process_submission()` directly can ever see. + // `alltfo_process_submission()` directly can ever see. 'args' => array( - 'atf_form_id' => array( + 'alltfo_form_id' => array( 'required' => true, 'type' => 'integer', 'sanitize_callback' => 'absint', @@ -64,15 +64,15 @@ function atf_register_rest_routes() { '/resume', array( 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_save_partial', + 'callback' => 'alltfo_rest_save_partial', // Public for the same reason `/submit` is: a half-finished form // belongs to a visitor who has no account. The nonce is checked in // the handler, and the form must have the feature switched on. 'permission_callback' => '__return_true', - // `atf_form_id`, for the same reason as `/submit` above: the bundle + // `alltfo_form_id`, for the same reason as `/submit` above: the bundle // posts the form's own FormData. 'args' => array( - 'atf_form_id' => array( + 'alltfo_form_id' => array( 'required' => true, 'type' => 'integer', 'sanitize_callback' => 'absint', @@ -87,13 +87,13 @@ function atf_register_rest_routes() { array( array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_list_forms', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_list_forms', + 'permission_callback' => 'alltfo_rest_can_edit', ), array( 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_create_form', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_create_form', + 'permission_callback' => 'alltfo_rest_can_edit', ), ) ); @@ -104,18 +104,18 @@ function atf_register_rest_routes() { array( array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_get_form', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_get_form', + 'permission_callback' => 'alltfo_rest_can_edit', ), array( 'methods' => WP_REST_Server::EDITABLE, - 'callback' => 'atf_rest_update_form', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_update_form', + 'permission_callback' => 'alltfo_rest_can_edit', ), array( 'methods' => WP_REST_Server::DELETABLE, - 'callback' => 'atf_rest_delete_form', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_delete_form', + 'permission_callback' => 'alltfo_rest_can_edit', ), ) ); @@ -125,8 +125,8 @@ function atf_register_rest_routes() { '/forms/(?P\d+)/duplicate', array( 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_duplicate_form', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_duplicate_form', + 'permission_callback' => 'alltfo_rest_can_edit', ) ); @@ -135,8 +135,8 @@ function atf_register_rest_routes() { '/forms/(?P\d+)/archive', array( 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_archive_form', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_archive_form', + 'permission_callback' => 'alltfo_rest_can_edit', ) ); @@ -145,8 +145,8 @@ function atf_register_rest_routes() { '/forms/(?P\d+)/unarchive', array( 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_unarchive_form', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_unarchive_form', + 'permission_callback' => 'alltfo_rest_can_edit', ) ); @@ -160,8 +160,8 @@ function atf_register_rest_routes() { // "No route was found matching the URL and request method" — a 404 // that reads like a missing route rather than a wrong verb. 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_preview_form', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_preview_form', + 'permission_callback' => 'alltfo_rest_can_edit', ) ); @@ -170,8 +170,8 @@ function atf_register_rest_routes() { '/forms/(?P\d+)/merge-tags', array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_merge_tags', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_merge_tags', + 'permission_callback' => 'alltfo_rest_can_edit', ) ); @@ -180,8 +180,8 @@ function atf_register_rest_routes() { '/forms/(?P\d+)/analytics', array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_analytics', - 'permission_callback' => 'atf_rest_can_read_entries', + 'callback' => 'alltfo_rest_analytics', + 'permission_callback' => 'alltfo_rest_can_read_entries', 'args' => array( 'dimension' => array( 'type' => 'string', @@ -193,7 +193,7 @@ function atf_register_rest_routes() { ); // The demo-data tools. Gated twice over: developer mode says "show me these", - // `atf_edit_forms` says "you may use them", and the two are not the same + // `alltfo_edit_forms` says "you may use them", and the two are not the same // question -- see `includes/dev-mode.php`. register_rest_route( $ns, @@ -201,13 +201,13 @@ function atf_register_rest_routes() { array( array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_demo_status', - 'permission_callback' => 'atf_rest_can_use_developer_tools', + 'callback' => 'alltfo_rest_demo_status', + 'permission_callback' => 'alltfo_rest_can_use_developer_tools', ), array( 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_demo_seed', - 'permission_callback' => 'atf_rest_can_use_developer_tools', + 'callback' => 'alltfo_rest_demo_seed', + 'permission_callback' => 'alltfo_rest_can_use_developer_tools', 'args' => array( 'count' => array( 'type' => 'integer', @@ -217,8 +217,8 @@ function atf_register_rest_routes() { ), array( 'methods' => WP_REST_Server::DELETABLE, - 'callback' => 'atf_rest_demo_remove', - 'permission_callback' => 'atf_rest_can_use_developer_tools', + 'callback' => 'alltfo_rest_demo_remove', + 'permission_callback' => 'alltfo_rest_can_use_developer_tools', ), ) ); @@ -228,8 +228,8 @@ function atf_register_rest_routes() { '/entries', array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_list_entries', - 'permission_callback' => 'atf_rest_can_read_entries', + 'callback' => 'alltfo_rest_list_entries', + 'permission_callback' => 'alltfo_rest_can_read_entries', ) ); @@ -239,18 +239,18 @@ function atf_register_rest_routes() { array( array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_get_entry', - 'permission_callback' => 'atf_rest_can_read_entries', + 'callback' => 'alltfo_rest_get_entry', + 'permission_callback' => 'alltfo_rest_can_read_entries', ), array( 'methods' => WP_REST_Server::EDITABLE, - 'callback' => 'atf_rest_update_entry', - 'permission_callback' => 'atf_rest_can_read_entries', + 'callback' => 'alltfo_rest_update_entry', + 'permission_callback' => 'alltfo_rest_can_read_entries', ), array( 'methods' => WP_REST_Server::DELETABLE, - 'callback' => 'atf_rest_delete_entry', - 'permission_callback' => 'atf_rest_can_delete_entries', + 'callback' => 'alltfo_rest_delete_entry', + 'permission_callback' => 'alltfo_rest_can_delete_entries', ), ) ); @@ -260,8 +260,8 @@ function atf_register_rest_routes() { '/entries/export', array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_export_entries', - 'permission_callback' => 'atf_rest_can_read_entries', + 'callback' => 'alltfo_rest_export_entries', + 'permission_callback' => 'alltfo_rest_can_read_entries', ) ); @@ -271,13 +271,13 @@ function atf_register_rest_routes() { array( array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_list_themes', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_list_themes', + 'permission_callback' => 'alltfo_rest_can_edit', ), array( 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_save_theme', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_save_theme', + 'permission_callback' => 'alltfo_rest_can_edit', ), ) ); @@ -287,8 +287,8 @@ function atf_register_rest_routes() { '/themes/(?P\d+)', array( 'methods' => WP_REST_Server::DELETABLE, - 'callback' => 'atf_rest_delete_theme', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_delete_theme', + 'permission_callback' => 'alltfo_rest_can_edit', ) ); @@ -297,8 +297,8 @@ function atf_register_rest_routes() { '/config', array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_config', - 'permission_callback' => 'atf_rest_can_edit', + 'callback' => 'alltfo_rest_config', + 'permission_callback' => 'alltfo_rest_can_edit', ) ); @@ -307,10 +307,10 @@ function atf_register_rest_routes() { '/mailpoet', array( 'methods' => WP_REST_Server::READABLE, - 'callback' => 'atf_rest_mailpoet', + 'callback' => 'alltfo_rest_mailpoet', // Editing forms is the capability that matters: connecting a form // to a list is editing what the form does on submit. - 'permission_callback' => 'atf_rest_can_edit', + 'permission_callback' => 'alltfo_rest_can_edit', ) ); @@ -319,8 +319,27 @@ function atf_register_rest_routes() { '/track', array( 'methods' => WP_REST_Server::CREATABLE, - 'callback' => 'atf_rest_track', + 'callback' => 'alltfo_rest_track', + // Public on purpose, for the same reason `/submit` is: the "someone + // began filling this form in" ping comes from a logged-out visitor + // on the front end. It records nothing but an anonymous counter + // bump against a published form — the handler verifies the form + // exists and has analytics switched on before touching anything — + // and nothing is read back or sent to any external service. 'permission_callback' => '__return_true', + 'args' => array( + 'form_id' => array( + 'required' => true, + 'type' => 'integer', + 'sanitize_callback' => 'absint', + ), + 'event' => array( + 'required' => true, + 'type' => 'string', + 'enum' => array( 'start' ), + 'sanitize_callback' => 'sanitize_key', + ), + ), ) ); } @@ -332,12 +351,12 @@ function atf_register_rest_routes() { * * @return true|WP_Error */ -function atf_rest_can_edit() { - if ( atf_can_edit_forms() ) { +function alltfo_rest_can_edit() { + if ( alltfo_can_edit_forms() ) { return true; } - return new WP_Error( 'atf_forbidden', __( 'You cannot edit forms.', 'allterrain-forms' ), array( 'status' => rest_authorization_required_code() ) ); + return new WP_Error( 'alltfo_forbidden', __( 'You cannot edit forms.', 'allterrain-forms' ), array( 'status' => rest_authorization_required_code() ) ); } /** @@ -348,7 +367,7 @@ function atf_rest_can_edit() { * @param WP_REST_Request $request The request. * @return true|WP_Error */ -function atf_rest_can_read_entries( $request ) { +function alltfo_rest_can_read_entries( $request ) { $form_id = (int) $request->get_param( 'form_id' ); // The analytics route names its form parameter `id`, because it lives at @@ -359,11 +378,11 @@ function atf_rest_can_read_entries( $request ) { $form_id = (int) $request->get_param( 'id' ); } - if ( atf_can_read_entries( $form_id ) ) { + if ( alltfo_can_read_entries( $form_id ) ) { return true; } - return new WP_Error( 'atf_forbidden', __( 'You cannot read entries.', 'allterrain-forms' ), array( 'status' => rest_authorization_required_code() ) ); + return new WP_Error( 'alltfo_forbidden', __( 'You cannot read entries.', 'allterrain-forms' ), array( 'status' => rest_authorization_required_code() ) ); } /** @@ -373,12 +392,12 @@ function atf_rest_can_read_entries( $request ) { * * @return true|WP_Error */ -function atf_rest_can_delete_entries() { - if ( current_user_can( 'atf_delete_entries' ) ) { +function alltfo_rest_can_delete_entries() { + if ( current_user_can( 'alltfo_delete_entries' ) ) { return true; } - return new WP_Error( 'atf_forbidden', __( 'You cannot delete entries.', 'allterrain-forms' ), array( 'status' => rest_authorization_required_code() ) ); + return new WP_Error( 'alltfo_forbidden', __( 'You cannot delete entries.', 'allterrain-forms' ), array( 'status' => rest_authorization_required_code() ) ); } /** @@ -389,8 +408,8 @@ function atf_rest_can_delete_entries() { * @param WP_REST_Request $request The request. * @return WP_REST_Response */ -function atf_rest_submit( $request ) { - $form_id = absint( $request->get_param( 'atf_form_id' ) ); +function alltfo_rest_submit( $request ) { + $form_id = absint( $request->get_param( 'alltfo_form_id' ) ); $body = $request->get_params(); @@ -398,9 +417,9 @@ function atf_rest_submit( $request ) { // public form's nonce is not an authorisation check -- it is a replay // deterrent, and a failure has to come back as a message the visitor can // act on rather than a 401 the bundle would render as a dead form. - $nonce = isset( $body['atf_nonce'] ) ? sanitize_text_field( (string) $body['atf_nonce'] ) : ''; + $nonce = isset( $body['alltfo_nonce'] ) ? sanitize_text_field( (string) $body['alltfo_nonce'] ) : ''; - if ( ! wp_verify_nonce( $nonce, 'atf_submit_' . $form_id ) ) { + if ( ! wp_verify_nonce( $nonce, 'alltfo_submit_' . $form_id ) ) { return rest_ensure_response( array( 'success' => false, @@ -411,7 +430,7 @@ function atf_rest_submit( $request ) { } $files = $request->get_file_params(); - $result = atf_process_submission( $form_id, $body, $files ); + $result = alltfo_process_submission( $form_id, $body, $files ); return rest_ensure_response( $result ); } @@ -424,13 +443,13 @@ function atf_rest_submit( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response */ -function atf_rest_save_partial( $request ) { - $form_id = absint( $request->get_param( 'atf_form_id' ) ); +function alltfo_rest_save_partial( $request ) { + $form_id = absint( $request->get_param( 'alltfo_form_id' ) ); $body = $request->get_params(); - $nonce = isset( $body['atf_nonce'] ) ? sanitize_text_field( (string) $body['atf_nonce'] ) : ''; + $nonce = isset( $body['alltfo_nonce'] ) ? sanitize_text_field( (string) $body['alltfo_nonce'] ) : ''; - if ( ! wp_verify_nonce( $nonce, 'atf_submit_' . $form_id ) ) { + if ( ! wp_verify_nonce( $nonce, 'alltfo_submit_' . $form_id ) ) { return rest_ensure_response( array( 'success' => false, @@ -439,10 +458,10 @@ function atf_rest_save_partial( $request ) { ); } - $saved = atf_save_partial( + $saved = alltfo_save_partial( $form_id, isset( $body['atf'] ) && is_array( $body['atf'] ) ? $body['atf'] : array(), - isset( $body[ ATF_RESUME_QUERY ] ) ? (string) $body[ ATF_RESUME_QUERY ] : '' + isset( $body[ ALLTFO_RESUME_QUERY ] ) ? (string) $body[ ALLTFO_RESUME_QUERY ] : '' ); if ( is_wp_error( $saved ) ) { @@ -469,12 +488,19 @@ function atf_rest_save_partial( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response */ -function atf_rest_track( $request ) { +function alltfo_rest_track( $request ) { $form_id = absint( $request->get_param( 'form_id' ) ); $event = sanitize_key( (string) $request->get_param( 'event' ) ); - if ( $form_id && 'start' === $event ) { - atf_record_start( $form_id ); + // Only a real form's counter can be bumped: an id pointing at another post + // type, or at nothing, is dropped without side effects, so the public + // route cannot be used to write meta onto arbitrary posts. Status is + // deliberately not checked — the renderer records views for any existing + // form, and the two counters must agree about which forms count. + $form = $form_id ? get_post( $form_id ) : null; + + if ( $form && ALLTFO_FORM_TYPE === $form->post_type && 'start' === $event ) { + alltfo_record_start( $form_id ); } return rest_ensure_response( array( 'ok' => true ) ); @@ -492,13 +518,13 @@ function atf_rest_track( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response */ -function atf_rest_list_forms( $request ) { +function alltfo_rest_list_forms( $request ) { $archived = rest_sanitize_boolean( $request->get_param( 'archived' ) ); $posts = get_posts( array( - 'post_type' => ATF_FORM_TYPE, - 'post_status' => $archived ? ATF_STATUS_ARCHIVED : array( 'publish', 'draft' ), + 'post_type' => ALLTFO_FORM_TYPE, + 'post_status' => $archived ? ALLTFO_STATUS_ARCHIVED : array( 'publish', 'draft' ), 'numberposts' => 200, 'orderby' => 'modified', 'order' => 'DESC', @@ -506,7 +532,7 @@ function atf_rest_list_forms( $request ) { ) ); - return rest_ensure_response( array_map( 'atf_form_summary', $posts ) ); + return rest_ensure_response( array_map( 'alltfo_form_summary', $posts ) ); } /** @@ -517,19 +543,19 @@ function atf_rest_list_forms( $request ) { * @param WP_Post $post The form. * @return array The summary row. */ -function atf_form_summary( $post ) { - $schema = atf_get_form_schema( $post->ID ); - $stats = atf_get_stats( $post->ID ); +function alltfo_form_summary( $post ) { + $schema = alltfo_get_form_schema( $post->ID ); + $stats = alltfo_get_stats( $post->ID ); return array( 'id' => $post->ID, 'title' => $post->post_title, 'status' => $post->post_status, 'modified' => $post->post_modified_gmt, - 'fields' => count( atf_input_fields( $schema ) ), + 'fields' => count( alltfo_input_fields( $schema ) ), 'theme' => $schema['settings']['theme'], - 'entries' => atf_count_entries( $post->ID ), - 'unread' => atf_count_entries_by_status( $post->ID, ATF_STATUS_UNREAD ), + 'entries' => alltfo_count_entries( $post->ID ), + 'unread' => alltfo_count_entries_by_status( $post->ID, ALLTFO_STATUS_UNREAD ), 'views' => $stats['views'], 'submissions' => $stats['submissions'], 'shortcode' => sprintf( '[allterrain_form id="%d"]', $post->ID ), @@ -544,15 +570,15 @@ function atf_form_summary( $post ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_archive_form( $request ) { +function alltfo_rest_archive_form( $request ) { $form_id = absint( $request->get_param( 'id' ) ); - $result = atf_archive_form( $form_id ); + $result = alltfo_archive_form( $form_id ); if ( is_wp_error( $result ) ) { return $result; } - return rest_ensure_response( atf_form_summary( get_post( $form_id ) ) ); + return rest_ensure_response( alltfo_form_summary( get_post( $form_id ) ) ); } /** @@ -563,15 +589,15 @@ function atf_rest_archive_form( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_unarchive_form( $request ) { +function alltfo_rest_unarchive_form( $request ) { $form_id = absint( $request->get_param( 'id' ) ); - $result = atf_unarchive_form( $form_id ); + $result = alltfo_unarchive_form( $form_id ); if ( is_wp_error( $result ) ) { return $result; } - return rest_ensure_response( atf_form_summary( get_post( $form_id ) ) ); + return rest_ensure_response( alltfo_form_summary( get_post( $form_id ) ) ); } /** @@ -582,11 +608,11 @@ function atf_rest_unarchive_form( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_create_form( $request ) { +function alltfo_rest_create_form( $request ) { $template = sanitize_key( (string) $request->get_param( 'template' ) ); $title = sanitize_text_field( (string) $request->get_param( 'title' ) ); - $form_id = atf_create_form_from_template( '' !== $template ? $template : 'blank', $title ); + $form_id = alltfo_create_form_from_template( '' !== $template ? $template : 'blank', $title ); if ( is_wp_error( $form_id ) ) { return $form_id; @@ -597,10 +623,10 @@ function atf_rest_create_form( $request ) { $imported = $request->get_param( 'schema' ); if ( $imported ) { - atf_save_form_schema( $form_id, $imported ); + alltfo_save_form_schema( $form_id, $imported ); } - return atf_rest_form_response( $form_id ); + return alltfo_rest_form_response( $form_id ); } /** @@ -611,8 +637,8 @@ function atf_rest_create_form( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_get_form( $request ) { - return atf_rest_form_response( absint( $request->get_param( 'id' ) ) ); +function alltfo_rest_get_form( $request ) { + return alltfo_rest_form_response( absint( $request->get_param( 'id' ) ) ); } /** @@ -623,12 +649,12 @@ function atf_rest_get_form( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_update_form( $request ) { +function alltfo_rest_update_form( $request ) { $form_id = absint( $request->get_param( 'id' ) ); $post = $form_id ? get_post( $form_id ) : null; - if ( ! $post || ATF_FORM_TYPE !== $post->post_type ) { - return new WP_Error( 'atf_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); + if ( ! $post || ALLTFO_FORM_TYPE !== $post->post_type ) { + return new WP_Error( 'alltfo_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); } $title = $request->get_param( 'title' ); @@ -645,10 +671,10 @@ function atf_rest_update_form( $request ) { $schema = $request->get_param( 'schema' ); if ( null !== $schema ) { - atf_save_form_schema( $form_id, $schema ); + alltfo_save_form_schema( $form_id, $schema ); } - return atf_rest_form_response( $form_id ); + return alltfo_rest_form_response( $form_id ); } /** @@ -663,12 +689,12 @@ function atf_rest_update_form( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_delete_form( $request ) { +function alltfo_rest_delete_form( $request ) { $form_id = absint( $request->get_param( 'id' ) ); $post = $form_id ? get_post( $form_id ) : null; - if ( ! $post || ATF_FORM_TYPE !== $post->post_type ) { - return new WP_Error( 'atf_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); + if ( ! $post || ALLTFO_FORM_TYPE !== $post->post_type ) { + return new WP_Error( 'alltfo_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); } wp_trash_post( $form_id ); @@ -680,7 +706,7 @@ function atf_rest_delete_form( $request ) { * * @param int $form_id The form. */ - do_action( 'atf_form_deleted', $form_id ); + do_action( 'alltfo_form_deleted', $form_id ); return rest_ensure_response( array( 'deleted' => true ) ); } @@ -693,17 +719,17 @@ function atf_rest_delete_form( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_duplicate_form( $request ) { +function alltfo_rest_duplicate_form( $request ) { $form_id = absint( $request->get_param( 'id' ) ); $post = $form_id ? get_post( $form_id ) : null; - if ( ! $post || ATF_FORM_TYPE !== $post->post_type ) { - return new WP_Error( 'atf_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); + if ( ! $post || ALLTFO_FORM_TYPE !== $post->post_type ) { + return new WP_Error( 'alltfo_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); } $copy_id = wp_insert_post( array( - 'post_type' => ATF_FORM_TYPE, + 'post_type' => ALLTFO_FORM_TYPE, /* translators: %s: the original form's title. */ 'post_title' => sprintf( __( '%s (copy)', 'allterrain-forms' ), $post->post_title ), 'post_status' => 'publish', @@ -716,9 +742,9 @@ function atf_rest_duplicate_form( $request ) { return $copy_id; } - atf_save_form_schema( $copy_id, atf_get_form_schema( $form_id ) ); + alltfo_save_form_schema( $copy_id, alltfo_get_form_schema( $form_id ) ); - return atf_rest_form_response( $copy_id ); + return alltfo_rest_form_response( $copy_id ); } /** @@ -732,12 +758,12 @@ function atf_rest_duplicate_form( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_preview_form( $request ) { +function alltfo_rest_preview_form( $request ) { $form_id = absint( $request->get_param( 'id' ) ); $post = $form_id ? get_post( $form_id ) : null; - if ( ! $post || ATF_FORM_TYPE !== $post->post_type ) { - return new WP_Error( 'atf_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); + if ( ! $post || ALLTFO_FORM_TYPE !== $post->post_type ) { + return new WP_Error( 'alltfo_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); } $schema = $request->get_param( 'schema' ); @@ -746,17 +772,17 @@ function atf_rest_preview_form( $request ) { // The unsaved schema is applied through a filter for the duration of this // one render rather than written to the database, so previewing never // changes the stored form. - $override = null !== $schema ? atf_normalize_schema( $schema ) : null; + $override = null !== $schema ? alltfo_normalize_schema( $schema ) : null; $filter = static function ( $stored, $raw ) use ( $override ) { return $override ? $override : $stored; }; if ( $override ) { - add_filter( 'atf_normalize_schema', $filter, 99, 2 ); + add_filter( 'alltfo_normalize_schema', $filter, 99, 2 ); } - $html = atf_render_form( + $html = alltfo_render_form( $form_id, array( 'preview' => true, @@ -765,7 +791,7 @@ function atf_rest_preview_form( $request ) { ); if ( $override ) { - remove_filter( 'atf_normalize_schema', $filter, 99 ); + remove_filter( 'alltfo_normalize_schema', $filter, 99 ); } return rest_ensure_response( array( 'html' => $html ) ); @@ -784,15 +810,15 @@ function atf_rest_preview_form( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_merge_tags( $request ) { +function alltfo_rest_merge_tags( $request ) { $form_id = absint( $request->get_param( 'id' ) ); $post = $form_id ? get_post( $form_id ) : null; - if ( ! $post || ATF_FORM_TYPE !== $post->post_type ) { - return new WP_Error( 'atf_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); + if ( ! $post || ALLTFO_FORM_TYPE !== $post->post_type ) { + return new WP_Error( 'alltfo_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); } - return rest_ensure_response( array( 'groups' => atf_merge_tag_catalogue( $form_id ) ) ); + return rest_ensure_response( array( 'groups' => alltfo_merge_tag_catalogue( $form_id ) ) ); } /** @@ -803,11 +829,11 @@ function atf_rest_merge_tags( $request ) { * @param int $form_id The form. * @return WP_REST_Response|WP_Error */ -function atf_rest_form_response( $form_id ) { +function alltfo_rest_form_response( $form_id ) { $post = $form_id ? get_post( $form_id ) : null; - if ( ! $post || ATF_FORM_TYPE !== $post->post_type ) { - return new WP_Error( 'atf_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); + if ( ! $post || ALLTFO_FORM_TYPE !== $post->post_type ) { + return new WP_Error( 'alltfo_form_missing', __( 'That form does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); } return rest_ensure_response( @@ -816,14 +842,14 @@ function atf_rest_form_response( $form_id ) { 'title' => $post->post_title, 'status' => $post->post_status, 'modified' => $post->post_modified_gmt, - 'schema' => atf_get_form_schema( $post->ID ), + 'schema' => alltfo_get_form_schema( $post->ID ), 'shortcode' => sprintf( '[allterrain_form id="%d"]', $post->ID ), - 'entries' => atf_count_entries( $post->ID ), + 'entries' => alltfo_count_entries( $post->ID ), // Where the title bar's eye button points. Nonced per response // rather than built in the browser, because the browser has no way // to mint a nonce and a preview URL without one is a way to read an // unpublished form. - 'previewUrl' => atf_form_preview_url( $post->ID ), + 'previewUrl' => alltfo_form_preview_url( $post->ID ), ) ); } @@ -836,13 +862,13 @@ function atf_rest_form_response( $form_id ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response */ -function atf_rest_list_entries( $request ) { +function alltfo_rest_list_entries( $request ) { $status = $request->get_param( 'status' ); - $result = atf_query_entries( + $result = alltfo_query_entries( array( 'form_id' => absint( $request->get_param( 'form_id' ) ), - 'status' => $status ? array_map( 'sanitize_key', (array) $status ) : array( ATF_STATUS_UNREAD, ATF_STATUS_READ ), + 'status' => $status ? array_map( 'sanitize_key', (array) $status ) : array( ALLTFO_STATUS_UNREAD, ALLTFO_STATUS_READ ), 'search' => (string) $request->get_param( 'search' ), 'page' => max( 1, (int) $request->get_param( 'page' ) ), 'per_page' => (int) $request->get_param( 'per_page' ) ? (int) $request->get_param( 'per_page' ) : 25, @@ -866,17 +892,17 @@ function atf_rest_list_entries( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_get_entry( $request ) { +function alltfo_rest_get_entry( $request ) { $entry_id = absint( $request->get_param( 'id' ) ); - $entry = atf_prepare_entry( $entry_id ); + $entry = alltfo_prepare_entry( $entry_id ); if ( ! $entry ) { - return new WP_Error( 'atf_entry_missing', __( 'That entry does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); + return new WP_Error( 'alltfo_entry_missing', __( 'That entry does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); } - if ( ATF_STATUS_UNREAD === $entry['status'] ) { - atf_set_entry_status( $entry_id, ATF_STATUS_READ ); - $entry['status'] = ATF_STATUS_READ; + if ( ALLTFO_STATUS_UNREAD === $entry['status'] ) { + alltfo_set_entry_status( $entry_id, ALLTFO_STATUS_READ ); + $entry['status'] = ALLTFO_STATUS_READ; } return rest_ensure_response( $entry ); @@ -890,13 +916,13 @@ function atf_rest_get_entry( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_update_entry( $request ) { +function alltfo_rest_update_entry( $request ) { $entry_id = absint( $request->get_param( 'id' ) ); $status = $request->get_param( 'status' ); $starred = $request->get_param( 'starred' ); if ( null !== $status ) { - $result = atf_set_entry_status( $entry_id, sanitize_key( (string) $status ) ); + $result = alltfo_set_entry_status( $entry_id, sanitize_key( (string) $status ) ); if ( is_wp_error( $result ) ) { return $result; @@ -904,14 +930,14 @@ function atf_rest_update_entry( $request ) { } if ( null !== $starred ) { - $result = atf_star_entry( $entry_id, (bool) $starred ); + $result = alltfo_star_entry( $entry_id, (bool) $starred ); if ( is_wp_error( $result ) ) { return $result; } } - return rest_ensure_response( atf_prepare_entry( $entry_id ) ); + return rest_ensure_response( alltfo_prepare_entry( $entry_id ) ); } /** @@ -922,15 +948,15 @@ function atf_rest_update_entry( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_delete_entry( $request ) { +function alltfo_rest_delete_entry( $request ) { $entry_id = absint( $request->get_param( 'id' ) ); $post = $entry_id ? get_post( $entry_id ) : null; - if ( ! $post || ATF_ENTRY_TYPE !== $post->post_type ) { - return new WP_Error( 'atf_entry_missing', __( 'That entry does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); + if ( ! $post || ALLTFO_ENTRY_TYPE !== $post->post_type ) { + return new WP_Error( 'alltfo_entry_missing', __( 'That entry does not exist.', 'allterrain-forms' ), array( 'status' => 404 ) ); } - atf_delete_entry_completely( $entry_id ); + alltfo_delete_entry_completely( $entry_id ); return rest_ensure_response( array( 'deleted' => true ) ); } @@ -948,11 +974,11 @@ function atf_rest_delete_entry( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_export_entries( $request ) { +function alltfo_rest_export_entries( $request ) { $form_id = absint( $request->get_param( 'form_id' ) ); $query = array( - 'status' => array( ATF_STATUS_UNREAD, ATF_STATUS_READ ), + 'status' => array( ALLTFO_STATUS_UNREAD, ALLTFO_STATUS_READ ), 'search' => (string) $request->get_param( 'search' ), 'after' => (string) $request->get_param( 'after' ), 'before' => (string) $request->get_param( 'before' ), @@ -964,8 +990,8 @@ function atf_rest_export_entries( $request ) { $export = 'json' === $format - ? atf_export_entries_json( $form_id, $query ) - : atf_export_entries_csv( $form_id, $query ); + ? alltfo_export_entries_json( $form_id, $query ) + : alltfo_export_entries_csv( $form_id, $query ); if ( is_wp_error( $export ) ) { return $export; @@ -990,9 +1016,9 @@ function atf_rest_export_entries( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response */ -function atf_rest_analytics( $request ) { +function alltfo_rest_analytics( $request ) { return rest_ensure_response( - atf_form_analytics( + alltfo_form_analytics( absint( $request->get_param( 'id' ) ), (string) $request->get_param( 'dimension' ) ) @@ -1006,10 +1032,10 @@ function atf_rest_analytics( $request ) { * * @return WP_REST_Response */ -function atf_rest_list_themes() { +function alltfo_rest_list_themes() { $themes = array(); - foreach ( atf_get_themes() as $slug => $theme ) { + foreach ( alltfo_get_themes() as $slug => $theme ) { $themes[] = array( 'slug' => $slug, 'label' => $theme['label'], @@ -1018,7 +1044,7 @@ function atf_rest_list_themes() { 'dark' => ! empty( $theme['dark'] ), 'id' => $theme['id'], 'tokens' => $theme['tokens'], - 'resolved' => atf_resolve_tokens( $slug ), + 'resolved' => alltfo_resolve_tokens( $slug ), ); } @@ -1033,8 +1059,8 @@ function atf_rest_list_themes() { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_save_theme( $request ) { - $saved = atf_save_theme( +function alltfo_rest_save_theme( $request ) { + $saved = alltfo_save_theme( array( 'id' => absint( $request->get_param( 'id' ) ), 'label' => (string) $request->get_param( 'label' ), @@ -1048,7 +1074,7 @@ function atf_rest_save_theme( $request ) { return $saved; } - $saved['resolved'] = atf_resolve_tokens( $saved['slug'] ); + $saved['resolved'] = alltfo_resolve_tokens( $saved['slug'] ); return rest_ensure_response( $saved ); } @@ -1061,8 +1087,8 @@ function atf_rest_save_theme( $request ) { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_delete_theme( $request ) { - $result = atf_delete_theme( absint( $request->get_param( 'id' ) ) ); +function alltfo_rest_delete_theme( $request ) { + $result = alltfo_delete_theme( absint( $request->get_param( 'id' ) ) ); if ( is_wp_error( $result ) ) { return $result; @@ -1082,10 +1108,10 @@ function atf_rest_delete_theme( $request ) { * * @return WP_REST_Response */ -function atf_rest_config() { +function alltfo_rest_config() { $types = array(); - foreach ( atf_get_field_types() as $slug => $definition ) { + foreach ( alltfo_get_field_types() as $slug => $definition ) { $types[] = array( 'type' => $slug, 'label' => $definition['label'], @@ -1101,25 +1127,25 @@ function atf_rest_config() { // the bundle because both lists are filterable, and a builder offering // a fixed five while the renderer draws a filtered seven is a builder // that quietly cannot reach two of them. - 'parts' => atf_field_type_parts( $slug ), + 'parts' => alltfo_field_type_parts( $slug ), ); } $tokens = array(); - foreach ( atf_theme_token_defaults() as $name => $default ) { + foreach ( alltfo_theme_token_defaults() as $name => $default ) { $tokens[] = array_merge( array( 'token' => $name, 'default' => $default, ), - atf_theme_token_control( $name ) + alltfo_theme_token_control( $name ) ); } $templates = array(); - foreach ( atf_form_templates() as $slug => $template ) { + foreach ( alltfo_form_templates() as $slug => $template ) { $templates[] = array( 'slug' => $slug, 'label' => $template['label'], @@ -1131,13 +1157,13 @@ function atf_rest_config() { return rest_ensure_response( array( 'fieldTypes' => $types, - 'groups' => atf_field_groups(), + 'groups' => alltfo_field_groups(), 'tokens' => $tokens, 'templates' => $templates, - 'operators' => atf_logic_operator_labels(), - 'countries' => atf_countries(), + 'operators' => alltfo_logic_operator_labels(), + 'countries' => alltfo_countries(), 'roles' => wp_roles()->get_names(), - 'canDelete' => current_user_can( 'atf_delete_entries' ), + 'canDelete' => current_user_can( 'alltfo_delete_entries' ), 'adminUrl' => admin_url(), ) ); @@ -1153,7 +1179,7 @@ function atf_rest_config() { * * @return array */ -function atf_logic_operator_labels() { +function alltfo_logic_operator_labels() { return array( 'is' => __( 'is', 'allterrain-forms' ), 'is_not' => __( 'is not', 'allterrain-forms' ), @@ -1174,7 +1200,7 @@ function atf_logic_operator_labels() { * Whether the request may use the developer tools. * * Two questions, not one. Developer mode is a preference and answers "show me - * these"; `atf_edit_forms` is a capability and answers "you may use them". + * these"; `alltfo_edit_forms` is a capability and answers "you may use them". * Checking only the preference would be an authorisation check that any user who * can write their own meta could pass. * @@ -1186,18 +1212,18 @@ function atf_logic_operator_labels() { * * @return true|WP_Error */ -function atf_rest_can_use_developer_tools() { - if ( ! atf_can_edit_forms() ) { +function alltfo_rest_can_use_developer_tools() { + if ( ! alltfo_can_edit_forms() ) { return new WP_Error( - 'atf_forbidden', + 'alltfo_forbidden', __( 'You cannot edit forms.', 'allterrain-forms' ), array( 'status' => rest_authorization_required_code() ) ); } - if ( ! atf_developer_mode() ) { + if ( ! alltfo_developer_mode() ) { return new WP_Error( - 'atf_developer_mode_off', + 'alltfo_developer_mode_off', __( 'Developer mode is off.', 'allterrain-forms' ), array( 'status' => 404 ) ); @@ -1213,8 +1239,8 @@ function atf_rest_can_use_developer_tools() { * * @return WP_REST_Response */ -function atf_rest_demo_status() { - return rest_ensure_response( atf_demo_status() ); +function alltfo_rest_demo_status() { + return rest_ensure_response( alltfo_demo_status() ); } /** @@ -1228,10 +1254,10 @@ function atf_rest_demo_status() { * @param WP_REST_Request $request The request. * @return WP_REST_Response|WP_Error */ -function atf_rest_demo_seed( $request ) { +function alltfo_rest_demo_seed( $request ) { $count = (int) $request->get_param( 'count' ); - return rest_ensure_response( atf_demo_seed( $count > 0 ? $count : ATF_DEMO_CHUNK ) ); + return rest_ensure_response( alltfo_demo_seed( $count > 0 ? $count : ALLTFO_DEMO_CHUNK ) ); } /** @@ -1241,6 +1267,6 @@ function atf_rest_demo_seed( $request ) { * * @return WP_REST_Response|WP_Error */ -function atf_rest_demo_remove() { - return rest_ensure_response( atf_demo_remove() ); +function alltfo_rest_demo_remove() { + return rest_ensure_response( alltfo_demo_remove() ); } diff --git a/includes/resume.php b/includes/resume.php index 88ef2e3..ad56d13 100644 --- a/includes/resume.php +++ b/includes/resume.php @@ -9,7 +9,7 @@ * the difference between a completed application and an empty afternoon. * * The design here is deliberately anonymous. A partial submission is stored as - * an entry in the `atf-partial` status, addressed by a **random token** that is + * an entry in the `alltfo-partial` status, addressed by a **random token** that is * never derived from anything about the person. No account is needed, no cookie * is set, and nothing links two partials together. The token is the only key. * @@ -25,7 +25,7 @@ defined( 'ABSPATH' ) || exit; /** The query flag that resumes a form. */ -const ATF_RESUME_QUERY = 'atf_resume'; +const ALLTFO_RESUME_QUERY = 'alltfo_resume'; /** * Saves a partial submission and returns the way back to it. @@ -42,35 +42,35 @@ * @param string $token An existing token to update, or empty to mint one. * @return array|WP_Error { token, url, expires } or why not. */ -function atf_save_partial( $form_id, $raw, $token = '' ) { +function alltfo_save_partial( $form_id, $raw, $token = '' ) { $form_id = absint( $form_id ); - $schema = atf_get_form_schema( $form_id ); + $schema = alltfo_get_form_schema( $form_id ); if ( empty( $schema['settings']['resume']['enabled'] ) ) { return new WP_Error( - 'atf_resume_disabled', + 'alltfo_resume_disabled', __( 'This form does not offer saving for later.', 'allterrain-forms' ), array( 'status' => 400 ) ); } - $availability = atf_form_availability( $form_id, $schema ); + $availability = alltfo_form_availability( $form_id, $schema ); if ( ! $availability['open'] ) { - return new WP_Error( 'atf_form_closed', $availability['message'], array( 'status' => 403 ) ); + return new WP_Error( 'alltfo_form_closed', $availability['message'], array( 'status' => 403 ) ); } - $values = atf_sanitize_submission( $schema, is_array( $raw ) ? $raw : array() ); + $values = alltfo_sanitize_submission( $schema, is_array( $raw ) ? $raw : array() ); $days = max( 1, (int) $schema['settings']['resume']['days'] ); $expiry = time() + ( $days * DAY_IN_SECONDS ); - $existing = '' !== $token ? atf_find_partial( $token ) : null; + $existing = '' !== $token ? alltfo_find_partial( $token ) : null; // A token minted on one form must not update another form's partial -- it // would overwrite a stranger-to-this-form's answers and rebrand their entry. // A mismatched token is treated as no token at all, so the save still // succeeds, as a fresh partial for this form, subject to the cap below. - if ( $existing && absint( get_post_meta( $existing->ID, ATF_META_FORM, true ) ) !== $form_id ) { + if ( $existing && absint( get_post_meta( $existing->ID, ALLTFO_META_FORM, true ) ) !== $form_id ) { $existing = null; } @@ -84,7 +84,7 @@ function atf_save_partial( $form_id, $raw, $token = '' ) { // the raw request value. The lookup tolerates decoration around a token // -- whitespace, a stray quote -- that must not be stored, because a // corrupted stored token would fail every later lookup. - $resume = json_decode( (string) get_post_meta( $existing->ID, ATF_META_RESUME, true ), true ); + $resume = json_decode( (string) get_post_meta( $existing->ID, ALLTFO_META_RESUME, true ), true ); $token = isset( $resume['token'] ) ? (string) $resume['token'] : $token; } else { // The `/resume` route is public, and a tokenless save writes a new row @@ -104,11 +104,11 @@ function atf_save_partial( $form_id, $raw, $token = '' ) { * @param int $limit New partials allowed per IP per hour. Default 30. * @param int $form_id The form being saved. */ - $limit = (int) apply_filters( 'atf_partial_rate_limit', 30, $form_id ); + $limit = (int) apply_filters( 'alltfo_partial_rate_limit', 30, $form_id ); - if ( $limit > 0 && atf_hit_rate_limit( 'partial', $limit ) ) { + if ( $limit > 0 && alltfo_hit_rate_limit( 'partial', $limit ) ) { return new WP_Error( - 'atf_partial_rate_limited', + 'alltfo_partial_rate_limited', __( 'Too many saved forms from this connection. Please try again later.', 'allterrain-forms' ), array( 'status' => 429 ) ); @@ -121,13 +121,13 @@ function atf_save_partial( $form_id, $raw, $token = '' ) { $entry_id = wp_insert_post( array( - 'post_type' => ATF_ENTRY_TYPE, + 'post_type' => ALLTFO_ENTRY_TYPE, 'post_title' => sprintf( /* translators: %s: the form's title. */ __( 'Incomplete — %s', 'allterrain-forms' ), get_the_title( $form_id ) ), - 'post_status' => ATF_STATUS_PARTIAL, + 'post_status' => ALLTFO_STATUS_PARTIAL, 'post_author' => get_current_user_id(), ), true @@ -137,13 +137,13 @@ function atf_save_partial( $form_id, $raw, $token = '' ) { return $entry_id; } - update_post_meta( $entry_id, ATF_META_FORM, $form_id ); + update_post_meta( $entry_id, ALLTFO_META_FORM, $form_id ); } - update_post_meta( $entry_id, ATF_META_VALUES, wp_slash( wp_json_encode( $values ) ) ); + update_post_meta( $entry_id, ALLTFO_META_VALUES, wp_slash( wp_json_encode( $values ) ) ); update_post_meta( $entry_id, - ATF_META_RESUME, + ALLTFO_META_RESUME, wp_slash( wp_json_encode( array( @@ -155,7 +155,7 @@ function atf_save_partial( $form_id, $raw, $token = '' ) { ) ); - $url = add_query_arg( ATF_RESUME_QUERY, $token, atf_form_action_url() ); + $url = add_query_arg( ALLTFO_RESUME_QUERY, $token, alltfo_form_action_url() ); /** * Fires after a partial submission is saved. @@ -170,7 +170,7 @@ function atf_save_partial( $form_id, $raw, $token = '' ) { * @param string $url The resume link. * @param array $values What has been filled in so far. */ - do_action( 'atf_partial_saved', $entry_id, $form_id, $url, $values ); + do_action( 'alltfo_partial_saved', $entry_id, $form_id, $url, $values ); return array( 'token' => $token, @@ -192,7 +192,7 @@ function atf_save_partial( $form_id, $raw, $token = '' ) { * @param string $token The token. * @return WP_Post|null The partial entry, or null when it is unknown or expired. */ -function atf_find_partial( $token ) { +function alltfo_find_partial( $token ) { $token = preg_replace( '/[^a-zA-Z0-9]/', '', (string) $token ); if ( strlen( $token ) < 16 ) { @@ -201,13 +201,13 @@ function atf_find_partial( $token ) { $found = get_posts( array( - 'post_type' => ATF_ENTRY_TYPE, - 'post_status' => ATF_STATUS_PARTIAL, + 'post_type' => ALLTFO_ENTRY_TYPE, + 'post_status' => ALLTFO_STATUS_PARTIAL, 'numberposts' => 1, 'suppress_filters' => false, 'meta_query' => array( array( - 'key' => ATF_META_RESUME, + 'key' => ALLTFO_META_RESUME, 'value' => '"' . $token . '"', 'compare' => 'LIKE', ), @@ -220,7 +220,7 @@ function atf_find_partial( $token ) { } $post = $found[0]; - $resume = json_decode( (string) get_post_meta( $post->ID, ATF_META_RESUME, true ), true ); + $resume = json_decode( (string) get_post_meta( $post->ID, ALLTFO_META_RESUME, true ), true ); if ( ! is_array( $resume ) || empty( $resume['token'] ) ) { return null; @@ -247,17 +247,17 @@ function atf_find_partial( $token ) { * @param string $token The token from the URL. * @return array { form_id: int, values: array, token: string } or an empty array. */ -function atf_resume_values( $token ) { - $post = atf_find_partial( $token ); +function alltfo_resume_values( $token ) { + $post = alltfo_find_partial( $token ); if ( ! $post ) { return array(); } - $values = json_decode( (string) get_post_meta( $post->ID, ATF_META_VALUES, true ), true ); + $values = json_decode( (string) get_post_meta( $post->ID, ALLTFO_META_VALUES, true ), true ); return array( - 'form_id' => (int) get_post_meta( $post->ID, ATF_META_FORM, true ), + 'form_id' => (int) get_post_meta( $post->ID, ALLTFO_META_FORM, true ), 'values' => is_array( $values ) ? $values : array(), 'token' => $token, 'entry' => $post->ID, @@ -267,7 +267,7 @@ function atf_resume_values( $token ) { /** * Deletes the partial a completed submission came from. * - * Hooked on `atf_entry_created`, so finishing a form clears the half-finished + * Hooked on `alltfo_entry_created`, so finishing a form clears the half-finished * copy of it. Without this the entries list carries a permanent shadow of every * application that was ever saved and then completed, and the resume link keeps * working long after it means anything. @@ -279,22 +279,22 @@ function atf_resume_values( $token ) { * @param array $values The accepted values. * @return void */ -function atf_clear_partial_on_submit( $entry_id, $form_id, $values ) { +function alltfo_clear_partial_on_submit( $entry_id, $form_id, $values ) { // The token travels in the submission that finishes the form, which is the // only thing tying the two together -- the partial is anonymous by design. // `$_POST` only covers the no-JavaScript form post; a REST submission with // a JSON body never fills the superglobal, so the pipeline also clears from - // the parsed request in `atf_process_submission()`. Both run; whichever is + // the parsed request in `alltfo_process_submission()`. Both run; whichever is // second finds nothing to delete. // phpcs:disable WordPress.Security.NonceVerification.Missing -- The submission's own nonce was verified before this action fired. - $token = isset( $_POST[ ATF_RESUME_QUERY ] ) - ? sanitize_text_field( wp_unslash( $_POST[ ATF_RESUME_QUERY ] ) ) + $token = isset( $_POST[ ALLTFO_RESUME_QUERY ] ) + ? sanitize_text_field( wp_unslash( $_POST[ ALLTFO_RESUME_QUERY ] ) ) : ''; // phpcs:enable WordPress.Security.NonceVerification.Missing - atf_clear_partial( $token ); + alltfo_clear_partial( $token ); } -add_action( 'atf_entry_created', 'atf_clear_partial_on_submit', 10, 3 ); +add_action( 'alltfo_entry_created', 'alltfo_clear_partial_on_submit', 10, 3 ); /** * Deletes the partial behind a resume token. @@ -307,14 +307,14 @@ function atf_clear_partial_on_submit( $entry_id, $form_id, $values ) { * @param string $token The token. * @return void */ -function atf_clear_partial( $token ) { +function alltfo_clear_partial( $token ) { $token = sanitize_text_field( (string) $token ); if ( '' === $token ) { return; } - $partial = atf_find_partial( $token ); + $partial = alltfo_find_partial( $token ); if ( $partial ) { wp_delete_post( $partial->ID, true ); @@ -332,11 +332,11 @@ function atf_clear_partial( $token ) { * * @return int How many were removed. */ -function atf_expire_partials() { +function alltfo_expire_partials() { $partials = get_posts( array( - 'post_type' => ATF_ENTRY_TYPE, - 'post_status' => ATF_STATUS_PARTIAL, + 'post_type' => ALLTFO_ENTRY_TYPE, + 'post_status' => ALLTFO_STATUS_PARTIAL, 'numberposts' => 200, 'fields' => 'ids', 'suppress_filters' => false, @@ -346,7 +346,7 @@ function atf_expire_partials() { $removed = 0; foreach ( $partials as $entry_id ) { - $resume = json_decode( (string) get_post_meta( $entry_id, ATF_META_RESUME, true ), true ); + $resume = json_decode( (string) get_post_meta( $entry_id, ALLTFO_META_RESUME, true ), true ); // A partial with no expiry recorded is malformed, and leaving it forever // would mean somebody's half-typed answers outliving every policy on the @@ -359,13 +359,13 @@ function atf_expire_partials() { continue; } - atf_delete_entry_completely( $entry_id ); + alltfo_delete_entry_completely( $entry_id ); ++$removed; } return $removed; } -add_action( 'atf_apply_retention', 'atf_expire_partials' ); +add_action( 'alltfo_apply_retention', 'alltfo_expire_partials' ); /** * The button that saves a form for later. @@ -380,7 +380,7 @@ function atf_expire_partials() { * @param string $token The token this form was resumed from, if any. * @return string */ -function atf_render_resume_button( $schema, $token = '' ) { +function alltfo_render_resume_button( $schema, $token = '' ) { if ( empty( $schema['settings']['resume']['enabled'] ) ) { return ''; } @@ -389,7 +389,7 @@ function atf_render_resume_button( $schema, $token = '' ) { '' . '', esc_html__( 'Save and continue later', 'allterrain-forms' ), - esc_attr( ATF_RESUME_QUERY ), + esc_attr( ALLTFO_RESUME_QUERY ), esc_attr( $token ) ); } diff --git a/includes/schema.php b/includes/schema.php index 201efbc..924340c 100644 --- a/includes/schema.php +++ b/includes/schema.php @@ -7,7 +7,7 @@ * because a form is only ever edited whole, and a partial write is always a bug. * * Everything that enters this file is untrusted. The builder posts a schema, an - * import posts a schema, a template posts a schema; `atf_normalize_schema()` is + * import posts a schema, a template posts a schema; `alltfo_normalize_schema()` is * the single door all three come through, and after it the rest of the plugin * can assume every key exists and every value is the type it claims to be. That * assumption is what lets the renderer and the validator be short. @@ -25,7 +25,7 @@ * * @since 0.1.0 */ -const ATF_SCHEMA_VERSION = 1; +const ALLTFO_SCHEMA_VERSION = 1; /** * An empty, valid schema. @@ -42,9 +42,9 @@ * * @return array A complete schema with no fields. */ -function atf_default_schema() { +function alltfo_default_schema() { $schema = array( - 'version' => ATF_SCHEMA_VERSION, + 'version' => ALLTFO_SCHEMA_VERSION, 'fields' => array(), 'settings' => array( 'theme' => 'clean', @@ -116,7 +116,7 @@ function atf_default_schema() { * * @param array $schema The default schema. */ - return apply_filters( 'atf_default_schema', $schema ); + return apply_filters( 'alltfo_default_schema', $schema ); } /** @@ -133,7 +133,7 @@ function atf_default_schema() { * @param mixed $raw A JSON string, an array, or anything else. * @return array A complete, valid schema. */ -function atf_normalize_schema( $raw ) { +function alltfo_normalize_schema( $raw ) { if ( is_string( $raw ) ) { $decoded = json_decode( $raw, true ); $raw = is_array( $decoded ) ? $decoded : array(); @@ -143,22 +143,22 @@ function atf_normalize_schema( $raw ) { $raw = array(); } - $defaults = atf_default_schema(); + $defaults = alltfo_default_schema(); $schema = array( - 'version' => ATF_SCHEMA_VERSION, + 'version' => ALLTFO_SCHEMA_VERSION, 'fields' => array(), - 'settings' => atf_normalize_settings( isset( $raw['settings'] ) ? $raw['settings'] : array(), $defaults['settings'] ), - 'notifications' => atf_normalize_notifications( isset( $raw['notifications'] ) ? $raw['notifications'] : array() ), - 'confirmations' => atf_normalize_confirmations( isset( $raw['confirmations'] ) ? $raw['confirmations'] : array() ), - 'actions' => atf_normalize_actions( isset( $raw['actions'] ) ? $raw['actions'] : array() ), + 'settings' => alltfo_normalize_settings( isset( $raw['settings'] ) ? $raw['settings'] : array(), $defaults['settings'] ), + 'notifications' => alltfo_normalize_notifications( isset( $raw['notifications'] ) ? $raw['notifications'] : array() ), + 'confirmations' => alltfo_normalize_confirmations( isset( $raw['confirmations'] ) ? $raw['confirmations'] : array() ), + 'actions' => alltfo_normalize_actions( isset( $raw['actions'] ) ? $raw['actions'] : array() ), ); $fields = isset( $raw['fields'] ) && is_array( $raw['fields'] ) ? $raw['fields'] : array(); $seen = array(); foreach ( $fields as $field ) { - $normalised = atf_normalize_field( $field, $seen ); + $normalised = alltfo_normalize_field( $field, $seen ); if ( $normalised ) { $seen[] = $normalised['id']; @@ -177,7 +177,7 @@ function atf_normalize_schema( $raw ) { * @param array $schema The normalised schema. * @param mixed $raw What was passed in. */ - return apply_filters( 'atf_normalize_schema', $schema, $raw ); + return apply_filters( 'alltfo_normalize_schema', $schema, $raw ); } /** @@ -193,7 +193,7 @@ function atf_normalize_schema( $raw ) { * @param string[] $seen Ids already used in this schema, so a duplicate can be re-issued. * @return array|null The field, or null when it is unusable. */ -function atf_normalize_field( $raw, $seen = array() ) { +function alltfo_normalize_field( $raw, $seen = array() ) { if ( ! is_array( $raw ) ) { return null; } @@ -204,7 +204,7 @@ function atf_normalize_field( $raw, $seen = array() ) { return null; } - $definition = atf_get_field_type( $type ); + $definition = alltfo_get_field_type( $type ); $id = isset( $raw['id'] ) ? preg_replace( '/[^a-zA-Z0-9_]/', '', (string) $raw['id'] ) : ''; @@ -212,7 +212,7 @@ function atf_normalize_field( $raw, $seen = array() ) { // from another site, or a hand-written JSON file, routinely has neither -- // and dropping the field would lose the question rather than fix the id. if ( '' === $id || in_array( $id, $seen, true ) ) { - $id = atf_generate_field_id( $seen ); + $id = alltfo_generate_field_id( $seen ); } $field = array( @@ -222,18 +222,18 @@ function atf_normalize_field( $raw, $seen = array() ) { 'placeholder' => isset( $raw['placeholder'] ) ? sanitize_text_field( (string) $raw['placeholder'] ) : '', 'hint' => isset( $raw['hint'] ) ? wp_kses_post( (string) $raw['hint'] ) : '', 'required' => ! empty( $raw['required'] ), - 'width' => atf_normalize_width( isset( $raw['width'] ) ? $raw['width'] : 'full' ), + 'width' => alltfo_normalize_width( isset( $raw['width'] ) ? $raw['width'] : 'full' ), 'cssClass' => isset( $raw['cssClass'] ) ? sanitize_html_class( (string) $raw['cssClass'] ) : '', 'default' => isset( $raw['default'] ) ? $raw['default'] : '', - 'choices' => atf_normalize_choices( isset( $raw['choices'] ) ? $raw['choices'] : array() ), - 'logic' => atf_normalize_logic( isset( $raw['logic'] ) ? $raw['logic'] : array() ), - 'messages' => atf_normalize_messages( isset( $raw['messages'] ) ? $raw['messages'] : array() ), + 'choices' => alltfo_normalize_choices( isset( $raw['choices'] ) ? $raw['choices'] : array() ), + 'logic' => alltfo_normalize_logic( isset( $raw['logic'] ) ? $raw['logic'] : array() ), + 'messages' => alltfo_normalize_messages( isset( $raw['messages'] ) ? $raw['messages'] : array() ), 'prefill' => isset( $raw['prefill'] ) ? sanitize_text_field( (string) $raw['prefill'] ) : '', ); // The default value is sanitised through the field's own type, so a default // for a checkbox group is an array and a default for a number is a number. - $field['default'] = atf_sanitize_field_value( $field['default'], $field ); + $field['default'] = alltfo_sanitize_field_value( $field['default'], $field ); $settings = $definition && is_array( $definition['settings'] ) ? $definition['settings'] : array(); @@ -256,7 +256,7 @@ function atf_normalize_field( $raw, $seen = array() ) { // Everything else is typed against its declared default, so an // imported schema cannot put an array where `strtotime()` or a // renderer will later assume a scalar. - $field[ $key ] = atf_coerce_setting( $raw[ $key ], $fallback ); + $field[ $key ] = alltfo_coerce_setting( $raw[ $key ], $fallback ); } // Validation bounds are common enough to live on the field rather than in @@ -269,7 +269,7 @@ function atf_normalize_field( $raw, $seen = array() ) { } // A named answer shape -- "an email address", "a ZIP code" -- enforced by - // `atf_validate_preset()`. The sentinel `custom` means "use `pattern`", + // `alltfo_validate_preset()`. The sentinel `custom` means "use `pattern`", // which the custom-rule builder writes alongside this flag. if ( isset( $raw['validation'] ) && is_scalar( $raw['validation'] ) && '' !== $raw['validation'] ) { $field['validation'] = sanitize_key( (string) $raw['validation'] ); @@ -280,7 +280,7 @@ function atf_normalize_field( $raw, $seen = array() ) { // and re-encoded through a whitelist, so an imported schema cannot smuggle // arbitrary structure through what is otherwise an opaque blob. if ( isset( $raw['validationRecipe'] ) && is_string( $raw['validationRecipe'] ) && '' !== $raw['validationRecipe'] ) { - $recipe = atf_normalize_validation_recipe( $raw['validationRecipe'] ); + $recipe = alltfo_normalize_validation_recipe( $raw['validationRecipe'] ); if ( '' !== $recipe ) { $field['validationRecipe'] = $recipe; @@ -315,7 +315,7 @@ function atf_normalize_field( $raw, $seen = array() ) { $subs = array(); foreach ( $field['fields'] as $sub ) { - $normalised = atf_normalize_field( $sub, $sub_seen ); + $normalised = alltfo_normalize_field( $sub, $sub_seen ); if ( $normalised ) { $sub_seen[] = $normalised['id']; @@ -326,7 +326,7 @@ function atf_normalize_field( $raw, $seen = array() ) { $field['fields'] = $subs; } - $field = atf_seed_field_defaults( $field, $definition ); + $field = alltfo_seed_field_defaults( $field, $definition ); /** * Filters one normalised field. @@ -336,7 +336,7 @@ function atf_normalize_field( $raw, $seen = array() ) { * @param array $field The normalised field. * @param mixed $raw What was passed in. */ - return apply_filters( 'atf_normalize_field', $field, $raw ); + return apply_filters( 'alltfo_normalize_field', $field, $raw ); } /** @@ -366,13 +366,13 @@ function atf_normalize_field( $raw, $seen = array() ) { * @param array|null $definition Its registered type, or null for an unknown type. * @return array The field, with any missing sub-list filled in. */ -function atf_seed_field_defaults( $field, $definition ) { +function alltfo_seed_field_defaults( $field, $definition ) { if ( ! $definition ) { return $field; } if ( ! empty( $definition['choices'] ) && empty( $field['choices'] ) ) { - $field['choices'] = atf_normalize_choices( + $field['choices'] = alltfo_normalize_choices( array( array( 'label' => __( 'First choice', 'allterrain-forms' ), @@ -404,7 +404,7 @@ function atf_seed_field_defaults( $field, $definition ) { // One text box, so a repeater built by an import is a repeater of something. if ( 'repeater' === $field['type'] && empty( $field['fields'] ) ) { $field['fields'] = array( - atf_normalize_field( + alltfo_normalize_field( array( 'id' => $field['id'] . '_1', 'type' => 'text', @@ -426,7 +426,7 @@ function atf_seed_field_defaults( $field, $definition ) { * @param mixed $width Requested width. * @return string One of full|half|third|two-thirds|quarter. */ -function atf_normalize_width( $width ) { +function alltfo_normalize_width( $width ) { $allowed = array( 'full', 'half', 'third', 'two-thirds', 'quarter' ); $width = is_scalar( $width ) ? (string) $width : 'full'; @@ -444,7 +444,7 @@ function atf_normalize_width( $width ) { * @param mixed $raw Raw choices. * @return array[] Normalised choices. */ -function atf_normalize_choices( $raw ) { +function alltfo_normalize_choices( $raw ) { if ( ! is_array( $raw ) ) { return array(); } @@ -497,7 +497,7 @@ function atf_normalize_choices( $raw ) { * Normalises a conditional-logic block. * * The shape is deliberately the same everywhere logic appears -- on a field, on - * a notification, on a confirmation -- so `atf_logic_passes()` is one function + * a notification, on a confirmation -- so `alltfo_logic_passes()` is one function * rather than three. * * @since 0.1.0 @@ -505,7 +505,7 @@ function atf_normalize_choices( $raw ) { * @param mixed $raw Raw logic. * @return array Normalised logic. */ -function atf_normalize_logic( $raw ) { +function alltfo_normalize_logic( $raw ) { $logic = array( 'enabled' => false, 'action' => 'show', @@ -530,7 +530,7 @@ function atf_normalize_logic( $raw ) { $logic['rules'][] = array( 'field' => preg_replace( '/[^a-zA-Z0-9_]/', '', (string) $rule['field'] ), - 'operator' => atf_normalize_operator( isset( $rule['operator'] ) ? $rule['operator'] : 'is' ), + 'operator' => alltfo_normalize_operator( isset( $rule['operator'] ) ? $rule['operator'] : 'is' ), 'value' => isset( $rule['value'] ) && is_scalar( $rule['value'] ) ? (string) $rule['value'] : '', ); } @@ -550,7 +550,7 @@ function atf_normalize_logic( $raw ) { * @param mixed $operator Requested operator. * @return string A supported operator. */ -function atf_normalize_operator( $operator ) { +function alltfo_normalize_operator( $operator ) { $allowed = array( 'is', 'is_not', @@ -579,7 +579,7 @@ function atf_normalize_operator( $operator ) { * @param mixed $raw Raw messages. * @return array */ -function atf_normalize_messages( $raw ) { +function alltfo_normalize_messages( $raw ) { if ( ! is_array( $raw ) ) { return array(); } @@ -613,7 +613,7 @@ function atf_normalize_messages( $raw ) { * @param mixed $fallback The declared default. * @return mixed The value, in the default's type. */ -function atf_coerce_setting( $value, $fallback ) { +function alltfo_coerce_setting( $value, $fallback ) { if ( is_array( $fallback ) ) { return is_array( $value ) ? $value : $fallback; } @@ -646,7 +646,7 @@ function atf_coerce_setting( $value, $fallback ) { * @param array $defaults The default settings. * @return array */ -function atf_normalize_settings( $raw, $defaults ) { +function alltfo_normalize_settings( $raw, $defaults ) { if ( ! is_array( $raw ) ) { return $defaults; } @@ -671,7 +671,7 @@ function atf_normalize_settings( $raw, $defaults ) { foreach ( $raw[ $key ] as $sub_key => $sub_value ) { $merged[ $sub_key ] = array_key_exists( $sub_key, $default ) - ? atf_coerce_setting( $sub_value, $default[ $sub_key ] ) + ? alltfo_coerce_setting( $sub_value, $default[ $sub_key ] ) : $sub_value; } @@ -679,7 +679,7 @@ function atf_normalize_settings( $raw, $defaults ) { continue; } - $settings[ $key ] = atf_coerce_setting( $raw[ $key ], $default ); + $settings[ $key ] = alltfo_coerce_setting( $raw[ $key ], $default ); } // The blocklist is newline-separated -- one term per line -- and the text @@ -729,7 +729,7 @@ function atf_normalize_settings( $raw, $defaults ) { * @param mixed $raw Raw notifications. * @return array[] */ -function atf_normalize_notifications( $raw ) { +function alltfo_normalize_notifications( $raw ) { if ( ! is_array( $raw ) ) { return array(); } @@ -757,7 +757,7 @@ function atf_normalize_notifications( $raw ) { 'subject' => isset( $notification['subject'] ) ? sanitize_text_field( (string) $notification['subject'] ) : '', 'message' => isset( $notification['message'] ) ? wp_kses_post( (string) $notification['message'] ) : '', 'attachFiles' => ! empty( $notification['attachFiles'] ), - 'logic' => atf_normalize_logic( isset( $notification['logic'] ) ? $notification['logic'] : array() ), + 'logic' => alltfo_normalize_logic( isset( $notification['logic'] ) ? $notification['logic'] : array() ), ); } @@ -772,7 +772,7 @@ function atf_normalize_notifications( $raw ) { * @param mixed $raw Raw confirmations. * @return array[] */ -function atf_normalize_confirmations( $raw ) { +function alltfo_normalize_confirmations( $raw ) { if ( ! is_array( $raw ) ) { return array(); } @@ -795,8 +795,8 @@ function atf_normalize_confirmations( $raw ) { 'url' => isset( $confirmation['url'] ) ? sanitize_text_field( (string) $confirmation['url'] ) : '', 'pageId' => isset( $confirmation['pageId'] ) ? absint( $confirmation['pageId'] ) : 0, 'query' => isset( $confirmation['query'] ) ? sanitize_text_field( (string) $confirmation['query'] ) : '', - 'success' => atf_normalize_success_screen( isset( $confirmation['success'] ) ? $confirmation['success'] : array() ), - 'logic' => atf_normalize_logic( isset( $confirmation['logic'] ) ? $confirmation['logic'] : array() ), + 'success' => alltfo_normalize_success_screen( isset( $confirmation['success'] ) ? $confirmation['success'] : array() ), + 'logic' => alltfo_normalize_logic( isset( $confirmation['logic'] ) ? $confirmation['logic'] : array() ), ); } @@ -807,7 +807,7 @@ function atf_normalize_confirmations( $raw ) { * Normalises a confirmation's success screen. * * The screen is what a message confirmation *looks like*: a style from - * `atf_success_styles()` plus the handful of knobs every style shares. An + * `alltfo_success_styles()` plus the handful of knobs every style shares. An * unknown style falls back to `simple` rather than erroring, so a form saved * by a newer version still shows something sensible on an older one. * @@ -816,7 +816,7 @@ function atf_normalize_confirmations( $raw ) { * @param mixed $raw Raw success screen config. * @return array */ -function atf_normalize_success_screen( $raw ) { +function alltfo_normalize_success_screen( $raw ) { if ( ! is_array( $raw ) ) { $raw = array(); } @@ -832,7 +832,7 @@ function atf_normalize_success_screen( $raw ) { $icon = function_exists( 'mb_substr' ) ? mb_substr( $icon, 0, 8 ) : substr( $icon, 0, 8 ); return array( - 'style' => array_key_exists( $style, atf_success_styles() ) ? $style : 'simple', + 'style' => array_key_exists( $style, alltfo_success_styles() ) ? $style : 'simple', 'title' => isset( $raw['title'] ) ? sanitize_text_field( (string) $raw['title'] ) : '', 'icon' => $icon, 'accent' => is_string( $accent ) ? $accent : '', @@ -850,7 +850,7 @@ function atf_normalize_success_screen( $raw ) { * @param mixed $raw Raw actions. * @return array[] */ -function atf_normalize_actions( $raw ) { +function alltfo_normalize_actions( $raw ) { if ( ! is_array( $raw ) ) { return array(); } @@ -866,7 +866,7 @@ function atf_normalize_actions( $raw ) { 'id' => isset( $action['id'] ) ? sanitize_key( $action['id'] ) : 'a' . ( $index + 1 ), 'type' => sanitize_key( $action['type'] ), 'enabled' => ! isset( $action['enabled'] ) || ! empty( $action['enabled'] ), - 'logic' => atf_normalize_logic( isset( $action['logic'] ) ? $action['logic'] : array() ), + 'logic' => alltfo_normalize_logic( isset( $action['logic'] ) ? $action['logic'] : array() ), // Action settings vary per action type, and the action's own handler // is what knows their shape. Kept as-is here and sanitised there, // which is the only place with enough context to do it properly. @@ -889,7 +889,7 @@ function atf_normalize_actions( $raw ) { * @param string[] $seen Ids already in use. * @return string A fresh id. */ -function atf_generate_field_id( $seen = array() ) { +function alltfo_generate_field_id( $seen = array() ) { $index = count( $seen ) + 1; while ( in_array( 'f' . $index, $seen, true ) ) { @@ -907,14 +907,14 @@ function atf_generate_field_id( $seen = array() ) { * @param int|WP_Post $form The form. * @return array The normalised schema. An unknown form gets the default one. */ -function atf_get_form_schema( $form ) { +function alltfo_get_form_schema( $form ) { $form_id = is_object( $form ) ? $form->ID : absint( $form ); if ( ! $form_id ) { - return atf_normalize_schema( array() ); + return alltfo_normalize_schema( array() ); } - return atf_normalize_schema( get_post_meta( $form_id, ATF_META_SCHEMA, true ) ); + return alltfo_normalize_schema( get_post_meta( $form_id, ALLTFO_META_SCHEMA, true ) ); } /** @@ -931,13 +931,13 @@ function atf_get_form_schema( $form ) { * @param array $schema A schema, normalised or not. * @return array The normalised schema that was stored. */ -function atf_save_form_schema( $form_id, $schema ) { +function alltfo_save_form_schema( $form_id, $schema ) { $form_id = absint( $form_id ); - $schema = atf_normalize_schema( $schema ); + $schema = alltfo_normalize_schema( $schema ); $json = wp_json_encode( $schema ); - update_post_meta( $form_id, ATF_META_SCHEMA, wp_slash( $json ) ); + update_post_meta( $form_id, ALLTFO_META_SCHEMA, wp_slash( $json ) ); /** * Fires after a form's schema is saved. @@ -947,7 +947,7 @@ function atf_save_form_schema( $form_id, $schema ) { * @param int $form_id The form. * @param array $schema The normalised schema that was stored. */ - do_action( 'atf_schema_saved', $form_id, $schema ); + do_action( 'alltfo_schema_saved', $form_id, $schema ); return $schema; } @@ -964,7 +964,7 @@ function atf_save_form_schema( $form_id, $schema ) { * @param string $field_id The id to find. * @return array|null The field, or null. */ -function atf_find_field( $schema, $field_id ) { +function alltfo_find_field( $schema, $field_id ) { $fields = isset( $schema['fields'] ) ? $schema['fields'] : array(); foreach ( $fields as $field ) { @@ -996,10 +996,10 @@ function atf_find_field( $schema, $field_id ) { * @param array $schema The schema. * @return array[] Input fields. */ -function atf_input_fields( $schema ) { +function alltfo_input_fields( $schema ) { $fields = isset( $schema['fields'] ) ? $schema['fields'] : array(); - return array_values( array_filter( $fields, 'atf_field_is_input' ) ); + return array_values( array_filter( $fields, 'alltfo_field_is_input' ) ); } /** @@ -1014,7 +1014,7 @@ function atf_input_fields( $schema ) { * @param array $schema The schema. * @return array[] { fields: array[], break: array|null } per page. */ -function atf_schema_pages( $schema ) { +function alltfo_schema_pages( $schema ) { $fields = isset( $schema['fields'] ) ? $schema['fields'] : array(); $pages = array(); $page = array( @@ -1051,8 +1051,8 @@ function atf_schema_pages( $schema ) { * @param array $schema The schema. * @return bool */ -function atf_is_multi_page( $schema ) { - return count( atf_schema_pages( $schema ) ) > 1; +function alltfo_is_multi_page( $schema ) { + return count( alltfo_schema_pages( $schema ) ) > 1; } /** @@ -1068,7 +1068,7 @@ function atf_is_multi_page( $schema ) { * @param string $json The raw recipe JSON. * @return string The normalised JSON, or an empty string when unusable. */ -function atf_normalize_validation_recipe( $json ) { +function alltfo_normalize_validation_recipe( $json ) { $raw = json_decode( $json, true ); if ( ! is_array( $raw ) ) { diff --git a/includes/shell-api.php b/includes/shell-api.php index d9afddb..60921f2 100644 --- a/includes/shell-api.php +++ b/includes/shell-api.php @@ -24,7 +24,7 @@ * * @since 0.1.0 */ -const ATF_SHELL_PREFIXES = array( 'openstation_', 'desktop_mode_' ); +const ALLTFO_SHELL_PREFIXES = array( 'openstation_', 'desktop_mode_' ); /** * Resolves a shell function to whichever name this install has. @@ -34,8 +34,8 @@ * @param string $name Bare function name, e.g. `register_window`. * @return string The callable name, or an empty string when no shell provides it. */ -function atf_shell_function( $name ) { - foreach ( ATF_SHELL_PREFIXES as $prefix ) { +function alltfo_shell_function( $name ) { + foreach ( ALLTFO_SHELL_PREFIXES as $prefix ) { if ( function_exists( $prefix . $name ) ) { return $prefix . $name; } @@ -52,8 +52,8 @@ function atf_shell_function( $name ) { * @param string $name Bare function name. * @return bool True when some spelling of it exists. */ -function atf_shell_has( $name ) { - return '' !== atf_shell_function( $name ); +function alltfo_shell_has( $name ) { + return '' !== alltfo_shell_function( $name ); } /** @@ -65,8 +65,8 @@ function atf_shell_has( $name ) { * @param mixed ...$args Arguments to pass through. * @return mixed The return value, or null when no shell provides it. */ -function atf_shell_call( $name, ...$args ) { - $fn = atf_shell_function( $name ); +function alltfo_shell_call( $name, ...$args ) { + $fn = alltfo_shell_function( $name ); return $fn ? call_user_func_array( $fn, $args ) : null; } @@ -84,10 +84,10 @@ function atf_shell_call( $name, ...$args ) { * @param string $name Bare hook name, e.g. `mode_init`. * @return string[] Hook names. */ -function atf_shell_hooks( $name ) { +function alltfo_shell_hooks( $name ) { $hooks = array(); - foreach ( ATF_SHELL_PREFIXES as $prefix ) { + foreach ( ALLTFO_SHELL_PREFIXES as $prefix ) { $hooks[] = $prefix . $name; } @@ -97,7 +97,7 @@ function atf_shell_hooks( $name ) { /** * Determines whether the shell is installed *and* switched on for this user. * - * Two separate questions, and both matter. `atf_shell_has()` answers "is the + * Two separate questions, and both matter. `alltfo_shell_has()` answers "is the * plugin active"; `openstation_is_enabled()` answers "has this particular user * opted in", since the shell is a per-user preference rather than a site-wide * one. Only when both hold should the builder present itself as a desktop app @@ -107,12 +107,12 @@ function atf_shell_hooks( $name ) { * * @return bool True when the desktop shell is active for the current user. */ -function atf_shell_is_active() { - if ( ! atf_shell_has( 'register_window' ) || ! atf_shell_has( 'is_enabled' ) ) { +function alltfo_shell_is_active() { + if ( ! alltfo_shell_has( 'register_window' ) || ! alltfo_shell_has( 'is_enabled' ) ) { return false; } - return (bool) atf_shell_call( 'is_enabled' ); + return (bool) alltfo_shell_call( 'is_enabled' ); } /** @@ -127,12 +127,12 @@ function atf_shell_is_active() { * * @return bool True when rendering inside a shell window iframe. */ -function atf_shell_is_chromeless() { - if ( ! atf_shell_has( 'is_chromeless_request' ) ) { +function alltfo_shell_is_chromeless() { + if ( ! alltfo_shell_has( 'is_chromeless_request' ) ) { return false; } - return (bool) atf_shell_call( 'is_chromeless_request' ); + return (bool) alltfo_shell_call( 'is_chromeless_request' ); } /** @@ -149,8 +149,8 @@ function atf_shell_is_chromeless() { * * @return void */ -function atf_shell_missing_notice() { - if ( atf_shell_has( 'register_window' ) || ! current_user_can( 'activate_plugins' ) ) { +function alltfo_shell_missing_notice() { + if ( alltfo_shell_has( 'register_window' ) || ! current_user_can( 'activate_plugins' ) ) { return; } @@ -167,4 +167,4 @@ function atf_shell_missing_notice() { ) ); } -add_action( 'admin_notices', 'atf_shell_missing_notice' ); +add_action( 'admin_notices', 'alltfo_shell_missing_notice' ); diff --git a/includes/shortcode.php b/includes/shortcode.php index ae37e4f..3cc75cd 100644 --- a/includes/shortcode.php +++ b/includes/shortcode.php @@ -6,7 +6,7 @@ * placement rather than per form: a theme override, whether to show the title. * * This is also where a non-JavaScript submission finishes its round trip. The - * result was stashed on `wp` by `atf_handle_post_submission()`; here it is + * result was stashed on `wp` by `alltfo_handle_post_submission()`; here it is * turned back into either a confirmation message or the same form with errors * against the right fields and every answer still in place. * @@ -15,7 +15,7 @@ defined( 'ABSPATH' ) || exit; -add_shortcode( 'allterrain_form', 'atf_shortcode' ); +add_shortcode( 'allterrain_form', 'alltfo_shortcode' ); /** * Renders the shortcode. @@ -25,7 +25,7 @@ * @param array $atts Shortcode attributes. * @return string */ -function atf_shortcode( $atts ) { +function alltfo_shortcode( $atts ) { $atts = shortcode_atts( array( 'id' => 0, @@ -44,14 +44,14 @@ function atf_shortcode( $atts ) { // Enqueued here rather than unconditionally, so a site with one form on one // page does not ship the bundle and the stylesheet to every other page. - atf_enqueue_form_assets(); + alltfo_enqueue_form_assets(); $args = array( 'theme' => sanitize_key( $atts['theme'] ), 'title' => 'show' === $atts['title'] ? 'show' : 'hide', ); - $stashed = atf_stash_result( $form_id ); + $stashed = alltfo_stash_result( $form_id ); if ( $stashed ) { $result = $stashed['result']; @@ -60,7 +60,7 @@ function atf_shortcode( $atts ) { $confirmation = $result['confirmation']; // A redirect confirmation already left the building in - // `atf_handle_post_submission()`; reaching here means it was a + // `alltfo_handle_post_submission()`; reaching here means it was a // message, or the redirect had nowhere to go. $args['message'] = isset( $confirmation['message'] ) && '' !== $confirmation['message'] ? $confirmation['message'] @@ -70,7 +70,7 @@ function atf_shortcode( $atts ) { : array(); } else { $args['errors'] = $result['errors']; - $args['values'] = atf_rehydrate_values( $form_id, $stashed['request'] ); + $args['values'] = alltfo_rehydrate_values( $form_id, $stashed['request'] ); if ( '' !== $result['message'] && ! $result['errors'] ) { // A form-level failure with no field errors -- a closed form, an @@ -79,13 +79,13 @@ function atf_shortcode( $atts ) { return sprintf( '%s', esc_html( $result['message'] ), - atf_render_form( $form_id, $args ) + alltfo_render_form( $form_id, $args ) ); } } } - return atf_render_form( $form_id, $args ); + return alltfo_render_form( $form_id, $args ); } /** @@ -101,10 +101,10 @@ function atf_shortcode( $atts ) { * @param array $raw The `atf` slice of the failed request. * @return array Field id => value. */ -function atf_rehydrate_values( $form_id, $raw ) { +function alltfo_rehydrate_values( $form_id, $raw ) { if ( ! is_array( $raw ) ) { return array(); } - return atf_sanitize_submission( atf_get_form_schema( $form_id ), $raw ); + return alltfo_sanitize_submission( alltfo_get_form_schema( $form_id ), $raw ); } diff --git a/includes/spam.php b/includes/spam.php index 4878107..2533073 100644 --- a/includes/spam.php +++ b/includes/spam.php @@ -33,14 +33,14 @@ * @param array $request The raw request, for the honeypot and timing fields. * @return array { spam: bool, reason: string } */ -function atf_screen_for_spam( $schema, $values, $request ) { +function alltfo_screen_for_spam( $schema, $values, $request ) { $settings = $schema['settings']['spam']; $verdict = array( 'spam' => false, 'reason' => '', ); - if ( ! empty( $settings['honeypot'] ) && ! empty( $request['atf_website'] ) ) { + if ( ! empty( $settings['honeypot'] ) && ! empty( $request['alltfo_website'] ) ) { $verdict = array( 'spam' => true, 'reason' => 'honeypot', @@ -48,7 +48,7 @@ function atf_screen_for_spam( $schema, $values, $request ) { } if ( ! $verdict['spam'] && $settings['timeTrap'] > 0 ) { - $elapsed = atf_submission_elapsed( $request ); + $elapsed = alltfo_submission_elapsed( $request ); // A negative or absent elapsed time means the timestamp was missing or // its signature did not match -- which is what a script that posts a @@ -61,7 +61,7 @@ function atf_screen_for_spam( $schema, $values, $request ) { } } - if ( ! $verdict['spam'] && $settings['rateLimit'] > 0 && atf_rate_limit_exceeded( $schema, $settings['rateLimit'] ) ) { + if ( ! $verdict['spam'] && $settings['rateLimit'] > 0 && alltfo_rate_limit_exceeded( $schema, $settings['rateLimit'] ) ) { $verdict = array( 'spam' => true, 'reason' => 'rate_limit', @@ -69,7 +69,7 @@ function atf_screen_for_spam( $schema, $values, $request ) { } if ( ! $verdict['spam'] && '' !== trim( (string) $settings['blocklist'] ) ) { - $hit = atf_blocklist_hit( $settings['blocklist'], $values ); + $hit = alltfo_blocklist_hit( $settings['blocklist'], $values ); if ( $hit ) { $verdict = array( @@ -79,15 +79,15 @@ function atf_screen_for_spam( $schema, $values, $request ) { } } - if ( ! $verdict['spam'] && ! empty( $settings['challenge'] ) && ! atf_challenge_answered( $request ) ) { + if ( ! $verdict['spam'] && ! empty( $settings['challenge'] ) && ! alltfo_challenge_answered( $request ) ) { $verdict = array( 'spam' => true, 'reason' => 'challenge', ); } - if ( ! $verdict['spam'] && ! empty( $settings['akismet'] ) && atf_akismet_available() ) { - if ( atf_akismet_says_spam( $schema, $values ) ) { + if ( ! $verdict['spam'] && ! empty( $settings['akismet'] ) && alltfo_akismet_available() ) { + if ( alltfo_akismet_says_spam( $schema, $values ) ) { $verdict = array( 'spam' => true, 'reason' => 'akismet', @@ -109,7 +109,7 @@ function atf_screen_for_spam( $schema, $values, $request ) { * @param array $values The submitted values. * @param array $request The raw request. */ - return apply_filters( 'atf_spam_verdict', $verdict, $schema, $values, $request ); + return apply_filters( 'alltfo_spam_verdict', $verdict, $schema, $values, $request ); } /** @@ -131,7 +131,7 @@ function atf_screen_for_spam( $schema, $values, $request ) { * @param int $form_id The form, so a signature cannot be replayed on another. * @return array { question: string, answer: int, signature: string } */ -function atf_make_challenge( $form_id ) { +function alltfo_make_challenge( $form_id ) { // Single digits, and addition only. The question is a spam check, not an // arithmetic exam -- anything harder starts excluding people, which is the // exact failure captchas are guilty of. @@ -148,7 +148,7 @@ function atf_make_challenge( $form_id ) { $right ), 'answer' => $answer, - 'signature' => atf_sign_challenge( $form_id, $answer ), + 'signature' => alltfo_sign_challenge( $form_id, $answer ), ); } @@ -169,7 +169,7 @@ function atf_make_challenge( $form_id ) { * produces it. Defaults to the current hour. * @return string */ -function atf_sign_challenge( $form_id, $answer, $bucket = '' ) { +function alltfo_sign_challenge( $form_id, $answer, $bucket = '' ) { if ( '' === $bucket ) { $bucket = gmdate( 'YmdH' ); } @@ -185,10 +185,10 @@ function atf_sign_challenge( $form_id, $answer, $bucket = '' ) { * @param array $request The raw request. * @return bool */ -function atf_challenge_answered( $request ) { - $given = isset( $request['atf_challenge'] ) ? trim( (string) $request['atf_challenge'] ) : ''; - $signature = isset( $request['atf_challenge_sig'] ) ? (string) $request['atf_challenge_sig'] : ''; - $form_id = isset( $request['atf_form_id'] ) ? absint( $request['atf_form_id'] ) : 0; +function alltfo_challenge_answered( $request ) { + $given = isset( $request['alltfo_challenge'] ) ? trim( (string) $request['alltfo_challenge'] ) : ''; + $signature = isset( $request['alltfo_challenge_sig'] ) ? (string) $request['alltfo_challenge_sig'] : ''; + $form_id = isset( $request['alltfo_form_id'] ) ? absint( $request['alltfo_form_id'] ) : 0; if ( '' === $given || '' === $signature || ! is_numeric( $given ) ) { return false; @@ -202,7 +202,7 @@ function atf_challenge_answered( $request ) { $buckets = array( gmdate( 'YmdH' ), gmdate( 'YmdH', time() - HOUR_IN_SECONDS ) ); foreach ( $buckets as $bucket ) { - if ( hash_equals( atf_sign_challenge( $form_id, (int) $given, $bucket ), $signature ) ) { + if ( hash_equals( alltfo_sign_challenge( $form_id, (int) $given, $bucket ), $signature ) ) { return true; } } @@ -222,20 +222,20 @@ function atf_challenge_answered( $request ) { * @param int $form_id The form. * @return string */ -function atf_render_challenge( $schema, $form_id ) { +function alltfo_render_challenge( $schema, $form_id ) { if ( empty( $schema['settings']['spam']['challenge'] ) ) { return ''; } - $challenge = atf_make_challenge( $form_id ); + $challenge = alltfo_make_challenge( $form_id ); $id = 'atf-challenge-' . $form_id; return sprintf( '
' . '' - . '' - . '' + . '' . '
', esc_attr( $id ), esc_html( $challenge['question'] ), @@ -254,16 +254,16 @@ function atf_render_challenge( $schema, $form_id ) { * @param array $request The raw request. * @return int|null Seconds, or null when the timestamp is missing or forged. */ -function atf_submission_elapsed( $request ) { - $issued = isset( $request['atf_t'] ) ? absint( $request['atf_t'] ) : 0; - $signature = isset( $request['atf_ts'] ) ? (string) $request['atf_ts'] : ''; - $form_id = isset( $request['atf_form_id'] ) ? absint( $request['atf_form_id'] ) : 0; +function alltfo_submission_elapsed( $request ) { + $issued = isset( $request['alltfo_t'] ) ? absint( $request['alltfo_t'] ) : 0; + $signature = isset( $request['alltfo_ts'] ) ? (string) $request['alltfo_ts'] : ''; + $form_id = isset( $request['alltfo_form_id'] ) ? absint( $request['alltfo_form_id'] ) : 0; if ( ! $issued || '' === $signature ) { return null; } - if ( ! hash_equals( atf_sign_timestamp( $form_id, $issued ), $signature ) ) { + if ( ! hash_equals( alltfo_sign_timestamp( $form_id, $issued ), $signature ) ) { return null; } @@ -283,8 +283,8 @@ function atf_submission_elapsed( $request ) { * @param int $limit Submissions allowed per hour. * @return bool */ -function atf_rate_limit_exceeded( $schema, $limit ) { - return atf_hit_rate_limit( 'submit', $limit ); +function alltfo_rate_limit_exceeded( $schema, $limit ) { + return alltfo_hit_rate_limit( 'submit', $limit ); } /** @@ -304,8 +304,8 @@ function atf_rate_limit_exceeded( $schema, $limit ) { * @return bool Whether the limit was already reached. Counting the hit and * answering in one step, so a caller cannot forget to increment. */ -function atf_hit_rate_limit( $bucket, $limit ) { - $ip = atf_client_ip(); +function alltfo_hit_rate_limit( $bucket, $limit ) { + $ip = alltfo_client_ip(); if ( '' === $ip ) { return false; @@ -318,7 +318,7 @@ function atf_hit_rate_limit( $bucket, $limit ) { return false; } - $key = 'atf_rl_' . md5( $bucket . '|' . $ip . '|' . gmdate( 'YmdH' ) ); + $key = 'alltfo_rl_' . md5( $bucket . '|' . $ip . '|' . gmdate( 'YmdH' ) ); $count = (int) get_transient( $key ); if ( $count >= $limit ) { @@ -343,14 +343,14 @@ function atf_hit_rate_limit( $bucket, $limit ) { * @param array $values The submitted values. * @return bool */ -function atf_blocklist_hit( $blocklist, $values ) { +function alltfo_blocklist_hit( $blocklist, $values ) { $terms = array_filter( array_map( 'trim', preg_split( '/\r\n|\r|\n/', $blocklist ) ) ); if ( ! $terms ) { return false; } - $haystack = strtolower( atf_flatten_values( $values ) ); + $haystack = strtolower( alltfo_flatten_values( $values ) ); foreach ( $terms as $term ) { if ( '' !== $term && false !== strpos( $haystack, strtolower( $term ) ) ) { @@ -369,7 +369,7 @@ function atf_blocklist_hit( $blocklist, $values ) { * @param mixed $values The values. * @return string */ -function atf_flatten_values( $values ) { +function alltfo_flatten_values( $values ) { if ( is_scalar( $values ) ) { return (string) $values; } @@ -381,7 +381,7 @@ function atf_flatten_values( $values ) { $parts = array(); foreach ( $values as $value ) { - $parts[] = atf_flatten_values( $value ); + $parts[] = alltfo_flatten_values( $value ); } return implode( ' ', $parts ); @@ -394,7 +394,7 @@ function atf_flatten_values( $values ) { * * @return bool */ -function atf_akismet_available() { +function alltfo_akismet_available() { return class_exists( 'Akismet' ) && method_exists( 'Akismet', 'get_api_key' ) && Akismet::get_api_key(); } @@ -411,8 +411,8 @@ function atf_akismet_available() { * @param array $values The submitted values. * @return bool */ -function atf_akismet_says_spam( $schema, $values ) { - if ( ! atf_akismet_available() ) { +function alltfo_akismet_says_spam( $schema, $values ) { + if ( ! alltfo_akismet_available() ) { return false; } @@ -422,7 +422,7 @@ function atf_akismet_says_spam( $schema, $values ) { // Akismet's accuracy depends heavily on being given the author and their // e-mail, so the first name-ish and the first e-mail field are found rather // than requiring the form's builder to nominate them. - foreach ( atf_input_fields( $schema ) as $field ) { + foreach ( alltfo_input_fields( $schema ) as $field ) { $value = isset( $values[ $field['id'] ] ) ? $values[ $field['id'] ] : ''; if ( '' === $email && 'email' === $field['type'] && is_string( $value ) ) { @@ -444,13 +444,13 @@ function atf_akismet_says_spam( $schema, $values ) { $request = array( 'blog' => get_option( 'home' ), - 'user_ip' => atf_client_ip(), + 'user_ip' => alltfo_client_ip(), 'user_agent' => isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '', 'referrer' => isset( $_SERVER['HTTP_REFERER'] ) ? esc_url_raw( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : '', 'comment_type' => 'contact-form', 'comment_author' => $author, 'comment_author_email' => $email, - 'comment_content' => atf_flatten_values( $values ), + 'comment_content' => alltfo_flatten_values( $values ), 'blog_lang' => get_locale(), 'blog_charset' => get_option( 'blog_charset' ), ); @@ -473,13 +473,13 @@ function atf_akismet_says_spam( $schema, $values ) { * @param string $verdict `spam` or `ham`. * @return void */ -function atf_akismet_submit_correction( $entry_id, $verdict ) { - if ( ! atf_akismet_available() ) { +function alltfo_akismet_submit_correction( $entry_id, $verdict ) { + if ( ! alltfo_akismet_available() ) { return; } - $context = json_decode( (string) get_post_meta( $entry_id, ATF_META_CONTEXT, true ), true ); - $values = json_decode( (string) get_post_meta( $entry_id, ATF_META_VALUES, true ), true ); + $context = json_decode( (string) get_post_meta( $entry_id, ALLTFO_META_CONTEXT, true ), true ); + $values = json_decode( (string) get_post_meta( $entry_id, ALLTFO_META_VALUES, true ), true ); if ( ! is_array( $context ) || ! is_array( $values ) ) { return; @@ -490,7 +490,7 @@ function atf_akismet_submit_correction( $entry_id, $verdict ) { 'user_ip' => isset( $context['ip'] ) ? $context['ip'] : '', 'user_agent' => isset( $context['userAgent'] ) ? $context['userAgent'] : '', 'comment_type' => 'contact-form', - 'comment_content' => atf_flatten_values( $values ), + 'comment_content' => alltfo_flatten_values( $values ), ); Akismet::http_post( build_query( $request ), 'spam' === $verdict ? 'submit-spam' : 'submit-ham' ); diff --git a/includes/submission.php b/includes/submission.php index 9cb31df..c1d268f 100644 --- a/includes/submission.php +++ b/includes/submission.php @@ -2,7 +2,7 @@ /** * The submission pipeline. * - * One function, `atf_process_submission()`, and every route into the plugin ends + * One function, `alltfo_process_submission()`, and every route into the plugin ends * at it: the REST endpoint the bundle posts to, the plain `POST` a form makes * with JavaScript off, and any programmatic call. There is exactly one place * where a submission is accepted, which is the only way to be sure the AJAX path @@ -47,15 +47,15 @@ * @type array $confirmation The resolved confirmation. * } */ -function atf_process_submission( $form_id, $request, $files = array() ) { +function alltfo_process_submission( $form_id, $request, $files = array() ) { $form_id = absint( $form_id ); $form = $form_id ? get_post( $form_id ) : null; - if ( ! $form || ATF_FORM_TYPE !== $form->post_type ) { - return atf_submission_failure( __( 'That form does not exist.', 'allterrain-forms' ) ); + if ( ! $form || ALLTFO_FORM_TYPE !== $form->post_type ) { + return alltfo_submission_failure( __( 'That form does not exist.', 'allterrain-forms' ) ); } - $schema = atf_get_form_schema( $form_id ); + $schema = alltfo_get_form_schema( $form_id ); /** * Fires before a submission is processed. @@ -66,56 +66,56 @@ function atf_process_submission( $form_id, $request, $files = array() ) { * @param array $request The raw request. * @param array $schema The form schema. */ - do_action( 'atf_before_submission', $form_id, $request, $schema ); + do_action( 'alltfo_before_submission', $form_id, $request, $schema ); - $availability = atf_form_availability( $form_id, $schema ); + $availability = alltfo_form_availability( $form_id, $schema ); if ( ! $availability['open'] ) { - return atf_submission_failure( $availability['message'] ); + return alltfo_submission_failure( $availability['message'] ); } // A preview never stores anything, never e-mails anyone and never counts. // The builder's preview posts through this same pipeline so that what it // shows is what a visitor would get -- including the validation errors. - $is_preview = ! empty( $request['atf_preview'] ) && atf_can_edit_forms(); + $is_preview = ! empty( $request['alltfo_preview'] ) && alltfo_can_edit_forms(); $raw = isset( $request['atf'] ) && is_array( $request['atf'] ) ? $request['atf'] : array(); - $values = atf_sanitize_submission( $schema, $raw ); + $values = alltfo_sanitize_submission( $schema, $raw ); - $uploads = atf_handle_uploads( $schema, $files, $form_id ); + $uploads = alltfo_handle_uploads( $schema, $files, $form_id ); if ( $uploads['errors'] ) { // Fields whose uploads succeeded before another field's failed do not // keep their attachments: the submission as a whole was refused, and an // attachment with no entry to belong to is an orphan nothing can find. foreach ( $uploads['values'] as $ids ) { - atf_delete_upload_attachments( $ids ); + alltfo_delete_upload_attachments( $ids ); } - return atf_submission_failure( atf_generic_error_message(), $uploads['errors'] ); + return alltfo_submission_failure( alltfo_generic_error_message(), $uploads['errors'] ); } foreach ( $uploads['values'] as $field_id => $ids ) { $values[ $field_id ] = $ids; } - $values = atf_apply_other_values( $schema, $values, $request ); - $values = atf_apply_calculations( $schema, $values ); + $values = alltfo_apply_other_values( $schema, $values, $request ); + $values = alltfo_apply_calculations( $schema, $values ); - $errors = atf_validate_submission( $schema, $values, array( 'form_id' => $form_id ) ); + $errors = alltfo_validate_submission( $schema, $values, array( 'form_id' => $form_id ) ); if ( $errors ) { // The uploads were stored before validation ran -- they had to be, a // broken file fails a submission too -- so a refused submission has to // take them back out or every failed attempt leaves files behind. foreach ( $uploads['values'] as $ids ) { - atf_delete_upload_attachments( $ids ); + alltfo_delete_upload_attachments( $ids ); } - return atf_submission_failure( atf_generic_error_message(), $errors ); + return alltfo_submission_failure( alltfo_generic_error_message(), $errors ); } - $spam = atf_screen_for_spam( $schema, $values, $request ); + $spam = alltfo_screen_for_spam( $schema, $values, $request ); if ( $is_preview ) { return array( @@ -123,7 +123,7 @@ function atf_process_submission( $form_id, $request, $files = array() ) { 'errors' => array(), 'message' => '', 'entry_id' => 0, - 'confirmation' => atf_resolve_confirmation( $schema, $values, 0, $form_id ), + 'confirmation' => alltfo_resolve_confirmation( $schema, $values, 0, $form_id ), 'preview' => true, ); } @@ -131,10 +131,10 @@ function atf_process_submission( $form_id, $request, $files = array() ) { $entry_id = 0; if ( ! empty( $schema['settings']['storage']['entries'] ) ) { - $entry_id = atf_store_entry( $form_id, $schema, $values, $spam ); + $entry_id = alltfo_store_entry( $form_id, $schema, $values, $spam ); if ( is_wp_error( $entry_id ) ) { - return atf_submission_failure( $entry_id->get_error_message() ); + return alltfo_submission_failure( $entry_id->get_error_message() ); } } @@ -153,18 +153,18 @@ function atf_process_submission( $form_id, $request, $files = array() ) { * @param int $form_id The form. * @param array $spam { spam, reason }. */ - do_action( 'atf_submission_spam', $entry_id, $form_id, $spam ); + do_action( 'alltfo_submission_spam', $entry_id, $form_id, $spam ); return array( 'success' => true, 'errors' => array(), 'message' => '', 'entry_id' => $entry_id, - 'confirmation' => atf_resolve_confirmation( $schema, $values, $entry_id, $form_id ), + 'confirmation' => alltfo_resolve_confirmation( $schema, $values, $entry_id, $form_id ), ); } - atf_record_submission( $form_id ); + alltfo_record_submission( $form_id ); /** * Fires once a submission has been accepted and stored. @@ -180,26 +180,26 @@ function atf_process_submission( $form_id, $request, $files = array() ) { * @param array $values The accepted values. * @param array $schema The form schema. */ - do_action( 'atf_entry_created', $entry_id, $form_id, $values, $schema ); + do_action( 'alltfo_entry_created', $entry_id, $form_id, $values, $schema ); // The resume token travels in the submission that finishes a saved form. // It is read from the parsed `$request` here rather than from `$_POST`, // because a REST submission with a JSON body never populates the - // superglobal -- the `$_POST` path in `atf_clear_partial_on_submit()` + // superglobal -- the `$_POST` path in `alltfo_clear_partial_on_submit()` // only ever saw the no-JavaScript form post. - if ( function_exists( 'atf_clear_partial' ) && ! empty( $request[ ATF_RESUME_QUERY ] ) ) { - atf_clear_partial( (string) $request[ ATF_RESUME_QUERY ] ); + if ( function_exists( 'alltfo_clear_partial' ) && ! empty( $request[ ALLTFO_RESUME_QUERY ] ) ) { + alltfo_clear_partial( (string) $request[ ALLTFO_RESUME_QUERY ] ); } - atf_run_actions( $schema, $values, $entry_id, $form_id, $request ); - atf_send_notifications( $schema, $values, $entry_id, $form_id ); + alltfo_run_actions( $schema, $values, $entry_id, $form_id, $request ); + alltfo_send_notifications( $schema, $values, $entry_id, $form_id ); return array( 'success' => true, 'errors' => array(), 'message' => '', 'entry_id' => $entry_id, - 'confirmation' => atf_resolve_confirmation( $schema, $values, $entry_id, $form_id ), + 'confirmation' => alltfo_resolve_confirmation( $schema, $values, $entry_id, $form_id ), ); } @@ -216,10 +216,10 @@ function atf_process_submission( $form_id, $request, $files = array() ) { * @param array $raw The `atf` slice of the request. * @return array Field id => sanitised value. */ -function atf_sanitize_submission( $schema, $raw ) { +function alltfo_sanitize_submission( $schema, $raw ) { $values = array(); - foreach ( atf_input_fields( $schema ) as $field ) { + foreach ( alltfo_input_fields( $schema ) as $field ) { // A file field's value never comes from the request body -- it is built // from `$_FILES` by the upload handler. Reading it here would let a // forged body claim an attachment id it does not own. @@ -229,7 +229,7 @@ function atf_sanitize_submission( $schema, $raw ) { $submitted = array_key_exists( $field['id'], $raw ) ? $raw[ $field['id'] ] : ''; - $values[ $field['id'] ] = atf_sanitize_field_value( $submitted, $field ); + $values[ $field['id'] ] = alltfo_sanitize_field_value( $submitted, $field ); } /** @@ -241,7 +241,7 @@ function atf_sanitize_submission( $schema, $raw ) { * @param array $schema The form schema. * @param array $raw The raw request slice. */ - return apply_filters( 'atf_sanitized_values', $values, $schema, $raw ); + return apply_filters( 'alltfo_sanitized_values', $values, $schema, $raw ); } /** @@ -249,7 +249,7 @@ function atf_sanitize_submission( $schema, $raw ) { * * The choice group posts `__other__` as its value and the free-text box posts * separately, so the two are rejoined here, before validation. The choice - * whitelist in `atf_validate_bounds()` is skipped for fields with "Other" + * whitelist in `alltfo_validate_bounds()` is skipped for fields with "Other" * enabled, because once the marker has been replaced the visitor's free text * is a legitimate answer no list could anticipate. * @@ -260,14 +260,14 @@ function atf_sanitize_submission( $schema, $raw ) { * @param array $request The raw request. * @return array The values, with `__other__` resolved. */ -function atf_apply_other_values( $schema, $values, $request ) { - $other = isset( $request['atf_other'] ) && is_array( $request['atf_other'] ) ? $request['atf_other'] : array(); +function alltfo_apply_other_values( $schema, $values, $request ) { + $other = isset( $request['alltfo_other'] ) && is_array( $request['alltfo_other'] ) ? $request['alltfo_other'] : array(); if ( ! $other ) { return $values; } - foreach ( atf_input_fields( $schema ) as $field ) { + foreach ( alltfo_input_fields( $schema ) as $field ) { if ( empty( $field['other'] ) || ! isset( $other[ $field['id'] ] ) ) { continue; } @@ -309,13 +309,13 @@ static function ( $item ) use ( $typed ) { * @param array $spam The spam verdict. * @return int|WP_Error The entry id. */ -function atf_store_entry( $form_id, $schema, $values, $spam = array() ) { +function alltfo_store_entry( $form_id, $schema, $values, $spam = array() ) { $storage = $schema['settings']['storage']; // A password never reaches storage. The registration action has already read // it out of the in-memory values by this point; what is written here is the // version with every password field blanked. - foreach ( atf_input_fields( $schema ) as $field ) { + foreach ( alltfo_input_fields( $schema ) as $field ) { if ( 'password' === $field['type'] ) { unset( $values[ $field['id'] ] ); } @@ -323,9 +323,9 @@ function atf_store_entry( $form_id, $schema, $values, $spam = array() ) { $entry_id = wp_insert_post( array( - 'post_type' => ATF_ENTRY_TYPE, - 'post_title' => atf_entry_title( $schema, $values, $form_id ), - 'post_status' => ! empty( $spam['spam'] ) ? ATF_STATUS_SPAM : ATF_STATUS_UNREAD, + 'post_type' => ALLTFO_ENTRY_TYPE, + 'post_title' => alltfo_entry_title( $schema, $values, $form_id ), + 'post_status' => ! empty( $spam['spam'] ) ? ALLTFO_STATUS_SPAM : ALLTFO_STATUS_UNREAD, 'post_author' => get_current_user_id(), 'post_content' => '', ), @@ -336,7 +336,7 @@ function atf_store_entry( $form_id, $schema, $values, $spam = array() ) { return $entry_id; } - $ip = $storage['ip'] ? atf_client_ip() : ''; + $ip = $storage['ip'] ? alltfo_client_ip() : ''; if ( $ip && $storage['anonymise'] ) { $ip = wp_privacy_anonymize_ip( $ip ); @@ -354,18 +354,18 @@ function atf_store_entry( $form_id, $schema, $values, $spam = array() ) { ); if ( ! empty( $schema['settings']['quiz']['enabled'] ) ) { - $context['quiz'] = atf_score_quiz( $schema, $values ); + $context['quiz'] = alltfo_score_quiz( $schema, $values ); } - update_post_meta( $entry_id, ATF_META_FORM, $form_id ); - update_post_meta( $entry_id, ATF_META_VALUES, wp_slash( wp_json_encode( $values ) ) ); - update_post_meta( $entry_id, ATF_META_CONTEXT, wp_slash( wp_json_encode( $context ) ) ); + update_post_meta( $entry_id, ALLTFO_META_FORM, $form_id ); + update_post_meta( $entry_id, ALLTFO_META_VALUES, wp_slash( wp_json_encode( $values ) ) ); + update_post_meta( $entry_id, ALLTFO_META_CONTEXT, wp_slash( wp_json_encode( $context ) ) ); // Files uploaded with this submission are parented to the entry, so deleting // the entry takes them with it and the media library shows what they belong // to rather than a wall of orphans. foreach ( $values as $field_id => $value ) { - $field = atf_find_field( $schema, $field_id ); + $field = alltfo_find_field( $schema, $field_id ); if ( ! $field || 'file' !== $field['type'] ) { continue; @@ -397,13 +397,13 @@ function atf_store_entry( $form_id, $schema, $values, $spam = array() ) { * @param int $form_id The form. * @return string */ -function atf_entry_title( $schema, $values, $form_id ) { - foreach ( atf_input_fields( $schema ) as $field ) { +function alltfo_entry_title( $schema, $values, $form_id ) { + foreach ( alltfo_input_fields( $schema ) as $field ) { if ( ! in_array( $field['type'], array( 'text', 'email', 'name' ), true ) ) { continue; } - $text = atf_format_field_value( + $text = alltfo_format_field_value( isset( $values[ $field['id'] ] ) ? $values[ $field['id'] ] : '', $field, 'table' @@ -431,7 +431,7 @@ function atf_entry_title( $schema, $values, $form_id ) { * @param array $errors Field id => message. * @return array */ -function atf_submission_failure( $message, $errors = array() ) { +function alltfo_submission_failure( $message, $errors = array() ) { return array( 'success' => false, 'errors' => $errors, @@ -448,7 +448,7 @@ function atf_submission_failure( $message, $errors = array() ) { * * @return string */ -function atf_generic_error_message() { +function alltfo_generic_error_message() { /** * Filters the message shown when a submission fails validation. * @@ -457,7 +457,7 @@ function atf_generic_error_message() { * @param string $message The message. */ return (string) apply_filters( - 'atf_validation_message', + 'alltfo_validation_message', __( 'Please check the form and try again.', 'allterrain-forms' ) ); } @@ -474,35 +474,35 @@ function atf_generic_error_message() { * * @return void */ -function atf_handle_post_submission() { - if ( is_admin() || ! isset( $_POST['atf_form_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- The nonce is checked below, once the form it belongs to is known. +function alltfo_handle_post_submission() { + if ( is_admin() || ! isset( $_POST['alltfo_form_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- The nonce is checked below, once the form it belongs to is known. return; } - $form_id = absint( $_POST['atf_form_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- As above. + $form_id = absint( $_POST['alltfo_form_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- As above. if ( ! $form_id ) { return; } - $nonce = isset( $_POST['atf_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['atf_nonce'] ) ) : ''; + $nonce = isset( $_POST['alltfo_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['alltfo_nonce'] ) ) : ''; - if ( ! wp_verify_nonce( $nonce, 'atf_submit_' . $form_id ) ) { + if ( ! wp_verify_nonce( $nonce, 'alltfo_submit_' . $form_id ) ) { // An expired nonce is the common case here -- a form left open in a tab // overnight -- so it is reported as something to retry rather than as an // attack. - atf_stash_result( + alltfo_stash_result( $form_id, - atf_submission_failure( __( 'This form expired. Please reload the page and try again.', 'allterrain-forms' ) ) + alltfo_submission_failure( __( 'This form expired. Please reload the page and try again.', 'allterrain-forms' ) ) ); return; } - $request = wp_unslash( $_POST ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Every value is sanitised through its own field type in `atf_sanitize_submission()`. - $files = isset( $_FILES ) ? $_FILES : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Validated in full by `atf_handle_uploads()`. + $request = wp_unslash( $_POST ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Every value is sanitised through its own field type in `alltfo_sanitize_submission()`. + $files = isset( $_FILES ) ? $_FILES : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Validated in full by `alltfo_handle_uploads()`. - $result = atf_process_submission( $form_id, $request, $files ); + $result = alltfo_process_submission( $form_id, $request, $files ); // A redirect confirmation has to happen before anything is printed, which is // the whole reason this runs on `wp` and not at render time. @@ -510,13 +510,13 @@ function atf_handle_post_submission() { $url = isset( $result['confirmation']['url'] ) ? $result['confirmation']['url'] : ''; if ( '' !== $url ) { - atf_redirect_to_confirmation( $url ); + alltfo_redirect_to_confirmation( $url ); } } - atf_stash_result( $form_id, $result, $request ); + alltfo_stash_result( $form_id, $result, $request ); } -add_action( 'wp', 'atf_handle_post_submission' ); +add_action( 'wp', 'alltfo_handle_post_submission' ); /** * Remembers a submission's result for the shortcode to render. @@ -528,7 +528,7 @@ function atf_handle_post_submission() { * @param array $request The request, so a failed form can be re-filled. * @return array|null The stashed result when reading. */ -function atf_stash_result( $form_id = 0, $result = null, $request = array() ) { +function alltfo_stash_result( $form_id = 0, $result = null, $request = array() ) { static $results = array(); if ( null !== $result ) { diff --git a/includes/templates.php b/includes/templates.php index 82b9bca..6744667 100644 --- a/includes/templates.php +++ b/includes/templates.php @@ -3,13 +3,13 @@ * The template library. * * A template is just a schema. Starting a form from one is - * `atf_save_form_schema( $new_form, atf_get_template( 'contact' ) )` -- there is + * `alltfo_save_form_schema( $new_form, alltfo_get_template( 'contact' ) )` -- there is * no template engine, no separate format, and no import path that differs from * the ordinary one. That is deliberate: a template that could express something * a hand-built form could not would be a second schema language to maintain. * * Which also means a site can turn any form it has into a template by exporting - * its schema, and register it through `atf_form_templates`. + * its schema, and register it through `alltfo_form_templates`. * * @package AllTerrain_Forms */ @@ -23,7 +23,7 @@ * * @return array Slug => { label, description, icon, schema }. */ -function atf_form_templates() { +function alltfo_form_templates() { $templates = array( 'blank' => array( @@ -739,7 +739,7 @@ function atf_form_templates() { * * @param array $templates Slug => { label, description, icon, schema }. */ - return apply_filters( 'atf_form_templates', $templates ); + return apply_filters( 'alltfo_form_templates', $templates ); } /** @@ -750,15 +750,15 @@ function atf_form_templates() { * @param string $slug Template slug. * @return array A complete schema. An unknown slug returns an empty form. */ -function atf_get_template( $slug ) { - $templates = atf_form_templates(); +function alltfo_get_template( $slug ) { + $templates = alltfo_form_templates(); $slug = sanitize_key( (string) $slug ); if ( ! isset( $templates[ $slug ] ) ) { - return atf_normalize_schema( array() ); + return alltfo_normalize_schema( array() ); } - return atf_normalize_schema( $templates[ $slug ]['schema'] ); + return alltfo_normalize_schema( $templates[ $slug ]['schema'] ); } /** @@ -770,12 +770,12 @@ function atf_get_template( $slug ) { * @param string $title The new form's title. * @return int|WP_Error The new form's id. */ -function atf_create_form_from_template( $slug, $title = '' ) { - if ( ! atf_can_edit_forms() ) { - return new WP_Error( 'atf_forbidden', __( 'You cannot create forms.', 'allterrain-forms' ), array( 'status' => 403 ) ); +function alltfo_create_form_from_template( $slug, $title = '' ) { + if ( ! alltfo_can_edit_forms() ) { + return new WP_Error( 'alltfo_forbidden', __( 'You cannot create forms.', 'allterrain-forms' ), array( 'status' => 403 ) ); } - $templates = atf_form_templates(); + $templates = alltfo_form_templates(); $slug = sanitize_key( (string) $slug ); if ( '' === $title ) { @@ -786,7 +786,7 @@ function atf_create_form_from_template( $slug, $title = '' ) { $form_id = wp_insert_post( array( - 'post_type' => ATF_FORM_TYPE, + 'post_type' => ALLTFO_FORM_TYPE, 'post_title' => sanitize_text_field( $title ), 'post_status' => 'publish', 'post_author' => get_current_user_id(), @@ -798,7 +798,7 @@ function atf_create_form_from_template( $slug, $title = '' ) { return $form_id; } - atf_save_form_schema( $form_id, atf_get_template( $slug ) ); + alltfo_save_form_schema( $form_id, alltfo_get_template( $slug ) ); /** * Fires after a form is created from a template. @@ -808,7 +808,7 @@ function atf_create_form_from_template( $slug, $title = '' ) { * @param int $form_id The new form. * @param string $slug The template it came from. */ - do_action( 'atf_form_created', $form_id, $slug ); + do_action( 'alltfo_form_created', $form_id, $slug ); return $form_id; } diff --git a/includes/themes.php b/includes/themes.php index 21ca293..b5243d0 100644 --- a/includes/themes.php +++ b/includes/themes.php @@ -37,7 +37,7 @@ * * @return array Token name => default value. */ -function atf_theme_token_defaults() { +function alltfo_theme_token_defaults() { $tokens = array( /* ------------------------------------------------------------ Colour */ @@ -148,7 +148,7 @@ function atf_theme_token_defaults() { * * @param array $tokens Token name => default value. */ - return apply_filters( 'atf_theme_tokens', $tokens ); + return apply_filters( 'alltfo_theme_tokens', $tokens ); } /** @@ -164,7 +164,7 @@ function atf_theme_token_defaults() { * @param string $token Token name. * @return array { control: string, options?: string[], unit?: string, label: string, group: string } */ -function atf_theme_token_control( $token ) { +function alltfo_theme_token_control( $token ) { $enums = array( 'field-style' => array( 'outline', 'filled', 'underline', 'none' ), 'label-position' => array( 'top', 'inside', 'floating', 'left', 'hidden' ), @@ -207,7 +207,7 @@ function atf_theme_token_control( $token ) { } $control['label'] = ucfirst( str_replace( '-', ' ', $token ) ); - $control['group'] = atf_theme_token_group( $token ); + $control['group'] = alltfo_theme_token_group( $token ); /** * Filters the Theme Studio control for one token. @@ -217,7 +217,7 @@ function atf_theme_token_control( $token ) { * @param array $control The control descriptor. * @param string $token Token name. */ - return apply_filters( 'atf_theme_token_control', $control, $token ); + return apply_filters( 'alltfo_theme_token_control', $control, $token ); } /** @@ -228,7 +228,7 @@ function atf_theme_token_control( $token ) { * @param string $token Token name. * @return string Group slug. */ -function atf_theme_token_group( $token ) { +function alltfo_theme_token_group( $token ) { $prefixes = array( 'radius-' => 'shape', 'shadow-' => 'shadow', @@ -269,7 +269,7 @@ function atf_theme_token_group( $token ) { * * @return array Theme slug => { label, description, tokens, dark }. */ -function atf_builtin_themes() { +function alltfo_builtin_themes() { $themes = array( 'clean' => array( @@ -592,21 +592,21 @@ function atf_builtin_themes() { * * @param array $themes Theme slug => definition. */ - return apply_filters( 'atf_builtin_themes', $themes ); + return apply_filters( 'alltfo_builtin_themes', $themes ); } /** * Themes registered in code by other plugins. * * A function-static rather than a global so nothing can reach in and mutate it - * without going through `atf_register_theme()`, which normalises. + * without going through `alltfo_register_theme()`, which normalises. * * @since 0.1.0 * * @param array|null $set Internal. Replaces the whole table. * @return array Theme slug => definition. */ -function &atf_theme_store( $set = null ) { +function &alltfo_theme_store( $set = null ) { static $themes = array(); if ( null !== $set ) { @@ -619,14 +619,14 @@ function &atf_theme_store( $set = null ) { /** * Registers a theme in code. * - * The parallel of `atf_register_field_type()`, and the right shape for a theme + * The parallel of `alltfo_register_field_type()`, and the right shape for a theme * that ships inside another plugin rather than one a user made in the Studio. * * Only the tokens a theme changes need listing -- everything else inherits from * the defaults, so a token added to the surface in a later release reaches every * registered theme without an edit. * - * Call it on `atf_loaded`. + * Call it on `alltfo_loaded`. * * @since 0.1.0 * @@ -641,22 +641,22 @@ function &atf_theme_store( $set = null ) { * } * @return true|WP_Error True on success. */ -function atf_register_theme( $slug, $args = array() ) { +function alltfo_register_theme( $slug, $args = array() ) { $slug = sanitize_key( $slug ); if ( '' === $slug ) { - return new WP_Error( 'atf_theme_slug', __( 'A theme needs a slug.', 'allterrain-forms' ) ); + return new WP_Error( 'alltfo_theme_slug', __( 'A theme needs a slug.', 'allterrain-forms' ) ); } if ( empty( $args['label'] ) ) { return new WP_Error( - 'atf_theme_label', + 'alltfo_theme_label', /* translators: %s: theme slug. */ sprintf( __( 'Theme "%s" needs a label.', 'allterrain-forms' ), $slug ) ); } - $themes = &atf_theme_store(); + $themes = &alltfo_theme_store(); $themes[ $slug ] = array( 'label' => (string) $args['label'], 'description' => isset( $args['description'] ) ? (string) $args['description'] : '', @@ -664,7 +664,7 @@ function atf_register_theme( $slug, $args = array() ) { // Sanitised at registration rather than at use, so a typo in a token // name is dropped once instead of being carried around and silently // ignored by every reader. - 'tokens' => atf_sanitize_tokens( isset( $args['tokens'] ) ? $args['tokens'] : array() ), + 'tokens' => alltfo_sanitize_tokens( isset( $args['tokens'] ) ? $args['tokens'] : array() ), ); return true; @@ -681,8 +681,8 @@ function atf_register_theme( $slug, $args = array() ) { * @param string $slug Theme slug. * @return bool True when a theme was removed. */ -function atf_unregister_theme( $slug ) { - $themes = &atf_theme_store(); +function alltfo_unregister_theme( $slug ) { + $themes = &alltfo_theme_store(); $slug = sanitize_key( $slug ); if ( ! isset( $themes[ $slug ] ) ) { @@ -704,14 +704,14 @@ function atf_unregister_theme( $slug ) { * * @return array Theme slug => { label, description, tokens, custom, id }. */ -function atf_get_themes() { +function alltfo_get_themes() { $themes = array(); // Three sources, each beating the one before: the built-ins, then anything // registered in code by another plugin, then the ones a user saved. A saved // theme winning on a slug collision is what lets a site override a shipped // theme and get it back by deleting theirs. - $registered = array_merge( atf_builtin_themes(), atf_theme_store() ); + $registered = array_merge( alltfo_builtin_themes(), alltfo_theme_store() ); foreach ( $registered as $slug => $theme ) { $themes[ $slug ] = array_merge( @@ -730,7 +730,7 @@ function atf_get_themes() { ); } - foreach ( atf_get_custom_themes() as $theme ) { + foreach ( alltfo_get_custom_themes() as $theme ) { $themes[ $theme['slug'] ] = $theme; } @@ -744,10 +744,10 @@ function atf_get_themes() { * * @return array[] Theme records. */ -function atf_get_custom_themes() { +function alltfo_get_custom_themes() { $posts = get_posts( array( - 'post_type' => ATF_THEME_TYPE, + 'post_type' => ALLTFO_THEME_TYPE, 'post_status' => array( 'publish', 'draft' ), 'numberposts' => 200, 'orderby' => 'title', @@ -759,13 +759,13 @@ function atf_get_custom_themes() { $themes = array(); foreach ( $posts as $post ) { - $tokens = json_decode( (string) get_post_meta( $post->ID, ATF_META_TOKENS, true ), true ); + $tokens = json_decode( (string) get_post_meta( $post->ID, ALLTFO_META_TOKENS, true ), true ); $themes[ $post->post_name ] = array( 'slug' => $post->post_name, 'label' => $post->post_title, 'description' => $post->post_excerpt, - 'tokens' => atf_sanitize_tokens( is_array( $tokens ) ? $tokens : array() ), + 'tokens' => alltfo_sanitize_tokens( is_array( $tokens ) ? $tokens : array() ), 'dark' => false, 'custom' => true, 'id' => $post->ID, @@ -787,8 +787,8 @@ function atf_get_custom_themes() { * @param string $slug Theme slug. * @return array The theme record. */ -function atf_get_theme( $slug ) { - $themes = atf_get_themes(); +function alltfo_get_theme( $slug ) { + $themes = alltfo_get_themes(); $slug = sanitize_key( (string) $slug ); if ( isset( $themes[ $slug ] ) ) { @@ -818,12 +818,12 @@ function atf_get_theme( $slug ) { * @param array $overrides Per-form token overrides. * @return array Every token, resolved. */ -function atf_resolve_tokens( $slug, $overrides = array() ) { - $theme = atf_get_theme( $slug ); +function alltfo_resolve_tokens( $slug, $overrides = array() ) { + $theme = alltfo_get_theme( $slug ); $tokens = array_merge( - atf_theme_token_defaults(), - atf_sanitize_tokens( $theme['tokens'] ), - atf_sanitize_tokens( is_array( $overrides ) ? $overrides : array() ) + alltfo_theme_token_defaults(), + alltfo_sanitize_tokens( $theme['tokens'] ), + alltfo_sanitize_tokens( is_array( $overrides ) ? $overrides : array() ) ); /** @@ -838,16 +838,16 @@ function atf_resolve_tokens( $slug, $overrides = array() ) { * @param string $slug Theme slug. * @param array $overrides The per-form overrides that were applied. */ - return apply_filters( 'atf_resolved_tokens', $tokens, $slug, $overrides ); + return apply_filters( 'alltfo_resolved_tokens', $tokens, $slug, $overrides ); } /** * Keeps a token map to known names and CSS-safe values. * * This is the security boundary of the whole theme system. Token values land - * inside a `#s', '', $html ); + // The wrapper's token declarations and the theme classes are exactly + // what is meant to differ; everything else must not. + $html = preg_replace( '/ style="[^"]*"/', '', $html ); $html = preg_replace( '/atf-theme-[a-z-]+/', '', $html ); $html = preg_replace( '/atf-labels-[a-z]+/', '', $html ); $html = preg_replace( '/atf-fields-[a-z]+/', '', $html ); $html = preg_replace( '/atf-is-dark/', '', $html ); $html = preg_replace( '/atf-\d+-\d+/', 'INSTANCE', $html ); - $html = preg_replace( '/name="atf_t" value="\d+"/', 'T', $html ); + $html = preg_replace( '/name="alltfo_t" value="\d+"/', 'T', $html ); $html = preg_replace( '/value="[a-f0-9]{32,}"/', 'HASH', $html ); // Runs of spaces collapsed, because the stripping above leaves them @@ -618,12 +618,12 @@ public function test_themes_do_not_change_the_markup() { return $html; }; - $clean = $strip( atf_render_form( $form_id, array( 'theme' => 'clean' ) ) ); + $clean = $strip( alltfo_render_form( $form_id, array( 'theme' => 'clean' ) ) ); - foreach ( array_keys( atf_builtin_themes() ) as $slug ) { + foreach ( array_keys( alltfo_builtin_themes() ) as $slug ) { $this->assertSame( $clean, - $strip( atf_render_form( $form_id, array( 'theme' => $slug ) ) ), + $strip( alltfo_render_form( $form_id, array( 'theme' => $slug ) ) ), sprintf( 'Theme "%s" changes the markup rather than only the tokens.', $slug ) ); } @@ -634,24 +634,24 @@ public function test_themes_do_not_change_the_markup() { * * A broken shortcode id must never print an error into a published page. * - * @covers ::atf_render_form + * @covers ::alltfo_render_form */ public function test_missing_form_is_silent_for_visitors() { wp_set_current_user( 0 ); - $this->assertSame( '', atf_render_form( 999999 ) ); + $this->assertSame( '', alltfo_render_form( 999999 ) ); } /** * …but says so to somebody who can fix it. * - * @covers ::atf_render_form + * @covers ::alltfo_render_form */ public function test_missing_form_is_loud_for_editors() { wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) ); - atf_add_capabilities(); + alltfo_add_capabilities(); - $this->assertStringContainsString( 'does not exist', atf_render_form( 999999 ) ); + $this->assertStringContainsString( 'does not exist', alltfo_render_form( 999999 ) ); } /** * The wording on a page break's buttons is the author's. @@ -662,10 +662,10 @@ public function test_missing_form_is_loud_for_editors() { * was in. Now that the canvas edits them, this is what says the value * survives normalisation and arrives on the page. * - * @covers ::atf_render_page + * @covers ::alltfo_render_page */ public function test_page_break_buttons_use_the_authors_words() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -689,7 +689,7 @@ public function test_page_break_buttons_use_the_authors_words() { ) ); - $html = atf_render_form( $form_id ); + $html = alltfo_render_form( $form_id ); $this->assertStringContainsString( '>Continue', $html, 'the next button' ); $this->assertStringContainsString( '>Go back', $html, 'the back button' ); @@ -702,10 +702,10 @@ public function test_page_break_buttons_use_the_authors_words() { * The empty string is the stored default, so "falls back" is the ordinary * case rather than the edge one. * - * @covers ::atf_render_page + * @covers ::alltfo_render_page */ public function test_page_break_buttons_fall_back() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -724,13 +724,13 @@ public function test_page_break_buttons_fall_back() { ) ); - $this->assertStringContainsString( '>Next', atf_render_form( $form_id ) ); + $this->assertStringContainsString( '>Next', alltfo_render_form( $form_id ) ); } /** * A repeater's add button says what its author told it to say. * - * @covers ::atf_render_repeater + * @covers ::alltfo_render_repeater */ public function test_repeater_add_button_uses_the_authors_words() { $html = $this->render_field( @@ -757,7 +757,7 @@ public function test_repeater_add_button_uses_the_authors_words() { * quote left both of those outside the repeater's namespace, where every * row wrote over the last and the sanitiser found nothing it recognised. * - * @covers ::atf_render_repeater_row + * @covers ::alltfo_render_repeater_row */ public function test_repeater_namespaces_bracketed_sub_field_names() { $html = $this->render_field( @@ -792,11 +792,11 @@ public function test_repeater_namespaces_bracketed_sub_field_names() { * with no way to reach it — which is exactly how these three came to be * write-only for as long as they were. * - * @covers ::atf_get_field_type + * @covers ::alltfo_get_field_type */ public function test_customisable_wording_is_declared() { - $page_break = atf_get_field_type( 'page_break' ); - $repeater = atf_get_field_type( 'repeater' ); + $page_break = alltfo_get_field_type( 'page_break' ); + $repeater = alltfo_get_field_type( 'repeater' ); $this->assertContains( 'nextlabel', $page_break['supports'] ); $this->assertContains( 'prevlabel', $page_break['supports'] ); @@ -812,7 +812,7 @@ public function test_customisable_wording_is_declared() { * a value with no control. * * @dataProvider data_reachable_settings - * @covers ::atf_render_field + * @covers ::alltfo_render_field * * @param array $field The field, merged over the defaults. * @param string $expected A fragment the rendered HTML must contain. @@ -921,7 +921,7 @@ public function data_reachable_settings() { * The assertion the fragment test above cannot make: "contains given-name" * would pass just as well if every other part were still there. * - * @covers ::atf_render_composite + * @covers ::alltfo_render_composite */ public function test_unchosen_parts_are_not_rendered() { $html = $this->render_field( @@ -943,7 +943,7 @@ public function test_unchosen_parts_are_not_rendered() { * answerable on an input that has a placeholder at all. The floating-label * theme rides on it; a space renders as nothing everywhere else. * - * @covers ::atf_control_attributes + * @covers ::alltfo_control_attributes */ public function test_placeholder_space_is_reserved() { $bare = $this->render_field( array( 'type' => 'text' ) ); @@ -968,10 +968,10 @@ public function test_placeholder_space_is_reserved() { * these; without them a live total that sums a repeater column shows 0 * until submit, then "corrects" itself — which reads as a broken form. * - * @covers ::atf_client_field + * @covers ::alltfo_client_field */ public function test_client_schema_includes_repeater_subfields() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -1003,7 +1003,7 @@ public function test_client_schema_includes_repeater_subfields() { ) ); - $html = atf_render_form( $form_id ); + $html = alltfo_render_form( $form_id ); preg_match( '/Ada' ) ); + $saved = alltfo_save_partial( $form_id, array( 'f1' => 'Ada' ) ); - $resumed = atf_resume_values( $saved['token'] ); + $resumed = alltfo_resume_values( $saved['token'] ); $this->assertStringNotContainsString( 'resumable_form(); - $first = atf_save_partial( $form_id, array( 'f1' => 'First' ) ); - $again = atf_save_partial( $form_id, array( 'f1' => 'Second' ), $first['token'] ); + $first = alltfo_save_partial( $form_id, array( 'f1' => 'First' ) ); + $again = alltfo_save_partial( $form_id, array( 'f1' => 'Second' ), $first['token'] ); $this->assertSame( $first['token'], $again['token'] ); $partials = get_posts( array( - 'post_type' => ATF_ENTRY_TYPE, - 'post_status' => ATF_STATUS_PARTIAL, + 'post_type' => ALLTFO_ENTRY_TYPE, + 'post_status' => ALLTFO_STATUS_PARTIAL, 'numberposts' => -1, 'fields' => 'ids', ) ); $this->assertCount( 1, $partials ); - $this->assertSame( 'Second', atf_resume_values( $first['token'] )['values']['f1'] ); + $this->assertSame( 'Second', alltfo_resume_values( $first['token'] )['values']['f1'] ); } /** @@ -193,18 +193,18 @@ public function test_saving_twice_updates_in_place() { * quote -- that must never be written into the resume meta, because a * corrupted stored token fails every later lookup. * - * @covers ::atf_save_partial + * @covers ::alltfo_save_partial */ public function test_an_update_keeps_the_stored_token_intact() { $form_id = $this->resumable_form(); - $saved = atf_save_partial( $form_id, array( 'f1' => 'First' ) ); + $saved = alltfo_save_partial( $form_id, array( 'f1' => 'First' ) ); - $again = atf_save_partial( $form_id, array( 'f1' => 'Second' ), ' ' . $saved['token'] . '"' ); + $again = alltfo_save_partial( $form_id, array( 'f1' => 'Second' ), ' ' . $saved['token'] . '"' ); $this->assertNotWPError( $again ); $this->assertSame( $saved['token'], $again['token'] ); - $this->assertNotNull( atf_find_partial( $saved['token'] ), 'The stored token was corrupted by the update.' ); - $this->assertSame( 'Second', atf_resume_values( $saved['token'] )['values']['f1'] ); + $this->assertNotNull( alltfo_find_partial( $saved['token'] ), 'The stored token was corrupted by the update.' ); + $this->assertSame( 'Second', alltfo_resume_values( $saved['token'] )['values']['f1'] ); } /** @@ -213,19 +213,19 @@ public function test_an_update_keeps_the_stored_token_intact() { * The mismatched token is treated as no token at all: the save succeeds as * a fresh partial for its own form, and the other form's answers survive. * - * @covers ::atf_save_partial + * @covers ::alltfo_save_partial */ public function test_a_foreign_token_does_not_update_another_forms_partial() { $first = $this->resumable_form(); $second = $this->resumable_form(); - $saved = atf_save_partial( $first, array( 'f1' => 'First form' ) ); - $cross = atf_save_partial( $second, array( 'f1' => 'Second form' ), $saved['token'] ); + $saved = alltfo_save_partial( $first, array( 'f1' => 'First form' ) ); + $cross = alltfo_save_partial( $second, array( 'f1' => 'Second form' ), $saved['token'] ); $this->assertNotWPError( $cross ); $this->assertNotSame( $saved['token'], $cross['token'], 'The save must mint a fresh token rather than reuse the other form\'s.' ); - $this->assertSame( 'First form', atf_resume_values( $saved['token'] )['values']['f1'], 'The first form\'s partial was overwritten.' ); - $this->assertSame( $second, atf_resume_values( $cross['token'] )['form_id'] ); + $this->assertSame( 'First form', alltfo_resume_values( $saved['token'] )['values']['f1'], 'The first form\'s partial was overwritten.' ); + $this->assertSame( $second, alltfo_resume_values( $cross['token'] )['form_id'] ); } /** @@ -235,7 +235,7 @@ public function test_a_foreign_token_does_not_update_another_forms_partial() { * entries table without bound. Updates are exempt: they need a token, and * the save that minted it already spent a slot. * - * @covers ::atf_save_partial + * @covers ::alltfo_save_partial */ public function test_partial_creation_is_rate_limited() { $previous_ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : null; @@ -244,7 +244,7 @@ public function test_partial_creation_is_rate_limited() { wp_set_current_user( 0 ); add_filter( - 'atf_partial_rate_limit', + 'alltfo_partial_rate_limit', static function () { return 2; } @@ -252,19 +252,19 @@ static function () { $form_id = $this->resumable_form(); - $this->assertNotWPError( atf_save_partial( $form_id, array( 'f1' => 'one' ) ) ); + $this->assertNotWPError( alltfo_save_partial( $form_id, array( 'f1' => 'one' ) ) ); - $second = atf_save_partial( $form_id, array( 'f1' => 'two' ) ); + $second = alltfo_save_partial( $form_id, array( 'f1' => 'two' ) ); $this->assertNotWPError( $second ); - $third = atf_save_partial( $form_id, array( 'f1' => 'three' ) ); + $third = alltfo_save_partial( $form_id, array( 'f1' => 'three' ) ); $this->assertWPError( $third ); - $this->assertSame( 'atf_partial_rate_limited', $third->get_error_code() ); + $this->assertSame( 'alltfo_partial_rate_limited', $third->get_error_code() ); // A visitor at the cap can still keep saving the partial they hold. - $this->assertNotWPError( atf_save_partial( $form_id, array( 'f1' => 'still saving' ), $second['token'] ) ); + $this->assertNotWPError( alltfo_save_partial( $form_id, array( 'f1' => 'still saving' ), $second['token'] ) ); if ( null === $previous_ip ) { unset( $_SERVER['REMOTE_ADDR'] ); @@ -277,15 +277,15 @@ static function () { * A token nobody issued resolves to nothing. * * @dataProvider data_bad_tokens - * @covers ::atf_find_partial + * @covers ::alltfo_find_partial * * @param string $token A token that must not resolve. */ public function test_bad_tokens_resolve_to_nothing( $token ) { $this->resumable_form(); - $this->assertNull( atf_find_partial( $token ) ); - $this->assertSame( array(), atf_resume_values( $token ) ); + $this->assertNull( alltfo_find_partial( $token ) ); + $this->assertSame( array(), alltfo_resume_values( $token ) ); } /** @@ -311,28 +311,28 @@ public function data_bad_tokens() { * The lookup narrows with a `LIKE`, so the final comparison has to be exact * or a token of all-percent signs would match the first partial in the table. * - * @covers ::atf_find_partial + * @covers ::alltfo_find_partial */ public function test_wildcards_cannot_match_a_real_token() { $form_id = $this->resumable_form(); - atf_save_partial( $form_id, array( 'f1' => 'Private' ) ); + alltfo_save_partial( $form_id, array( 'f1' => 'Private' ) ); - $this->assertNull( atf_find_partial( str_repeat( '%', 32 ) ) ); - $this->assertNull( atf_find_partial( str_repeat( '_', 32 ) ) ); + $this->assertNull( alltfo_find_partial( str_repeat( '%', 32 ) ) ); + $this->assertNull( alltfo_find_partial( str_repeat( '_', 32 ) ) ); } /** * Two tokens are never the same. * - * @covers ::atf_save_partial + * @covers ::alltfo_save_partial */ public function test_tokens_are_unique_and_long() { $form_id = $this->resumable_form(); $tokens = array(); for ( $i = 0; $i < 20; $i++ ) { - $saved = atf_save_partial( $form_id, array( 'f1' => 'x' ) ); + $saved = alltfo_save_partial( $form_id, array( 'f1' => 'x' ) ); $tokens[] = $saved['token']; $this->assertSame( 32, strlen( $saved['token'] ) ); @@ -344,16 +344,16 @@ public function test_tokens_are_unique_and_long() { /** * An expired token stops working. * - * @covers ::atf_find_partial + * @covers ::alltfo_find_partial */ public function test_an_expired_token_is_refused() { $form_id = $this->resumable_form(); - $saved = atf_save_partial( $form_id, array( 'f1' => 'Ada' ) ); - $partial = atf_find_partial( $saved['token'] ); + $saved = alltfo_save_partial( $form_id, array( 'f1' => 'Ada' ) ); + $partial = alltfo_find_partial( $saved['token'] ); update_post_meta( $partial->ID, - ATF_META_RESUME, + ALLTFO_META_RESUME, wp_slash( wp_json_encode( array( @@ -364,24 +364,24 @@ public function test_an_expired_token_is_refused() { ) ); - $this->assertNull( atf_find_partial( $saved['token'] ) ); + $this->assertNull( alltfo_find_partial( $saved['token'] ) ); } /** * The expiry sweep removes expired partials and keeps live ones. * - * @covers ::atf_expire_partials + * @covers ::alltfo_expire_partials */ public function test_expiry_sweep() { $form_id = $this->resumable_form(); - $live = atf_save_partial( $form_id, array( 'f1' => 'Live' ) ); - $stale = atf_save_partial( $form_id, array( 'f1' => 'Stale' ) ); - $stale_id = atf_find_partial( $stale['token'] )->ID; + $live = alltfo_save_partial( $form_id, array( 'f1' => 'Live' ) ); + $stale = alltfo_save_partial( $form_id, array( 'f1' => 'Stale' ) ); + $stale_id = alltfo_find_partial( $stale['token'] )->ID; update_post_meta( $stale_id, - ATF_META_RESUME, + ALLTFO_META_RESUME, wp_slash( wp_json_encode( array( @@ -392,10 +392,10 @@ public function test_expiry_sweep() { ) ); - atf_expire_partials(); + alltfo_expire_partials(); $this->assertNull( get_post( $stale_id ) ); - $this->assertNotNull( atf_find_partial( $live['token'] ) ); + $this->assertNotNull( alltfo_find_partial( $live['token'] ) ); } /** @@ -403,64 +403,64 @@ public function test_expiry_sweep() { * * Somebody saving a draft three times must not use up the quota. * - * @covers ::atf_count_entries + * @covers ::alltfo_count_entries */ public function test_partials_do_not_count_as_submissions() { $form_id = $this->resumable_form(); - atf_save_partial( $form_id, array( 'f1' => 'a' ) ); - atf_save_partial( $form_id, array( 'f1' => 'b' ) ); + alltfo_save_partial( $form_id, array( 'f1' => 'a' ) ); + alltfo_save_partial( $form_id, array( 'f1' => 'b' ) ); - $this->assertSame( 0, atf_count_entries( $form_id ) ); + $this->assertSame( 0, alltfo_count_entries( $form_id ) ); } /** * A partial is not in the entries list. * - * @covers ::atf_query_entries + * @covers ::alltfo_query_entries */ public function test_partials_are_not_in_the_entries_list() { wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) ); - atf_add_capabilities(); + alltfo_add_capabilities(); $form_id = $this->resumable_form(); - atf_save_partial( $form_id, array( 'f1' => 'Half done' ) ); + alltfo_save_partial( $form_id, array( 'f1' => 'Half done' ) ); - $this->assertSame( 0, atf_query_entries( array( 'form_id' => $form_id ) )['total'] ); + $this->assertSame( 0, alltfo_query_entries( array( 'form_id' => $form_id ) )['total'] ); } /** * Completing a form deletes the partial it came from. * - * @covers ::atf_clear_partial_on_submit + * @covers ::alltfo_clear_partial_on_submit */ public function test_finishing_clears_the_partial() { $form_id = $this->resumable_form(); - $saved = atf_save_partial( $form_id, array( 'f1' => 'Ada' ) ); + $saved = alltfo_save_partial( $form_id, array( 'f1' => 'Ada' ) ); - $this->assertNotNull( atf_find_partial( $saved['token'] ) ); + $this->assertNotNull( alltfo_find_partial( $saved['token'] ) ); // The token travels in the finishing submission, which is the only thing // tying the two together. - $_POST[ ATF_RESUME_QUERY ] = $saved['token']; + $_POST[ ALLTFO_RESUME_QUERY ] = $saved['token']; $issued = time() - 30; - atf_process_submission( + alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), 'atf' => array( 'f1' => 'Ada Lovelace' ), ) ); - unset( $_POST[ ATF_RESUME_QUERY ] ); + unset( $_POST[ ALLTFO_RESUME_QUERY ] ); - $this->assertNull( atf_find_partial( $saved['token'] ), 'The partial outlived the submission that finished it.' ); + $this->assertNull( alltfo_find_partial( $saved['token'] ), 'The partial outlived the submission that finished it.' ); } /** @@ -470,47 +470,47 @@ public function test_finishing_clears_the_partial() { * from the parsed request inside the pipeline rather than only from the * superglobal. * - * @covers ::atf_clear_partial + * @covers ::alltfo_clear_partial */ public function test_a_json_submission_clears_the_partial() { $form_id = $this->resumable_form(); - $saved = atf_save_partial( $form_id, array( 'f1' => 'Ada' ) ); + $saved = alltfo_save_partial( $form_id, array( 'f1' => 'Ada' ) ); - $this->assertNotNull( atf_find_partial( $saved['token'] ) ); + $this->assertNotNull( alltfo_find_partial( $saved['token'] ) ); $issued = time() - 30; // The token rides in the request array only -- `$_POST` stays empty, // exactly as it is for a `fetch()` posting JSON to the REST route. - atf_process_submission( + alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), - ATF_RESUME_QUERY => $saved['token'], + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), + ALLTFO_RESUME_QUERY => $saved['token'], 'atf' => array( 'f1' => 'Ada Lovelace' ), ) ); - $this->assertNull( atf_find_partial( $saved['token'] ), 'A JSON submission left the partial behind.' ); + $this->assertNull( alltfo_find_partial( $saved['token'] ), 'A JSON submission left the partial behind.' ); } /** * A resumed form renders with the saved answers in it. * - * @covers ::atf_render_form + * @covers ::alltfo_render_form */ public function test_a_resumed_form_renders_its_values() { $form_id = $this->resumable_form(); - $saved = atf_save_partial( $form_id, array( 'f1' => 'Ada Lovelace' ) ); + $saved = alltfo_save_partial( $form_id, array( 'f1' => 'Ada Lovelace' ) ); - $_GET[ ATF_RESUME_QUERY ] = $saved['token']; + $_GET[ ALLTFO_RESUME_QUERY ] = $saved['token']; - $html = atf_render_form( $form_id ); + $html = alltfo_render_form( $form_id ); - unset( $_GET[ ATF_RESUME_QUERY ] ); + unset( $_GET[ ALLTFO_RESUME_QUERY ] ); $this->assertStringContainsString( 'Ada Lovelace', $html ); $this->assertStringContainsString( 'data-atf-resume', $html ); @@ -519,19 +519,19 @@ public function test_a_resumed_form_renders_its_values() { /** * A token for one form does not resume a different one. * - * @covers ::atf_render_form + * @covers ::alltfo_render_form */ public function test_a_token_only_resumes_its_own_form() { $first = $this->resumable_form(); $second = $this->resumable_form(); - $saved = atf_save_partial( $first, array( 'f1' => 'Belongs to the first form' ) ); + $saved = alltfo_save_partial( $first, array( 'f1' => 'Belongs to the first form' ) ); - $_GET[ ATF_RESUME_QUERY ] = $saved['token']; + $_GET[ ALLTFO_RESUME_QUERY ] = $saved['token']; - $html = atf_render_form( $second ); + $html = alltfo_render_form( $second ); - unset( $_GET[ ATF_RESUME_QUERY ] ); + unset( $_GET[ ALLTFO_RESUME_QUERY ] ); $this->assertStringNotContainsString( 'Belongs to the first form', $html ); } @@ -539,10 +539,10 @@ public function test_a_token_only_resumes_its_own_form() { /** * The button only appears on a form that offers saving. * - * @covers ::atf_render_resume_button + * @covers ::alltfo_render_resume_button */ public function test_the_button_is_conditional() { - $off = atf_test_form( + $off = alltfo_test_form( array( 'fields' => array( array( @@ -553,7 +553,7 @@ public function test_the_button_is_conditional() { ) ); - $this->assertStringNotContainsString( 'data-atf-resume', atf_render_form( $off ) ); - $this->assertStringContainsString( 'data-atf-resume', atf_render_form( $this->resumable_form() ) ); + $this->assertStringNotContainsString( 'data-atf-resume', alltfo_render_form( $off ) ); + $this->assertStringContainsString( 'data-atf-resume', alltfo_render_form( $this->resumable_form() ) ); } } diff --git a/tests/phpunit/tests/schema.php b/tests/phpunit/tests/schema.php index 323d101..e30041d 100644 --- a/tests/phpunit/tests/schema.php +++ b/tests/phpunit/tests/schema.php @@ -2,7 +2,7 @@ /** * Schema normalisation. * - * `atf_normalize_schema()` is the single door everything untrusted comes through + * `alltfo_normalize_schema()` is the single door everything untrusted comes through * — the builder, an import, a template — and everything downstream assumes what * it guarantees. These tests pin those guarantees. * @@ -15,18 +15,18 @@ * * @group allterrain-forms */ -class ATF_Test_Schema extends WP_UnitTestCase { +class ALLTFO_Test_Schema extends WP_UnitTestCase { /** * Rubbish in gives a valid schema out rather than an exception. * * @dataProvider data_rubbish - * @covers ::atf_normalize_schema + * @covers ::alltfo_normalize_schema * * @param mixed $input Something that is not a schema. */ public function test_normalises_anything( $input ) { - $schema = atf_normalize_schema( $input ); + $schema = alltfo_normalize_schema( $input ); $this->assertIsArray( $schema ); $this->assertArrayHasKey( 'fields', $schema ); @@ -62,11 +62,11 @@ public function data_rubbish() { * Field ids are what logic, calculations and merge tags all reference, so a * duplicate makes every one of them address the wrong field. * - * @covers ::atf_normalize_schema - * @covers ::atf_generate_field_id + * @covers ::alltfo_normalize_schema + * @covers ::alltfo_generate_field_id */ public function test_field_ids_are_unique() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( 'type' => 'text' ), @@ -96,10 +96,10 @@ public function test_field_ids_are_unique() { /** * A field with no type is dropped; there is nothing to render. * - * @covers ::atf_normalize_field + * @covers ::alltfo_normalize_field */ public function test_typeless_fields_are_dropped() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( 'label' => 'No type here' ), @@ -118,10 +118,10 @@ public function test_typeless_fields_are_dropped() { /** * A field's type-specific settings are filled in from its registration. * - * @covers ::atf_normalize_field + * @covers ::alltfo_normalize_field */ public function test_type_settings_are_merged() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( @@ -143,10 +143,10 @@ public function test_type_settings_are_merged() { /** * A choice with a label and no value takes the label as its value. * - * @covers ::atf_normalize_choices + * @covers ::alltfo_normalize_choices */ public function test_choices_normalise() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( @@ -179,10 +179,10 @@ public function test_choices_normalise() { * * Sending only `spam.honeypot` must not wipe `spam.timeTrap`. * - * @covers ::atf_normalize_settings + * @covers ::alltfo_normalize_settings */ public function test_partial_settings_keep_siblings() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'settings' => array( 'spam' => array( 'honeypot' => false ), @@ -201,12 +201,12 @@ public function test_partial_settings_keep_siblings() { * `schedule.start` rides straight into `strtotime()` -- which fatals on an * array on PHP 8. The default's own type is the contract. * - * @covers ::atf_normalize_settings - * @covers ::atf_coerce_setting - * @covers ::atf_normalize_field + * @covers ::alltfo_normalize_settings + * @covers ::alltfo_coerce_setting + * @covers ::alltfo_normalize_field */ public function test_settings_are_coerced_to_their_declared_types() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'settings' => array( 'schedule' => array( @@ -240,10 +240,10 @@ public function test_settings_are_coerced_to_their_declared_types() { /** * An HTML block is filtered, so editing a form is not a way to run script. * - * @covers ::atf_normalize_field + * @covers ::alltfo_normalize_field */ public function test_html_block_is_filtered() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( @@ -262,10 +262,10 @@ public function test_html_block_is_filtered() { /** * A repeater's sub-fields go through the same normaliser. * - * @covers ::atf_normalize_field + * @covers ::alltfo_normalize_field */ public function test_repeater_subfields_normalise() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( @@ -294,11 +294,11 @@ public function test_repeater_subfields_normalise() { /** * A schema survives a round trip through storage unchanged. * - * @covers ::atf_save_form_schema - * @covers ::atf_get_form_schema + * @covers ::alltfo_save_form_schema + * @covers ::alltfo_get_form_schema */ public function test_schema_round_trips() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -321,7 +321,7 @@ public function test_schema_round_trips() { ) ); - $stored = atf_get_form_schema( $form_id ); + $stored = alltfo_get_form_schema( $form_id ); $this->assertSame( "Quotes ' and \" and \\ backslash", $stored['fields'][0]['label'] ); $this->assertSame( 'Ünïcödé — em dash', $stored['fields'][1]['choices'][0]['label'] ); @@ -331,11 +331,11 @@ public function test_schema_round_trips() { /** * Pages split at each page break, and there is always at least one. * - * @covers ::atf_schema_pages - * @covers ::atf_is_multi_page + * @covers ::alltfo_schema_pages + * @covers ::alltfo_is_multi_page */ public function test_pages_split_at_breaks() { - $single = atf_normalize_schema( + $single = alltfo_normalize_schema( array( 'fields' => array( array( @@ -346,10 +346,10 @@ public function test_pages_split_at_breaks() { ) ); - $this->assertCount( 1, atf_schema_pages( $single ) ); - $this->assertFalse( atf_is_multi_page( $single ) ); + $this->assertCount( 1, alltfo_schema_pages( $single ) ); + $this->assertFalse( alltfo_is_multi_page( $single ) ); - $multi = atf_normalize_schema( + $multi = alltfo_normalize_schema( array( 'fields' => array( array( @@ -376,10 +376,10 @@ public function test_pages_split_at_breaks() { ) ); - $pages = atf_schema_pages( $multi ); + $pages = alltfo_schema_pages( $multi ); $this->assertCount( 3, $pages ); - $this->assertTrue( atf_is_multi_page( $multi ) ); + $this->assertTrue( alltfo_is_multi_page( $multi ) ); $this->assertSame( 'f1', $pages[0]['fields'][0]['id'] ); $this->assertSame( 'b1', $pages[0]['break']['id'], 'A break belongs to the page it closes.' ); $this->assertNull( $pages[2]['break'] ); @@ -388,20 +388,20 @@ public function test_pages_split_at_breaks() { /** * An empty schema still has a page, so nothing has to special-case it. * - * @covers ::atf_schema_pages + * @covers ::alltfo_schema_pages */ public function test_empty_schema_has_one_page() { - $this->assertCount( 1, atf_schema_pages( atf_normalize_schema( array() ) ) ); + $this->assertCount( 1, alltfo_schema_pages( alltfo_normalize_schema( array() ) ) ); } /** * Layout fields do not count as inputs. * - * @covers ::atf_input_fields - * @covers ::atf_field_is_input + * @covers ::alltfo_input_fields + * @covers ::alltfo_field_is_input */ public function test_layout_fields_are_not_inputs() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( @@ -424,7 +424,7 @@ public function test_layout_fields_are_not_inputs() { ) ); - $this->assertSame( array( 'f1', 'f2' ), wp_list_pluck( atf_input_fields( $schema ), 'id' ) ); + $this->assertSame( array( 'f1', 'f2' ), wp_list_pluck( alltfo_input_fields( $schema ), 'id' ) ); } /** @@ -434,19 +434,19 @@ public function test_layout_fields_are_not_inputs() { * still has that answer in every entry, and pretending the field was * decorative would drop the column from the export. * - * @covers ::atf_field_is_input + * @covers ::alltfo_field_is_input */ public function test_unknown_type_is_treated_as_an_input() { - $this->assertTrue( atf_field_is_input( array( 'type' => 'some_plugins_field' ) ) ); + $this->assertTrue( alltfo_field_is_input( array( 'type' => 'some_plugins_field' ) ) ); } /** * A field can be found anywhere, including inside a repeater. * - * @covers ::atf_find_field + * @covers ::alltfo_find_field */ public function test_find_field_reaches_into_repeaters() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( @@ -463,8 +463,8 @@ public function test_find_field_reaches_into_repeaters() { ) ); - $this->assertSame( 'inner', atf_find_field( $schema, 'inner' )['id'] ); - $this->assertNull( atf_find_field( $schema, 'nope' ) ); + $this->assertSame( 'inner', alltfo_find_field( $schema, 'inner' )['id'] ); + $this->assertNull( alltfo_find_field( $schema, 'nope' ) ); } /** @@ -479,12 +479,12 @@ public function test_find_field_reaches_into_repeaters() { * watching the form render. * * @dataProvider data_choice_types - * @covers ::atf_seed_field_defaults + * @covers ::alltfo_seed_field_defaults * * @param string $type A field type that is a list of choices. */ public function test_a_choice_field_is_never_left_empty( $type ) { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( @@ -512,7 +512,7 @@ public function test_a_choice_field_is_never_left_empty( $type ) { public function data_choice_types() { $cases = array(); - foreach ( atf_get_field_types() as $slug => $definition ) { + foreach ( alltfo_get_field_types() as $slug => $definition ) { if ( ! empty( $definition['choices'] ) ) { $cases[ $slug ] = array( $slug ); } @@ -527,10 +527,10 @@ public function data_choice_types() { * The seeding must be a fallback, not a policy. Overwriting or appending to a * real list would corrupt every imported form it touched. * - * @covers ::atf_seed_field_defaults + * @covers ::alltfo_seed_field_defaults */ public function test_seeding_never_touches_real_choices() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( @@ -557,10 +557,10 @@ public function test_seeding_never_touches_real_choices() { * Choices are the shared answer scale and rows are the statements. One * without the other is still an unanswerable question. * - * @covers ::atf_seed_field_defaults + * @covers ::alltfo_seed_field_defaults */ public function test_a_likert_gets_statements_as_well_as_a_scale() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( @@ -578,10 +578,10 @@ public function test_a_likert_gets_statements_as_well_as_a_scale() { /** * A repeater gets something to repeat. * - * @covers ::atf_seed_field_defaults + * @covers ::alltfo_seed_field_defaults */ public function test_a_repeater_gets_a_sub_field() { - $schema = atf_normalize_schema( + $schema = alltfo_normalize_schema( array( 'fields' => array( array( diff --git a/tests/phpunit/tests/submission.php b/tests/phpunit/tests/submission.php index b8ea4d1..6015314 100644 --- a/tests/phpunit/tests/submission.php +++ b/tests/phpunit/tests/submission.php @@ -4,7 +4,7 @@ * * Everything a form does between "somebody pressed Send" and "there is an entry" * — availability, spam screening, storage, notifications and confirmations — - * goes through `atf_process_submission()`, so this is where the plugin's actual + * goes through `alltfo_process_submission()`, so this is where the plugin's actual * behaviour is pinned. * * @package AllTerrain_Forms @@ -16,7 +16,7 @@ * * @group allterrain-forms */ -class ATF_Test_Submission extends WP_UnitTestCase { +class ALLTFO_Test_Submission extends WP_UnitTestCase { /** * A form with one required text field and one email field. @@ -31,7 +31,7 @@ class ATF_Test_Submission extends WP_UnitTestCase { public function set_up() { parent::set_up(); - $this->form_id = atf_test_form( + $this->form_id = alltfo_test_form( array( 'fields' => array( array( @@ -63,10 +63,10 @@ private function request( $values ) { $issued = time() - 30; return array( - 'atf_form_id' => $this->form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $this->form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $this->form_id, $issued ), + 'alltfo_form_id' => $this->form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $this->form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $this->form_id, $issued ), 'atf' => $values, ); } @@ -74,11 +74,11 @@ private function request( $values ) { /** * A good submission is stored, with its values. * - * @covers ::atf_process_submission - * @covers ::atf_store_entry + * @covers ::alltfo_process_submission + * @covers ::alltfo_store_entry */ public function test_a_good_submission_is_stored() { - $result = atf_process_submission( + $result = alltfo_process_submission( $this->form_id, $this->request( array( @@ -94,11 +94,11 @@ public function test_a_good_submission_is_stored() { $entry = get_post( $result['entry_id'] ); - $this->assertSame( ATF_ENTRY_TYPE, $entry->post_type ); - $this->assertSame( ATF_STATUS_UNREAD, $entry->post_status ); - $this->assertSame( $this->form_id, (int) get_post_meta( $entry->ID, ATF_META_FORM, true ) ); + $this->assertSame( ALLTFO_ENTRY_TYPE, $entry->post_type ); + $this->assertSame( ALLTFO_STATUS_UNREAD, $entry->post_status ); + $this->assertSame( $this->form_id, (int) get_post_meta( $entry->ID, ALLTFO_META_FORM, true ) ); - $values = json_decode( get_post_meta( $entry->ID, ATF_META_VALUES, true ), true ); + $values = json_decode( get_post_meta( $entry->ID, ALLTFO_META_VALUES, true ), true ); $this->assertSame( 'Ada Lovelace', $values['f1'] ); $this->assertSame( 'ada@example.com', $values['f2'] ); @@ -107,29 +107,29 @@ public function test_a_good_submission_is_stored() { /** * A submission missing a required field is refused, and nothing is stored. * - * @covers ::atf_process_submission + * @covers ::alltfo_process_submission */ public function test_validation_failure_stores_nothing() { - $before = wp_count_posts( ATF_ENTRY_TYPE ); + $before = wp_count_posts( ALLTFO_ENTRY_TYPE ); - $result = atf_process_submission( $this->form_id, $this->request( array( 'f1' => '' ) ) ); + $result = alltfo_process_submission( $this->form_id, $this->request( array( 'f1' => '' ) ) ); $this->assertFalse( $result['success'] ); $this->assertArrayHasKey( 'f1', $result['errors'] ); $this->assertSame( 0, $result['entry_id'] ); - $after = wp_count_posts( ATF_ENTRY_TYPE ); + $after = wp_count_posts( ALLTFO_ENTRY_TYPE ); - $this->assertEquals( $before->{ATF_STATUS_UNREAD} ?? 0, $after->{ATF_STATUS_UNREAD} ?? 0 ); + $this->assertEquals( $before->{ALLTFO_STATUS_UNREAD} ?? 0, $after->{ALLTFO_STATUS_UNREAD} ?? 0 ); } /** * The entry title is built from a meaningful answer. * - * @covers ::atf_entry_title + * @covers ::alltfo_entry_title */ public function test_entry_title_is_readable() { - $result = atf_process_submission( $this->form_id, $this->request( array( 'f1' => 'Grace Hopper' ) ) ); + $result = alltfo_process_submission( $this->form_id, $this->request( array( 'f1' => 'Grace Hopper' ) ) ); $this->assertStringContainsString( 'Grace Hopper', get_the_title( $result['entry_id'] ) ); } @@ -137,10 +137,10 @@ public function test_entry_title_is_readable() { /** * A submission works through the REST route, not just the function. * - * Every other test here calls `atf_process_submission()` directly, which + * Every other test here calls `alltfo_process_submission()` directly, which * skips WordPress's own argument validation — and that is exactly where this * plugin once had a bug that no unit test could see: the route declared - * `form_id` as required while the form posts `atf_form_id`, so WordPress + * `form_id` as required while the form posts `alltfo_form_id`, so WordPress * rejected every real submission with "Missing parameter(s)" before the * callback ever ran. * @@ -148,19 +148,19 @@ public function test_entry_title_is_readable() { * form actually posts, so the route's contract and the markup's contract are * checked against each other. * - * @covers ::atf_rest_submit + * @covers ::alltfo_rest_submit */ public function test_submitting_through_the_rest_route() { $issued = time() - 30; - $request = new WP_REST_Request( 'POST', '/' . ATF_REST_NAMESPACE . '/submit' ); + $request = new WP_REST_Request( 'POST', '/' . ALLTFO_REST_NAMESPACE . '/submit' ); $request->set_body_params( array( - 'atf_form_id' => $this->form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $this->form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $this->form_id, $issued ), + 'alltfo_form_id' => $this->form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $this->form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $this->form_id, $issued ), 'atf' => array( 'f1' => 'Through REST', 'f2' => 'rest@example.com', @@ -176,7 +176,7 @@ public function test_submitting_through_the_rest_route() { $this->assertTrue( $data['success'], wp_json_encode( $data ) ); $this->assertGreaterThan( 0, $data['entry_id'] ); - $this->assertSame( ATF_STATUS_UNREAD, get_post_status( $data['entry_id'] ) ); + $this->assertSame( ALLTFO_STATUS_UNREAD, get_post_status( $data['entry_id'] ) ); } /** @@ -186,11 +186,11 @@ public function test_submitting_through_the_rest_route() { * named exactly what `/submit` insists on, or the two drift apart again the * next time either is edited. * - * @covers ::atf_render_hidden_fields + * @covers ::alltfo_render_hidden_fields */ public function test_the_form_posts_what_the_route_requires() { $routes = rest_get_server()->get_routes(); - $route = $routes[ '/' . ATF_REST_NAMESPACE . '/submit' ][0]; + $route = $routes[ '/' . ALLTFO_REST_NAMESPACE . '/submit' ][0]; $required = array(); @@ -202,7 +202,7 @@ public function test_the_form_posts_what_the_route_requires() { $this->assertNotEmpty( $required ); - $html = atf_render_form( $this->form_id ); + $html = alltfo_render_form( $this->form_id ); foreach ( $required as $name ) { $this->assertStringContainsString( @@ -218,90 +218,90 @@ public function test_the_form_posts_what_the_route_requires() { /** * A filled honeypot is spam. * - * @covers ::atf_screen_for_spam + * @covers ::alltfo_screen_for_spam */ public function test_honeypot_catches_a_bot() { $request = $this->request( array( 'f1' => 'Bot' ) ); - $request['atf_website'] = 'https://spam.example'; + $request['alltfo_website'] = 'https://spam.example'; - $result = atf_process_submission( $this->form_id, $request ); + $result = alltfo_process_submission( $this->form_id, $request ); // The visitor is told it worked. Telling a spammer they were caught is // how they learn to get past it, and telling a false positive they // failed loses a real enquiry twice. $this->assertTrue( $result['success'] ); - $this->assertSame( ATF_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); + $this->assertSame( ALLTFO_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); } /** * A submission faster than a human is spam. * - * @covers ::atf_screen_for_spam + * @covers ::alltfo_screen_for_spam */ public function test_time_trap_catches_an_instant_submission() { $issued = time(); - $result = atf_process_submission( + $result = alltfo_process_submission( $this->form_id, array( - 'atf_form_id' => $this->form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $this->form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $this->form_id, $issued ), + 'alltfo_form_id' => $this->form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $this->form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $this->form_id, $issued ), 'atf' => array( 'f1' => 'Fast' ), ) ); - $this->assertSame( ATF_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); + $this->assertSame( ALLTFO_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); } /** * A request with no timestamp at all — a bare field list — is spam. * - * @covers ::atf_submission_elapsed + * @covers ::alltfo_submission_elapsed */ public function test_missing_timestamp_is_spam() { - $result = atf_process_submission( + $result = alltfo_process_submission( $this->form_id, array( - 'atf_form_id' => $this->form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $this->form_id ), + 'alltfo_form_id' => $this->form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $this->form_id ), 'atf' => array( 'f1' => 'Scripted' ), ) ); - $this->assertSame( ATF_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); + $this->assertSame( ALLTFO_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); } /** * A forged timestamp cannot defeat the time trap. * - * @covers ::atf_submission_elapsed + * @covers ::alltfo_submission_elapsed */ public function test_forged_timestamp_is_rejected() { - $result = atf_process_submission( + $result = alltfo_process_submission( $this->form_id, array( - 'atf_form_id' => $this->form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $this->form_id ), + 'alltfo_form_id' => $this->form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $this->form_id ), // Claims the form was served an hour ago, but the signature is // nonsense, so the claim is not believed. - 'atf_t' => time() - 3600, - 'atf_ts' => 'made-up-signature', + 'alltfo_t' => time() - 3600, + 'alltfo_ts' => 'made-up-signature', 'atf' => array( 'f1' => 'Forged' ), ) ); - $this->assertSame( ATF_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); + $this->assertSame( ALLTFO_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); } /** * A blocked word files the submission as spam. * - * @covers ::atf_blocklist_hit + * @covers ::alltfo_blocklist_hit */ public function test_blocklist() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -317,27 +317,27 @@ public function test_blocklist() { $issued = time() - 30; - $result = atf_process_submission( + $result = alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), 'atf' => array( 'f1' => 'Buy CRYPTO now' ), ) ); - $this->assertSame( ATF_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); + $this->assertSame( ALLTFO_STATUS_SPAM, get_post_status( $result['entry_id'] ) ); } /** * The arithmetic challenge accepts a right answer and refuses a wrong one. * - * @covers ::atf_challenge_answered + * @covers ::alltfo_challenge_answered */ public function test_challenge() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -354,34 +354,34 @@ public function test_challenge() { $issued = time() - 30; $send = function ( $answer, $signature ) use ( $form_id, $issued ) { - return atf_process_submission( + return alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), - 'atf_challenge' => $answer, - 'atf_challenge_sig' => $signature, + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), + 'alltfo_challenge' => $answer, + 'alltfo_challenge_sig' => $signature, 'atf' => array( 'f1' => 'Human' ), ) ); }; - $right = $send( '12', atf_sign_challenge( $form_id, 12 ) ); + $right = $send( '12', alltfo_sign_challenge( $form_id, 12 ) ); - $this->assertSame( ATF_STATUS_UNREAD, get_post_status( $right['entry_id'] ) ); + $this->assertSame( ALLTFO_STATUS_UNREAD, get_post_status( $right['entry_id'] ) ); // A wrong answer, correctly signed for a *different* number. - $wrong = $send( '11', atf_sign_challenge( $form_id, 12 ) ); + $wrong = $send( '11', alltfo_sign_challenge( $form_id, 12 ) ); - $this->assertSame( ATF_STATUS_SPAM, get_post_status( $wrong['entry_id'] ) ); + $this->assertSame( ALLTFO_STATUS_SPAM, get_post_status( $wrong['entry_id'] ) ); // No answer at all, which is what a script that never read the question // sends. $absent = $send( '', '' ); - $this->assertSame( ATF_STATUS_SPAM, get_post_status( $absent['entry_id'] ) ); + $this->assertSame( ALLTFO_STATUS_SPAM, get_post_status( $absent['entry_id'] ) ); } /** @@ -392,30 +392,30 @@ public function test_challenge() { * (answer, signature) pair stops replaying within two hours instead of * working forever. * - * @covers ::atf_challenge_answered - * @covers ::atf_sign_challenge + * @covers ::alltfo_challenge_answered + * @covers ::alltfo_sign_challenge */ public function test_challenge_signature_expires() { $request = static function ( $signature ) { return array( - 'atf_form_id' => 7, - 'atf_challenge' => '12', - 'atf_challenge_sig' => $signature, + 'alltfo_form_id' => 7, + 'alltfo_challenge' => '12', + 'alltfo_challenge_sig' => $signature, ); }; $this->assertTrue( - atf_challenge_answered( $request( atf_sign_challenge( 7, 12 ) ) ), + alltfo_challenge_answered( $request( alltfo_sign_challenge( 7, 12 ) ) ), 'A signature from the current hour must verify.' ); $this->assertTrue( - atf_challenge_answered( $request( atf_sign_challenge( 7, 12, gmdate( 'YmdH', time() - HOUR_IN_SECONDS ) ) ) ), + alltfo_challenge_answered( $request( alltfo_sign_challenge( 7, 12, gmdate( 'YmdH', time() - HOUR_IN_SECONDS ) ) ) ), 'A form rendered just before the hour rolled over must still submit.' ); $this->assertFalse( - atf_challenge_answered( $request( atf_sign_challenge( 7, 12, gmdate( 'YmdH', time() - 2 * HOUR_IN_SECONDS ) ) ) ), + alltfo_challenge_answered( $request( alltfo_sign_challenge( 7, 12, gmdate( 'YmdH', time() - 2 * HOUR_IN_SECONDS ) ) ) ), 'A signature from two hours ago must have expired.' ); } @@ -423,12 +423,12 @@ public function test_challenge_signature_expires() { /** * A challenge signature cannot be replayed on another form. * - * @covers ::atf_sign_challenge + * @covers ::alltfo_sign_challenge */ public function test_challenge_signature_is_per_form() { $this->assertNotSame( - atf_sign_challenge( 1, 12 ), - atf_sign_challenge( 2, 12 ), + alltfo_sign_challenge( 1, 12 ), + alltfo_sign_challenge( 2, 12 ), 'A signature valid on one form must not be valid on another.' ); } @@ -439,10 +439,10 @@ public function test_challenge_signature_is_per_form() { * A challenge whose expected answer travels alongside the question is * decoration. * - * @covers ::atf_render_challenge + * @covers ::alltfo_render_challenge */ public function test_challenge_does_not_leak_its_answer() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -456,10 +456,10 @@ public function test_challenge_does_not_leak_its_answer() { ) ); - $html = atf_render_form( $form_id ); + $html = alltfo_render_form( $form_id ); - $this->assertStringContainsString( 'atf_challenge', $html ); - $this->assertStringContainsString( 'atf_challenge_sig', $html ); + $this->assertStringContainsString( 'alltfo_challenge', $html ); + $this->assertStringContainsString( 'alltfo_challenge_sig', $html ); // The question is "What is A plus B?"; the answer must appear nowhere in // the markup as a value. @@ -483,14 +483,14 @@ public function test_challenge_does_not_leak_its_answer() { * * A closed form that still accepts a POST is a form that is not closed. * - * @covers ::atf_form_availability + * @covers ::alltfo_form_availability */ public function test_a_closed_form_refuses_a_post() { // A user who cannot edit forms, because anyone who can is deliberately // never locked out by a schedule. wp_set_current_user( self::factory()->user->create( array( 'role' => 'subscriber' ) ) ); - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -509,13 +509,13 @@ public function test_a_closed_form_refuses_a_post() { $issued = time() - 30; - $result = atf_process_submission( + $result = alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), 'atf' => array( 'f1' => 'Too late' ), ) ); @@ -528,12 +528,12 @@ public function test_a_closed_form_refuses_a_post() { /** * A login-only form refuses a logged-out visitor. * - * @covers ::atf_form_availability + * @covers ::alltfo_form_availability */ public function test_login_required() { wp_set_current_user( 0 ); - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -545,7 +545,7 @@ public function test_login_required() { ) ); - $availability = atf_form_availability( $form_id ); + $availability = alltfo_form_availability( $form_id ); $this->assertFalse( $availability['open'] ); $this->assertSame( 'login', $availability['reason'] ); @@ -558,12 +558,12 @@ public function test_login_required() { * holds no role at all -- logging out must not be the way past the role * gate. * - * @covers ::atf_form_availability + * @covers ::alltfo_form_availability */ public function test_role_restriction_closes_the_form_to_logged_out_visitors() { wp_set_current_user( 0 ); - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -575,7 +575,7 @@ public function test_role_restriction_closes_the_form_to_logged_out_visitors() { ) ); - $availability = atf_form_availability( $form_id ); + $availability = alltfo_form_availability( $form_id ); $this->assertFalse( $availability['open'] ); $this->assertSame( 'role', $availability['reason'] ); @@ -584,7 +584,7 @@ public function test_role_restriction_closes_the_form_to_logged_out_visitors() { // holds the role gets through. wp_set_current_user( self::factory()->user->create( array( 'role' => 'editor' ) ) ); - $this->assertTrue( atf_form_availability( $form_id )['open'] ); + $this->assertTrue( alltfo_form_availability( $form_id )['open'] ); } /** @@ -593,13 +593,13 @@ public function test_role_restriction_closes_the_form_to_logged_out_visitors() { * They are the person who needs to test the form, and a closed notice with * no way past it is how a scheduling bug survives to launch day. * - * @covers ::atf_form_availability + * @covers ::alltfo_form_availability */ public function test_editors_can_always_reach_a_closed_form() { wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) ); - atf_add_capabilities(); + alltfo_add_capabilities(); - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'settings' => array( 'schedule' => array( 'end' => gmdate( 'Y-m-d H:i:s', time() - DAY_IN_SECONDS ) ), @@ -607,18 +607,18 @@ public function test_editors_can_always_reach_a_closed_form() { ) ); - $this->assertTrue( atf_form_availability( $form_id )['open'] ); + $this->assertTrue( alltfo_form_availability( $form_id )['open'] ); } /** * A submission limit closes the form once it is reached. * - * @covers ::atf_form_availability + * @covers ::alltfo_form_availability */ public function test_total_submission_limit() { wp_set_current_user( self::factory()->user->create( array( 'role' => 'subscriber' ) ) ); - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -638,13 +638,13 @@ public function test_total_submission_limit() { $send = function () use ( $form_id ) { $issued = time() - 30; - return atf_process_submission( + return alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), 'atf' => array( 'f1' => 'Someone' ), ) ); @@ -692,7 +692,7 @@ private function allow_cli_uploads() { require_once ABSPATH . 'wp-admin/includes/file.php'; add_filter( - 'atf_upload_overrides', + 'alltfo_upload_overrides', static function ( $overrides ) { $overrides['action'] = 'wp_handle_sideload'; @@ -708,13 +708,13 @@ static function ( $overrides ) { * a submission too -- so a refused submission has to delete them, or every * failed attempt leaves an orphan on disk forever. * - * @covers ::atf_process_submission - * @covers ::atf_delete_upload_attachments + * @covers ::alltfo_process_submission + * @covers ::alltfo_delete_upload_attachments */ public function test_a_submission_that_fails_validation_deletes_its_uploads() { $this->allow_cli_uploads(); - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -736,7 +736,7 @@ public function test_a_submission_that_fails_validation_deletes_its_uploads() { $uploaded = 0; add_action( - 'atf_file_uploaded', + 'alltfo_file_uploaded', static function ( $attachment_id ) use ( &$uploaded ) { $uploaded = $attachment_id; } @@ -746,16 +746,16 @@ static function ( $attachment_id ) use ( &$uploaded ) { // The required text field is empty, so validation refuses the // submission after the upload has already been stored. - $result = atf_process_submission( + $result = alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), 'atf' => array( 'f1' => '' ), ), - array( 'atf_file_f9' => $this->fake_upload( 'notes.txt', 'Plain text.' ) ) + array( 'alltfo_file_f9' => $this->fake_upload( 'notes.txt', 'Plain text.' ) ) ); $this->assertFalse( $result['success'] ); @@ -770,13 +770,13 @@ static function ( $attachment_id ) use ( &$uploaded ) { * The whole submission fails, so the attachments the successful field * already created must not stay behind. * - * @covers ::atf_process_submission - * @covers ::atf_delete_upload_attachments + * @covers ::alltfo_process_submission + * @covers ::alltfo_delete_upload_attachments */ public function test_an_upload_error_deletes_the_other_fields_uploads() { $this->allow_cli_uploads(); - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -797,7 +797,7 @@ public function test_an_upload_error_deletes_the_other_fields_uploads() { $uploaded = 0; add_action( - 'atf_file_uploaded', + 'alltfo_file_uploaded', static function ( $attachment_id ) use ( &$uploaded ) { $uploaded = $attachment_id; } @@ -807,18 +807,18 @@ static function ( $attachment_id ) use ( &$uploaded ) { // The second field's file wears a forbidden extension, so it is refused // before it touches disk -- after the first field's file was stored. - $result = atf_process_submission( + $result = alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), 'atf' => array(), ), array( - 'atf_file_ok' => $this->fake_upload( 'notes.txt', 'Plain text.' ), - 'atf_file_bad' => $this->fake_upload( 'evil.php', ' $this->fake_upload( 'notes.txt', 'Plain text.' ), + 'alltfo_file_bad' => $this->fake_upload( 'evil.php', ' array( array( @@ -852,13 +852,13 @@ public function test_storage_can_be_off() { $issued = time() - 30; - $result = atf_process_submission( + $result = alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), 'atf' => array( 'f1' => 'Not kept' ), ) ); @@ -870,10 +870,10 @@ public function test_storage_can_be_off() { /** * A password is never written into an entry. * - * @covers ::atf_store_entry + * @covers ::alltfo_store_entry */ public function test_passwords_are_never_stored() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -890,13 +890,13 @@ public function test_passwords_are_never_stored() { $issued = time() - 30; - $result = atf_process_submission( + $result = alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), 'atf' => array( 'u' => 'ada', 'p' => 'correct horse battery staple', @@ -904,22 +904,22 @@ public function test_passwords_are_never_stored() { ) ); - $stored = get_post_meta( $result['entry_id'], ATF_META_VALUES, true ); + $stored = get_post_meta( $result['entry_id'], ALLTFO_META_VALUES, true ); $this->assertStringNotContainsString( 'correct horse battery staple', $stored ); $this->assertArrayNotHasKey( 'p', json_decode( $stored, true ) ); } /** - * `atf_entry_created` fires with the entry and the values. + * `alltfo_entry_created` fires with the entry and the values. * - * @covers ::atf_process_submission + * @covers ::alltfo_process_submission */ public function test_entry_created_action_fires() { $seen = array(); add_action( - 'atf_entry_created', + 'alltfo_entry_created', static function ( $entry_id, $form_id, $values ) use ( &$seen ) { $seen = compact( 'entry_id', 'form_id', 'values' ); }, @@ -927,7 +927,7 @@ static function ( $entry_id, $form_id, $values ) use ( &$seen ) { 3 ); - $result = atf_process_submission( $this->form_id, $this->request( array( 'f1' => 'Hooked' ) ) ); + $result = alltfo_process_submission( $this->form_id, $this->request( array( 'f1' => 'Hooked' ) ) ); $this->assertSame( $result['entry_id'], $seen['entry_id'] ); $this->assertSame( $this->form_id, $seen['form_id'] ); @@ -937,10 +937,10 @@ static function ( $entry_id, $form_id, $values ) use ( &$seen ) { /** * A confirmation is resolved and returned. * - * @covers ::atf_resolve_confirmation + * @covers ::alltfo_resolve_confirmation */ public function test_default_confirmation() { - $result = atf_process_submission( $this->form_id, $this->request( array( 'f1' => 'Ada' ) ) ); + $result = alltfo_process_submission( $this->form_id, $this->request( array( 'f1' => 'Ada' ) ) ); $this->assertSame( 'message', $result['confirmation']['type'] ); $this->assertStringContainsString( 'Thank you', $result['confirmation']['message'] ); @@ -954,11 +954,11 @@ public function test_default_confirmation() { * outside. `rawurlencode()` on one is a fatal on PHP 8; the array is * dropped and the rest of the query survives. * - * @covers ::atf_confirmation_url + * @covers ::alltfo_confirmation_url */ public function test_confirmation_query_drops_nested_values() { $confirmation = array_merge( - atf_default_confirmation(), + alltfo_default_confirmation(), array( 'type' => 'redirect', 'url' => 'https://example.com/thanks', @@ -966,7 +966,7 @@ public function test_confirmation_query_drops_nested_values() { ) ); - $url = atf_confirmation_url( $confirmation, array() ); + $url = alltfo_confirmation_url( $confirmation, array() ); $this->assertStringContainsString( 'plain=ok', $url ); $this->assertStringNotContainsString( 'nested', $url, 'A nested value has no defensible flattening and is dropped.' ); @@ -975,10 +975,10 @@ public function test_confirmation_query_drops_nested_values() { /** * Conditional confirmations pick the first that matches. * - * @covers ::atf_resolve_confirmation + * @covers ::alltfo_resolve_confirmation */ public function test_conditional_confirmation() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -1026,13 +1026,13 @@ public function test_conditional_confirmation() { $send = function ( $value ) use ( $form_id ) { $issued = time() - 30; - return atf_process_submission( + return alltfo_process_submission( $form_id, array( - 'atf_form_id' => $form_id, - 'atf_nonce' => wp_create_nonce( 'atf_submit_' . $form_id ), - 'atf_t' => $issued, - 'atf_ts' => atf_sign_timestamp( $form_id, $issued ), + 'alltfo_form_id' => $form_id, + 'alltfo_nonce' => wp_create_nonce( 'alltfo_submit_' . $form_id ), + 'alltfo_t' => $issued, + 'alltfo_ts' => alltfo_sign_timestamp( $form_id, $issued ), 'atf' => array( 'why' => $value ), ) ); @@ -1091,12 +1091,12 @@ static function ( $short_circuit, $atts ) use ( $sent ) { /** * A notification is sent, with the answers in it. * - * @covers ::atf_send_notifications + * @covers ::alltfo_send_notifications */ public function test_notification_is_sent() { $sent = $this->capture_mail(); - atf_process_submission( + alltfo_process_submission( $this->form_id, $this->request( array( @@ -1119,15 +1119,15 @@ public function test_notification_is_sent() { /** * Spam never reaches anybody's inbox. * - * @covers ::atf_process_submission + * @covers ::alltfo_process_submission */ public function test_spam_is_not_emailed() { $sent = $this->capture_mail(); $request = $this->request( array( 'f1' => 'Bot' ) ); - $request['atf_website'] = 'https://spam.example'; + $request['alltfo_website'] = 'https://spam.example'; - atf_process_submission( $this->form_id, $request ); + alltfo_process_submission( $this->form_id, $request ); // Captured through `pre_wp_mail` rather than read off the mock mailer, // so this asserts that nothing was *attempted* — in an environment where @@ -1139,29 +1139,29 @@ public function test_spam_is_not_emailed() { /** * Analytics count a submission but not a builder's own preview. * - * @covers ::atf_record_submission + * @covers ::alltfo_record_submission */ public function test_submission_is_counted() { - $before = atf_get_stats( $this->form_id )['submissions']; + $before = alltfo_get_stats( $this->form_id )['submissions']; - atf_process_submission( $this->form_id, $this->request( array( 'f1' => 'Counted' ) ) ); + alltfo_process_submission( $this->form_id, $this->request( array( 'f1' => 'Counted' ) ) ); - $this->assertSame( $before + 1, atf_get_stats( $this->form_id )['submissions'] ); + $this->assertSame( $before + 1, alltfo_get_stats( $this->form_id )['submissions'] ); } /** * A preview runs the whole pipeline and stores nothing. * - * @covers ::atf_process_submission + * @covers ::alltfo_process_submission */ public function test_preview_stores_nothing() { wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) ); - atf_add_capabilities(); + alltfo_add_capabilities(); $request = $this->request( array( 'f1' => 'Previewing' ) ); - $request['atf_preview'] = '1'; + $request['alltfo_preview'] = '1'; - $result = atf_process_submission( $this->form_id, $request ); + $result = alltfo_process_submission( $this->form_id, $request ); $this->assertTrue( $result['success'] ); $this->assertSame( 0, $result['entry_id'] ); @@ -1171,16 +1171,16 @@ public function test_preview_stores_nothing() { /** * A preview still validates, so what it shows is what a visitor would get. * - * @covers ::atf_process_submission + * @covers ::alltfo_process_submission */ public function test_preview_still_validates() { wp_set_current_user( self::factory()->user->create( array( 'role' => 'administrator' ) ) ); - atf_add_capabilities(); + alltfo_add_capabilities(); $request = $this->request( array( 'f1' => '' ) ); - $request['atf_preview'] = '1'; + $request['alltfo_preview'] = '1'; - $result = atf_process_submission( $this->form_id, $request ); + $result = alltfo_process_submission( $this->form_id, $request ); $this->assertFalse( $result['success'] ); $this->assertArrayHasKey( 'f1', $result['errors'] ); diff --git a/tests/phpunit/tests/successScreen.php b/tests/phpunit/tests/successScreen.php index 17cd335..563e500 100644 --- a/tests/phpunit/tests/successScreen.php +++ b/tests/phpunit/tests/successScreen.php @@ -17,15 +17,15 @@ * * @group allterrain-forms */ -class ATF_Test_Success_Screen extends WP_UnitTestCase { +class ALLTFO_Test_Success_Screen extends WP_UnitTestCase { /** * The style registry carries the promised presets. * - * @covers ::atf_success_styles + * @covers ::alltfo_success_styles */ public function test_the_styles_ship() { - $styles = atf_success_styles(); + $styles = alltfo_success_styles(); foreach ( array( 'plain', 'simple', 'minimal', 'card', 'check', 'confetti', 'fireworks', 'sparkles', 'typewriter' ) as $key ) { $this->assertArrayHasKey( $key, $styles ); @@ -36,8 +36,8 @@ public function test_the_styles_ship() { /** * The registry is filterable, and a filtered-in style survives normalisation. * - * @covers ::atf_success_styles - * @covers ::atf_normalize_success_screen + * @covers ::alltfo_success_styles + * @covers ::alltfo_normalize_success_screen */ public function test_a_plugin_can_register_a_style() { $add = static function ( $styles ) { @@ -50,28 +50,28 @@ public function test_a_plugin_can_register_a_style() { return $styles; }; - add_filter( 'atf_success_styles', $add ); + add_filter( 'alltfo_success_styles', $add ); - $success = atf_normalize_success_screen( array( 'style' => 'disco' ) ); + $success = alltfo_normalize_success_screen( array( 'style' => 'disco' ) ); $this->assertSame( 'disco', $success['style'] ); - remove_filter( 'atf_success_styles', $add ); + remove_filter( 'alltfo_success_styles', $add ); } /** * Normalisation fills every knob and refuses what it does not know. * - * @covers ::atf_normalize_success_screen + * @covers ::alltfo_normalize_success_screen */ public function test_normalisation_is_complete_and_suspicious() { - $defaults = atf_normalize_success_screen( array() ); + $defaults = alltfo_normalize_success_screen( array() ); $this->assertSame( 'simple', $defaults['style'] ); $this->assertSame( 'medium', $defaults['intensity'] ); $this->assertFalse( $defaults['showButton'] ); - $mangled = atf_normalize_success_screen( + $mangled = alltfo_normalize_success_screen( array( 'style' => 'raveparty', 'intensity' => 'ludicrous', @@ -92,11 +92,11 @@ public function test_normalisation_is_complete_and_suspicious() { * A confirmation stores its screen, and the resolver hands it out with * merge tags replaced. * - * @covers ::atf_resolve_confirmation - * @covers ::atf_resolve_success_screen + * @covers ::alltfo_resolve_confirmation + * @covers ::alltfo_resolve_success_screen */ public function test_the_resolved_confirmation_carries_the_screen() { - $form_id = atf_test_form( + $form_id = alltfo_test_form( array( 'fields' => array( array( @@ -119,8 +119,8 @@ public function test_the_resolved_confirmation_carries_the_screen() { ) ); - $schema = atf_get_form_schema( $form_id ); - $resolved = atf_resolve_confirmation( $schema, array( 'f1' => 'Ada' ), 0, $form_id ); + $schema = alltfo_get_form_schema( $form_id ); + $resolved = alltfo_resolve_confirmation( $schema, array( 'f1' => 'Ada' ), 0, $form_id ); $this->assertSame( 'confetti', $resolved['success']['style'] ); $this->assertSame( 'Nice one, Ada!', $resolved['success']['title'] ); @@ -129,13 +129,13 @@ public function test_the_resolved_confirmation_carries_the_screen() { /** * A form with no confirmations still resolves a complete screen. * - * @covers ::atf_resolve_confirmation - * @covers ::atf_default_confirmation + * @covers ::alltfo_resolve_confirmation + * @covers ::alltfo_default_confirmation */ public function test_the_default_confirmation_has_a_screen() { - $form_id = atf_test_form(); - $schema = atf_get_form_schema( $form_id ); - $resolved = atf_resolve_confirmation( $schema, array(), 0, $form_id ); + $form_id = alltfo_test_form(); + $schema = alltfo_get_form_schema( $form_id ); + $resolved = alltfo_resolve_confirmation( $schema, array(), 0, $form_id ); $this->assertSame( 'simple', $resolved['success']['style'] ); } @@ -143,10 +143,10 @@ public function test_the_default_confirmation_has_a_screen() { /** * The static render: same classes the bundle builds, style on the root. * - * @covers ::atf_success_screen_html + * @covers ::alltfo_success_screen_html */ public function test_static_markup_matches_the_bundle_contract() { - $html = atf_success_screen_html( + $html = alltfo_success_screen_html( '

Saved.

', array( 'style' => 'card', @@ -165,10 +165,10 @@ public function test_static_markup_matches_the_bundle_contract() { /** * Plain is exactly the old confirmation, untouched. * - * @covers ::atf_success_screen_html + * @covers ::alltfo_success_screen_html */ public function test_plain_is_the_old_markup() { - $html = atf_success_screen_html( '

Done.

', array( 'style' => 'plain' ) ); + $html = alltfo_success_screen_html( '

Done.

', array( 'style' => 'plain' ) ); $this->assertStringNotContainsString( 'atf-success', $html ); $this->assertSame( '

Done.

', $html ); @@ -178,10 +178,10 @@ public function test_plain_is_the_old_markup() { * The check style draws its SVG; the accent rides as a custom property; * hostile markup in the message is filtered on the way out. * - * @covers ::atf_success_screen_html + * @covers ::alltfo_success_screen_html */ public function test_the_render_is_styled_and_safe() { - $html = atf_success_screen_html( + $html = alltfo_success_screen_html( 'Fine. ', array( 'style' => 'check', @@ -198,10 +198,10 @@ public function test_the_render_is_styled_and_safe() { * The again-button renders as a link — the one reset that works without * the bundle. * - * @covers ::atf_success_screen_html + * @covers ::alltfo_success_screen_html */ public function test_the_again_button_is_a_link() { - $html = atf_success_screen_html( + $html = alltfo_success_screen_html( 'Done.', array( 'style' => 'simple', diff --git a/tests/phpunit/tests/themes.php b/tests/phpunit/tests/themes.php index 7d02091..833e51a 100644 --- a/tests/phpunit/tests/themes.php +++ b/tests/phpunit/tests/themes.php @@ -8,10 +8,10 @@ * control that does nothing; a CSS custom property no token declares is a value * no theme can reach. Both directions are asserted against the real stylesheet. * - * **A theme cannot inject CSS.** Token values land inside a `
%s