Skip to content
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Use standard HTML5 markup to create fully functional forms for WordPress
- Multilingual support with Polylang
- Predefined static HTML forms via filter hooks
- Dynamic values, like %USER_EMAIL% for pre-populating form data
- Simple spam prevention

## Why?

Expand Down Expand Up @@ -157,6 +158,39 @@ function my_email_thankyou( $return ) {
}
```

### Filter: wplf_honeypot

By default, forms has honeypot field to detect spambots. Submissions detected as spam are saved as a trash, so false positives can be detected. WordPress core cleans the trash after 30 days from saving. Turn off dy returning false.

```php
add_filter( 'wplf_honeypot' , '__return_false' );
```

### Filter: wplf_honeypot_field_name

Change the honeypot default field name (send_hugs_to_developers) to something else. Use obsecure but obiviosuly fake name.

```php
add_filter( 'wplf_honeypot_field_name' , 'please_send_candy' );
```

### Filter: wplf_save_spam

Submissions marked as spam are saved as a trash, so false positives can be detected. WordPress core cleans the trash after 30 days from saving. Turn off dy returning false.

```php
add_filter( 'wplf_save_spam' , '__return_false' );
```

#### Form specific hooks

This filter supports form specific hooks:

- `wplf_{form_id}_save_spam`
- `wplf_{form_slug}_save_spam`

These filters are only applied for the target form by ID or slug.

### Filter: wplf_disable_validate_additional_fields

Dynamically generated fields are disabled by default. If you want to allow fields that are not set in the form to be submitted you can use this filter.
Expand Down
6 changes: 5 additions & 1 deletion classes/class-cpt-wplf-form.php
Original file line number Diff line number Diff line change
Expand Up @@ -961,7 +961,11 @@ class="libre-form libre-form-<?php echo esc_attr( $id . ' ' . $xclass ); ?>"
<input type="hidden" name="referrer" value="<?php the_permalink(); ?>">
<input type="hidden" name="_referrer_id" value="<?php echo esc_attr( get_the_id() ); ?>">
<?php endif; ?>
<input type="hidden" name="_form_id" value="<?php echo esc_attr( $id ); ?>">
<input type="hidden" name="_form_id" value="<?php echo esc_attr( $id ); ?>">
<?php if ( apply_filters( 'wplf_honeypot', true ) ) :
$honeypot_name = apply_filters( 'wplf_honeypot_field_name', 'send_hugs_to_developers' ); ?>
<input type="checkbox" name="<?php echo esc_attr( $honeypot_name ); ?>" value="1" style="display:none !important" tabindex="-1" autocomplete="off">
<?php endif; ?>
</form>
<?php
$output = ob_get_clean();
Expand Down
18 changes: 18 additions & 0 deletions classes/class-cpt-wplf-submission.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public function __construct() {
add_action( 'manage_posts_custom_column', array( $this, 'custom_columns_display_cpt' ), 10, 2 );
add_action( 'restrict_manage_posts', array( $this, 'form_filter_dropdown' ) );
add_filter( 'pre_get_posts', array( $this, 'filter_by_form' ) );
add_filter( 'display_post_states', array( $this, 'post_states' ), 10, 2 );

// add custom bulk actions
add_action( 'admin_notices', array( $this, 'wplf_submission_bulk_action_admin_notice' ) );
Expand Down Expand Up @@ -174,6 +175,23 @@ public function filter_by_form( $query ) {
return $query;
}

/**
* Show if message is marked as spam
*/
public static function post_states( $post_states, $post ) {
if ( 'wplf-submission' !== $post->post_type ) {
return $post_states;
}

$is_spam = get_post_meta( $post->ID, '_is_spam', true );

if ( $is_spam ) {
$post_states['wplf_is_spam'] = __( 'Spam', 'wp-libre-form' );
}

return $post_states;
}

public function register_wplf_submission_bulk_actions( $bulk_actions ) {
$bulk_actions['wplf_resend_copy'] = __( 'Resend email copy', 'wp-libre-form' );
return $bulk_actions;
Expand Down
35 changes: 34 additions & 1 deletion inc/wplf-ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ function wplf_ajax_submit_handler() {

$return = new stdClass();
$return->ok = 1;
$return->spam = false;
$return->spam_save = true;

// allow user to pre-process the post fields
do_action( 'wplf_pre_validate_submission' );
Expand All @@ -26,16 +28,33 @@ function wplf_ajax_submit_handler() {
$return->title = $form->post_title;
$return = apply_filters( "wplf_{$form->post_name}_validate_submission", $return );
$return = apply_filters( "wplf_{$form->ID}_validate_submission", $return );

// allow save spam setting filtering
$return->spam_save = apply_filters( 'wplf_save_spam', $return->spam_save );
$return->spam_save = apply_filters( "wplf_{$form->post_name}_save_spam", $return->spam_save );
$return->spam_save = apply_filters( "wplf_{$form->ID}_save_spam", $return->spam_save );
}

// if message is spam and spam messages should not be saved as trash, return error.
if ( $return->spam && ! $return->spam_save ) {
$return->ok = 0;
$return->error = __( 'Something went wrong, please try again.', 'wp-libre-form' );
}

if ( $return->ok ) {
// the title is the value of whatever the first field was in the form
$title_format = get_post_meta( $form->ID, '_wplf_title_format', true );

// change post status to trash if spam, WP core cleans trash every 30 days
$post_status = 'publish';
if ( $return->spam ) {
$post_status = 'trash';
}

// create submission post
$post_id = wp_insert_post( array(
'post_title' => '',
'post_status' => 'publish',
'post_status' => $post_status,
'post_type' => 'wplf-submission',
) );

Expand Down Expand Up @@ -73,6 +92,20 @@ function wplf_ajax_submit_handler() {
}
}

// bail if spam submission
if ( $return->spam ) {
// mark submission as a spam
add_post_meta( $post_id, '_is_spam', true, true );

// set return
$return->ok = 0;
$return->error = __( 'Something went wrong, please try again.', 'wp-libre-form' );

// respond with json
wp_send_json( $return );
wp_die();
}

// handle files
$uploads_path = wp_upload_dir();
$should_store_images_in_medialibrary = get_post_meta( $form->ID, '_wplf_media_library', true );
Expand Down
28 changes: 26 additions & 2 deletions inc/wplf-form-validation.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,35 @@ function wplf_validate_form_exists( $return ) {
return $return;
}

/**
* Check simple honeypot form spam
*/
add_filter( 'wplf_validate_submission', 'wplf_validate_check_honeypot', 2 );
function wplf_validate_check_honeypot( $return ) {
// skip this validation if submission has already failed
if ( ! $return->ok ) {
return $return;
}

// skip this validation if honeypot is turned off
if ( ! apply_filters( 'wplf_honeypot', true ) ) {
return $return;
}

// check if honeypot exists and has some value, mark as spam if true
$honeypot_name = apply_filters( 'wplf_honeypot_field_name', 'send_hugs_to_developers' );

if ( ! empty( $_POST[ $honeypot_name ] ) && true === (bool) $_POST[ $honeypot_name ] ) {
$return->spam = true;
}

return $return;
}

/**
* Check for required fields that are empty
*/
add_filter( 'wplf_validate_submission', 'wplf_validate_required_empty', 2 );
add_filter( 'wplf_validate_submission', 'wplf_validate_required_empty', 3 );
function wplf_validate_required_empty( $return ) {
// skip this validation if submission has already failed
if ( ! $return->ok ) {
Expand Down Expand Up @@ -68,7 +92,7 @@ function wplf_validate_required_empty( $return ) {
/**
* Check that submission has only fields that are set in form
*/
add_filter( 'wplf_validate_submission', 'wplf_validate_additional_fields', 3 );
add_filter( 'wplf_validate_submission', 'wplf_validate_additional_fields', 4 );
function wplf_validate_additional_fields( $return ) {
// skip this validation if submission has already failed
if ( ! $return->ok ) {
Expand Down