Plugin Directory

Changeset 3339262


Ignore:
Timestamp:
08/04/2025 08:46:57 PM (7 months ago)
Author:
fullworks
Message:

Release version 4.11

Location:
clean-and-simple-contact-form-by-meg-nicholas
Files:
6 added
36 edited
1 copied

Legend:

Unmodified
Added
Removed
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/ajax.php

    r2551686 r3339262  
    1414    if ( $result['valid'] ) {
    1515        $result['sent'] = $contact->SendMail();
     16       
     17        // Action hook for AJAX form submission
     18        if ( $result['sent'] ) {
     19            do_action( 'cscf_form_submitted_ajax', $contact );
     20        }
    1621    }
    1722
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/changelog.txt

    r3146820 r3339262  
     1= 4.11 =
     2* Added REST API support for headless WordPress implementations
     3  - New endpoint at /wp-json/cscf/v1/submit with authentication
     4  - Configurable user capability requirements
     5  - Full form validation (excluding reCAPTCHA for authenticated requests)
     6* Added SMTP configuration via wp-config constants
     7  - Support for all major email services (Gmail, SendGrid, Mailgun, etc.)
     8  - Useful for development with tools like Mailpit
     9  - No UI needed - server-level configuration
     10* Added developer hooks for extensibility
     11  - Action hooks: cscf_before_send_email, cscf_after_send_email, cscf_form_submitted (plus type-specific variants)
     12  - Filter hook: cscf_form_data for REST API data modification
     13* Added comprehensive developer documentation
     14  - Hooks and filters guide with examples
     15  - REST API implementation guide
     16  - SMTP configuration guide
     17* Improved extensibility for third-party integrations (CRMs, webhooks, mailing lists)
     18* Improved phone number validation
     19  - Now validates format (only allows digits, +, (), -, and spaces)
     20  - Format validation applies even when phone field is optional
     21  - Fixed bug where phone validation error used wrong error key
     22* Improved form validation user experience
     23  - reCAPTCHA validation now skipped if other form errors exist
     24  - Prevents users from being blocked by reCAPTCHA when fixing validation errors
     25* Fixed JavaScript bugs
     26  - Fixed server-side validation errors not displaying when using AJAX submission
     27  - Fixed jQuery selector looking for div instead of span elements for error display
     28  - Fixed deprecated jQuery .selector usage for jQuery 3.0+ compatibility
     29* Added comprehensive unit tests for form validation
     30* Removed deprecated load_plugin_textdomain() function - WordPress handles translations automatically since v4.6
     31
     32= 4.10 =
     33* Added opt in
     34* Added code to comply with current plugin guidelines
     35
    136= 4.9.1 =
    2 * corrected link markup in settings pag
     37* corrected link markup in settings page
    338
    439= 4.9 =
     
    4580
    4681= 4.7.1 =
    47 * Tested with Wordpress version 5.3
     82* Tested with WordPress version 5.3
    4883Fixed XSS vulnerability in GDPR consent message
    4984= 4.7.0 =
    50 * Tested with Wordpress version 4.9.6
     85* Tested with WordPress version 4.9.6
    5186* Added consent to contact checkbox for GDPR compliance
    5287= 4.6.2 =
     
    167202= 4.1.2 =
    168203* Added some FAQs
    169 * Added alternative shortcode [cscf-contact-form] for use when conflicts could occur.
    170 * Updated the documentation.
    171 * Recaptcha form now responds to language changes
    172 * Updated pot file to reflect new name space
    173 * Changed name space from cff to cscf
    174 * Settings screen: recaptcha theme and key inputs are immediately enabled/disabled as the 'Use reCAPTCHA' box is clicked.
    175 * Corrected some html seen as invalid by http://validator.w3.org/
    176 * removed '<?=' and replaced with '<?php echo' in cscf_settings, thanks go to andrewbacon
    177 * Added notice to setting screen when JetPack's contact form is active
    178 * Fixed problem where 'Please enter a valid email address' was not translating in the 'confirm email address' input
    179 = 4.1.1 =
    180 * Fixed potential conflicts with themes that use bootstrap
    181 * Enabled internationalisation, this plugin will now work with multiple languages
    182 * Added German translation file for my German friends, thanks to faktorzweinet for the translation
    183 = 4.1.0 =
    184 * Fixed a bug in class.cff_settings.php where php opening tag had got missed off. This problem caused the settings screen not to display correctly but only occurred with some versions of php. Please upgrade if you have this problem.
    185 = 4.0.9 =
    186 * Switched header argument of wp_mail over to a filter to remove any potential conflicts with other emailing plugins or themes
    187 * The ability to set a different recipient email address. Previously all email was sent to the WordPress administrator email address.
    188 * Allow the email subject to be customised.
    189 = 4.0.8 =
    190 * Fixed a bug: When using reCAPTCHA ajax did not work.
    191 * Fixed a bug: Ajax validation was not checking email address were equal (server side was doing it instead)
    192 * Improvement: Ajax now works better.
    193 * Documentation update: nicer links (worked how to do them in markdown!), changelog and upgrade notice sections now correctly formatted.
    194 = 4.0.7 =
    195 * Fixed a bug: Plugin name is actually clean-and-simple-contact-form now (not contact-form) but this new name needed to be updated in the plugin settings definitions. I also needed to rename contact-form.php to clean-and-simple-contact-form.php. My thanks to Jakub for finding this bug.
    196 * If your webpage is ssl then reCAPTCHA will now also use ssl mode.
    197 
    198 
    199 == Upgrade Notice ==
    200 = 4.7.0 =
    201 Tested with Wordpress version 4.9.6. Added 'consent to contact' GDPR compliance message
    202 = 4.6.2 =
    203 Updated translations. Tested up to WordPress 4.6.1.
    204 = 4.6.0 =
    205 Updated translations. Correct textdomain. Prevent multiple clicks.
    206 = 4.5.1 =
    207 Translation updates
    208 = 4.5.0 =
    209 Added support for Google Recaptcha2. Updated translation. Fixed layout bug.
    210 = 4.4.4 =
    211 Added languages, css fix for twenty fifteen theme, remove 'notice' errors, remove empty divs
    212 = 4.4.3 =
    213 Tested up to 4.1
    214 = 4.4.2 =
    215 Akismet tweak and translation updates
    216 = 4.4.1 =
    217 Fixed XSS issue
    218 = 4.4.0 =
    219 Added option for enquiry to email themselves a copy of the message plus Polish translation updated
    220 = 4.3.4 =
    221 Email now includes page url of contact form, removed link in main contact form view
    222 = 4.3.3 =
    223 Hebrew Language added, name field moved to top of form, added 'reply-to'
    224 = 4.3.2 =
    225 Added Norwegian and Brazilian Portugese Translations
    226 = 4.3.1 =
    227 Checked compatibility with WP 3.8 and TwentyFourteen theme, translation updates, defaults for new installations
    228 = 4.3.0 =
    229 Contact form is now filtered for spam when the Akismet plugin is present.
    230 [Learn more](http://www.megnicholas.co.uk/articles/contact-form-plugin-can-detect-spam/ "Learn More").
    231 = 4.2.5 =
    232 Small bug fix
    233 = 4.2.4 =
    234 'Confirm Email' can now be turned off. Arabic translation added.
    235 = 4.2.3 =
    236 Multiple recipients are now possible
    237 = 4.2.2 =
    238 Remove ALL possibility of conflicts with other plugins that also include Google reCAPTCHA library
    239 = 4.2.1 =
    240 Translation and housekeeping updates
    241 = 4.2.0 =
    242 Translation and documentation updates
    243 = 4.1.9 =
    244 Support for [Bootstrap 3](http://www.megnicholas.co.uk/articles/version-4-1-9-supports-bootstrap-3/ "More information on 4.1.9")
    245 = 4.1.8 =
    246 Added Russian translation and some modifications to Estonian and Spanish translations
    247 = 4.1.7
    248 More translations. A helpful note about the short code to use has been put on the settings screen
    249 = 4.1.6 =
    250 Ability to specify a 'From' address. This email will be used to send the mail instead of the form filler's email address.
    251 = 4.1.5 =
    252 Works with themes that pre-process the html.
    253 = 4.1.4 =
    254 New translations - Slovak and Catalan
    255 = 4.1.3 =
    256 Form now submits via ajax!
    257 = 4.1.2 =
    258 Alternative shortcode, recaptcha internationalisation, Jetpack conflict warning notice
    259 = 4.1.1 =
    260 Internationalisation, fixed conflict with some bootstrapped themes.
    261 = 4.1.0 =
    262 Please upgrade if your settings screen is not displaying.
    263 = 4.0.9 =
    264 More customisation: recipient email address, and email subject.
    265 = 4.0.8 =
    266 Ajax now works when your form has reCAPTCHA on it. Ajax validation is now cleaner.
    267 = 4.0.7 =
    268 Fixed a bug which occurred when plugin name was changed. reCAPTCHA will now use ssl if your webpage is ssl.
     204* Added alternative shortcode
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/class.cscf.php

    r3254319 r3339262  
    2121            $this,
    2222            'RegisterAdminStyles',
    23         ) );
    24 
    25         add_action( 'init', array(
    26             $this,
    27             'RegisterTextDomain',
    2823        ) );
    2924
     
    4439        //create the settings page
    4540        $settings = new cscf_settings();
    46     }
    47 
    48 
    49     function RegisterTextDomain() {
    50         //$path = CSCF_PLUGIN_DIR . '/languages';
    51         $path = '/' . CSCF_PLUGIN_NAME . '/languages';
    52         load_plugin_textdomain( 'clean-and-simple-contact-form-by-meg-nicholas', false, $path );
    5341    }
    5442
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/class.cscf_contact.php

    r3254319 r3339262  
    1919    var $PostID;
    2020    var $IsSpam;
     21    var $IsRestApi = false;
    2122
    2223    function __construct() {
     
    2829        }
    2930        $request_method = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD']??'' ) );
    30         if ( $request_method === 'POST' ) {
     31        if ( $request_method === 'POST' && ! $this->IsRestApi ) {
    3132            // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- No action, nonce is not required for $_POST['cscf_nonce'] check later, array sanitized
    3233            if ( isset( $_POST['cscf'] ) ) {
     
    7374    }
    7475
     76    /**
     77     * Set contact data from array (used by REST API)
     78     *
     79     * @param array $data Contact form data
     80     * @param int $post_id Post ID where form was submitted from
     81     * @param bool $is_rest_api Whether this is a REST API request
     82     */
     83    public function set_from_array( $data, $post_id = null, $is_rest_api = false ) {
     84        $this->IsRestApi = $is_rest_api;
     85       
     86        // Filter to allow modification of form data before processing
     87        $data = apply_filters( 'cscf_form_data', $data, $post_id, $is_rest_api );
     88       
     89        if ( isset( $data['name'] ) ) {
     90            $this->Name = sanitize_text_field( $data['name'] );
     91        }
     92        if ( isset( $data['email'] ) ) {
     93            $this->Email = sanitize_email( $data['email'] );
     94        }
     95        if ( isset( $data['confirm-email'] ) ) {
     96            $this->ConfirmEmail = sanitize_email( $data['confirm-email'] );
     97        }
     98        if ( isset( $data['email-sender'] ) ) {
     99            $this->EmailToSender = $data['email-sender'] ? true : false;
     100        }
     101        if ( isset( $data['message'] ) ) {
     102            $this->Message = sanitize_textarea_field( $data['message'] );
     103        }
     104        if ( isset( $data['phone-number'] ) ) {
     105            $this->PhoneNumber = sanitize_text_field( $data['phone-number'] );
     106        }
     107        if ( isset( $data['contact-consent'] ) ) {
     108            $this->ContactConsent = $data['contact-consent'] ? true : false;
     109        }
     110        if ( $post_id !== null ) {
     111            $this->PostID = absint( $post_id );
     112        }
     113    }
     114
    75115    public function IsValid() {
    76116        $this->Errors = array();
    77117        $request_method = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD']??'' ) );
    78         if ( $request_method !== 'POST' ) {
     118        if ( $request_method !== 'POST' && ! $this->IsRestApi ) {
    79119            return false;
    80120        }
    81121
    82         //check nonce
    83         // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- No action, not stored just a nonce check
    84         if ( ! wp_verify_nonce( $_POST['cscf_nonce'] ?? '', 'cscf_contact' ) ) {
    85             return false;
     122        //check nonce (skip for REST API as it uses WordPress authentication)
     123        if ( ! $this->IsRestApi ) {
     124            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- No action, not stored just a nonce check
     125            if ( ! wp_verify_nonce( $_POST['cscf_nonce'] ?? '', 'cscf_contact' ) ) {
     126                return false;
     127            }
    86128        }
    87129
     
    120162        }
    121163
    122         //mandatory phone number
    123         if ( cscf_PluginSettings::PhoneNumber() && cscf_PluginSettings::PhoneNumberMandatory() ) {
    124             if ( strlen( $this->PhoneNumber ) < 8 ) {
    125                 $this->Errors['confirm-email'] = esc_html__( 'Please enter a valid phone number.', 'clean-and-simple-contact-form-by-meg-nicholas' );
    126             }
     164        //phone number validation
     165        if ( cscf_PluginSettings::PhoneNumber() && strlen( $this->PhoneNumber ) > 0 ) {
     166            // Validate format - only allow digits, +, (), -, and spaces
     167            if ( ! preg_match( '/^[0-9\+\(\)\-\s]+$/', $this->PhoneNumber ) ) {
     168                $this->Errors['phone-number'] = esc_html__( 'Phone number can only contain numbers, +, (), - and spaces.', 'clean-and-simple-contact-form-by-meg-nicholas' );
     169            }
     170            // Check length for mandatory fields
     171            elseif ( cscf_PluginSettings::PhoneNumberMandatory() && strlen( $this->PhoneNumber ) < 8 ) {
     172                $this->Errors['phone-number'] = esc_html__( 'Please enter a valid phone number (minimum 8 characters).', 'clean-and-simple-contact-form-by-meg-nicholas' );
     173            }
     174        }
     175        // Check if phone is mandatory but not provided
     176        elseif ( cscf_PluginSettings::PhoneNumber() && cscf_PluginSettings::PhoneNumberMandatory() && strlen( $this->PhoneNumber ) == 0 ) {
     177            $this->Errors['phone-number'] = esc_html__( 'Please enter your phone number.', 'clean-and-simple-contact-form-by-meg-nicholas' );
    127178        }
    128179
     
    134185        }
    135186
    136         //check recaptcha but only if we have keys
    137         if ( $this->RecaptchaPublicKey <> '' && $this->RecaptchaPrivateKey <> '' ) {
     187        //check recaptcha but only if we have keys, not REST API, and no other validation errors
     188        //This prevents reCAPTCHA from blocking users who need to fix other form errors
     189        if ( $this->RecaptchaPublicKey <> '' && $this->RecaptchaPrivateKey <> '' && ! $this->IsRestApi && count( $this->Errors ) == 0 ) {
    138190            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- No action, no form fields are being saved
    139191            $resp = csf_RecaptchaV2::VerifyResponse( sanitize_text_field($_SERVER["REMOTE_ADDR"]??''), $this->RecaptchaPrivateKey, sanitize_text_field($_POST["g-recaptcha-response"]??''));
     
    153205            return true;
    154206        }
     207
     208        // Action hook before sending email
     209        do_action( 'cscf_before_send_email', $this );
    155210
    156211        $filters = new cscf_Filters;
     
    194249        $filters->remove( 'wp_mail_from_name' );
    195250
     251        // Action hook after sending email
     252        do_action( 'cscf_after_send_email', $this, $result );
     253
    196254        //send an email to the form-filler
    197255        if ( $this->EmailToSender ) {
     
    228286        }
    229287
     288        // Action hook for successful form submission
     289        if ( $result ) {
     290            do_action( 'cscf_form_submitted', $this );
     291        }
     292
    230293        return $result;
    231294    }
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/class.cscf_pluginsettings.php

    r2561035 r3339262  
    193193        return isset($options['confirm-email']) ? true : false;
    194194    }
     195
     196    static function RestApiEnabled()
     197    {
     198        $options = get_option(CSCF_OPTIONS_KEY);
     199        return isset($options['enable_rest_api']) ? true : false;
     200    }
     201
     202    static function RestApiCapability()
     203    {
     204        $options = get_option(CSCF_OPTIONS_KEY);
     205        return isset($options['rest_api_capability']) ? $options['rest_api_capability'] : 'edit_posts';
     206    }
    195207}
    196208
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/class.cscf_settings.php

    r3254319 r3339262  
    215215            'recaptcha_private_key',
    216216            'class' => 'recaptcha-field',
     217        ) );
     218       
     219        // REST API Settings
     220        add_settings_section(
     221            'section_rest_api',
     222            '<h3>' . esc_html__( 'REST API Settings', 'clean-and-simple-contact-form-by-meg-nicholas' ) . '</h3>',
     223            array(
     224                $this,
     225                'print_section_info_rest_api',
     226            ),
     227            'contact-form-settings'
     228        );
     229        add_settings_field( 'enable_rest_api', esc_html__( 'Enable REST API :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
     230            $this,
     231            'create_fields',
     232        ), 'contact-form-settings', 'section_rest_api', array(
     233            'enable_rest_api',
     234        ) );
     235        add_settings_field( 'rest_api_capability', esc_html__( 'Required User Capability :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
     236            $this,
     237            'create_fields',
     238        ), 'contact-form-settings', 'section_rest_api', array(
     239            'rest_api_capability',
    217240        ) );
    218241    }
     
    317340        }
    318341
     342        // REST API settings
     343        if ( isset( $input['rest_api_capability'] ) ) {
     344            $input['rest_api_capability'] = sanitize_text_field( $input['rest_api_capability'] );
     345            // Validate capability exists
     346            if ( empty( $input['rest_api_capability'] ) ) {
     347                $input['rest_api_capability'] = 'edit_posts';
     348            }
     349        }
     350
    319351        //tidy up the keys
    320352        $tidiedRecipients = array();
     
    343375        //print 'Enter your styling settings below:';
    344376
     377    }
     378
     379    public function print_section_info_rest_api() {
     380        echo '<p>';
     381        print esc_html__( 'Enable REST API support for headless WordPress implementations.', 'clean-and-simple-contact-form-by-meg-nicholas' );
     382        echo '</p><p>';
     383        print esc_html__( 'When enabled, authenticated users can submit the form via: POST /wp-json/cscf/v1/submit', 'clean-and-simple-contact-form-by-meg-nicholas' );
     384        echo '</p>';
    345385    }
    346386
     
    516556                               name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[use_client_validation]"><?php
    517557                break;
     558            case 'enable_rest_api':
     559                $checked = cscf_PluginSettings::RestApiEnabled() === true ? 'checked' : '';
     560                ?><label for="enable_rest_api" class="screen-reader-text">
     561                <?php esc_html_e('enable REST API', 'clean-and-simple-contact-form-by-meg-nicholas'); ?>
     562                </label><input type="checkbox" <?php echo esc_attr( $checked ); ?>  id="enable_rest_api"
     563                         name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[enable_rest_api]"><?php
     564                break;
     565            case 'rest_api_capability':
     566                $capability = cscf_PluginSettings::RestApiCapability();
     567                ?><label for="rest_api_capability" class="screen-reader-text">
     568                <?php esc_html_e('REST API required capability', 'clean-and-simple-contact-form-by-meg-nicholas'); ?>
     569                </label><input type="text" size="40" id="rest_api_capability"
     570                         name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[rest_api_capability]"
     571                         value="<?php echo esc_attr( $capability ); ?>" />
     572                <p class="description"><?php esc_html_e( 'Default: edit_posts. Common capabilities: edit_posts, publish_posts, manage_options', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></p><?php
     573                break;
    518574            default:
    519575                break;
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/clean-and-simple-contact-form-by-meg-nicholas.php

    r3254319 r3339262  
    88Plugin URI: https://fullworks.net/products/clean-and-simple-contact-form
    99Description: A clean and simple contact form with Google reCAPTCHA and Twitter Bootstrap markup.
    10 Version: 4.10
     10Version: 4.11
    1111Requires at least: 5.6
    1212Requires PHP: 7.4
     
    5050require 'class.view.php';
    5151require 'class.cscf_filters.php';
     52require 'class.cscf_rest_api.php';
    5253require 'ajax.php';
    5354require 'recaptchav2.php';
     
    7576
    7677if ( ! defined( 'CSCF_VERSION_NUM' ) ) {
    77     define( 'CSCF_VERSION_NUM', '4.10' );
     78    define( 'CSCF_VERSION_NUM', '4.11' );
    7879}
    7980
     
    9192
    9293$cscf = new cscf();
     94$cscf_rest_api = new cscf_rest_api();
     95
     96// Configure SMTP if constants are defined
     97if ( defined( 'CSCF_USE_SMTP' ) && CSCF_USE_SMTP ) {
     98    add_action( 'phpmailer_init', function( $phpmailer ) {
     99        $phpmailer->isSMTP();
     100       
     101        // Required settings
     102        if ( defined( 'CSCF_SMTP_HOST' ) ) {
     103            $phpmailer->Host = CSCF_SMTP_HOST;
     104        }
     105       
     106        if ( defined( 'CSCF_SMTP_PORT' ) ) {
     107            $phpmailer->Port = (int) CSCF_SMTP_PORT;
     108        }
     109       
     110        // Authentication settings
     111        if ( defined( 'CSCF_SMTP_AUTH' ) && CSCF_SMTP_AUTH ) {
     112            $phpmailer->SMTPAuth = true;
     113           
     114            if ( defined( 'CSCF_SMTP_USER' ) ) {
     115                $phpmailer->Username = CSCF_SMTP_USER;
     116            }
     117           
     118            if ( defined( 'CSCF_SMTP_PASS' ) ) {
     119                $phpmailer->Password = CSCF_SMTP_PASS;
     120            }
     121        } else {
     122            $phpmailer->SMTPAuth = false;
     123        }
     124       
     125        // Security settings
     126        if ( defined( 'CSCF_SMTP_SECURE' ) ) {
     127            $phpmailer->SMTPSecure = CSCF_SMTP_SECURE; // 'tls' or 'ssl' or empty string
     128        }
     129       
     130        // Optional: From email override
     131        if ( defined( 'CSCF_SMTP_FROM' ) ) {
     132            $phpmailer->From = CSCF_SMTP_FROM;
     133        }
     134       
     135        // Optional: From name override
     136        if ( defined( 'CSCF_SMTP_FROM_NAME' ) ) {
     137            $phpmailer->FromName = CSCF_SMTP_FROM_NAME;
     138        }
     139       
     140        // Debug mode
     141        if ( defined( 'CSCF_SMTP_DEBUG' ) && CSCF_SMTP_DEBUG ) {
     142            $phpmailer->SMTPDebug = 2;
     143        }
     144    });
     145}
    93146
    94147/*get the current version and update options to the new option*/
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/js/jquery.validate.contact.form.js

    r2551686 r3339262  
    77    $form.find("#recaptcha_response_field").focus(function () {
    88
    9         $errele = $form.find("div[for='cscf_recaptcha']");
     9        $errele = $form.find("span[for='cscf_recaptcha']");
    1010        $errele.html('');
    1111
     
    5656                            jQuery('html,body')
    5757                                .animate({
    58                                     scrollTop: jQuery($div.selector)
    59                                         .offset().top
     58                                    scrollTop: $div.offset().top
    6059                                }, 'slow');
    6160                        }
     
    6362
    6463                    else {
     64                        // Clear any previous errors first
     65                        $form.find("span.help-inline.help-block.error").html('').css('display', 'none');
     66                        $form.find('.form-group').removeClass('has-error').addClass('has-success');
     67                        $form.find('.control-group').removeClass('error').addClass('success');
     68                       
    6569                        $.each(response.errorlist, function (name, value) {
    66                             $errele = $form.find("div[for='cscf_" + name + "']");
    67                             $errele.html(value);
    68                             $errele.closest('.form-group').removeClass('has-success').addClass('has-error');
    69                             $errele.closest('.control-group').removeClass('success').addClass('error'); // support for bootstrap 2
     70                            // Debug logging
     71                            if (window.console) {
     72                                console.log("Error for field: " + name + ", message: " + value);
     73                            }
     74                           
     75                            $errele = $form.find("span[for='cscf_" + name + "']");
     76                            if ($errele.length > 0) {
     77                                $errele.html(value);
     78                                $errele.css('display', 'block');
     79                                $errele.closest('.form-group').removeClass('has-success').addClass('has-error');
     80                                $errele.closest('.control-group').removeClass('success').addClass('error'); // support for bootstrap 2
     81                            } else if (window.console) {
     82                                console.log("Could not find error element for: cscf_" + name);
     83                            }
    7084                        });
    7185                        $button.removeAttr("disabled");
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/languages/clean-and-simple-contact-form-by-meg-nicholas-pl_PL.po

    r3142234 r3339262  
    77"PO-Revision-Date: 2024-08-27 12:26+0100\n"
    88"Last-Translator: \n"
    9 "Language-Team: Kacper Ruciński <kacper.rucinski@gmail.com>\n"
     9"Language-Team: Kacper Ruciński\n"
    1010"Language: pl_PL\n"
    1111"MIME-Version: 1.0\n"
     
    4242#: clean-and-simple-contact-form-by-meg-nicholas/views/contact-form.view.php:34
    4343msgid "Please give your name."
    44 msgstr "Prosimy wpisać imię i nazwisko."
     44msgstr "Prosimy się przedstawić."
    4545
    4646#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:110
    4747msgid "Please enter a message."
    48 msgstr "Prosimy wpisać wiadomość."
     48msgstr "Prosimy wprowadzić wiadomość."
    4949
    5050#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:115,
     
    5252#: clean-and-simple-contact-form-by-meg-nicholas/views/contact-form.view.php:93
    5353msgid "Please enter a valid email address."
    54 msgstr "Prosimy wpisać poprawny adres e-mail."
     54msgstr "Prosimy wprowadzić poprawny adres e-mail."
    5555
    5656#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:121
    5757msgid "Please enter a valid phone number."
    58 msgstr "Pros wprowadzić poprawny numer telefonu."
     58msgstr "Prosimy wprowadzić poprawny numer telefonu."
    5959
    6060#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:128,
     
    6565#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:137
    6666msgid "Please solve the recaptcha to continue."
    67 msgstr "Proszę rozwiązać recaptcha, aby kontynuować."
     67msgstr "Prosimy rozwiązać reCAPTCHA, aby kontynuować."
    6868
    6969#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:170
     
    8282#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:175
    8383msgid "Page URL"
    84 msgstr "Strona URL"
     84msgstr "URL strony"
    8585
    8686#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:176,
     
    129129#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:30
    130130msgid "Contact Form Settings"
    131 msgstr "Ustawienia Contact Form"
     131msgstr "Ustawienia formularza kontaktowego"
    132132
    133133#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:31
    134134msgid "Contact Form"
    135 msgstr "Contact Form"
     135msgstr "Formularz kontaktowy"
    136136
    137137#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:43
    138138msgid "Clean and Simple Contact Form Settings"
    139 msgstr "Ustawienia Clean and Simple Contact Form"
     139msgstr "Ustawienia wtyczki Przejrzysty i prosty formularz kontaktowy"
    140140
    141141#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:52
     
    223223"Use the plugin default stylesheet (un-tick to use your theme style sheet "
    224224"instead) :"
    225 msgstr "Użyj domyślnego stylu wtyczki (odznacz, aby użyć stylów motywu "
     225msgstr "Użyj domyślnego stylu wtyczki (odznacz, aby użyć stylów motywu):"
    226226
    227227#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:168
     
    235235#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:187
    236236msgid "Use reCAPTCHA :"
    237 msgstr "Użyj reCAPTCHA :"
     237msgstr "Użyj reCAPTCHA:"
    238238
    239239#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:194
     
    255255msgstr ""
    256256"Najlepszym sposobem na okazanie uznania dla tej darmowej wtyczki i "
    257 "utrzymanie jej jest wsparcie jej poprzez zainstalowanie Fullworks Anti Spam "
     257"jej utrzymanie jest wsparcie jej poprzez zainstalowanie Fullworks Anti Spam "
    258258"Pro"
    259259
     
    263263"compare it with Akismet, yet extremely effective."
    264264msgstr ""
    265 "Dzięki 14-dniowemu bezpłatnemu okresowi próbnemu jest on zaskakująco "
    266 "przystępny cenowo w porównaniu z Akismet, a jednocześnie niezwykle skuteczny."
     265"Oferując darmowy 14-dniowy okres próbny, jest on zaskakująco przystępny "
     266"cenowo w porównaniu z Akismet, a jednocześnie niezwykle skuteczny."
    267267
    268268#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:226,
     
    273273#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:221
    274274msgid "Congratulations: you are protected by Fullworks Anti Spam"
    275 msgstr "Gratulacje: jesteś chroniony przez Fullworks Anti Spam"
     275msgstr "Gratulacje! Ochronę zapewnia Ci Fullworks Anti Spam"
    276276
    277277#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:222
    278278msgid "Configure"
    279 msgstr "Konfiguracja"
     279msgstr "Skonfiguruj"
    280280
    281281#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:222
     
    291291"With a 14 day free trial, will automatically log all messages from this form."
    292292msgstr ""
    293 "Dzięki 14-dniowemu bezpłatnemu okresowi próbnemu automatycznie rejestruje "
    294 "wszystkie wiadomości z tego formularza."
     293"Oferując darmowy 14-dniowy okres próbny, automatycznie rejestruje wszystkie "
     294"wiadomości z tego formularza."
    295295
    296296#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:243
     
    402402
    403403#~ msgid "Clean and Simple Contact Form!"
    404 #~ msgstr "Clean and Simple Contact Form!"
     404#~ msgstr "Przejrzysty i prosty formularz kontaktowy!"
    405405
    406406#~ msgid "You are using version"
     
    420420
    421421#~ msgid "*New*"
    422 #~ msgstr "*Nowe*"
     422#~ msgstr "*Nowość*"
    423423
    424424#~ msgid "Clean and Simple Contact Form"
    425 #~ msgstr "Czyste i proste Formularz kontaktowy"
     425#~ msgstr "Przejrzysty i prosty formularz kontaktowy"
    426426
    427427#~ msgid ""
     
    436436#~ "Bootstrap markup."
    437437#~ msgstr ""
    438 #~ "Czysty i prosty formularz kontaktowy z Google i Twitter Bootstrap "
    439 #~ "reCAPTCHA znaczników."
     438#~ "Przejrzysty i prosty formularz kontaktowy z Google reCAPTCHA i znacznikami "
     439#~ Twitter Bootstrap."
    440440
    441441#~ msgid "Meghan Nicholas"
     
    446446
    447447#~ msgid "Sorry the code wasn't entered correctly please try again."
    448 #~ msgstr ""
    449 #~ "Przepraszamy, kod nie został wprowadzony poprawnie. Spróbuj ponownie."
     448#~ msgstr "Przepraszamy, kod nie został wprowadzony poprawnie. Spróbuj ponownie."
    450449
    451450#~ msgid "Red"
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/languages/clean-and-simple-contact-form-by-meg-nicholas.pot

    r3254319 r3339262  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Clean and Simple Contact Form 4.10\n"
     5"Project-Id-Version: Contact Form Clean and Simple 4.11\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/clean-and-simple-contact-form-by-meg-nicholas\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2025-03-10T17:28:16+00:00\n"
     12"POT-Creation-Date: 2025-08-04T19:28:59+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.10.0\n"
     
    1717#. Plugin Name of the plugin
    1818#: clean-and-simple-contact-form-by-meg-nicholas.php
    19 msgid "Clean and Simple Contact Form"
     19msgid "Contact Form Clean and Simple"
    2020msgstr ""
    2121
     
    4040msgstr ""
    4141
    42 #: class.cscf.php:68
    43 msgid "Settings"
    44 msgstr ""
    45 
    46 #: class.cscf_contact.php:91
     42#: class.cscf_contact.php:133
    4743msgid "Sorry the email addresses do not match."
    4844msgstr ""
    4945
    50 #: class.cscf_contact.php:97
     46#: class.cscf_contact.php:139
    5147#: views/contact-form.view.php:63
    5248msgid "Please give your email address."
    5349msgstr ""
    5450
    55 #: class.cscf_contact.php:103
     51#: class.cscf_contact.php:145
    5652msgid "Please confirm your email address."
    5753msgstr ""
    5854
    59 #: class.cscf_contact.php:109
     55#: class.cscf_contact.php:151
    6056#: views/contact-form.view.php:34
    6157msgid "Please give your name."
    6258msgstr ""
    6359
    64 #: class.cscf_contact.php:114
     60#: class.cscf_contact.php:156
    6561msgid "Please enter a message."
    6662msgstr ""
    6763
    68 #: class.cscf_contact.php:119
     64#: class.cscf_contact.php:161
    6965#: views/contact-form.view.php:64
    7066#: views/contact-form.view.php:93
     
    7268msgstr ""
    7369
    74 #: class.cscf_contact.php:125
     70#: class.cscf_contact.php:167
    7571msgid "Please enter a valid phone number."
    7672msgstr ""
    7773
    78 #: class.cscf_contact.php:132
     74#: class.cscf_contact.php:174
    7975#: views/contact-form.view.php:198
    8076msgid "Please give your consent."
    8177msgstr ""
    8278
    83 #: class.cscf_contact.php:142
     79#: class.cscf_contact.php:184
    8480msgid "Please solve the recaptcha to continue."
    8581msgstr ""
    8682
    87 #: class.cscf_contact.php:175
     83#: class.cscf_contact.php:220
    8884msgid "From"
    8985msgstr ""
    9086
    91 #: class.cscf_contact.php:176
     87#: class.cscf_contact.php:221
    9288msgid "Email"
    9389msgstr ""
    9490
    95 #: class.cscf_contact.php:178
    96 #: class.cscf_contact.php:219
     91#: class.cscf_contact.php:223
     92#: class.cscf_contact.php:267
    9793msgid "Phone"
    9894msgstr ""
    9995
    100 #: class.cscf_contact.php:180
     96#: class.cscf_contact.php:225
    10197msgid "Page URL"
    10298msgstr ""
    10399
    104 #: class.cscf_contact.php:181
    105 #: class.cscf_contact.php:221
     100#: class.cscf_contact.php:226
     101#: class.cscf_contact.php:269
    106102msgid "Message"
    107103msgstr ""
    108104
    109 #: class.cscf_contact.php:183
    110 #: class.cscf_contact.php:216
     105#: class.cscf_contact.php:228
     106#: class.cscf_contact.php:264
    111107msgid "yes"
    112108msgstr ""
    113109
    114 #: class.cscf_contact.php:183
    115 #: class.cscf_contact.php:216
     110#: class.cscf_contact.php:228
     111#: class.cscf_contact.php:264
    116112msgid "no"
    117113msgstr ""
    118114
    119 #: class.cscf_contact.php:214
     115#: class.cscf_contact.php:262
    120116msgid "Here is a copy of your message :"
    121117msgstr ""
     
    141137msgstr ""
    142138
     139#: class.cscf_rest_api.php:48
     140msgid "Authentication required."
     141msgstr ""
     142
     143#: class.cscf_rest_api.php:58
     144msgid "Insufficient permissions."
     145msgstr ""
     146
     147#: class.cscf_rest_api.php:96
     148msgid "Validation failed."
     149msgstr ""
     150
     151#: class.cscf_rest_api.php:110
     152msgid "Failed to send email."
     153msgstr ""
     154
    143155#: class.cscf_settings.php:29
    144156msgid "Contact Form Settings"
     
    261273msgstr ""
    262274
    263 #: class.cscf_settings.php:224
     275#: class.cscf_settings.php:222
     276msgid "REST API Settings"
     277msgstr ""
     278
     279#: class.cscf_settings.php:229
     280msgid "Enable REST API :"
     281msgstr ""
     282
     283#: class.cscf_settings.php:235
     284msgid "Required User Capability :"
     285msgstr ""
     286
     287#: class.cscf_settings.php:247
    264288msgid "Congratulations: you are protected by Fullworks Anti Spam"
    265289msgstr ""
    266290
    267 #: class.cscf_settings.php:225
     291#: class.cscf_settings.php:248
    268292msgid "Configure"
    269293msgstr ""
    270294
    271 #: class.cscf_settings.php:225
     295#: class.cscf_settings.php:248
    272296msgid "Anti Spam Settings here"
    273297msgstr ""
    274298
    275 #: class.cscf_settings.php:227
     299#: class.cscf_settings.php:250
    276300msgid "The best way to show your appreciation for this free plugin and keep it maintained is to support it by installing Fullworks Anti Spam Pro"
    277301msgstr ""
    278302
    279 #: class.cscf_settings.php:228
     303#: class.cscf_settings.php:251
    280304msgid "With a 14 day free trial, you will find it surprisingly affordable when you compare it with Akismet, yet extremely effective."
    281305msgstr ""
    282306
    283 #: class.cscf_settings.php:229
    284 #: class.cscf_settings.php:232
     307#: class.cscf_settings.php:252
     308#: class.cscf_settings.php:255
    285309msgid "Try Fullworks Anti Spam Pro now and support the maintenance this FREE contact form plugin"
    286310msgstr ""
    287311
    288 #: class.cscf_settings.php:239
     312#: class.cscf_settings.php:262
    289313msgid "Message logging is enabled by  Fullworks Anti Spam Pro"
    290314msgstr ""
    291315
    292 #: class.cscf_settings.php:241
     316#: class.cscf_settings.php:264
    293317msgid "View Logs here"
    294318msgstr ""
    295319
    296 #: class.cscf_settings.php:243
     320#: class.cscf_settings.php:266
    297321msgid "Enable message log by installing Fullworks Anti Spam Pro"
    298322msgstr ""
    299323
    300 #: class.cscf_settings.php:244
     324#: class.cscf_settings.php:267
    301325msgid "With a 14 day free trial, will automatically log all messages from this form."
    302326msgstr ""
    303327
    304 #: class.cscf_settings.php:245
     328#: class.cscf_settings.php:268
    305329msgid "Enable logs now"
    306330msgstr ""
    307331
    308 #: class.cscf_settings.php:332
     332#: class.cscf_settings.php:364
    309333msgid "Enter your reCAPTCHA settings below :"
    310334msgstr ""
    311335
    312 #: class.cscf_settings.php:333
     336#: class.cscf_settings.php:365
    313337msgid "To use reCAPTCHA you must get an API key from"
    314338msgstr ""
    315339
    316 #: class.cscf_settings.php:338
     340#: class.cscf_settings.php:370
    317341msgid "Enter your message settings below :"
    318342msgstr ""
    319343
    320 #: class.cscf_settings.php:459
     344#: class.cscf_settings.php:381
     345msgid "Enable REST API support for headless WordPress implementations."
     346msgstr ""
     347
     348#: class.cscf_settings.php:383
     349msgid "When enabled, authenticated users can submit the form via: POST /wp-json/cscf/v1/submit"
     350msgstr ""
     351
     352#: class.cscf_settings.php:396
     353msgid "use recaptcha"
     354msgstr ""
     355
     356#: class.cscf_settings.php:403
     357msgid "load stylesheet"
     358msgstr ""
     359
     360#: class.cscf_settings.php:410
     361msgid "recaptcha public key"
     362msgstr ""
     363
     364#: class.cscf_settings.php:418
     365msgid "recaptcha private key"
     366msgstr ""
     367
     368#: class.cscf_settings.php:430
     369msgid "recipient email"
     370msgstr ""
     371
     372#: class.cscf_settings.php:437
     373msgid "add button for new recipient email"
     374msgstr ""
     375
     376#: class.cscf_settings.php:443
     377msgid "remove button for new recipient email"
     378msgstr ""
     379
     380#: class.cscf_settings.php:457
     381msgid "confirm email"
     382msgstr ""
     383
     384#: class.cscf_settings.php:464
     385msgid "override from address"
     386msgstr ""
     387
     388#: class.cscf_settings.php:471
     389msgid "email to sender"
     390msgstr ""
     391
     392#: class.cscf_settings.php:478
     393msgid "contact consent"
     394msgstr ""
     395
     396#: class.cscf_settings.php:484
     397msgid "contact consent message"
     398msgstr ""
     399
     400#: class.cscf_settings.php:492
     401msgid "phone number"
     402msgstr ""
     403
     404#: class.cscf_settings.php:499
     405msgid "phone number mandatory"
     406msgstr ""
     407
     408#: class.cscf_settings.php:506
     409msgid "from email address"
     410msgstr ""
     411
     412#: class.cscf_settings.php:513
     413msgid "email subject"
     414msgstr ""
     415
     416#: class.cscf_settings.php:519
     417msgid "sent message heading"
     418msgstr ""
     419
     420#: class.cscf_settings.php:526
     421msgid "sent message body"
     422msgstr ""
     423
     424#: class.cscf_settings.php:532
     425msgid "message"
     426msgstr ""
     427
     428#: class.cscf_settings.php:540
     429msgid "recaptcha theme"
     430msgstr ""
     431
     432#: class.cscf_settings.php:545
    321433msgid "Light"
    322434msgstr ""
    323435
    324 #: class.cscf_settings.php:461
     436#: class.cscf_settings.php:547
    325437msgid "Dark"
     438msgstr ""
     439
     440#: class.cscf_settings.php:554
     441msgid "use client validation"
     442msgstr ""
     443
     444#: class.cscf_settings.php:561
     445msgid "enable REST API"
     446msgstr ""
     447
     448#: class.cscf_settings.php:568
     449msgid "REST API required capability"
     450msgstr ""
     451
     452#: class.cscf_settings.php:572
     453msgid "Default: edit_posts. Common capabilities: edit_posts, publish_posts, manage_options"
     454msgstr ""
     455
     456#. translators: %s is the path to the view file
     457#: class.view.php:25
     458msgid "View %s not found"
    326459msgstr ""
    327460
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/readme.txt

    r3254319 r3339262  
    77License URI: http://www.gnu.org/licenses/gpl.html
    88Tags: contact, form, contact form, feedback form, bootstrap
    9 Tested up to: 6.7
    10 Stable tag: 4.10
     9Tested up to: 6.8
     10Stable tag: 4.11
    1111
    1212A clean and simple contact form with Bootstrap markup.
     
    1414
    1515== Description ==
    16 A clean and simple AJAX contact form with Google reCAPTCHA, Twitter Bootstrap markup and  spam filtering.
     16A clean and simple AJAX contact form with Google reCAPTCHA, Twitter Bootstrap markup, spam filtering, and REST API support for headless WordPress implementations.
    1717
    1818*   **Clean**: all user inputs are stripped in order to avoid cross-site scripting (XSS) vulnerabilities.
     
    2222*   **Stylish**: Use the included stylesheet or switch it off and use your own for seamless integration with your website.
    2323Uses **Twitter Bootstrap** classes.
     24
     25*   **REST API Support**: Enable headless WordPress implementations to submit forms via authenticated REST API endpoints.
    2426
    2527
     
    6668*   Original plugin written by an **experienced PHP programmer**, Megan Nicholas, the code is rock solid, safe, and rigorously tested as standard practice.
    6769
     70*   **Headless WordPress ready**. REST API support allows you to submit forms from decoupled frontends, mobile apps, or any external application with proper authentication.
     71
    6872Hopefully this plugin will fulfil all your needs.
    6973
     
    136140
    137141*   **Contact consent**: This option allows you to be GDPR compliant by adding a 'Consent to contact' check box at the bottom of the form.
     142
     143*   **Enable REST API**: Turn on REST API support to allow headless WordPress implementations to submit forms.
     144
     145*   **Required User Capability**: Set the minimum WordPress user capability required to use the REST API (default: edit_posts).
     146
     147
     148== REST API for Headless WordPress ==
     149
     150This plugin includes REST API support, making it perfect for headless WordPress implementations, mobile applications, and decoupled frontend frameworks like React, Vue.js, or Angular.
     151
     152= Enabling REST API =
     153
     1541. Go to the plugin settings page
     1552. Find the "REST API Settings" section
     1563. Check "Enable REST API"
     1574. Set the required user capability (default: edit_posts)
     1585. Save your settings
     159
     160= API Endpoint =
     161
     162**POST** `/wp-json/cscf/v1/submit`
     163
     164= Authentication =
     165
     166The REST API requires WordPress user authentication. Users must be logged in and have the capability specified in settings (default: edit_posts).
     167
     168For headless implementations, you can use:
     169- Application Passwords (WordPress 5.6+)
     170- JWT Authentication plugins
     171- OAuth plugins
     172- Basic Authentication (development only)
     173
     174= Request Format =
     175
     176Send a POST request with JSON body:
     177
     178```json
     179{
     180  "name": "John Doe",
     181  "email": "john@example.com",
     182  "confirm_email": "john@example.com",
     183  "message": "Your message here",
     184  "phone_number": "+1234567890",
     185  "contact_consent": true,
     186  "email_sender": false,
     187  "post_id": 123
     188}
     189```
     190
     191**Required fields:**
     192- `name`: Sender's name
     193- `email`: Sender's email address
     194- `message`: The message content
     195
     196**Optional fields:**
     197- `confirm_email`: Required if email confirmation is enabled in settings
     198- `phone_number`: Required if phone number is set as mandatory in settings
     199- `contact_consent`: Required if contact consent is enabled in settings
     200- `email_sender`: Set to true to send a copy to the sender
     201- `post_id`: The ID of the page/post where the form would normally be displayed
     202
     203= Response Format =
     204
     205**Success Response (200):**
     206```json
     207{
     208  "success": true,
     209  "message": "Message Sent"
     210}
     211```
     212
     213**Validation Error Response (400):**
     214```json
     215{
     216  "code": "validation_failed",
     217  "message": "Validation failed.",
     218  "data": {
     219    "status": 400,
     220    "errors": {
     221      "email": "Please enter a valid email address.",
     222      "message": "Please enter a message."
     223    }
     224  }
     225}
     226```
     227
     228**Authentication Error Response (401):**
     229```json
     230{
     231  "code": "rest_forbidden",
     232  "message": "Authentication required.",
     233  "data": {
     234    "status": 401
     235  }
     236}
     237```
     238
     239= Example Implementation =
     240
     241**JavaScript (fetch API):**
     242```javascript
     243const formData = {
     244  name: "John Doe",
     245  email: "john@example.com",
     246  confirm_email: "john@example.com",
     247  message: "This is a test message from the REST API"
     248};
     249
     250fetch('https://yoursite.com/wp-json/cscf/v1/submit', {
     251  method: 'POST',
     252  headers: {
     253    'Content-Type': 'application/json',
     254    'Authorization': 'Bearer YOUR_AUTH_TOKEN'
     255  },
     256  body: JSON.stringify(formData)
     257})
     258.then(response => response.json())
     259.then(data => {
     260  if (data.success) {
     261    console.log('Message sent successfully!');
     262  } else {
     263    console.error('Validation errors:', data.data.errors);
     264  }
     265});
     266```
     267
     268= Important Notes =
     269
     270- REST API is disabled by default for security
     271- reCAPTCHA is bypassed for REST API submissions (authentication provides security)
     272- All other form validations and spam filtering still apply
     273- Form submissions via REST API are processed identically to regular submissions
     274- Email notifications work the same way as standard form submissions
    138275
    139276
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/shortcodes/contact-form.php

    r2551686 r3339262  
    99    if ( $contact->IsValid() ) {
    1010        if ( $contact->SendMail() ) {
     11            // Action hook for standard form submission
     12            do_action( 'cscf_form_submitted_standard', $contact );
     13           
    1114            $view = new CSCF_View( 'message-sent' );
    1215            $view->Set( 'heading', cscf_PluginSettings::SentMessageHeading() );
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/vendor/autoload.php

    r3254319 r3339262  
    1515        }
    1616    }
    17     trigger_error(
    18         $err,
    19         E_USER_ERROR
    20     );
     17    throw new RuntimeException($err);
    2118}
    2219
    2320require_once __DIR__ . '/composer/autoload_real.php';
    2421
    25 return ComposerAutoloaderInitde3652cf7e4bf8e2010815060c1bc76c::getLoader();
     22return ComposerAutoloaderInit27d86f03d1c986263483b369986ee068::getLoader();
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/vendor/composer/InstalledVersions.php

    r3254319 r3339262  
    2828{
    2929    /**
     30     * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
     31     * @internal
     32     */
     33    private static $selfDir = null;
     34
     35    /**
    3036     * @var mixed[]|null
    3137     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
    3238     */
    3339    private static $installed;
     40
     41    /**
     42     * @var bool
     43     */
     44    private static $installedIsLocalDir;
    3445
    3546    /**
     
    310321        self::$installed = $data;
    311322        self::$installedByVendor = array();
     323
     324        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
     325        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
     326        // so we have to assume it does not, and that may result in duplicate data being returned when listing
     327        // all installed packages for example
     328        self::$installedIsLocalDir = false;
     329    }
     330
     331    /**
     332     * @return string
     333     */
     334    private static function getSelfDir()
     335    {
     336        if (self::$selfDir === null) {
     337            self::$selfDir = strtr(__DIR__, '\\', '/');
     338        }
     339
     340        return self::$selfDir;
    312341    }
    313342
     
    323352
    324353        $installed = array();
     354        $copiedLocalDir = false;
    325355
    326356        if (self::$canGetVendors) {
     357            $selfDir = self::getSelfDir();
    327358            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
     359                $vendorDir = strtr($vendorDir, '\\', '/');
    328360                if (isset(self::$installedByVendor[$vendorDir])) {
    329361                    $installed[] = self::$installedByVendor[$vendorDir];
     
    331363                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
    332364                    $required = require $vendorDir.'/composer/installed.php';
    333                     $installed[] = self::$installedByVendor[$vendorDir] = $required;
    334                     if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
    335                         self::$installed = $installed[count($installed) - 1];
     365                    self::$installedByVendor[$vendorDir] = $required;
     366                    $installed[] = $required;
     367                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
     368                        self::$installed = $required;
     369                        self::$installedIsLocalDir = true;
    336370                    }
     371                }
     372                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
     373                    $copiedLocalDir = true;
    337374                }
    338375            }
     
    351388        }
    352389
    353         if (self::$installed !== array()) {
     390        if (self::$installed !== array() && !$copiedLocalDir) {
    354391            $installed[] = self::$installed;
    355392        }
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/vendor/composer/autoload_real.php

    r3254319 r3339262  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInitde3652cf7e4bf8e2010815060c1bc76c
     5class ComposerAutoloaderInit27d86f03d1c986263483b369986ee068
    66{
    77    private static $loader;
     
    2525        require __DIR__ . '/platform_check.php';
    2626
    27         spl_autoload_register(array('ComposerAutoloaderInitde3652cf7e4bf8e2010815060c1bc76c', 'loadClassLoader'), true, true);
     27        spl_autoload_register(array('ComposerAutoloaderInit27d86f03d1c986263483b369986ee068', 'loadClassLoader'), true, true);
    2828        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
    29         spl_autoload_unregister(array('ComposerAutoloaderInitde3652cf7e4bf8e2010815060c1bc76c', 'loadClassLoader'));
     29        spl_autoload_unregister(array('ComposerAutoloaderInit27d86f03d1c986263483b369986ee068', 'loadClassLoader'));
    3030
    3131        require __DIR__ . '/autoload_static.php';
    32         call_user_func(\Composer\Autoload\ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::getInitializer($loader));
     32        call_user_func(\Composer\Autoload\ComposerStaticInit27d86f03d1c986263483b369986ee068::getInitializer($loader));
    3333
    3434        $loader->register(true);
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/vendor/composer/autoload_static.php

    r3254319 r3339262  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c
     7class ComposerStaticInit27d86f03d1c986263483b369986ee068
    88{
    99    public static $prefixLengthsPsr4 = array (
     
    3838    {
    3939        return \Closure::bind(function () use ($loader) {
    40             $loader->prefixLengthsPsr4 = ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::$prefixLengthsPsr4;
    41             $loader->prefixDirsPsr4 = ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::$prefixDirsPsr4;
    42             $loader->prefixesPsr0 = ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::$prefixesPsr0;
    43             $loader->classMap = ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::$classMap;
     40            $loader->prefixLengthsPsr4 = ComposerStaticInit27d86f03d1c986263483b369986ee068::$prefixLengthsPsr4;
     41            $loader->prefixDirsPsr4 = ComposerStaticInit27d86f03d1c986263483b369986ee068::$prefixDirsPsr4;
     42            $loader->prefixesPsr0 = ComposerStaticInit27d86f03d1c986263483b369986ee068::$prefixesPsr0;
     43            $loader->classMap = ComposerStaticInit27d86f03d1c986263483b369986ee068::$classMap;
    4444
    4545        }, null, ClassLoader::class);
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/vendor/composer/installed.php

    r3254319 r3339262  
    22    'root' => array(
    33        'name' => 'fullworks/clean-and-simple-contact-form',
    4         'pretty_version' => 'dev-main',
    5         'version' => 'dev-main',
    6         'reference' => '6057cf8bf7c1cd56b1f7d6b170e7208543f25dde',
     4        'pretty_version' => 'v4.11',
     5        'version' => '4.11.0.0',
     6        'reference' => '801b967317613364d9e34394960f064495cb2283',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    3030        ),
    3131        'fullworks/clean-and-simple-contact-form' => array(
    32             'pretty_version' => 'dev-main',
    33             'version' => 'dev-main',
    34             'reference' => '6057cf8bf7c1cd56b1f7d6b170e7208543f25dde',
     32            'pretty_version' => 'v4.11',
     33            'version' => '4.11.0.0',
     34            'reference' => '801b967317613364d9e34394960f064495cb2283',
    3535            'type' => 'wordpress-plugin',
    3636            'install_path' => __DIR__ . '/../../',
  • clean-and-simple-contact-form-by-meg-nicholas/tags/4.11/vendor/composer/platform_check.php

    r3142234 r3339262  
    2020        }
    2121    }
    22     trigger_error(
    23         'Composer detected issues in your platform: ' . implode(' ', $issues),
    24         E_USER_ERROR
     22    throw new \RuntimeException(
     23        'Composer detected issues in your platform: ' . implode(' ', $issues)
    2524    );
    2625}
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/ajax.php

    r2551686 r3339262  
    1414    if ( $result['valid'] ) {
    1515        $result['sent'] = $contact->SendMail();
     16       
     17        // Action hook for AJAX form submission
     18        if ( $result['sent'] ) {
     19            do_action( 'cscf_form_submitted_ajax', $contact );
     20        }
    1621    }
    1722
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/changelog.txt

    r3146820 r3339262  
     1= 4.11 =
     2* Added REST API support for headless WordPress implementations
     3  - New endpoint at /wp-json/cscf/v1/submit with authentication
     4  - Configurable user capability requirements
     5  - Full form validation (excluding reCAPTCHA for authenticated requests)
     6* Added SMTP configuration via wp-config constants
     7  - Support for all major email services (Gmail, SendGrid, Mailgun, etc.)
     8  - Useful for development with tools like Mailpit
     9  - No UI needed - server-level configuration
     10* Added developer hooks for extensibility
     11  - Action hooks: cscf_before_send_email, cscf_after_send_email, cscf_form_submitted (plus type-specific variants)
     12  - Filter hook: cscf_form_data for REST API data modification
     13* Added comprehensive developer documentation
     14  - Hooks and filters guide with examples
     15  - REST API implementation guide
     16  - SMTP configuration guide
     17* Improved extensibility for third-party integrations (CRMs, webhooks, mailing lists)
     18* Improved phone number validation
     19  - Now validates format (only allows digits, +, (), -, and spaces)
     20  - Format validation applies even when phone field is optional
     21  - Fixed bug where phone validation error used wrong error key
     22* Improved form validation user experience
     23  - reCAPTCHA validation now skipped if other form errors exist
     24  - Prevents users from being blocked by reCAPTCHA when fixing validation errors
     25* Fixed JavaScript bugs
     26  - Fixed server-side validation errors not displaying when using AJAX submission
     27  - Fixed jQuery selector looking for div instead of span elements for error display
     28  - Fixed deprecated jQuery .selector usage for jQuery 3.0+ compatibility
     29* Added comprehensive unit tests for form validation
     30* Removed deprecated load_plugin_textdomain() function - WordPress handles translations automatically since v4.6
     31
     32= 4.10 =
     33* Added opt in
     34* Added code to comply with current plugin guidelines
     35
    136= 4.9.1 =
    2 * corrected link markup in settings pag
     37* corrected link markup in settings page
    338
    439= 4.9 =
     
    4580
    4681= 4.7.1 =
    47 * Tested with Wordpress version 5.3
     82* Tested with WordPress version 5.3
    4883Fixed XSS vulnerability in GDPR consent message
    4984= 4.7.0 =
    50 * Tested with Wordpress version 4.9.6
     85* Tested with WordPress version 4.9.6
    5186* Added consent to contact checkbox for GDPR compliance
    5287= 4.6.2 =
     
    167202= 4.1.2 =
    168203* Added some FAQs
    169 * Added alternative shortcode [cscf-contact-form] for use when conflicts could occur.
    170 * Updated the documentation.
    171 * Recaptcha form now responds to language changes
    172 * Updated pot file to reflect new name space
    173 * Changed name space from cff to cscf
    174 * Settings screen: recaptcha theme and key inputs are immediately enabled/disabled as the 'Use reCAPTCHA' box is clicked.
    175 * Corrected some html seen as invalid by http://validator.w3.org/
    176 * removed '<?=' and replaced with '<?php echo' in cscf_settings, thanks go to andrewbacon
    177 * Added notice to setting screen when JetPack's contact form is active
    178 * Fixed problem where 'Please enter a valid email address' was not translating in the 'confirm email address' input
    179 = 4.1.1 =
    180 * Fixed potential conflicts with themes that use bootstrap
    181 * Enabled internationalisation, this plugin will now work with multiple languages
    182 * Added German translation file for my German friends, thanks to faktorzweinet for the translation
    183 = 4.1.0 =
    184 * Fixed a bug in class.cff_settings.php where php opening tag had got missed off. This problem caused the settings screen not to display correctly but only occurred with some versions of php. Please upgrade if you have this problem.
    185 = 4.0.9 =
    186 * Switched header argument of wp_mail over to a filter to remove any potential conflicts with other emailing plugins or themes
    187 * The ability to set a different recipient email address. Previously all email was sent to the WordPress administrator email address.
    188 * Allow the email subject to be customised.
    189 = 4.0.8 =
    190 * Fixed a bug: When using reCAPTCHA ajax did not work.
    191 * Fixed a bug: Ajax validation was not checking email address were equal (server side was doing it instead)
    192 * Improvement: Ajax now works better.
    193 * Documentation update: nicer links (worked how to do them in markdown!), changelog and upgrade notice sections now correctly formatted.
    194 = 4.0.7 =
    195 * Fixed a bug: Plugin name is actually clean-and-simple-contact-form now (not contact-form) but this new name needed to be updated in the plugin settings definitions. I also needed to rename contact-form.php to clean-and-simple-contact-form.php. My thanks to Jakub for finding this bug.
    196 * If your webpage is ssl then reCAPTCHA will now also use ssl mode.
    197 
    198 
    199 == Upgrade Notice ==
    200 = 4.7.0 =
    201 Tested with Wordpress version 4.9.6. Added 'consent to contact' GDPR compliance message
    202 = 4.6.2 =
    203 Updated translations. Tested up to WordPress 4.6.1.
    204 = 4.6.0 =
    205 Updated translations. Correct textdomain. Prevent multiple clicks.
    206 = 4.5.1 =
    207 Translation updates
    208 = 4.5.0 =
    209 Added support for Google Recaptcha2. Updated translation. Fixed layout bug.
    210 = 4.4.4 =
    211 Added languages, css fix for twenty fifteen theme, remove 'notice' errors, remove empty divs
    212 = 4.4.3 =
    213 Tested up to 4.1
    214 = 4.4.2 =
    215 Akismet tweak and translation updates
    216 = 4.4.1 =
    217 Fixed XSS issue
    218 = 4.4.0 =
    219 Added option for enquiry to email themselves a copy of the message plus Polish translation updated
    220 = 4.3.4 =
    221 Email now includes page url of contact form, removed link in main contact form view
    222 = 4.3.3 =
    223 Hebrew Language added, name field moved to top of form, added 'reply-to'
    224 = 4.3.2 =
    225 Added Norwegian and Brazilian Portugese Translations
    226 = 4.3.1 =
    227 Checked compatibility with WP 3.8 and TwentyFourteen theme, translation updates, defaults for new installations
    228 = 4.3.0 =
    229 Contact form is now filtered for spam when the Akismet plugin is present.
    230 [Learn more](http://www.megnicholas.co.uk/articles/contact-form-plugin-can-detect-spam/ "Learn More").
    231 = 4.2.5 =
    232 Small bug fix
    233 = 4.2.4 =
    234 'Confirm Email' can now be turned off. Arabic translation added.
    235 = 4.2.3 =
    236 Multiple recipients are now possible
    237 = 4.2.2 =
    238 Remove ALL possibility of conflicts with other plugins that also include Google reCAPTCHA library
    239 = 4.2.1 =
    240 Translation and housekeeping updates
    241 = 4.2.0 =
    242 Translation and documentation updates
    243 = 4.1.9 =
    244 Support for [Bootstrap 3](http://www.megnicholas.co.uk/articles/version-4-1-9-supports-bootstrap-3/ "More information on 4.1.9")
    245 = 4.1.8 =
    246 Added Russian translation and some modifications to Estonian and Spanish translations
    247 = 4.1.7
    248 More translations. A helpful note about the short code to use has been put on the settings screen
    249 = 4.1.6 =
    250 Ability to specify a 'From' address. This email will be used to send the mail instead of the form filler's email address.
    251 = 4.1.5 =
    252 Works with themes that pre-process the html.
    253 = 4.1.4 =
    254 New translations - Slovak and Catalan
    255 = 4.1.3 =
    256 Form now submits via ajax!
    257 = 4.1.2 =
    258 Alternative shortcode, recaptcha internationalisation, Jetpack conflict warning notice
    259 = 4.1.1 =
    260 Internationalisation, fixed conflict with some bootstrapped themes.
    261 = 4.1.0 =
    262 Please upgrade if your settings screen is not displaying.
    263 = 4.0.9 =
    264 More customisation: recipient email address, and email subject.
    265 = 4.0.8 =
    266 Ajax now works when your form has reCAPTCHA on it. Ajax validation is now cleaner.
    267 = 4.0.7 =
    268 Fixed a bug which occurred when plugin name was changed. reCAPTCHA will now use ssl if your webpage is ssl.
     204* Added alternative shortcode
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/class.cscf.php

    r3254319 r3339262  
    2121            $this,
    2222            'RegisterAdminStyles',
    23         ) );
    24 
    25         add_action( 'init', array(
    26             $this,
    27             'RegisterTextDomain',
    2823        ) );
    2924
     
    4439        //create the settings page
    4540        $settings = new cscf_settings();
    46     }
    47 
    48 
    49     function RegisterTextDomain() {
    50         //$path = CSCF_PLUGIN_DIR . '/languages';
    51         $path = '/' . CSCF_PLUGIN_NAME . '/languages';
    52         load_plugin_textdomain( 'clean-and-simple-contact-form-by-meg-nicholas', false, $path );
    5341    }
    5442
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/class.cscf_contact.php

    r3254319 r3339262  
    1919    var $PostID;
    2020    var $IsSpam;
     21    var $IsRestApi = false;
    2122
    2223    function __construct() {
     
    2829        }
    2930        $request_method = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD']??'' ) );
    30         if ( $request_method === 'POST' ) {
     31        if ( $request_method === 'POST' && ! $this->IsRestApi ) {
    3132            // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- No action, nonce is not required for $_POST['cscf_nonce'] check later, array sanitized
    3233            if ( isset( $_POST['cscf'] ) ) {
     
    7374    }
    7475
     76    /**
     77     * Set contact data from array (used by REST API)
     78     *
     79     * @param array $data Contact form data
     80     * @param int $post_id Post ID where form was submitted from
     81     * @param bool $is_rest_api Whether this is a REST API request
     82     */
     83    public function set_from_array( $data, $post_id = null, $is_rest_api = false ) {
     84        $this->IsRestApi = $is_rest_api;
     85       
     86        // Filter to allow modification of form data before processing
     87        $data = apply_filters( 'cscf_form_data', $data, $post_id, $is_rest_api );
     88       
     89        if ( isset( $data['name'] ) ) {
     90            $this->Name = sanitize_text_field( $data['name'] );
     91        }
     92        if ( isset( $data['email'] ) ) {
     93            $this->Email = sanitize_email( $data['email'] );
     94        }
     95        if ( isset( $data['confirm-email'] ) ) {
     96            $this->ConfirmEmail = sanitize_email( $data['confirm-email'] );
     97        }
     98        if ( isset( $data['email-sender'] ) ) {
     99            $this->EmailToSender = $data['email-sender'] ? true : false;
     100        }
     101        if ( isset( $data['message'] ) ) {
     102            $this->Message = sanitize_textarea_field( $data['message'] );
     103        }
     104        if ( isset( $data['phone-number'] ) ) {
     105            $this->PhoneNumber = sanitize_text_field( $data['phone-number'] );
     106        }
     107        if ( isset( $data['contact-consent'] ) ) {
     108            $this->ContactConsent = $data['contact-consent'] ? true : false;
     109        }
     110        if ( $post_id !== null ) {
     111            $this->PostID = absint( $post_id );
     112        }
     113    }
     114
    75115    public function IsValid() {
    76116        $this->Errors = array();
    77117        $request_method = sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD']??'' ) );
    78         if ( $request_method !== 'POST' ) {
     118        if ( $request_method !== 'POST' && ! $this->IsRestApi ) {
    79119            return false;
    80120        }
    81121
    82         //check nonce
    83         // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- No action, not stored just a nonce check
    84         if ( ! wp_verify_nonce( $_POST['cscf_nonce'] ?? '', 'cscf_contact' ) ) {
    85             return false;
     122        //check nonce (skip for REST API as it uses WordPress authentication)
     123        if ( ! $this->IsRestApi ) {
     124            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- No action, not stored just a nonce check
     125            if ( ! wp_verify_nonce( $_POST['cscf_nonce'] ?? '', 'cscf_contact' ) ) {
     126                return false;
     127            }
    86128        }
    87129
     
    120162        }
    121163
    122         //mandatory phone number
    123         if ( cscf_PluginSettings::PhoneNumber() && cscf_PluginSettings::PhoneNumberMandatory() ) {
    124             if ( strlen( $this->PhoneNumber ) < 8 ) {
    125                 $this->Errors['confirm-email'] = esc_html__( 'Please enter a valid phone number.', 'clean-and-simple-contact-form-by-meg-nicholas' );
    126             }
     164        //phone number validation
     165        if ( cscf_PluginSettings::PhoneNumber() && strlen( $this->PhoneNumber ) > 0 ) {
     166            // Validate format - only allow digits, +, (), -, and spaces
     167            if ( ! preg_match( '/^[0-9\+\(\)\-\s]+$/', $this->PhoneNumber ) ) {
     168                $this->Errors['phone-number'] = esc_html__( 'Phone number can only contain numbers, +, (), - and spaces.', 'clean-and-simple-contact-form-by-meg-nicholas' );
     169            }
     170            // Check length for mandatory fields
     171            elseif ( cscf_PluginSettings::PhoneNumberMandatory() && strlen( $this->PhoneNumber ) < 8 ) {
     172                $this->Errors['phone-number'] = esc_html__( 'Please enter a valid phone number (minimum 8 characters).', 'clean-and-simple-contact-form-by-meg-nicholas' );
     173            }
     174        }
     175        // Check if phone is mandatory but not provided
     176        elseif ( cscf_PluginSettings::PhoneNumber() && cscf_PluginSettings::PhoneNumberMandatory() && strlen( $this->PhoneNumber ) == 0 ) {
     177            $this->Errors['phone-number'] = esc_html__( 'Please enter your phone number.', 'clean-and-simple-contact-form-by-meg-nicholas' );
    127178        }
    128179
     
    134185        }
    135186
    136         //check recaptcha but only if we have keys
    137         if ( $this->RecaptchaPublicKey <> '' && $this->RecaptchaPrivateKey <> '' ) {
     187        //check recaptcha but only if we have keys, not REST API, and no other validation errors
     188        //This prevents reCAPTCHA from blocking users who need to fix other form errors
     189        if ( $this->RecaptchaPublicKey <> '' && $this->RecaptchaPrivateKey <> '' && ! $this->IsRestApi && count( $this->Errors ) == 0 ) {
    138190            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- No action, no form fields are being saved
    139191            $resp = csf_RecaptchaV2::VerifyResponse( sanitize_text_field($_SERVER["REMOTE_ADDR"]??''), $this->RecaptchaPrivateKey, sanitize_text_field($_POST["g-recaptcha-response"]??''));
     
    153205            return true;
    154206        }
     207
     208        // Action hook before sending email
     209        do_action( 'cscf_before_send_email', $this );
    155210
    156211        $filters = new cscf_Filters;
     
    194249        $filters->remove( 'wp_mail_from_name' );
    195250
     251        // Action hook after sending email
     252        do_action( 'cscf_after_send_email', $this, $result );
     253
    196254        //send an email to the form-filler
    197255        if ( $this->EmailToSender ) {
     
    228286        }
    229287
     288        // Action hook for successful form submission
     289        if ( $result ) {
     290            do_action( 'cscf_form_submitted', $this );
     291        }
     292
    230293        return $result;
    231294    }
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/class.cscf_pluginsettings.php

    r2561035 r3339262  
    193193        return isset($options['confirm-email']) ? true : false;
    194194    }
     195
     196    static function RestApiEnabled()
     197    {
     198        $options = get_option(CSCF_OPTIONS_KEY);
     199        return isset($options['enable_rest_api']) ? true : false;
     200    }
     201
     202    static function RestApiCapability()
     203    {
     204        $options = get_option(CSCF_OPTIONS_KEY);
     205        return isset($options['rest_api_capability']) ? $options['rest_api_capability'] : 'edit_posts';
     206    }
    195207}
    196208
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/class.cscf_settings.php

    r3254319 r3339262  
    215215            'recaptcha_private_key',
    216216            'class' => 'recaptcha-field',
     217        ) );
     218       
     219        // REST API Settings
     220        add_settings_section(
     221            'section_rest_api',
     222            '<h3>' . esc_html__( 'REST API Settings', 'clean-and-simple-contact-form-by-meg-nicholas' ) . '</h3>',
     223            array(
     224                $this,
     225                'print_section_info_rest_api',
     226            ),
     227            'contact-form-settings'
     228        );
     229        add_settings_field( 'enable_rest_api', esc_html__( 'Enable REST API :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
     230            $this,
     231            'create_fields',
     232        ), 'contact-form-settings', 'section_rest_api', array(
     233            'enable_rest_api',
     234        ) );
     235        add_settings_field( 'rest_api_capability', esc_html__( 'Required User Capability :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
     236            $this,
     237            'create_fields',
     238        ), 'contact-form-settings', 'section_rest_api', array(
     239            'rest_api_capability',
    217240        ) );
    218241    }
     
    317340        }
    318341
     342        // REST API settings
     343        if ( isset( $input['rest_api_capability'] ) ) {
     344            $input['rest_api_capability'] = sanitize_text_field( $input['rest_api_capability'] );
     345            // Validate capability exists
     346            if ( empty( $input['rest_api_capability'] ) ) {
     347                $input['rest_api_capability'] = 'edit_posts';
     348            }
     349        }
     350
    319351        //tidy up the keys
    320352        $tidiedRecipients = array();
     
    343375        //print 'Enter your styling settings below:';
    344376
     377    }
     378
     379    public function print_section_info_rest_api() {
     380        echo '<p>';
     381        print esc_html__( 'Enable REST API support for headless WordPress implementations.', 'clean-and-simple-contact-form-by-meg-nicholas' );
     382        echo '</p><p>';
     383        print esc_html__( 'When enabled, authenticated users can submit the form via: POST /wp-json/cscf/v1/submit', 'clean-and-simple-contact-form-by-meg-nicholas' );
     384        echo '</p>';
    345385    }
    346386
     
    516556                               name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[use_client_validation]"><?php
    517557                break;
     558            case 'enable_rest_api':
     559                $checked = cscf_PluginSettings::RestApiEnabled() === true ? 'checked' : '';
     560                ?><label for="enable_rest_api" class="screen-reader-text">
     561                <?php esc_html_e('enable REST API', 'clean-and-simple-contact-form-by-meg-nicholas'); ?>
     562                </label><input type="checkbox" <?php echo esc_attr( $checked ); ?>  id="enable_rest_api"
     563                         name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[enable_rest_api]"><?php
     564                break;
     565            case 'rest_api_capability':
     566                $capability = cscf_PluginSettings::RestApiCapability();
     567                ?><label for="rest_api_capability" class="screen-reader-text">
     568                <?php esc_html_e('REST API required capability', 'clean-and-simple-contact-form-by-meg-nicholas'); ?>
     569                </label><input type="text" size="40" id="rest_api_capability"
     570                         name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[rest_api_capability]"
     571                         value="<?php echo esc_attr( $capability ); ?>" />
     572                <p class="description"><?php esc_html_e( 'Default: edit_posts. Common capabilities: edit_posts, publish_posts, manage_options', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></p><?php
     573                break;
    518574            default:
    519575                break;
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/clean-and-simple-contact-form-by-meg-nicholas.php

    r3254319 r3339262  
    88Plugin URI: https://fullworks.net/products/clean-and-simple-contact-form
    99Description: A clean and simple contact form with Google reCAPTCHA and Twitter Bootstrap markup.
    10 Version: 4.10
     10Version: 4.11
    1111Requires at least: 5.6
    1212Requires PHP: 7.4
     
    5050require 'class.view.php';
    5151require 'class.cscf_filters.php';
     52require 'class.cscf_rest_api.php';
    5253require 'ajax.php';
    5354require 'recaptchav2.php';
     
    7576
    7677if ( ! defined( 'CSCF_VERSION_NUM' ) ) {
    77     define( 'CSCF_VERSION_NUM', '4.10' );
     78    define( 'CSCF_VERSION_NUM', '4.11' );
    7879}
    7980
     
    9192
    9293$cscf = new cscf();
     94$cscf_rest_api = new cscf_rest_api();
     95
     96// Configure SMTP if constants are defined
     97if ( defined( 'CSCF_USE_SMTP' ) && CSCF_USE_SMTP ) {
     98    add_action( 'phpmailer_init', function( $phpmailer ) {
     99        $phpmailer->isSMTP();
     100       
     101        // Required settings
     102        if ( defined( 'CSCF_SMTP_HOST' ) ) {
     103            $phpmailer->Host = CSCF_SMTP_HOST;
     104        }
     105       
     106        if ( defined( 'CSCF_SMTP_PORT' ) ) {
     107            $phpmailer->Port = (int) CSCF_SMTP_PORT;
     108        }
     109       
     110        // Authentication settings
     111        if ( defined( 'CSCF_SMTP_AUTH' ) && CSCF_SMTP_AUTH ) {
     112            $phpmailer->SMTPAuth = true;
     113           
     114            if ( defined( 'CSCF_SMTP_USER' ) ) {
     115                $phpmailer->Username = CSCF_SMTP_USER;
     116            }
     117           
     118            if ( defined( 'CSCF_SMTP_PASS' ) ) {
     119                $phpmailer->Password = CSCF_SMTP_PASS;
     120            }
     121        } else {
     122            $phpmailer->SMTPAuth = false;
     123        }
     124       
     125        // Security settings
     126        if ( defined( 'CSCF_SMTP_SECURE' ) ) {
     127            $phpmailer->SMTPSecure = CSCF_SMTP_SECURE; // 'tls' or 'ssl' or empty string
     128        }
     129       
     130        // Optional: From email override
     131        if ( defined( 'CSCF_SMTP_FROM' ) ) {
     132            $phpmailer->From = CSCF_SMTP_FROM;
     133        }
     134       
     135        // Optional: From name override
     136        if ( defined( 'CSCF_SMTP_FROM_NAME' ) ) {
     137            $phpmailer->FromName = CSCF_SMTP_FROM_NAME;
     138        }
     139       
     140        // Debug mode
     141        if ( defined( 'CSCF_SMTP_DEBUG' ) && CSCF_SMTP_DEBUG ) {
     142            $phpmailer->SMTPDebug = 2;
     143        }
     144    });
     145}
    93146
    94147/*get the current version and update options to the new option*/
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/js/jquery.validate.contact.form.js

    r2551686 r3339262  
    77    $form.find("#recaptcha_response_field").focus(function () {
    88
    9         $errele = $form.find("div[for='cscf_recaptcha']");
     9        $errele = $form.find("span[for='cscf_recaptcha']");
    1010        $errele.html('');
    1111
     
    5656                            jQuery('html,body')
    5757                                .animate({
    58                                     scrollTop: jQuery($div.selector)
    59                                         .offset().top
     58                                    scrollTop: $div.offset().top
    6059                                }, 'slow');
    6160                        }
     
    6362
    6463                    else {
     64                        // Clear any previous errors first
     65                        $form.find("span.help-inline.help-block.error").html('').css('display', 'none');
     66                        $form.find('.form-group').removeClass('has-error').addClass('has-success');
     67                        $form.find('.control-group').removeClass('error').addClass('success');
     68                       
    6569                        $.each(response.errorlist, function (name, value) {
    66                             $errele = $form.find("div[for='cscf_" + name + "']");
    67                             $errele.html(value);
    68                             $errele.closest('.form-group').removeClass('has-success').addClass('has-error');
    69                             $errele.closest('.control-group').removeClass('success').addClass('error'); // support for bootstrap 2
     70                            // Debug logging
     71                            if (window.console) {
     72                                console.log("Error for field: " + name + ", message: " + value);
     73                            }
     74                           
     75                            $errele = $form.find("span[for='cscf_" + name + "']");
     76                            if ($errele.length > 0) {
     77                                $errele.html(value);
     78                                $errele.css('display', 'block');
     79                                $errele.closest('.form-group').removeClass('has-success').addClass('has-error');
     80                                $errele.closest('.control-group').removeClass('success').addClass('error'); // support for bootstrap 2
     81                            } else if (window.console) {
     82                                console.log("Could not find error element for: cscf_" + name);
     83                            }
    7084                        });
    7185                        $button.removeAttr("disabled");
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/languages/clean-and-simple-contact-form-by-meg-nicholas-pl_PL.po

    r3142234 r3339262  
    77"PO-Revision-Date: 2024-08-27 12:26+0100\n"
    88"Last-Translator: \n"
    9 "Language-Team: Kacper Ruciński <kacper.rucinski@gmail.com>\n"
     9"Language-Team: Kacper Ruciński\n"
    1010"Language: pl_PL\n"
    1111"MIME-Version: 1.0\n"
     
    4242#: clean-and-simple-contact-form-by-meg-nicholas/views/contact-form.view.php:34
    4343msgid "Please give your name."
    44 msgstr "Prosimy wpisać imię i nazwisko."
     44msgstr "Prosimy się przedstawić."
    4545
    4646#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:110
    4747msgid "Please enter a message."
    48 msgstr "Prosimy wpisać wiadomość."
     48msgstr "Prosimy wprowadzić wiadomość."
    4949
    5050#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:115,
     
    5252#: clean-and-simple-contact-form-by-meg-nicholas/views/contact-form.view.php:93
    5353msgid "Please enter a valid email address."
    54 msgstr "Prosimy wpisać poprawny adres e-mail."
     54msgstr "Prosimy wprowadzić poprawny adres e-mail."
    5555
    5656#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:121
    5757msgid "Please enter a valid phone number."
    58 msgstr "Pros wprowadzić poprawny numer telefonu."
     58msgstr "Prosimy wprowadzić poprawny numer telefonu."
    5959
    6060#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:128,
     
    6565#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:137
    6666msgid "Please solve the recaptcha to continue."
    67 msgstr "Proszę rozwiązać recaptcha, aby kontynuować."
     67msgstr "Prosimy rozwiązać reCAPTCHA, aby kontynuować."
    6868
    6969#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:170
     
    8282#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:175
    8383msgid "Page URL"
    84 msgstr "Strona URL"
     84msgstr "URL strony"
    8585
    8686#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_contact.php:176,
     
    129129#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:30
    130130msgid "Contact Form Settings"
    131 msgstr "Ustawienia Contact Form"
     131msgstr "Ustawienia formularza kontaktowego"
    132132
    133133#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:31
    134134msgid "Contact Form"
    135 msgstr "Contact Form"
     135msgstr "Formularz kontaktowy"
    136136
    137137#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:43
    138138msgid "Clean and Simple Contact Form Settings"
    139 msgstr "Ustawienia Clean and Simple Contact Form"
     139msgstr "Ustawienia wtyczki Przejrzysty i prosty formularz kontaktowy"
    140140
    141141#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:52
     
    223223"Use the plugin default stylesheet (un-tick to use your theme style sheet "
    224224"instead) :"
    225 msgstr "Użyj domyślnego stylu wtyczki (odznacz, aby użyć stylów motywu "
     225msgstr "Użyj domyślnego stylu wtyczki (odznacz, aby użyć stylów motywu):"
    226226
    227227#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:168
     
    235235#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:187
    236236msgid "Use reCAPTCHA :"
    237 msgstr "Użyj reCAPTCHA :"
     237msgstr "Użyj reCAPTCHA:"
    238238
    239239#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:194
     
    255255msgstr ""
    256256"Najlepszym sposobem na okazanie uznania dla tej darmowej wtyczki i "
    257 "utrzymanie jej jest wsparcie jej poprzez zainstalowanie Fullworks Anti Spam "
     257"jej utrzymanie jest wsparcie jej poprzez zainstalowanie Fullworks Anti Spam "
    258258"Pro"
    259259
     
    263263"compare it with Akismet, yet extremely effective."
    264264msgstr ""
    265 "Dzięki 14-dniowemu bezpłatnemu okresowi próbnemu jest on zaskakująco "
    266 "przystępny cenowo w porównaniu z Akismet, a jednocześnie niezwykle skuteczny."
     265"Oferując darmowy 14-dniowy okres próbny, jest on zaskakująco przystępny "
     266"cenowo w porównaniu z Akismet, a jednocześnie niezwykle skuteczny."
    267267
    268268#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:226,
     
    273273#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:221
    274274msgid "Congratulations: you are protected by Fullworks Anti Spam"
    275 msgstr "Gratulacje: jesteś chroniony przez Fullworks Anti Spam"
     275msgstr "Gratulacje! Ochronę zapewnia Ci Fullworks Anti Spam"
    276276
    277277#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:222
    278278msgid "Configure"
    279 msgstr "Konfiguracja"
     279msgstr "Skonfiguruj"
    280280
    281281#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:222
     
    291291"With a 14 day free trial, will automatically log all messages from this form."
    292292msgstr ""
    293 "Dzięki 14-dniowemu bezpłatnemu okresowi próbnemu automatycznie rejestruje "
    294 "wszystkie wiadomości z tego formularza."
     293"Oferując darmowy 14-dniowy okres próbny, automatycznie rejestruje wszystkie "
     294"wiadomości z tego formularza."
    295295
    296296#: clean-and-simple-contact-form-by-meg-nicholas/class.cscf_settings.php:243
     
    402402
    403403#~ msgid "Clean and Simple Contact Form!"
    404 #~ msgstr "Clean and Simple Contact Form!"
     404#~ msgstr "Przejrzysty i prosty formularz kontaktowy!"
    405405
    406406#~ msgid "You are using version"
     
    420420
    421421#~ msgid "*New*"
    422 #~ msgstr "*Nowe*"
     422#~ msgstr "*Nowość*"
    423423
    424424#~ msgid "Clean and Simple Contact Form"
    425 #~ msgstr "Czyste i proste Formularz kontaktowy"
     425#~ msgstr "Przejrzysty i prosty formularz kontaktowy"
    426426
    427427#~ msgid ""
     
    436436#~ "Bootstrap markup."
    437437#~ msgstr ""
    438 #~ "Czysty i prosty formularz kontaktowy z Google i Twitter Bootstrap "
    439 #~ "reCAPTCHA znaczników."
     438#~ "Przejrzysty i prosty formularz kontaktowy z Google reCAPTCHA i znacznikami "
     439#~ Twitter Bootstrap."
    440440
    441441#~ msgid "Meghan Nicholas"
     
    446446
    447447#~ msgid "Sorry the code wasn't entered correctly please try again."
    448 #~ msgstr ""
    449 #~ "Przepraszamy, kod nie został wprowadzony poprawnie. Spróbuj ponownie."
     448#~ msgstr "Przepraszamy, kod nie został wprowadzony poprawnie. Spróbuj ponownie."
    450449
    451450#~ msgid "Red"
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/languages/clean-and-simple-contact-form-by-meg-nicholas.pot

    r3254319 r3339262  
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Clean and Simple Contact Form 4.10\n"
     5"Project-Id-Version: Contact Form Clean and Simple 4.11\n"
    66"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/clean-and-simple-contact-form-by-meg-nicholas\n"
    77"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
     
    1010"Content-Type: text/plain; charset=UTF-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "POT-Creation-Date: 2025-03-10T17:28:16+00:00\n"
     12"POT-Creation-Date: 2025-08-04T19:28:59+00:00\n"
    1313"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
    1414"X-Generator: WP-CLI 2.10.0\n"
     
    1717#. Plugin Name of the plugin
    1818#: clean-and-simple-contact-form-by-meg-nicholas.php
    19 msgid "Clean and Simple Contact Form"
     19msgid "Contact Form Clean and Simple"
    2020msgstr ""
    2121
     
    4040msgstr ""
    4141
    42 #: class.cscf.php:68
    43 msgid "Settings"
    44 msgstr ""
    45 
    46 #: class.cscf_contact.php:91
     42#: class.cscf_contact.php:133
    4743msgid "Sorry the email addresses do not match."
    4844msgstr ""
    4945
    50 #: class.cscf_contact.php:97
     46#: class.cscf_contact.php:139
    5147#: views/contact-form.view.php:63
    5248msgid "Please give your email address."
    5349msgstr ""
    5450
    55 #: class.cscf_contact.php:103
     51#: class.cscf_contact.php:145
    5652msgid "Please confirm your email address."
    5753msgstr ""
    5854
    59 #: class.cscf_contact.php:109
     55#: class.cscf_contact.php:151
    6056#: views/contact-form.view.php:34
    6157msgid "Please give your name."
    6258msgstr ""
    6359
    64 #: class.cscf_contact.php:114
     60#: class.cscf_contact.php:156
    6561msgid "Please enter a message."
    6662msgstr ""
    6763
    68 #: class.cscf_contact.php:119
     64#: class.cscf_contact.php:161
    6965#: views/contact-form.view.php:64
    7066#: views/contact-form.view.php:93
     
    7268msgstr ""
    7369
    74 #: class.cscf_contact.php:125
     70#: class.cscf_contact.php:167
    7571msgid "Please enter a valid phone number."
    7672msgstr ""
    7773
    78 #: class.cscf_contact.php:132
     74#: class.cscf_contact.php:174
    7975#: views/contact-form.view.php:198
    8076msgid "Please give your consent."
    8177msgstr ""
    8278
    83 #: class.cscf_contact.php:142
     79#: class.cscf_contact.php:184
    8480msgid "Please solve the recaptcha to continue."
    8581msgstr ""
    8682
    87 #: class.cscf_contact.php:175
     83#: class.cscf_contact.php:220
    8884msgid "From"
    8985msgstr ""
    9086
    91 #: class.cscf_contact.php:176
     87#: class.cscf_contact.php:221
    9288msgid "Email"
    9389msgstr ""
    9490
    95 #: class.cscf_contact.php:178
    96 #: class.cscf_contact.php:219
     91#: class.cscf_contact.php:223
     92#: class.cscf_contact.php:267
    9793msgid "Phone"
    9894msgstr ""
    9995
    100 #: class.cscf_contact.php:180
     96#: class.cscf_contact.php:225
    10197msgid "Page URL"
    10298msgstr ""
    10399
    104 #: class.cscf_contact.php:181
    105 #: class.cscf_contact.php:221
     100#: class.cscf_contact.php:226
     101#: class.cscf_contact.php:269
    106102msgid "Message"
    107103msgstr ""
    108104
    109 #: class.cscf_contact.php:183
    110 #: class.cscf_contact.php:216
     105#: class.cscf_contact.php:228
     106#: class.cscf_contact.php:264
    111107msgid "yes"
    112108msgstr ""
    113109
    114 #: class.cscf_contact.php:183
    115 #: class.cscf_contact.php:216
     110#: class.cscf_contact.php:228
     111#: class.cscf_contact.php:264
    116112msgid "no"
    117113msgstr ""
    118114
    119 #: class.cscf_contact.php:214
     115#: class.cscf_contact.php:262
    120116msgid "Here is a copy of your message :"
    121117msgstr ""
     
    141137msgstr ""
    142138
     139#: class.cscf_rest_api.php:48
     140msgid "Authentication required."
     141msgstr ""
     142
     143#: class.cscf_rest_api.php:58
     144msgid "Insufficient permissions."
     145msgstr ""
     146
     147#: class.cscf_rest_api.php:96
     148msgid "Validation failed."
     149msgstr ""
     150
     151#: class.cscf_rest_api.php:110
     152msgid "Failed to send email."
     153msgstr ""
     154
    143155#: class.cscf_settings.php:29
    144156msgid "Contact Form Settings"
     
    261273msgstr ""
    262274
    263 #: class.cscf_settings.php:224
     275#: class.cscf_settings.php:222
     276msgid "REST API Settings"
     277msgstr ""
     278
     279#: class.cscf_settings.php:229
     280msgid "Enable REST API :"
     281msgstr ""
     282
     283#: class.cscf_settings.php:235
     284msgid "Required User Capability :"
     285msgstr ""
     286
     287#: class.cscf_settings.php:247
    264288msgid "Congratulations: you are protected by Fullworks Anti Spam"
    265289msgstr ""
    266290
    267 #: class.cscf_settings.php:225
     291#: class.cscf_settings.php:248
    268292msgid "Configure"
    269293msgstr ""
    270294
    271 #: class.cscf_settings.php:225
     295#: class.cscf_settings.php:248
    272296msgid "Anti Spam Settings here"
    273297msgstr ""
    274298
    275 #: class.cscf_settings.php:227
     299#: class.cscf_settings.php:250
    276300msgid "The best way to show your appreciation for this free plugin and keep it maintained is to support it by installing Fullworks Anti Spam Pro"
    277301msgstr ""
    278302
    279 #: class.cscf_settings.php:228
     303#: class.cscf_settings.php:251
    280304msgid "With a 14 day free trial, you will find it surprisingly affordable when you compare it with Akismet, yet extremely effective."
    281305msgstr ""
    282306
    283 #: class.cscf_settings.php:229
    284 #: class.cscf_settings.php:232
     307#: class.cscf_settings.php:252
     308#: class.cscf_settings.php:255
    285309msgid "Try Fullworks Anti Spam Pro now and support the maintenance this FREE contact form plugin"
    286310msgstr ""
    287311
    288 #: class.cscf_settings.php:239
     312#: class.cscf_settings.php:262
    289313msgid "Message logging is enabled by  Fullworks Anti Spam Pro"
    290314msgstr ""
    291315
    292 #: class.cscf_settings.php:241
     316#: class.cscf_settings.php:264
    293317msgid "View Logs here"
    294318msgstr ""
    295319
    296 #: class.cscf_settings.php:243
     320#: class.cscf_settings.php:266
    297321msgid "Enable message log by installing Fullworks Anti Spam Pro"
    298322msgstr ""
    299323
    300 #: class.cscf_settings.php:244
     324#: class.cscf_settings.php:267
    301325msgid "With a 14 day free trial, will automatically log all messages from this form."
    302326msgstr ""
    303327
    304 #: class.cscf_settings.php:245
     328#: class.cscf_settings.php:268
    305329msgid "Enable logs now"
    306330msgstr ""
    307331
    308 #: class.cscf_settings.php:332
     332#: class.cscf_settings.php:364
    309333msgid "Enter your reCAPTCHA settings below :"
    310334msgstr ""
    311335
    312 #: class.cscf_settings.php:333
     336#: class.cscf_settings.php:365
    313337msgid "To use reCAPTCHA you must get an API key from"
    314338msgstr ""
    315339
    316 #: class.cscf_settings.php:338
     340#: class.cscf_settings.php:370
    317341msgid "Enter your message settings below :"
    318342msgstr ""
    319343
    320 #: class.cscf_settings.php:459
     344#: class.cscf_settings.php:381
     345msgid "Enable REST API support for headless WordPress implementations."
     346msgstr ""
     347
     348#: class.cscf_settings.php:383
     349msgid "When enabled, authenticated users can submit the form via: POST /wp-json/cscf/v1/submit"
     350msgstr ""
     351
     352#: class.cscf_settings.php:396
     353msgid "use recaptcha"
     354msgstr ""
     355
     356#: class.cscf_settings.php:403
     357msgid "load stylesheet"
     358msgstr ""
     359
     360#: class.cscf_settings.php:410
     361msgid "recaptcha public key"
     362msgstr ""
     363
     364#: class.cscf_settings.php:418
     365msgid "recaptcha private key"
     366msgstr ""
     367
     368#: class.cscf_settings.php:430
     369msgid "recipient email"
     370msgstr ""
     371
     372#: class.cscf_settings.php:437
     373msgid "add button for new recipient email"
     374msgstr ""
     375
     376#: class.cscf_settings.php:443
     377msgid "remove button for new recipient email"
     378msgstr ""
     379
     380#: class.cscf_settings.php:457
     381msgid "confirm email"
     382msgstr ""
     383
     384#: class.cscf_settings.php:464
     385msgid "override from address"
     386msgstr ""
     387
     388#: class.cscf_settings.php:471
     389msgid "email to sender"
     390msgstr ""
     391
     392#: class.cscf_settings.php:478
     393msgid "contact consent"
     394msgstr ""
     395
     396#: class.cscf_settings.php:484
     397msgid "contact consent message"
     398msgstr ""
     399
     400#: class.cscf_settings.php:492
     401msgid "phone number"
     402msgstr ""
     403
     404#: class.cscf_settings.php:499
     405msgid "phone number mandatory"
     406msgstr ""
     407
     408#: class.cscf_settings.php:506
     409msgid "from email address"
     410msgstr ""
     411
     412#: class.cscf_settings.php:513
     413msgid "email subject"
     414msgstr ""
     415
     416#: class.cscf_settings.php:519
     417msgid "sent message heading"
     418msgstr ""
     419
     420#: class.cscf_settings.php:526
     421msgid "sent message body"
     422msgstr ""
     423
     424#: class.cscf_settings.php:532
     425msgid "message"
     426msgstr ""
     427
     428#: class.cscf_settings.php:540
     429msgid "recaptcha theme"
     430msgstr ""
     431
     432#: class.cscf_settings.php:545
    321433msgid "Light"
    322434msgstr ""
    323435
    324 #: class.cscf_settings.php:461
     436#: class.cscf_settings.php:547
    325437msgid "Dark"
     438msgstr ""
     439
     440#: class.cscf_settings.php:554
     441msgid "use client validation"
     442msgstr ""
     443
     444#: class.cscf_settings.php:561
     445msgid "enable REST API"
     446msgstr ""
     447
     448#: class.cscf_settings.php:568
     449msgid "REST API required capability"
     450msgstr ""
     451
     452#: class.cscf_settings.php:572
     453msgid "Default: edit_posts. Common capabilities: edit_posts, publish_posts, manage_options"
     454msgstr ""
     455
     456#. translators: %s is the path to the view file
     457#: class.view.php:25
     458msgid "View %s not found"
    326459msgstr ""
    327460
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/readme.txt

    r3254319 r3339262  
    77License URI: http://www.gnu.org/licenses/gpl.html
    88Tags: contact, form, contact form, feedback form, bootstrap
    9 Tested up to: 6.7
    10 Stable tag: 4.10
     9Tested up to: 6.8
     10Stable tag: 4.11
    1111
    1212A clean and simple contact form with Bootstrap markup.
     
    1414
    1515== Description ==
    16 A clean and simple AJAX contact form with Google reCAPTCHA, Twitter Bootstrap markup and  spam filtering.
     16A clean and simple AJAX contact form with Google reCAPTCHA, Twitter Bootstrap markup, spam filtering, and REST API support for headless WordPress implementations.
    1717
    1818*   **Clean**: all user inputs are stripped in order to avoid cross-site scripting (XSS) vulnerabilities.
     
    2222*   **Stylish**: Use the included stylesheet or switch it off and use your own for seamless integration with your website.
    2323Uses **Twitter Bootstrap** classes.
     24
     25*   **REST API Support**: Enable headless WordPress implementations to submit forms via authenticated REST API endpoints.
    2426
    2527
     
    6668*   Original plugin written by an **experienced PHP programmer**, Megan Nicholas, the code is rock solid, safe, and rigorously tested as standard practice.
    6769
     70*   **Headless WordPress ready**. REST API support allows you to submit forms from decoupled frontends, mobile apps, or any external application with proper authentication.
     71
    6872Hopefully this plugin will fulfil all your needs.
    6973
     
    136140
    137141*   **Contact consent**: This option allows you to be GDPR compliant by adding a 'Consent to contact' check box at the bottom of the form.
     142
     143*   **Enable REST API**: Turn on REST API support to allow headless WordPress implementations to submit forms.
     144
     145*   **Required User Capability**: Set the minimum WordPress user capability required to use the REST API (default: edit_posts).
     146
     147
     148== REST API for Headless WordPress ==
     149
     150This plugin includes REST API support, making it perfect for headless WordPress implementations, mobile applications, and decoupled frontend frameworks like React, Vue.js, or Angular.
     151
     152= Enabling REST API =
     153
     1541. Go to the plugin settings page
     1552. Find the "REST API Settings" section
     1563. Check "Enable REST API"
     1574. Set the required user capability (default: edit_posts)
     1585. Save your settings
     159
     160= API Endpoint =
     161
     162**POST** `/wp-json/cscf/v1/submit`
     163
     164= Authentication =
     165
     166The REST API requires WordPress user authentication. Users must be logged in and have the capability specified in settings (default: edit_posts).
     167
     168For headless implementations, you can use:
     169- Application Passwords (WordPress 5.6+)
     170- JWT Authentication plugins
     171- OAuth plugins
     172- Basic Authentication (development only)
     173
     174= Request Format =
     175
     176Send a POST request with JSON body:
     177
     178```json
     179{
     180  "name": "John Doe",
     181  "email": "john@example.com",
     182  "confirm_email": "john@example.com",
     183  "message": "Your message here",
     184  "phone_number": "+1234567890",
     185  "contact_consent": true,
     186  "email_sender": false,
     187  "post_id": 123
     188}
     189```
     190
     191**Required fields:**
     192- `name`: Sender's name
     193- `email`: Sender's email address
     194- `message`: The message content
     195
     196**Optional fields:**
     197- `confirm_email`: Required if email confirmation is enabled in settings
     198- `phone_number`: Required if phone number is set as mandatory in settings
     199- `contact_consent`: Required if contact consent is enabled in settings
     200- `email_sender`: Set to true to send a copy to the sender
     201- `post_id`: The ID of the page/post where the form would normally be displayed
     202
     203= Response Format =
     204
     205**Success Response (200):**
     206```json
     207{
     208  "success": true,
     209  "message": "Message Sent"
     210}
     211```
     212
     213**Validation Error Response (400):**
     214```json
     215{
     216  "code": "validation_failed",
     217  "message": "Validation failed.",
     218  "data": {
     219    "status": 400,
     220    "errors": {
     221      "email": "Please enter a valid email address.",
     222      "message": "Please enter a message."
     223    }
     224  }
     225}
     226```
     227
     228**Authentication Error Response (401):**
     229```json
     230{
     231  "code": "rest_forbidden",
     232  "message": "Authentication required.",
     233  "data": {
     234    "status": 401
     235  }
     236}
     237```
     238
     239= Example Implementation =
     240
     241**JavaScript (fetch API):**
     242```javascript
     243const formData = {
     244  name: "John Doe",
     245  email: "john@example.com",
     246  confirm_email: "john@example.com",
     247  message: "This is a test message from the REST API"
     248};
     249
     250fetch('https://yoursite.com/wp-json/cscf/v1/submit', {
     251  method: 'POST',
     252  headers: {
     253    'Content-Type': 'application/json',
     254    'Authorization': 'Bearer YOUR_AUTH_TOKEN'
     255  },
     256  body: JSON.stringify(formData)
     257})
     258.then(response => response.json())
     259.then(data => {
     260  if (data.success) {
     261    console.log('Message sent successfully!');
     262  } else {
     263    console.error('Validation errors:', data.data.errors);
     264  }
     265});
     266```
     267
     268= Important Notes =
     269
     270- REST API is disabled by default for security
     271- reCAPTCHA is bypassed for REST API submissions (authentication provides security)
     272- All other form validations and spam filtering still apply
     273- Form submissions via REST API are processed identically to regular submissions
     274- Email notifications work the same way as standard form submissions
    138275
    139276
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/shortcodes/contact-form.php

    r2551686 r3339262  
    99    if ( $contact->IsValid() ) {
    1010        if ( $contact->SendMail() ) {
     11            // Action hook for standard form submission
     12            do_action( 'cscf_form_submitted_standard', $contact );
     13           
    1114            $view = new CSCF_View( 'message-sent' );
    1215            $view->Set( 'heading', cscf_PluginSettings::SentMessageHeading() );
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/vendor/autoload.php

    r3254319 r3339262  
    1515        }
    1616    }
    17     trigger_error(
    18         $err,
    19         E_USER_ERROR
    20     );
     17    throw new RuntimeException($err);
    2118}
    2219
    2320require_once __DIR__ . '/composer/autoload_real.php';
    2421
    25 return ComposerAutoloaderInitde3652cf7e4bf8e2010815060c1bc76c::getLoader();
     22return ComposerAutoloaderInit27d86f03d1c986263483b369986ee068::getLoader();
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/vendor/composer/InstalledVersions.php

    r3254319 r3339262  
    2828{
    2929    /**
     30     * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to
     31     * @internal
     32     */
     33    private static $selfDir = null;
     34
     35    /**
    3036     * @var mixed[]|null
    3137     * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
    3238     */
    3339    private static $installed;
     40
     41    /**
     42     * @var bool
     43     */
     44    private static $installedIsLocalDir;
    3445
    3546    /**
     
    310321        self::$installed = $data;
    311322        self::$installedByVendor = array();
     323
     324        // when using reload, we disable the duplicate protection to ensure that self::$installed data is
     325        // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
     326        // so we have to assume it does not, and that may result in duplicate data being returned when listing
     327        // all installed packages for example
     328        self::$installedIsLocalDir = false;
     329    }
     330
     331    /**
     332     * @return string
     333     */
     334    private static function getSelfDir()
     335    {
     336        if (self::$selfDir === null) {
     337            self::$selfDir = strtr(__DIR__, '\\', '/');
     338        }
     339
     340        return self::$selfDir;
    312341    }
    313342
     
    323352
    324353        $installed = array();
     354        $copiedLocalDir = false;
    325355
    326356        if (self::$canGetVendors) {
     357            $selfDir = self::getSelfDir();
    327358            foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
     359                $vendorDir = strtr($vendorDir, '\\', '/');
    328360                if (isset(self::$installedByVendor[$vendorDir])) {
    329361                    $installed[] = self::$installedByVendor[$vendorDir];
     
    331363                    /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
    332364                    $required = require $vendorDir.'/composer/installed.php';
    333                     $installed[] = self::$installedByVendor[$vendorDir] = $required;
    334                     if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
    335                         self::$installed = $installed[count($installed) - 1];
     365                    self::$installedByVendor[$vendorDir] = $required;
     366                    $installed[] = $required;
     367                    if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
     368                        self::$installed = $required;
     369                        self::$installedIsLocalDir = true;
    336370                    }
     371                }
     372                if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
     373                    $copiedLocalDir = true;
    337374                }
    338375            }
     
    351388        }
    352389
    353         if (self::$installed !== array()) {
     390        if (self::$installed !== array() && !$copiedLocalDir) {
    354391            $installed[] = self::$installed;
    355392        }
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/vendor/composer/autoload_real.php

    r3254319 r3339262  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInitde3652cf7e4bf8e2010815060c1bc76c
     5class ComposerAutoloaderInit27d86f03d1c986263483b369986ee068
    66{
    77    private static $loader;
     
    2525        require __DIR__ . '/platform_check.php';
    2626
    27         spl_autoload_register(array('ComposerAutoloaderInitde3652cf7e4bf8e2010815060c1bc76c', 'loadClassLoader'), true, true);
     27        spl_autoload_register(array('ComposerAutoloaderInit27d86f03d1c986263483b369986ee068', 'loadClassLoader'), true, true);
    2828        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
    29         spl_autoload_unregister(array('ComposerAutoloaderInitde3652cf7e4bf8e2010815060c1bc76c', 'loadClassLoader'));
     29        spl_autoload_unregister(array('ComposerAutoloaderInit27d86f03d1c986263483b369986ee068', 'loadClassLoader'));
    3030
    3131        require __DIR__ . '/autoload_static.php';
    32         call_user_func(\Composer\Autoload\ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::getInitializer($loader));
     32        call_user_func(\Composer\Autoload\ComposerStaticInit27d86f03d1c986263483b369986ee068::getInitializer($loader));
    3333
    3434        $loader->register(true);
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/vendor/composer/autoload_static.php

    r3254319 r3339262  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c
     7class ComposerStaticInit27d86f03d1c986263483b369986ee068
    88{
    99    public static $prefixLengthsPsr4 = array (
     
    3838    {
    3939        return \Closure::bind(function () use ($loader) {
    40             $loader->prefixLengthsPsr4 = ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::$prefixLengthsPsr4;
    41             $loader->prefixDirsPsr4 = ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::$prefixDirsPsr4;
    42             $loader->prefixesPsr0 = ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::$prefixesPsr0;
    43             $loader->classMap = ComposerStaticInitde3652cf7e4bf8e2010815060c1bc76c::$classMap;
     40            $loader->prefixLengthsPsr4 = ComposerStaticInit27d86f03d1c986263483b369986ee068::$prefixLengthsPsr4;
     41            $loader->prefixDirsPsr4 = ComposerStaticInit27d86f03d1c986263483b369986ee068::$prefixDirsPsr4;
     42            $loader->prefixesPsr0 = ComposerStaticInit27d86f03d1c986263483b369986ee068::$prefixesPsr0;
     43            $loader->classMap = ComposerStaticInit27d86f03d1c986263483b369986ee068::$classMap;
    4444
    4545        }, null, ClassLoader::class);
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/vendor/composer/installed.php

    r3254319 r3339262  
    22    'root' => array(
    33        'name' => 'fullworks/clean-and-simple-contact-form',
    4         'pretty_version' => 'dev-main',
    5         'version' => 'dev-main',
    6         'reference' => '6057cf8bf7c1cd56b1f7d6b170e7208543f25dde',
     4        'pretty_version' => 'v4.11',
     5        'version' => '4.11.0.0',
     6        'reference' => '801b967317613364d9e34394960f064495cb2283',
    77        'type' => 'wordpress-plugin',
    88        'install_path' => __DIR__ . '/../../',
     
    3030        ),
    3131        'fullworks/clean-and-simple-contact-form' => array(
    32             'pretty_version' => 'dev-main',
    33             'version' => 'dev-main',
    34             'reference' => '6057cf8bf7c1cd56b1f7d6b170e7208543f25dde',
     32            'pretty_version' => 'v4.11',
     33            'version' => '4.11.0.0',
     34            'reference' => '801b967317613364d9e34394960f064495cb2283',
    3535            'type' => 'wordpress-plugin',
    3636            'install_path' => __DIR__ . '/../../',
  • clean-and-simple-contact-form-by-meg-nicholas/trunk/vendor/composer/platform_check.php

    r3142234 r3339262  
    2020        }
    2121    }
    22     trigger_error(
    23         'Composer detected issues in your platform: ' . implode(' ', $issues),
    24         E_USER_ERROR
     22    throw new \RuntimeException(
     23        'Composer detected issues in your platform: ' . implode(' ', $issues)
    2524    );
    2625}
Note: See TracChangeset for help on using the changeset viewer.