Skip to content
Merged
2 changes: 1 addition & 1 deletion config.php
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
// Plugin version.
if ( ! defined( 'ATBDP_VERSION' ) ) {
define( 'ATBDP_VERSION', '8.8.6' );
define( 'ATBDP_VERSION', '8.8.7' );
}
// Plugin Folder Path.
if ( ! defined( 'ATBDP_DIR' ) ) {
Expand Down
2 changes: 1 addition & 1 deletion directorist-base.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: Directorist - Business Directory Solution
* Plugin URI: https://wpwax.com
* Description: A comprehensive solution to create professional looking directory site of any kind. Like Yelp, Foursquare, etc.
* Version: 8.8.6
* Version: 8.8.7
* Requires PHP: 7.4
* Author: wpWax
* Author URI: https://wpwax.com
Expand Down
54 changes: 51 additions & 3 deletions includes/classes/class-ajax-handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -949,14 +949,62 @@ public function atbdp_post_attachment_upload() {
throw new \Exception( __( 'Invalid directory type!', 'directorist' ), 400 );
}

$fixed_file = ( ! empty( $_FILES[ $field_id . 'async-upload' ] ) ) ? directorist_clean( wp_unslash( $_FILES[ $field_id . 'async-upload' ] ) ) : '';
if ( empty( $post_id ) ) {
$upload_token = isset( $_POST['upload_token'] ) ? sanitize_text_field( wp_unslash( $_POST['upload_token'] ) ) : '';
$token_data = $upload_token ? get_transient( 'directorist_file_upload_' . $upload_token ) : false;

if (
empty( $token_data )
|| ! is_array( $token_data )
|| (int) ( $token_data['directory'] ?? 0 ) !== $directory
|| (string) ( $token_data['field_key'] ?? '' ) !== $field_id
) {
throw new \Exception( __( 'Invalid upload request!', 'directorist' ), 403 );
}
}

if ( ! empty( $post_id ) ) {
$post_type = get_post_type( $post_id );
$post_type_object = $post_type ? get_post_type_object( $post_type ) : null;

if ( ! $post_type_object || ! current_user_can( $post_type_object->cap->edit_post, $post_id ) ) {
throw new \Exception( __( 'You are not allowed to upload files for this post.', 'directorist' ), 403 );
}
}

$form_fields = get_term_meta( $directory, 'submission_form_fields', true );
$field_config = array_values( wp_list_filter( $form_fields['fields'], [ 'field_key' => $field_id ] ) );
$field_config = current( $field_config );
$field_config = [];

if ( ! empty( $form_fields['fields'] ) && is_array( $form_fields['fields'] ) ) {
$field_config = array_values( wp_list_filter( $form_fields['fields'], [ 'field_key' => $field_id ] ) );
$field_config = current( $field_config );
}

if ( empty( $field_config ) || ! is_array( $field_config ) || empty( $field_config['field_key'] ) || 'file' !== ( $field_config['type'] ?? '' ) ) {
throw new \Exception( __( 'Invalid upload field!', 'directorist' ), 400 );
}

$field_id = sanitize_text_field( $field_config['field_key'] );
$fixed_file = ( ! empty( $_FILES[ $field_id . 'async-upload' ] ) ) ? directorist_clean( wp_unslash( $_FILES[ $field_id . 'async-upload' ] ) ) : '';

if ( empty( $fixed_file ) ) {
throw new \Exception( __( 'No file supplied.', 'directorist' ), 400 );
}

$file_type = ! empty( $field_config['file_type'] ) ? $field_config['file_type'] : 'image';
$file_size = ! empty( $field_config['file_size'] ) ? $field_config['file_size'] : '2mb';
$max_size = wp_convert_hr_to_bytes( $file_size );

if ( $max_size > 0 && ! empty( $fixed_file['size'] ) && (int) $fixed_file['size'] > $max_size ) {
throw new \Exception(
sprintf(
/* translators: %s: maximum file size */
__( 'Uploaded file is larger than the allowed size of %s.', 'directorist' ),
size_format( $max_size )
),
400
);
}

if ( in_array( $file_type, [ '', 'all_types', 'all' ], true ) ) {
$file_types = directorist_get_supported_file_types();
Expand Down
192 changes: 178 additions & 14 deletions includes/classes/class-formgent.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,18 @@
if ( ! class_exists( 'ATBDP_Formgent' ) ) {
class ATBDP_Formgent
{
protected static $hooks_registered = false;
public function __construct() {
if ( self::$hooks_registered ) {
return;
}

self::$hooks_registered = true;

add_action( 'formgent_after_create_form_response_token', [ $this, 'after_create_form_response_token' ], 10, 3 );
add_action( 'rest_api_init', [ $this, 'rest_api_init' ] );

add_filter( 'formgent_email_send_to', [ $this, 'route_email_to_listing_owner' ], 10, 5 );
}

public function after_create_form_response_token( $response_token, $dto, \WP_REST_Request $wp_rest_request ) {
Expand All @@ -26,6 +35,161 @@ public function after_create_form_response_token( $response_token, $dto, \WP_RES
$response_repository->add_meta( $dto->get_id(), 'listing_id', absint( $external_data['listing_id'] ) );
}

public function route_email_to_listing_owner( $send_to, $email, $response, $form_answers_data, $queue ) {
$response_id = is_object( $queue ) && ! empty( $queue->response_id ) ? absint( $queue->response_id ) : 0;

if ( empty( $response_id ) ) {
return $send_to;
}

$listing_id = absint( formgent_response_repository()->get_meta_value( $response_id, 'listing_id' ) );

if ( empty( $listing_id ) ) {
return $send_to;
}

$should_route = ! $this->recipient_matches_form_email_answer( $send_to, $form_answers_data );

$should_route = (bool) apply_filters(
'directorist_formgent_route_email_to_listing_owner',
$should_route,
$listing_id,
$send_to,
$email,
$response,
$form_answers_data,
$queue
);

if ( ! $should_route ) {
return $send_to;
}

$recipient = $this->get_listing_owner_email_recipient( $listing_id );

$recipient = apply_filters(
'directorist_formgent_listing_owner_email_recipient',
$recipient,
$listing_id,
$send_to,
$email,
$response,
$form_answers_data,
$queue
);

$listing_owner_recipients = $this->normalize_email_recipients( $recipient );

if ( empty( $listing_owner_recipients ) ) {
return $send_to;
}

$send_to_recipients = $this->normalize_email_recipients( $send_to );
$recipients = array_values( array_unique( array_merge( $send_to_recipients, $listing_owner_recipients ) ) );

return count( $recipients ) > 1 ? $recipients : reset( $recipients );
}

protected function get_listing_owner_email_recipient( $listing_id ) {
$post_author_id = absint( get_post_field( 'post_author', $listing_id ) );

if ( empty( $post_author_id ) ) {
return '';
}

$contact_recipient = get_user_meta( $post_author_id, 'directorist_contact_owner_recipient', true );
$recipient_type = ! empty( $contact_recipient ) ? $contact_recipient : 'author';

if ( 'listing_email' === $recipient_type ) {
$listing_email = sanitize_email( get_post_meta( $listing_id, '_email', true ) );

if ( is_email( $listing_email ) ) {
return $listing_email;
}
}

$user = get_userdata( $post_author_id );

if ( empty( $user->user_email ) ) {
return '';
}

return sanitize_email( $user->user_email );
}

protected function recipient_matches_form_email_answer( $send_to, $form_answers_data ) {
$send_to_emails = $this->normalize_email_recipients( $send_to );

if ( empty( $send_to_emails ) || empty( $form_answers_data ) || ! is_array( $form_answers_data ) ) {
return false;
}

foreach ( $form_answers_data as $answer ) {
$field_type = '';
$value = '';

if ( is_object( $answer ) ) {
if ( method_exists( $answer, 'get_field_type' ) ) {
$field_type = $answer->get_field_type();
}

if ( method_exists( $answer, 'get_value' ) ) {
$value = $answer->get_value();
}
} elseif ( is_array( $answer ) ) {
$field_type = $answer['field_type'] ?? '';
$value = $answer['value'] ?? '';
}

if ( 'email' !== $field_type ) {
continue;
}

$answer_emails = $this->normalize_email_recipients( $value );

if ( array_intersect( $send_to_emails, $answer_emails ) ) {
return true;
}
}

return false;
}

protected function normalize_email_recipients( $emails ) {
if ( empty( $emails ) ) {
return [];
}

if ( is_array( $emails ) ) {
$normalized = [];

foreach ( $emails as $email ) {
$normalized = array_merge( $normalized, $this->normalize_email_recipients( $email ) );
}

return array_values( array_unique( $normalized ) );
}

if ( ! is_string( $emails ) ) {
return [];
}

preg_match_all( '/[A-Z0-9._%+\-]+@[A-Z0-9.\-]+\.[A-Z]{2,}/i', $emails, $matches );
$emails = ! empty( $matches[0] ) ? $matches[0] : preg_split( '/[,;]/', $emails );

$normalized = [];

foreach ( $emails as $email ) {
$email = sanitize_email( trim( $email ) );

if ( is_email( $email ) ) {
$normalized[] = strtolower( $email );
}
}

return array_values( array_unique( $normalized ) );
}

public function rest_api_init() {
register_rest_route(
'directorist', '/formgent/responses', [
Expand All @@ -34,31 +198,31 @@ public function rest_api_init() {
'permission_callback' => [ $this, 'check_permission' ],
]
);

register_rest_route(
'directorist', '/formgent/responses/kpis', [
'methods' => 'GET',
'callback' => [ $this, 'get_kpis' ],
'permission_callback' => [ $this, 'check_permission' ],
]
);

register_rest_route(
'directorist', '/formgent/responses', [
'methods' => 'DELETE',
'callback' => [ $this, 'delete_responses' ],
'permission_callback' => [ $this, 'check_permission' ],
]
);

register_rest_route(
'directorist', '/formgent/responses/read', [
'methods' => 'POST',
'callback' => [ $this, 'read_responses' ],
'permission_callback' => [ $this, 'check_permission' ],
]
);

register_rest_route(
'directorist', '/formgent/responses/single', [
'methods' => 'GET',
Expand All @@ -76,7 +240,7 @@ public function rest_api_init() {
*/
public function check_permission( $request ) {
$user_id = get_current_user_id();

// If user ID is 0, try to authenticate from cookies
if ( empty( $user_id ) && isset( $_COOKIE[ LOGGED_IN_COOKIE ] ) ) {
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- wp_validate_auth_cookie() handles sanitization
Expand All @@ -86,7 +250,7 @@ public function check_permission( $request ) {
wp_set_current_user( $user_id );
}
}

return ! empty( $user_id );
}

Expand Down Expand Up @@ -120,8 +284,8 @@ public function single_response( $request ) {
$listing_permalink = ATBDP_Permalink::get_listing_permalink( $listing_id, get_the_permalink( $listing_id ) );
}

return rest_ensure_response(
[
return rest_ensure_response(
[
'success' => true,
'response' => $response,
'fields' => $fields,
Expand Down Expand Up @@ -174,16 +338,16 @@ public function delete_responses( $request ) {
public function get_responses( $request ) {
$page = absint( $request->get_param( 'page' ) );
$per_page = absint( $request->get_param( 'per_page' ) );

$query = $this->get_responses_query();
$count_query = clone $query;

$responses = $query->select( 'response.*', 'post.post_title as listing_title', 'post.post_author as listing_owner' )->with(
'user', function( $query ) {
$query->select( 'ID', 'user_email', 'display_name' );
}
)->pagination( $page, $per_page );

$responses = array_map(
function( $response ) {
// Handle cases where user might be null (non-logged-in submissions)
Expand All @@ -201,7 +365,7 @@ function( $response ) {
return $response;
}, $responses
);

return [
'total' => $count_query->count(),
'responses' => $responses
Expand Down Expand Up @@ -347,11 +511,11 @@ protected function sanitize_response_field_options( array $options ) {

protected function get_responses_query() {
$user_id = get_current_user_id();

if ( empty( $user_id ) ) {
return Response::query( 'response' )->where( 'response.id', 0 );
}

return Response::query( 'response' )
->join(
ResponseMeta::get_table_name() . ' as response_meta', function( $join ) {
Expand Down
Loading
Loading