Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/motors-car-dealership-classified-listings/elementor/MotorsElementorWidgetsFree.php
+++ b/motors-car-dealership-classified-listings/elementor/MotorsElementorWidgetsFree.php
@@ -119,6 +119,20 @@
public static function motors_ew_editor_enqueue_scripts() {
wp_enqueue_style( 'stm-elementor-icons', STM_LISTINGS_URL . '/assets/elementor/icons/style.css', array(), STM_LISTINGS_V );
wp_enqueue_style( 'motors-elementor-editor', STM_LISTINGS_URL . '/assets/elementor/css/editor.css', array(), STM_LISTINGS_V );
+
+ if ( apply_filters( 'mvl_is_addon_enabled', false, 'forms_editor' ) && defined( 'STM_LISTINGS_PRO_URL' ) && defined( 'STM_LISTINGS_PRO_V' ) ) {
+ if ( ! wp_style_is( 'mvl-forms', 'registered' ) ) {
+ $forms_css_path = STM_LISTINGS_PRO_URL . '/addons/FormsEditor/assets/css/mvl-forms.css';
+ wp_register_style(
+ 'mvl-forms',
+ $forms_css_path,
+ array(),
+ STM_LISTINGS_PRO_V,
+ 'all'
+ );
+ }
+ wp_enqueue_style( 'mvl-forms' );
+ }
}
public static function motors_ew_register_elementor_widget_categories() {
--- a/motors-car-dealership-classified-listings/elementor/inc/Widgets/LoginRegister.php
+++ b/motors-car-dealership-classified-listings/elementor/inc/Widgets/LoginRegister.php
@@ -38,6 +38,7 @@
$widget_styles = parent::get_style_depends();
$widget_styles[] = 'uniform';
$widget_styles[] = 'uniform-init';
+ $widget_styles[] = 'mvl-forms';
return $widget_styles;
}
--- a/motors-car-dealership-classified-listings/includes/actions.php
+++ b/motors-car-dealership-classified-listings/includes/actions.php
@@ -298,12 +298,24 @@
}
function stm_listings_ajax_save_user_data() {
- check_ajax_referer( 'stm_listings_user_data_nonce', 'security', false );
+ if ( ! check_ajax_referer( 'stm_listings_user_data_nonce', 'security', false ) ) {
+ wp_send_json(
+ array(
+ 'error' => true,
+ 'error_msg' => esc_html__( 'Security check failed. Please reload the page and try again.', 'stm_vehicles_listing' ),
+ )
+ );
+ }
$response = array();
if ( ! is_user_logged_in() ) {
- die( 'You are not logged in' );
+ wp_send_json(
+ array(
+ 'error' => true,
+ 'error_msg' => esc_html__( 'You are not logged in.', 'stm_vehicles_listing' ),
+ )
+ );
}
$got_error_validation = false;
@@ -312,9 +324,64 @@
$user_current = wp_get_current_user();
$user_id = $user_current->ID;
$user = apply_filters( 'stm_get_user_custom_fields', $user_id );
+ $is_forms_editor = apply_filters( 'mvl_is_addon_enabled', false, 'forms_editor' );
+ $forms_editor_email_slug = '';
/*Get current editing values*/
- $user_mail = apply_filters( 'stm_listings_input', $user['email'], 'stm_email' );
+ $default_user_mail = isset( $user['email'] ) ? $user['email'] : '';
+ $user_mail = apply_filters( 'stm_listings_input', $default_user_mail, 'stm_email' );
+ if ( $is_forms_editor ) {
+ if ( class_exists( 'MotorsVehiclesListingProAddonsFormsEditorConfigConfig' ) ) {
+ $sign_up_form_config = MotorsVehiclesListingProAddonsFormsEditorConfigConfig::instance_of( 'sign_up' );
+
+ if ( $sign_up_form_config ) {
+ $form_data = $sign_up_form_config->data();
+ $saved_values = $sign_up_form_config->get_values();
+ $form_data_fields = $form_data['fields'] ?? array();
+
+ foreach ( $form_data_fields as $field_id => $field_config ) {
+ if ( isset( $field_config['type'] ) && 'editable_zone' === $field_config['type'] ) {
+ $zone_fields = $saved_values[ $field_id ]['fields'] ?? $field_config['fields'] ?? array();
+
+ if ( ! empty( $zone_fields ) && ! isset( $zone_fields[0] ) ) {
+ $normalized_fields = array();
+ foreach ( $zone_fields as $zone_field_key => $zone_field_data ) {
+ $zone_field_data['id'] = $zone_field_key;
+ $normalized_fields[] = $zone_field_data;
+ }
+ $zone_fields = $normalized_fields;
+ }
+
+ foreach ( $zone_fields as $zone_field ) {
+ $field_type = $zone_field['type'] ?? '';
+ $field_settings = $zone_field['settings'] ?? array();
+ $field_slug = $zone_field['slug'] ?? '';
+ $field_id_name = $zone_field['id'] ?? '';
+ $has_show_email = ! empty( $field_settings['show_email'] );
+
+ if ( 'email' !== $field_type || ( ! $has_show_email && ! in_array( $field_slug, array( 'stm_user_mail', 'sign_up_stm_user_mail' ), true ) ) ) {
+ continue;
+ }
+
+ $email_post_keys = array_filter( array( $field_slug, $field_id_name ) );
+ foreach ( $email_post_keys as $email_post_key ) {
+ if ( ! empty( $_POST[ $email_post_key ] ) ) {
+ $forms_editor_email_slug = $email_post_key;
+ $user_mail = sanitize_email( wp_unslash( $_POST[ $email_post_key ] ) );
+ break 3;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ $forms_editor_user_mail = apply_filters( 'stm_listings_input', '', 'stm_user_mail' );
+ if ( empty( $user_mail ) && ! empty( $forms_editor_user_mail ) ) {
+ $user_mail = $forms_editor_user_mail;
+ }
+ }
$user_mail = sanitize_email( $user_mail );
/*Socials*/
$socs = array( 'facebook', 'twitter', 'linkedin', 'youtube' );
@@ -486,7 +553,9 @@
}
/*Author description*/
- $new_user_data['description'] = sanitize_textarea_field( $_POST['author_description'] );
+ if ( isset( $_POST['author_description'] ) ) {
+ $new_user_data['description'] = sanitize_textarea_field( $_POST['author_description'] );
+ }
$user_error = wp_update_user( $new_user_data );
if ( is_wp_error( $user_error ) ) {
@@ -498,19 +567,22 @@
Change fields with secondary privilegy*/
/*POST key => user_meta_key*/
$changed_info = array(
- 'stm_first_name' => 'first_name',
- 'stm_last_name' => 'last_name',
- 'stm_phone' => 'stm_phone',
- 'stm_user_facebook' => 'stm_user_facebook',
- 'stm_user_twitter' => 'stm_user_twitter',
- 'stm_user_linkedin' => 'stm_user_linkedin',
- 'stm_user_youtube' => 'stm_user_youtube',
+ 'stm_first_name' => 'first_name',
+ 'stm_last_name' => 'last_name',
+ 'stm_phone' => 'stm_phone',
+ 'stm_user_first_name' => 'first_name',
+ 'stm_user_last_name' => 'last_name',
+ 'stm_user_phone' => 'stm_phone',
+ 'stm_user_facebook' => 'stm_user_facebook',
+ 'stm_user_twitter' => 'stm_user_twitter',
+ 'stm_user_linkedin' => 'stm_user_linkedin',
+ 'stm_user_youtube' => 'stm_user_youtube',
);
foreach ( $changed_info as $change_to_key => $change_info ) {
if ( isset( $_POST[ $change_to_key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
$escaped_value = $_POST[ $change_to_key ];
- if ( 'stm_phone' === $change_to_key ) {
+ if ( in_array( $change_to_key, array( 'stm_phone', 'stm_user_phone' ), true ) ) {
$escaped_value = preg_replace( '/[^0-9+-()s]/', '', $escaped_value );
} else {
$escaped_value = sanitize_text_field( $escaped_value );
@@ -518,10 +590,39 @@
update_user_meta( $user_id, $change_info, $escaped_value );
}
}
+
+ // Save form editor fields if forms editor is enabled
+ if ( $is_forms_editor && class_exists( 'MotorsVehiclesListingProAddonsFormsEditorHelpersFormFieldsHandler' ) ) {
+ $forms_editor_skip_fields = array(
+ 'stm_nickname',
+ 'stm_user_password',
+ 'stm_user_first_name',
+ 'stm_user_last_name',
+ 'stm_user_phone',
+ 'stm_user_mail',
+ );
+
+ if ( ! empty( $forms_editor_email_slug ) && ! in_array( $forms_editor_email_slug, $forms_editor_skip_fields, true ) ) {
+ $forms_editor_skip_fields[] = $forms_editor_email_slug;
+ }
+
+ // Save sign_up form fields (skip password and nickname)
+ MotorsVehiclesListingProAddonsFormsEditorHelpersFormFieldsHandler::save_form_fields_to_user_meta(
+ $user_id,
+ 'sign_up',
+ array(
+ 'skip_fields' => $forms_editor_skip_fields,
+ 'preserve_existing_files' => true,
+ )
+ );
+ }
} else {
if ( $demo ) {
$error_msg = esc_html__( 'Site is on demo mode', 'stm_vehicles_listing' );
$got_error_validation = true;
+ } elseif ( ! $password_check ) {
+ $error_msg = esc_html__( 'Please enter your current password to confirm changes.', 'stm_vehicles_listing' );
+ $got_error_validation = true;
}
}
@@ -976,20 +1077,42 @@
}
$args['listing_id'] = isset( $_POST['car'] ) ? $_POST['car'] : 0;
- $args['car'] = get_the_title( $args['listing_id'] );
+ $args['car'] = $args['listing_id'] ? get_the_title( $args['listing_id'] ) : '';
$args['year'] = isset( $_POST['stm_year'] ) && $_POST['stm_year'] ? intval( $_POST['stm_year'] ) : 0;
- $user_id = get_post_meta( $args['listing_id'], 'stm_car_user', true );
+ $form_type = isset( $_POST['form_type'] ) ? sanitize_text_field( $_POST['form_type'] ) : 'trade_in';
+ $form_slug = isset( $_POST['form_slug'] ) ? sanitize_key( wp_unslash( $_POST['form_slug'] ) ) : $form_type;
- if ( ! $user_id ) {
- $user_id = get_post_field( 'post_author', $args['listing_id'] );
+ // Try to enrich smart tags and files via FormsEditor helper if available.
+ $helper_class = 'MotorsVehiclesListingProAddonsFormsEditorHelpersFormSubmission';
+ if ( class_exists( $helper_class ) ) {
+ $built = $helper_class::build( $form_slug, $_POST, $_FILES, $args );
+ if ( isset( $built['smart_tags'] ) && is_array( $built['smart_tags'] ) ) {
+ $args = $built['smart_tags'];
+ }
+ if ( isset( $built['attachments'] ) && is_array( $built['attachments'] ) ) {
+ $files = $built['attachments'];
+ }
}
- if ( ! empty( $args ) && $user_id ) {
+
+ $email_config = ( 'sell_your_car' === $form_type && apply_filters( 'mvl_is_addon_enabled', false, 'email_manager' ) ) ? 'sell_your_car' : 'trade_in';
+
+ if ( 'sell_your_car' === $form_type && apply_filters( 'mvl_is_addon_enabled', false, 'email_manager' ) ) {
+ $recipient_email = get_option( 'admin_email' );
+ } else {
+ $user_id = get_post_meta( $args['listing_id'], 'stm_car_user', true );
+ if ( ! $user_id ) {
+ $user_id = get_post_field( 'post_author', $args['listing_id'] );
+ }
+ $recipient_email = $user_id ? get_userdata( $user_id )->user_email : get_option( 'admin_email' );
+ }
+
+ if ( ! empty( $args ) && ! empty( $recipient_email ) ) {
do_action(
'mvl_send_email',
array(
- 'config' => 'trade_in',
+ 'config' => $email_config,
'files' => $files,
- 'to' => get_userdata( $user_id )->user_email,
+ 'to' => $recipient_email,
'smart_tags_args' => $args,
)
);
@@ -1021,7 +1144,11 @@
//Ajax request test drive
function stm_ajax_add_test_drive() {
check_ajax_referer( 'stm_add_test_drive_nonce', 'security', false );
- $response['errors'] = array();
+ $response = array(
+ 'errors' => array(),
+ 'status' => 'danger',
+ 'response' => '',
+ );
if ( ! isset( $_POST['name'] ) || ! $_POST['name'] ) {
$response['response'] = esc_html__( 'Please fill all fields', 'stm_vehicles_listing' );
@@ -1060,26 +1187,40 @@
$car_owner = get_post_meta( $vehicle_id, 'stm_car_user', true );
$car_owner = $car_owner ? $car_owner : get_post_field( 'post_author', $vehicle_id );
+ $send_to = '';
if ( ! empty( $car_owner ) ) {
-
$user_fields = stm_get_user_custom_fields( $car_owner );
if ( ! empty( $user_fields ) && ! empty( $user_fields['email'] ) ) {
$send_to = $user_fields['email'];
}
+ }
+
+ $smart_tags = array(
+ 'name' => isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '',
+ 'email' => isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '',
+ 'phone' => isset( $_POST['phone'] ) ? sanitize_text_field( wp_unslash( $_POST['phone'] ) ) : '',
+ 'date' => isset( $_POST['date'] ) ? sanitize_text_field( wp_unslash( $_POST['date'] ) ) : '',
+ 'listing_id' => intval( $vehicle_id ),
+ 'car' => get_the_title( $vehicle_id ),
+ );
+
+ $form_slug = isset( $_POST['form_slug'] ) ? sanitize_key( wp_unslash( $_POST['form_slug'] ) ) : 'test_drive';
+ $files = array();
+ $helper_class = 'MotorsVehiclesListingProAddonsFormsEditorHelpersFormSubmission';
+ if ( class_exists( $helper_class ) ) {
+ $built = $helper_class::build( $form_slug, $_POST, $_FILES, $smart_tags );
+ $smart_tags = $built['smart_tags'];
+ $files = $built['attachments'];
+ }
+ if ( ! empty( $send_to ) ) {
do_action(
'mvl_send_email',
array(
'config' => 'test_drive',
'to' => $send_to,
- 'smart_tags_args' => array(
- 'name' => sanitize_text_field( $_POST['name'] ),
- 'email' => sanitize_email( $_POST['email'] ),
- 'phone' => sanitize_text_field( $_POST['phone'] ),
- 'date' => sanitize_text_field( $_POST['date'] ),
- 'listing_id' => intval( $vehicle_id ),
- 'car' => get_the_title( $vehicle_id ),
- ),
+ 'files' => $files,
+ 'smart_tags_args' => $smart_tags,
)
);
}
--- a/motors-car-dealership-classified-listings/includes/admin/categories.php
+++ b/motors-car-dealership-classified-listings/includes/admin/categories.php
@@ -381,7 +381,7 @@
),
'group' => 'filter',
),
- 'dropdown_skins' => array(
+ 'dropdown_skins' => array(
'label' => esc_html__( 'Select a skin for this field that will be used in the inventory filter.', 'stm_vehicles_listing' ),
'type' => 'radio-image',
'dependency' => array(
@@ -402,7 +402,7 @@
),
'group' => 'skins',
),
- 'numeric_skins' => array(
+ 'numeric_skins' => array(
'label' => esc_html__( 'Select a skin for this field that will be used in the inventory filter.', 'stm_vehicles_listing' ),
'type' => 'radio-image',
'dependency' => array(
@@ -416,9 +416,14 @@
'url' => STM_LISTINGS_URL . '/assets/images/pro/custom_field_skins/numeric-1.png',
),
'skin_2' => array(
- 'label' => 'Range with Dropdowns',
- 'url' => STM_LISTINGS_URL . '/assets/images/pro/custom_field_skins/numeric-2.png',
- 'pro_field' => true,
+ 'label' => 'Range with Dropdowns',
+ 'url' => STM_LISTINGS_URL . '/assets/images/pro/custom_field_skins/numeric-2.png',
+ 'pro_field' => true,
+ 'dependency' => array(
+ 'slug' => 'slider',
+ 'value' => 'dropdown',
+ 'type' => 'not_empty',
+ ),
),
'skin_3' => array(
'label' => 'Range with Inputs',
@@ -605,6 +610,52 @@
echo wp_kses_post( apply_filters( 'stm_vl_depends_filter', $attributes ) );
}
+
+function motors_custom_field_choice_dependency( $attributes, $choice_args ) {
+ if ( empty( $choice_args['dependency'] ) ) {
+ return $attributes;
+ }
+
+ $dependency = $choice_args['dependency'];
+ $slugs = array();
+ $attr_list = array();
+
+ $is_multiple = ! empty( $dependency[0] ) && is_array( $dependency[0] );
+
+ if ( $is_multiple ) {
+ foreach ( $dependency as $dep_item ) {
+ if ( is_array( $dep_item ) && isset( $dep_item['slug'] ) ) {
+ $slugs[] = $dep_item['slug'];
+ foreach ( $dep_item as $key => $value ) {
+ if ( 'slug' !== $key ) {
+ $attr_list[ $key ] = 'data-' . $key . '="' . esc_attr( $value ) . '"';
+ }
+ }
+ }
+ }
+ } else {
+ foreach ( $dependency as $key => $value ) {
+ if ( 'slug' === $key ) {
+ $slugs[] = $value;
+ } else {
+ $attr_list[ $key ] = 'data-' . $key . '="' . esc_attr( $value ) . '"';
+ }
+ }
+ }
+
+ if ( empty( $slugs ) ) {
+ return $attributes;
+ }
+
+ $attributes = ' data-choice-depends-on="' . esc_attr( implode( ',', $slugs ) ) . '" ';
+ $attributes .= implode( ' ', $attr_list );
+ $attributes .= ' style="display: none;"';
+
+ return $attributes;
+}
+
+add_filter( 'stm_listings_choice_dependency_attributes', 'motors_custom_field_choice_dependency', 10, 2 );
+
function stm_vehicles_listing_has_preview( $settings ) {
$class = '';
--- a/motors-car-dealership-classified-listings/includes/admin/categories/field.php
+++ b/motors-car-dealership-classified-listings/includes/admin/categories/field.php
@@ -143,10 +143,32 @@
<?php endif; ?>
<div class="stm_custom_fields__radio--wrapper stm_custom_fields__radio-image-grid">
<?php
+ $default_options = motors_page_options();
+ $default_choices = isset( $default_options[ $field_key ]['choices'] ) ? $default_options[ $field_key ]['choices'] : array();
+
foreach ( $field['choices'] as $choice_value => $choice_args ) :
$checked = ( ! empty( $field['value'] ) ) ? checked( $field['value'], $choice_value, false ) : '';
+
+ if ( ! is_array( $choice_args ) ) {
+ $choice_args = array( 'label' => $choice_args );
+ }
+
+ if ( isset( $default_choices[ $choice_value ]['dependency'] ) ) {
+ $choice_args['dependency'] = $default_choices[ $choice_value ]['dependency'];
+ }
+
+ if ( 'numeric_skins' === $field_key && 'skin_2' === $choice_value && empty( $choice_args['dependency'] ) ) {
+ $choice_args['dependency'] = array(
+ 'slug' => 'slider',
+ 'value' => 'dropdown',
+ 'type' => 'not_empty',
+ );
+ }
+
+ $dep_attrs = apply_filters( 'stm_listings_choice_dependency_attributes', '', $choice_args );
+ $dep_classes = isset( $choice_args['pro_field'] ) && $choice_args['pro_field'] ? 'stm-pro-field' : '';
?>
- <div class="stm_custom_fields__radio--inside <?php echo isset( $choice_args['pro_field'] ) && $choice_args['pro_field'] ? 'stm-pro-field' : ''; ?>">
+ <div class="stm_custom_fields__radio--inside <?php echo esc_attr( $dep_classes ); ?>" <?php echo wp_kses_post( $dep_attrs ); ?>>
<?php if ( isset( $choice_args['pro_field'] ) && $choice_args['pro_field'] ) : ?>
<div class="stm-pro-field-inner">
<label for="<?php echo esc_attr( $prefix_id . $field_key . '-' . $choice_value ); ?>">
--- a/motors-car-dealership-classified-listings/includes/admin/setup-wizard/main.php
+++ b/motors-car-dealership-classified-listings/includes/admin/setup-wizard/main.php
@@ -12,17 +12,6 @@
function mvl_setup_wizard_sub_menu_admin_page_contents() {
require_once MVL_SETUP_WIZARD_TEMPLATES_PATH . 'index.php';
}
-function mvl_setup_wizard_admin_menu() {
- add_submenu_page(
- 'null',
- __( 'Welcome', 'stm_vehicles_listing' ),
- __( 'Hidden', 'stm_vehicles_listing' ),
- 'manage_options',
- 'mvl-welcome-setup',
- 'mvl_setup_wizard_sub_menu_admin_page_contents'
- );
-}
-add_action( 'admin_menu', 'mvl_setup_wizard_admin_menu' );
function mvl_plugin_activation() {
add_option( 'mvl_plugin_do_activation_redirect', true );
@@ -32,8 +21,12 @@
function mvl_plugin_redirect() {
if ( get_option( 'mvl_plugin_do_activation_redirect', false ) ) {
delete_option( 'mvl_plugin_do_activation_redirect' );
- if ( ! isset( $_GET['activate-multi'] ) && ! defined( 'MOTORS_THEME' ) ) {
- wp_safe_redirect( 'admin.php?page=mvl-welcome-setup' );
+ if ( ! get_option( 'mvl_has_been_activated', false ) ) {
+ update_option( 'mvl_has_been_activated', true );
+ if ( ! isset( $_GET['activate-multi'] ) && ! defined( 'MOTORS_THEME' ) ) {
+ wp_safe_redirect( 'admin.php?page=mvl-welcome-setup' );
+ exit;
+ }
}
}
}
--- a/motors-car-dealership-classified-listings/includes/class/Addons/Addons.php
+++ b/motors-car-dealership-classified-listings/includes/class/Addons/Addons.php
@@ -13,6 +13,7 @@
public const SAVED_SEARCH = 'saved_search';
public const EMAIL_MANAGER = 'email_manager';
public const CAR_INFO_AUTO_COMPLETE = 'car_info_auto_complete';
+ public const FORMS_EDITOR = 'forms_editor';
public static function all() : array {
return array(
@@ -21,6 +22,7 @@
self::SAVED_SEARCH,
self::EMAIL_MANAGER,
self::CAR_INFO_AUTO_COMPLETE,
+ self::FORMS_EDITOR,
);
}
@@ -33,16 +35,50 @@
);
}
+ public static function get_menu_badge_html( array $addon ) : string {
+ if ( empty( $addon['badge'] ) ) {
+ return '';
+ }
+ $color = isset( $addon['badge_color'] ) ? $addon['badge_color'] : '#dba617';
+ $text_color = isset( $addon['badge_text_color'] ) ? $addon['badge_text_color'] : '#fff';
+ $style = 'background-color:' . esc_attr( $color ) . '; color:' . esc_attr( $text_color );
+
+ return ' <span class="mvl-menu-badge" style="' . $style . '">' . esc_html( $addon['badge'] ) . '</span>';
+ }
+
public static function list() : array {
return array(
- self::VIN_DECODER => array(
- 'name' => esc_html__( 'VIN Decoder', 'stm_vehicles_listing' ),
- 'url' => esc_url( STM_LISTINGS_URL . '/assets/addons/img/VinDecoder.png' ),
- 'settings' => admin_url( 'admin.php?page=vin_decoders_settings' ),
- 'description' => esc_html__( 'Get a comprehensive overview of a vehicle’s history with important details like make and mileage by VIN number. Connect up to 5 VIN services for comprehensive insights.', 'stm_vehicles_listing' ),
+ self::FORMS_EDITOR => array(
+ 'name' => esc_html__( 'Form Builder', 'stm_vehicles_listing' ),
+ 'url' => esc_url( STM_LISTINGS_URL . '/assets/addons/img/FormsEditor.png' ),
+ 'settings' => home_url( 'motors/forms-editor/' ),
+ 'description' => esc_html__( 'Lets you fully customize Motors forms with a drag-and-drop editor. Add, remove, and reorder fields, choose from multiple field types, and adjust the form structure to match your business needs.', 'stm_vehicles_listing' ),
+ 'pro_url' => 'https://stylemixthemes.com/car-dealer-plugin/pricing/?utm_source=motorswpadmin&utm_campaign=motors-plugin&licenses=1&billing_cycle=annual',
+ 'documentation' => 'https://docs.stylemixthemes.com/motors-car-dealer-classifieds-and-listing/motors-pro-addons/forms-builder',
+ 'img_url' => 'forms-editor',
+ 'toggle' => true,
+ 'badge' => 'NEW',
+ 'badge_color' => '#ffaa0040',
+ 'badge_text_color' => '#ffaa00',
+ ),
+ self::EMAIL_MANAGER => array(
+ 'name' => esc_html__( 'Email Template Manager', 'stm_vehicles_listing' ),
+ 'url' => esc_url( STM_LISTINGS_URL . '/assets/addons/img/EmailManager.png' ),
+ 'settings' => apply_filters( 'mvl_email_manager_url', '' ),
+ 'description' => esc_html__( 'Manage your email templates and send them to your users.', 'stm_vehicles_listing' ),
+ 'pro_url' => 'https://stylemixthemes.com/car-dealer-plugin/pricing/?utm_source=motorswpadmin&utm_campaign=motors-plugin&licenses=1&billing_cycle=annual',
+ 'documentation' => 'https://docs.stylemixthemes.com/motors-car-dealer-classifieds-and-listing/motors-pro-addons/email-manager',
+ 'img_url' => 'email-manager',
+ 'toggle' => true,
+ ),
+ self::CAR_INFO_AUTO_COMPLETE => array(
+ 'name' => esc_html__( 'Car Info Autocomplete', 'stm_vehicles_listing' ),
+ 'url' => esc_url( STM_LISTINGS_URL . '/assets/addons/img/CarInfoAutoComplete.png' ),
+ 'settings' => admin_url( 'admin.php?page=car_info_auto_complete_settings' ),
+ 'description' => esc_html__( 'Automatically fill in vehicle details by selecting a make, model, year, or VIN. Speeds up listing creation and ensures accurate data.', 'stm_vehicles_listing' ),
+ 'documentation' => 'https://docs.stylemixthemes.com/motors-car-dealer-classifieds-and-listing/motors-pro-addons/car-info-autocomplete',
+ 'img_url' => 'car-info-auto-complete',
'pro_url' => 'https://stylemixthemes.com/car-dealer-plugin/pricing/?utm_source=wp-admin&utm_medium=push&utm_campaign=motors&utm_content=gopro',
- 'documentation' => 'https://docs.stylemixthemes.com/motors-car-dealer-classifieds-and-listing/motors-pro-addons/vin-decoder',
- 'img_url' => 'vin-decoder',
'toggle' => true,
),
self::SAVED_SEARCH => array(
@@ -65,34 +101,14 @@
'img_url' => 'social-login',
'toggle' => true,
),
- self::CAR_INFO_AUTO_COMPLETE => array(
- 'name' => esc_html__( 'Car Info Autocomplete', 'stm_vehicles_listing' ),
- 'url' => esc_url( STM_LISTINGS_URL . '/assets/addons/img/CarInfoAutoComplete.png' ),
- 'settings' => admin_url( 'admin.php?page=car_info_auto_complete_settings' ),
- 'description' => esc_html__( 'Automatically fill in vehicle details by selecting a make, model, year, or VIN. Speeds up listing creation and ensures accurate data.', 'stm_vehicles_listing' ),
- 'documentation' => 'https://docs.stylemixthemes.com/motors-car-dealer-classifieds-and-listing/motors-pro-addons/car-info-autocomplete',
- 'img_url' => 'car-info-auto-complete',
+ self::VIN_DECODER => array(
+ 'name' => esc_html__( 'VIN Decoder', 'stm_vehicles_listing' ),
+ 'url' => esc_url( STM_LISTINGS_URL . '/assets/addons/img/VinDecoder.png' ),
+ 'settings' => admin_url( 'admin.php?page=vin_decoders_settings' ),
+ 'description' => esc_html__( 'Get a comprehensive overview of a vehicle’s history with important details like make and mileage by VIN number. Connect up to 5 VIN services for comprehensive insights.', 'stm_vehicles_listing' ),
'pro_url' => 'https://stylemixthemes.com/car-dealer-plugin/pricing/?utm_source=wp-admin&utm_medium=push&utm_campaign=motors&utm_content=gopro',
- 'toggle' => true,
- ),
- self::EMAIL_MANAGER => array(
- 'name' => esc_html__( 'Email Template Manager', 'stm_vehicles_listing' ),
- 'url' => esc_url( STM_LISTINGS_URL . '/assets/addons/img/EmailManager.png' ),
- 'settings' => apply_filters( 'mvl_email_manager_url', '' ),
- 'description' => esc_html__( 'Manage your email templates and send them to your users.', 'stm_vehicles_listing' ),
- 'pro_url' => 'https://stylemixthemes.com/car-dealer-plugin/pricing/?utm_source=motorswpadmin&utm_campaign=motors-plugin&licenses=1&billing_cycle=annual',
- 'documentation' => 'https://docs.stylemixthemes.com/motors-car-dealer-classifieds-and-listing/motors-pro-addons/email-manager',
- 'img_url' => 'email-manager',
- 'toggle' => true,
- ),
- self::EMAIL_MANAGER => array(
- 'name' => esc_html__( 'Email Template Manager', 'stm_vehicles_listing' ),
- 'url' => esc_url( STM_LISTINGS_URL . '/assets/addons/img/EmailManager.png' ),
- 'settings' => apply_filters( 'mvl_email_manager_url', '' ),
- 'description' => esc_html__( 'Manage your email templates and send them to your users.', 'stm_vehicles_listing' ),
- 'pro_url' => 'https://stylemixthemes.com/car-dealer-plugin/pricing/?utm_source=motorswpadmin&utm_campaign=motors-plugin&licenses=1&billing_cycle=annual',
- 'documentation' => 'https://docs.stylemixthemes.com/motors-car-dealer-classifieds-and-listing/motors-pro-addons/email-manager',
- 'img_url' => 'email-manager',
+ 'documentation' => 'https://docs.stylemixthemes.com/motors-car-dealer-classifieds-and-listing/motors-pro-addons/vin-decoder',
+ 'img_url' => 'vin-decoder',
'toggle' => true,
),
);
--- a/motors-car-dealership-classified-listings/includes/class/Addons/settings.php
+++ b/motors-car-dealership-classified-listings/includes/class/Addons/settings.php
@@ -20,10 +20,12 @@
continue;
}
+ $menu_title = $addon['name'] . Addons::get_menu_badge_html( $addon );
+
add_submenu_page(
'mvl_plugin_settings',
$addon['name'],
- $addon['name'],
+ $menu_title,
'manage_options',
$key,
function () use ( $key ) {
--- a/motors-car-dealership-classified-listings/includes/class/Plugin/Settings.php
+++ b/motors-car-dealership-classified-listings/includes/class/Plugin/Settings.php
@@ -266,6 +266,16 @@
);
add_submenu_page(
+ 'tools.php',
+ esc_html__( 'Motors Setup Wizard', 'stm_vehicles_listing' ),
+ esc_html__( 'Motors Setup Wizard', 'stm_vehicles_listing' ),
+ 'manage_options',
+ 'mvl-welcome-setup',
+ 'mvl_setup_wizard_sub_menu_admin_page_contents',
+ 101
+ );
+
+ add_submenu_page(
'mvl_plugin_settings',
esc_html__( 'Help Center', 'stm_vehicles_listing' ),
'<span style="color: #FC7B40; font-weight: 700;">' . esc_html__( 'Help Center', 'stm_vehicles_listing' ) . '</span>',
--- a/motors-car-dealership-classified-listings/includes/enqueue.php
+++ b/motors-car-dealership-classified-listings/includes/enqueue.php
@@ -188,6 +188,11 @@
wp_register_script( 'motors-datetimepicker', STM_LISTINGS_URL . '/assets/js/motors-datetimepicker.js', array( 'jquery' ), STM_LISTINGS_V, true );
wp_register_script( 'mvl-lightgallery-init', STM_LISTINGS_URL . '/assets/js/frontend/lightgallery-init.js', null, STM_LISTINGS_V, true );
wp_register_script( 'mvl-swiper-init', STM_LISTINGS_URL . '/assets/js/frontend/swiper-init.js', null, STM_LISTINGS_V, true );
+ //tooltip
+ wp_register_script( 'mvl-tooltip', STM_LISTINGS_URL . '/assets/js/listing-manager/libs/tooltip.js', null, STM_LISTINGS_V, true );
+ wp_enqueue_script( 'mvl-tooltip', STM_LISTINGS_URL . '/assets/js/listing-manager/libs/tooltip.js', null, STM_LISTINGS_V, true );
+ wp_register_style( 'mvl-tooltip', STM_LISTINGS_URL . '/assets/css/mvl-tooltip.css', null, STM_LISTINGS_V );
+ wp_enqueue_style( 'mvl-tooltip', STM_LISTINGS_URL . '/assets/css/mvl-tooltip.css', null, STM_LISTINGS_V );
wp_enqueue_script(
'listings-init',
--- a/motors-car-dealership-classified-listings/includes/functions.php
+++ b/motors-car-dealership-classified-listings/includes/functions.php
@@ -910,7 +910,263 @@
);
}
+/**
+ * Get test drive fields from Forms Editor
+ *
+ * @param object $form_config Forms Editor form config instance.
+ * @return array Array of fields in metabox format.
+ */
+function stm_get_test_drive_fields_from_forms_editor( $form_config ) {
+ $fields = array();
+
+ if ( ! $form_config ) {
+ return $fields;
+ }
+
+ $form_data = $form_config->data();
+ $saved_values = $form_config->get_values();
+ $form_fields = $form_data['fields'] ?? array();
+
+ // Loop through all form fields
+ foreach ( $form_fields as $field_id => $field_config ) {
+ // Look for editable_zone
+ if ( isset( $field_config['type'] ) && 'editable_zone' === $field_config['type'] ) {
+ // Get saved zone fields or default fields
+ $zone_saved_fields = $saved_values[ $field_id ]['fields'] ?? array();
+ $zone_default_fields = $field_config['fields'] ?? array();
+ $zone_fields = ! empty( $zone_saved_fields ) ? $zone_saved_fields : $zone_default_fields;
+
+ // Transform each field
+ foreach ( $zone_fields as $zone_field ) {
+ if ( empty( $zone_field['slug'] ) ) {
+ continue;
+ }
+
+ $slug = $zone_field['slug'];
+ $type = $zone_field['type'] ?? 'input';
+
+ // Skip file_upload and custom_html fields - they shouldn't be in metabox
+ if ( in_array( $type, array( 'file_upload', 'custom_html' ), true ) ) {
+ continue;
+ }
+
+ $label = $zone_field['label'] ?? ucfirst( $slug );
+
+ // Map field types
+ $metabox_type = stm_map_forms_editor_type_to_metabox_type( $type );
+
+ $field_data = array(
+ 'label' => $label,
+ 'type' => $metabox_type,
+ );
+
+ // Add description if available
+ if ( ! empty( $zone_field['description'] ) ) {
+ $field_data['description'] = $zone_field['description'];
+ }
+
+ // Add placeholder if available (for select/dropdown)
+ if ( ! empty( $zone_field['placeholder'] ) && 'dropdown' === $type ) {
+ $field_data['placeholder'] = $zone_field['placeholder'];
+ }
+
+ // Get field settings
+ $settings = $zone_field['settings'] ?? array();
+
+ // Check if settings are stored directly in zone_field (backward compatibility)
+ if ( empty( $settings ) && is_array( $zone_field ) ) {
+ if ( isset( $zone_field['bind_custom_field'] ) ) {
+ $settings['bind_custom_field'] = $zone_field['bind_custom_field'];
+ }
+ if ( isset( $zone_field['custom_field_source'] ) ) {
+ $settings['custom_field_source'] = $zone_field['custom_field_source'];
+ }
+ if ( isset( $zone_field['custom_source'] ) ) {
+ $settings['custom_source'] = $zone_field['custom_source'];
+ }
+ }
+
+ // Check bind_custom_field
+ $bind_custom_field_raw = $settings['bind_custom_field'] ?? false;
+ $bind_custom_field = ( true === $bind_custom_field_raw || 'true' === $bind_custom_field_raw || '1' === $bind_custom_field_raw || 1 === $bind_custom_field_raw );
+
+ $custom_field_source = isset( $settings['custom_field_source'] ) ? trim( (string) $settings['custom_field_source'] ) : '';
+ if ( empty( $custom_field_source ) && isset( $settings['custom_source'] ) ) {
+ $custom_field_source = trim( (string) $settings['custom_source'] );
+ }
+
+ // Check if field needs options (dropdown, radio, checkbox)
+ $needs_options = in_array( $type, array( 'dropdown', 'radio', 'checkbox' ), true );
+
+ if ( $needs_options ) {
+ $options = array();
+
+ // If bound to custom field, get options from taxonomy
+ if ( $bind_custom_field && ! empty( $custom_field_source ) && taxonomy_exists( $custom_field_source ) ) {
+ $terms = get_terms(
+ array(
+ 'taxonomy' => $custom_field_source,
+ 'hide_empty' => false,
+ 'orderby' => 'name',
+ 'order' => 'ASC',
+ )
+ );
+
+ if ( ! is_wp_error( $terms ) && ! empty( $terms ) && is_array( $terms ) ) {
+ foreach ( $terms as $term ) {
+ if ( is_object( $term ) && isset( $term->name ) && ! empty( $term->name ) ) {
+ $options[ $term->name ] = $term->name;
+ }
+ }
+ }
+ } elseif ( ! empty( $zone_field['options'] ) && is_array( $zone_field['options'] ) ) {
+ $options = $zone_field['options'];
+ }
+
+ // Add options if we have any
+ if ( ! empty( $options ) ) {
+ $field_data['options'] = $options;
+ if ( $bind_custom_field ) {
+ $field_data['bind_custom_field'] = true;
+ $field_data['custom_field_source'] = $custom_field_source;
+ }
+ }
+ }
+
+ // For textarea add rows
+ if ( 'textarea' === $type ) {
+ $field_data['rows'] = isset( $zone_field['rows'] ) ? intval( $zone_field['rows'] ) : 5;
+ }
+
+ $fields[ $slug ] = $field_data;
+ }
+ }
+ }
+
+ return $fields;
+}
+
+/**
+ * Map Forms Editor field type to metabox field type
+ *
+ * @param string $forms_editor_type Forms Editor field type.
+ * @return string Metabox field type.
+ */
+function stm_map_forms_editor_type_to_metabox_type( $forms_editor_type ) {
+ $mapping = array(
+ 'input' => 'text',
+ 'email' => 'text',
+ 'phone' => 'text',
+ 'datetime' => 'text',
+ 'date' => 'text',
+ 'time' => 'text',
+ 'dropdown' => 'select',
+ 'textarea' => 'textarea',
+ 'checkbox' => 'checkbox',
+ 'radio' => 'radio',
+ );
+
+ return isset( $mapping[ $forms_editor_type ] ) ? $mapping[ $forms_editor_type ] : 'text';
+}
+
+/**
+ * Check if option value matches meta value (for select/radio/checkbox)
+ *
+ * @param string|array $meta Meta value to compare.
+ * @param string $option_key Option key.
+ * @param string $option_value Option value.
+ * @param bool $is_bound_to_custom_field Whether field is bound to custom field.
+ * @param bool $is_array Whether meta is an array (for checkboxes).
+ * @return bool True if matches.
+ */
+function stm_option_matches_meta( $meta, $option_key, $option_value, $is_bound_to_custom_field = false, $is_array = false ) {
+ if ( $is_array ) {
+ if ( ! is_array( $meta ) ) {
+ $meta = is_string( $meta ) && is_serialized( $meta ) ? maybe_unserialize( $meta ) : ( ! empty( $meta ) ? array( $meta ) : array() );
+ }
+ $meta_array = array_filter( array_map( 'trim', array_map( 'strval', $meta ) ) );
+ if ( empty( $meta_array ) ) {
+ return false;
+ }
+ $form_value = is_numeric( $option_key ) ? $option_value : $option_key;
+ $form_value_str = trim( (string) $form_value );
+ $option_key_str = trim( (string) $option_key );
+ $option_value_str = trim( (string) $option_value );
+
+ if ( $is_bound_to_custom_field ) {
+ return in_array( $form_value_str, $meta_array, true ) || in_array( $option_key_str, $meta_array, true ) || in_array( $option_value_str, $meta_array, true );
+ }
+
+ $found = in_array( $form_value_str, $meta_array, true ) || in_array( $option_key_str, $meta_array, true ) || in_array( $option_value_str, $meta_array, true );
+
+ if ( ! $found ) {
+ foreach ( $meta_array as $meta_val ) {
+ $meta_lower = strtolower( trim( (string) $meta_val ) );
+ if ( strtolower( $form_value_str ) === $meta_lower || strtolower( $option_key_str ) === $meta_lower || strtolower( $option_value_str ) === $meta_lower ) {
+ return true;
+ }
+ }
+ }
+ return $found;
+ }
+
+ $meta_str = trim( (string) $meta );
+ $form_value = is_numeric( $option_key ) ? $option_value : $option_key;
+ $form_value_str = trim( (string) $form_value );
+ $option_key_str = trim( (string) $option_key );
+ $option_value_str = trim( (string) $option_value );
+
+ if ( $is_bound_to_custom_field ) {
+ $matches = ( $meta_str === $form_value_str ) || ( $meta_str === $option_key_str ) || ( $meta_str === $option_value_str );
+ } else {
+ $matches = ( $meta_str === $form_value_str ) || ( $meta_str === $option_key_str ) || ( $meta_str === $option_value_str );
+ }
+
+ if ( ! $matches && ! empty( $meta_str ) ) {
+ $meta_lower = strtolower( $meta_str );
+ $matches = ( strtolower( $form_value_str ) === $meta_lower || strtolower( $option_key_str ) === $meta_lower || strtolower( $option_value_str ) === $meta_lower );
+ }
+
+ return $matches;
+}
+
function stm_add_test_drives_metaboxes() {
+ $fields = array();
+
+ // Check if Forms Editor addon is enabled
+ $is_forms_editor_enabled = function_exists( 'mvl_is_addon_enabled' ) && mvl_is_addon_enabled( false, 'forms_editor' );
+
+ if ( $is_forms_editor_enabled && class_exists( 'MotorsVehiclesListingProAddonsFormsEditorConfigConfig' ) ) {
+ // Get fields from Forms Editor
+ $form_config = MotorsVehiclesListingProAddonsFormsEditorConfigConfig::instance_of( 'test_drive' );
+
+ if ( $form_config ) {
+ $fields = stm_get_test_drive_fields_from_forms_editor( $form_config );
+ }
+ }
+
+ // Fallback to default fields if Forms Editor is not enabled or returned no fields
+ if ( empty( $fields ) ) {
+ $fields = array(
+ 'name' => array(
+ 'label' => __( 'Name', 'stm_vehicles_listing' ),
+ 'type' => 'text',
+ ),
+ 'email' => array(
+ 'label' => __( 'E-mail', 'stm_vehicles_listing' ),
+ 'type' => 'text',
+ ),
+ 'phone' => array(
+ 'label' => __( 'Phone', 'stm_vehicles_listing' ),
+ 'type' => 'text',
+ ),
+ 'date' => array(
+ 'label' => __( 'Day', 'stm_vehicles_listing' ),
+ 'type' => 'text',
+ ),
+ );
+ }
+
add_meta_box(
'test_drive_form',
__( 'Credentials', 'stm_vehicles_listing' ),
@@ -919,59 +1175,121 @@
'normal',
'',
array(
- 'fields' => array(
- 'name' => array(
- 'label' => __( 'Name', 'stm_vehicles_listing' ),
- 'type' => 'text',
- ),
- 'email' => array(
- 'label' => __( 'E-mail', 'stm_vehicles_listing' ),
- 'type' => 'text',
- ),
- 'phone' => array(
- 'label' => __( 'Phone', 'stm_vehicles_listing' ),
- 'type' => 'text',
- ),
- 'date' => array(
- 'label' => __( 'Day', 'stm_vehicles_listing' ),
- 'type' => 'text',
- ),
- ),
+ 'fields' => $fields,
)
);
}
function display_metaboxes( $post, $metabox ) {
+ if ( ! isset( $metabox['args']['fields'] ) || ! is_array( $metabox['args']['fields'] ) ) {
+ return;
+ }
$fields = $metabox['args']['fields'];
+ if ( empty( $fields ) || ! isset( $post->ID ) ) {
+ return;
+ }
- $html = '<input type="hidden" name="stm_custom_nonce" value="' . wp_create_nonce( basename( __FILE__ ) ) . '" />';//phpcs:ignore
+ $html = '<input type="hidden" name="stm_custom_nonce" value="' . esc_attr( wp_create_nonce( basename( __FILE__ ) ) ) . '" />';//phpcs:ignore
$html .= '<table class="form-table stm">';
+
foreach ( $fields as $key => $field ) {
- $meta = get_post_meta( $post->ID, $key, true );
- if ( 'hidden' !== $field['type'] ) {
- if ( 'separator' !== $field['type'] ) {
- $html .= '<tr class="stm_admin_' . $key . '"><th><label for="' . $key . '">' . $field['label'] . '</label></th><td>';
+ if ( ! is_array( $field ) || empty( $field['type'] ) || empty( $field['label'] ) ) {
+ continue;
+ }
+
+ $meta = get_post_meta( $post->ID, $key, true );
+ $field_type = $field['type'];
+
+ if ( 'hidden' !== $field_type ) {
+ if ( 'separator' !== $field_type ) {
+ $html .= '<tr class="stm_admin_' . esc_attr( $key ) . '"><th><label for="' . esc_attr( $key ) . '">' . esc_html( $field['label'] ) . '</label></th><td>';
} else {
- $html .= '<tr><th><h3>' . $field['label'] . '</h3></th><td>';
+ $html .= '<tr><th><h3>' . esc_html( $field['label'] ) . '</h3></th><td>';
}
}
- switch ( $field['type'] ) {
+ switch ( $field_type ) {
case 'text':
if ( empty( $meta ) && ! empty( $field['default'] ) && 'auto-draft' === $post->post_status ) {
$meta = $field['default'];
}
- echo '<input type="text" name="' . esc_attr( $key ) . '" id="' . esc_attr( $key ) . '" value="' . esc_attr( $meta ) . '" />';
+ $html .= '<input type="text" name="' . esc_attr( $key ) . '" id="' . esc_attr( $key ) . '" value="' . esc_attr( $meta ) . '" />';
if ( isset( $field['description'] ) ) {
- $html .= '<p class="textfield-description">' . $field['description'] . '</p>';
+ $html .= '<p class="textfield-description">' . esc_html( $field['description'] ) . '</p>';
}
break;
case 'select':
+ if ( empty( $field['options'] ) || ! is_array( $field['options'] ) ) {
+ break;
+ }
+
$html .= '<select name="' . esc_attr( $key ) . '" id="' . esc_attr( $key ) . '">';
+ if ( ! empty( $field['placeholder'] ) ) {
+ $html .= '<option value="">' . esc_html( $field['placeholder'] ) . '</option>';
+ }
+
+ $is_bound = ! empty( $field['bind_custom_field'] );
foreach ( $field['options'] as $option_key => $option_value ) {
- $html .= '<option' . ( $meta === $option_key ? ' selected="selected"' : '' ) . ' value="' . esc_attr( $option_key ) . '">' . esc_html( $option_value ) . '</option>';
+ $is_selected = stm_option_matches_meta( $meta, $option_key, $option_value, $is_bound, false );
+ if ( empty( trim( (string) $meta ) ) && empty( $option_key ) && empty( $field['placeholder'] ) ) {
+ $is_selected = true;
+ }
+ $selected = $is_selected ? ' selected="selected"' : '';
+ $html .= '<option' . $selected . ' value="' . esc_attr( $option_key ) . '">' . esc_html( $option_value ) . '</option>';
}
$html .= '</select>';
+ if ( ! empty( $field['description'] ) ) {
+ $html .= '<p class="textfield-description">' . esc_html( $field['description'] ) . '</p>';
+ }
+ break;
+ case 'textarea':
+ if ( empty( $meta ) && ! empty( $field['default'] ) && isset( $post->post_status ) && 'auto-draft' === $post->post_status ) {
+ $meta = $field['default'];
+ }
+ $rows = isset( $field['rows'] ) ? absint( $field['rows'] ) : 5;
+ $html .= '<textarea name="' . esc_attr( $key ) . '" id="' . esc_attr( $key ) . '" rows="' . esc_attr( $rows ) . '">' . esc_textarea( $meta ) . '</textarea>';
+ if ( ! empty( $field['description'] ) ) {
+ $html .= '<p class="textfield-description">' . esc_html( $field['description'] ) . '</p>';
+ }
+ break;
+ case 'checkbox':
+ $has_options = ! empty( $field['options'] ) && is_array( $field['options'] );
+
+ if ( $has_options ) {
+ $is_bound = ! empty( $field['bind_custom_field'] );
+ foreach ( $field['options'] as $option_key => $option_value ) {
+ $form_value = is_numeric( $option_key ) ? $option_value : $option_key;
+ $is_checked = stm_option_matches_meta( $meta, $option_key, $option_value, $is_bound, true );
+ $checked = $is_checked ? 'checked="checked"' : '';
+ $option_id = sanitize_title( $key . '-' . $option_key );
+ $html .= '<label><input type="checkbox" name="' . esc_attr( $key ) . '[]" id="' . esc_attr( $option_id ) . '" value="' . esc_attr( $form_value ) . '" ' . $checked . ' /> ' . esc_html( $option_value ) . '</label><br />';
+ }
+ } else {
+ // Single checkbox
+ if ( is_string( $meta ) && is_serialized( $meta ) ) {
+ $meta = maybe_unserialize( $meta );
+ }
+ $checked = ( ! empty( $meta ) && ( '1' === $meta || 1 === $meta || true === $meta ) ) ? 'checked="checked"' : '';
+ $html .= '<input type="checkbox" name="' . esc_attr( $key ) . '" id="' . esc_attr( $key ) . '" value="1" ' . $checked . ' />';
+ }
+
+ if ( ! empty( $field['description'] ) ) {
+ $html .= '<p class="textfield-description">' . esc_html( $field['description'] ) . '</p>';
+ }
+ break;
+ case 'radio':
+ if ( ! empty( $field['options'] ) && is_array( $field['options'] ) ) {
+ $is_bound = ! empty( $field['bind_custom_field'] );
+ foreach ( $field['options'] as $option_key => $option_value ) {
+ $form_value = is_numeric( $option_key ) ? $option_value : $option_key;
+ $is_checked = stm_option_matches_meta( $meta, $option_key, $option_value, $is_bound, false );
+ $checked = $is_checked ? 'checked="checked"' : '';
+ $html .= '<label><input type="radio" name="' . esc_attr( $key ) . '" value="' . esc_attr( $form_value ) . '" ' . $checked . ' /> ' . esc_html( $option_value ) . '</label><br />';
+ }
+ }
+ if ( ! empty( $field['description'] ) ) {
+ $html .= '<p class="textfield-description">' . esc_html( $field['description'] ) . '</p>';
+ }
break;
}
$html .= '</td></tr>';
@@ -982,68 +1300,143 @@
}
function stm_save_metaboxes( $post_id ) {
-
- if ( ! isset( $_POST['stm_custom_nonce'] ) ) {
+ if ( ! isset( $_POST['stm_custom_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['stm_custom_nonce'] ) ), basename( __FILE__ ) ) ) {
return $post_id;
}
+
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
+
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
}
- $metaboxes = array(
- 'fields' => array(
- 'name' => array(
+
+ $post_type = get_post_type( $post_id );
+ if ( ! $post_type ) {
+ return $post_id;
+ }
+
+ // For test_drive_request, try to get fields from Forms Editor
+ $test_drive_fields = array();
+ if ( 'test_drive_request' === $post_type ) {
+ $is_forms_editor_enabled = function_exists( 'mvl_is_addon_enabled' ) && mvl_is_addon_enabled( false, 'forms_editor' );
+
+ if ( $is_forms_editor_enabled && class_exists( 'MotorsVehiclesListingProAddonsFormsEditorConfigConfig' ) ) {
+ $form_config = MotorsVehiclesListingProAddonsFormsEditorConfigConfig::instance_of( 'test_drive' );
+
+ if ( $form_config ) {
+ $test_drive_fields = stm_get_test_drive_fields_from_forms_editor( $form_config );
+ }
+ }
+ }
+
+ // Fallback to default fields if Forms Editor is not enabled or returned no fields
+ if ( empty( $test_drive_fields ) && 'test_drive_request' === $post_type ) {
+ $test_drive_fields = array(
+ 'name' => array(
'label' => __( 'Name', 'stm_vehicles_listing' ),
'type' => 'text',
),
- 'email' => array(
+ 'email' => array(
'label' => __( 'E-mail', 'stm_vehicles_listing' ),
'type' => 'text',
),
- 'phone' => array(
+ 'phone' => array(
'label' => __( 'Phone', 'stm_vehicles_listing' ),
'type' => 'text',
),
- 'date' => array(
+ 'date' => array(
'label' => __( 'Day', 'stm_vehicles_listing' ),
'type' => 'text',
),
- //dealer reviews
- 'stm_review_added_by' => array(
- 'label' => __( 'User added by', 'stm_vehicles_listing' ),
- 'type' => 'select',
- ),
- 'stm_review_added_on' => array(
- 'label' => __( 'User added on', 'stm_vehicles_listing' ),
- 'type' => 'select',
- ),
- 'stm_rate_1' => array(
- 'label' => __( 'Rate 1', 'stm_vehicles_listing' ),
- 'type' => 'select',
- ),
- 'stm_rate_2' => array(
- 'label' => __( 'Rate 2', 'stm_vehicles_listing' ),
- 'type' => 'select',
- ),
- 'stm_rate_3' => array(
- 'label' => __( 'Rate 3', 'stm_vehicles_listing' ),
- 'type' => 'select',
- ),
- 'stm_recommended' => array(
- 'label' => __( 'Recommended', 'stm_vehicles_listing' ),
- 'type' => 'select',
- ),
+ );
+ }
+
+ $metaboxes = array(
+ 'fields' => array_merge(
+ $test_drive_fields,
+ array(
+ //dealer reviews
+ 'stm_review_added_by' => array(
+ 'label' => __( 'User added by', 'stm_vehicles_listing' ),
+ 'type' => 'select',
+ ),
+ 'stm_review_added_on' => array(
+ 'label' => __( 'User added on', 'stm_vehicles_listing' ),
+ 'type' => 'select',
+ ),
+ 'stm_rate_1' => array(
+ 'label' => __( 'Rate 1', 'stm_vehicles_listing' ),
+ 'type' => 'select',
+ ),
+ 'stm_rate_2' => array(
+ 'label' => __( 'Rate 2', 'stm_vehicles_listing' ),
+ 'type' => 'select',
+ ),
+ 'stm_rate_3' => array(
+ 'label' => __( 'Rate 3', 'stm_vehicles_listing' ),
+ 'type' => 'select',
+ ),
+ 'stm_recommended' => array(
+ 'label' => __( 'Recommended', 'stm_vehicles_listing' ),
+ 'type' => 'select',
+ ),
+ )
),
);
foreach ( $metaboxes as $stm_field_key => $fields ) {
+ if ( ! is_array( $fields ) ) {
+ continue;
+ }
foreach ( $fields as $field => $data ) {
- $old = get_post_meta( $post_id, $field, true );
+ if ( ! is_array( $data ) || empty( $data['type'] ) ) {
+ continue;
+ }
+
+ $old = get_post_meta( $post_id, $field, true );
+ $field_type = $data['type'];
+
+ // Handle checkbox - can be single or multiple
+ if ( 'checkbox' === $field_type ) {
+ $has_options = ! empty( $data['options'] ) && is_array( $data['options'] );
+
+ if ( $has_options ) {
+ // Multiple checkboxes - save as array
+ $new = isset( $_POST[ $field ] ) && is_array( $_POST[ $field ] )
+ ? array_map( 'sanitize_text_field', wp_unslash( $_POST[ $field ] ) )
+ : array();
+
+ $old_array = is_array( $old ) ? $old : ( ! empty( $old ) ? array( $old ) : array() );
+ sort( $new );
+ sort( $old_array );
+
+ if ( $new !== $old_array ) {
+ if ( ! empty( $new ) ) {
+ update_post_meta( $post_id, $field, $new );
+ } else {
+ delete_post_meta( $post_id, $field, $old );
+ }
+ }
+ } else {
+ // Single checkbox - save as '1' or ''
+ $new = isset( $_POST[ $field ] ) ? '1' : '';
+ if ( $new !== $old ) {
+ if ( '' !== $new ) {
+ update_post_meta( $post_id, $field, $new );
+ } else {
+ delete_post_meta( $post_id, $field, $old );
+ }
+ }
+ }
+ continue;
+ }
+
+ // Handle other field types
if ( isset( $_POST[ $field ] ) ) {
- if ( 'listing_select' === $data['type'] ) {
+ if ( 'listing_select' === $field_type ) {
$new_array = (array) $_POST[ $field ];
$new_array = array_map( 'sanitize_text_field', $new_array );
$new_imploded = implode( ',', $new_array );
@@ -1052,8 +1445,17 @@
} elseif ( '' === $new_imploded && $old ) {
delete_post_meta( $post_id, $field, $old );
}
+ } elseif ( 'textarea' === $field_type ) {
+ $new = sanitize_textarea_field( wp_unslash( $_POST[ $field ] ) );
+ if ( $new !== $old ) {
+ if ( '' !== $new ) {
+ update_post_meta( $post_id, $field, $new );
+ } else {
+ delete_post_meta( $post_id, $field, $old );
+ }
+ }
} else {
- $new = sanitize_text_field( $_POST[ $field ] );
+ $new = sanitize_text_field( wp_unslash( $_POST[ $field ] ) );
if ( $new && $new !== $old ) {
update_post_meta( $post_id, $field, $new );
} elseif ( '' === $new && $old ) {
@@ -1061,7 +1463,10 @@
}
}
} else {
- delete_post_meta( $post_id, $field, $old );
+ // For checkbox, if not set, delete the meta
+ if ( 'checkbox' !== $field_type ) {
+ delete_post_meta( $post_id, $field, $old );
+ }
}
}
--- a/motors-car-dealership-classified-listings/includes/helpers.php
+++ b/motors-car-dealership-classified-listings/includes/helpers.php
@@ -277,39 +277,50 @@
add_filter( 'wp_kses_allowed_html', 'mvl_wp_kses_allowed_html' );
function mvl_wp_kses_allowed_html( $allowed_html ) {
$allowed_atts = array(
- 'align' => array(),
- 'class' => array(),
- 'type' => array(),
- 'id' => array(),
- 'dir' => array(),
- 'lang' => array(),
- 'style' => array(),
- 'xml:lang' => array(),
- 'src' => array(),
- 'alt' => array(),
- 'href' => array(),
- 'rel' => array(),
- 'rev' => array(),
- 'target' => array(),
- 'novalidate' => array(),
- 'value' => array(),
- 'name' => array(),
- 'tabindex' => array(),
- 'action' => array(),
- 'method' => array(),
- 'for' => array(),
- 'width' => array(),
- 'height' => array(),
- 'data' => array(),
- 'title' => array(),
- 'placeholder' => array(),
- 'selected' => array(),
+ 'align' => array(),
+ 'class' => array(),
+ 'type' => array(),
+ 'id' => array(),
+ 'dir' => array(),
+ 'lang' => array(),
+ 'style' => array(),
+ 'xml:lang' => array(),
+ 'src' => array(),
+ 'alt' => array(),
+ 'href' => array(),
+ 'rel' => array(),
+ 'rev' => array(),
+ 'target' => array(),
+ 'novalidate' => array(),
+ 'value' => array(),
+ 'name' => array(),
+ 'tabindex' => array(),
+ 'action' => array(),
+ 'method' => array(),
+ 'for' => array(),
+ 'width' => array(),
+ 'height' => array(),
+ 'data-*' => true,
+ 'title' => array(),
+ 'placeholder' => array(),
+ 'selected' => array(),
+ 'disabled' => array(),
+ 'checked' => array(),
+ 'required' => array(),
+ 'readonly' => array(),
+ 'autocomplete' => array(),
);
$allowed_html['select'] = $allowed_atts;
$allowed_html['input'] = $allowed_atts;
$allowed_html['option'] = $allowed_atts;
$allowed_html['option']['selected'] = array();
+ $allowed_html['form'] = $allowed_atts;
+ $allowed_html['textarea'] = $allowed_atts;
+ $allowed_html['button'] = $allowed_atts;
+ $allowed_html['label'] = $allowed_atts;
+ $allowed_html['div'] = $allowed_atts;
+ $allowed_html['span'] = $allowed_atts;
$allowed_html['img'] = array(
'src' => true,
@@ -1255,8 +1266,15 @@
$car_video_main = get_post_meta( $post_id, 'gallery_video', true );
$car_videos = get_post_meta( $post_id, 'gallery_videos', true );
- if ( ! empty( $car_video_main ) ) {
- $car_video[] = $car_video_main;
+ if ( is_string( $car_videos ) && '' !== $car_videos ) {
+ $car_videos = array( $car_videos );
+ } else {
+ $car_videos = is_array( $car_videos ) ? $car_videos : array();
+ }
+ $car_videos = array_values( array_filter( $car_videos ) );
+
+ if ( ! empty( $car_video_main ) && ! in_array( $car_video_main, $car_videos, true ) ) {
+ array_unshift( $car_videos, $car_video_main );
}
if ( ! empty( $car_videos ) ) {
@@ -1267,6 +1285,7 @@
}
}
+ $car_video = array_values( array_unique( $car_video ) );
$car_media['car_videos'] = $car_video;
$car_media['car_videos_posters'] = $car_videos_posters;
$car_media['car_videos_count'] = count( $car_video );
--- a/motors-car-dealership-classified-listings/includes/user-extra.php
+++ b/motors-car-dealership-classified-listings/includes/user-extra.php
@@ -4,18 +4,85 @@
add_action( 'edit_user_profile', 'stm_show_user_extra_fields' );
if ( ! function_exists( 'stm_show_user_extra_fields' ) ) {
- function stm_show_user_extra_fields( $user ) { ?>
+ function stm_show_user_extra_fields( $user ) {
+ $is_forms_editor = apply_filters( 'mvl_is_addon_enabled', false, 'forms_editor' );
+ $form_config = null;
+ $sign_up_form_config = null;
+ $form_data = array();
+ $sign_up_form_data = array();
+ $fields = array();
+ $sign_up_fields = array();
+ $saved_values = array();
+ $sign_up_saved_values = array();
+
+ if ( $is_forms_editor ) {
+ if ( class_exists( 'MotorsVehiclesListingProAddonsFormsEditorConfigConfig' ) ) {
+ $form_config = MotorsVehiclesListingProAddonsFormsEditorConfigConfig::instance_of( 'become_dealer' );
+ $sign_up_form_config = MotorsVehiclesListingProAddonsFormsEditorConfigConfig::instance_of( 'sign_up' );
+
+ if ( $form_config instanceof MotorsVehiclesListingProAddonsFormsEditorConfigFormConfig ) {
+ $form_data = $form_config->data();
+ $fields = $form_data['fields'] ?? array();
+ $saved_values = $form_config->get_values();
+ }
+
+ if ( $sign_up_form_config instanceof MotorsVehiclesListingProAddonsFormsEditorConfigFormConfig ) {
+ $sign_up_form_data = $sign_up_form_config->data();
+ $sign_up_fields = $sign_up_form_data['fields'] ?? array();
+ $sign_up_saved_values = $sign_up_form_config->get_values();
+ }
+ }
+ }
+ ?>
<h3><?php esc_html_e( 'STM User/Dealer additional fields', 'stm_vehicles_listing' ); ?></h3>
<table class="form-table">
+ <?php if ( $is_forms_editor && $sign_up_form_config instanceof MotorsVehiclesListingProAddonsFormsEditorConfigFormConfig && ! empty( $sign_up_fields ) ) : ?>
+ <?php
+ $excluded_slugs = array( 'stm_nickname', 'stm_user_password', 'stm_user_first_name', 'stm_user_last_name', 'stm_user_phone', 'stm_user_mail' );
+ $has_sign_up_fields = false;
+
+ foreach ( $sign_up_fields as $field_id => $field_config ) {
+ $field_slug = $field_config['slug'] ?? '';
+ $field_type = $field_config['type'] ?? '';
+
+ if ( in_array( $field_type, array( 'header', 'button' ), true ) ) {
+ continue;
+ }
+ if ( ! empty( $field_slug ) && in_array( $field_slug, $excluded_slugs, true ) ) {
+ continue;
+ }
+ $has_sign_up_fields = true;
+ break;
+ }
+ if ( $has_sign_up_fields ) :
+ foreach ( $sign_up_fields as $field_id => $field_config ) :
+ $sign_up_form_config->render_field_admin_table(
+ $field_id,
+ $field_config,
+ $sign_up_saved_values,
+ array( 'header', 'button' ),
+ array(
+ 'excluded_slugs' => $excluded_slugs,
+ 'user_meta' => true,
+ 'user_id' => $user->ID,
+ )
+ );
+ endforeach;
+ ?>
+ <?php endif; ?>
+ <?php endif; ?>
+
<tr>
<th><label for="stm_show_email"><?php esc_html_e( 'Email visibility', 'stm_vehicles_listing' ); ?></label></th>
-
<td>
+ <?php
+ $stm_show_email = get_the_author_meta( 'stm_show_email', $user->ID );
+ ?>
<label for="stm_show_email">
- <input type="checkbox" name="stm_show_email" id="stm_show_email" <?php echo ( ! empty( get_the_author_meta( 'stm_show_email', $user->ID ) ) ) ? 'checked="checked"' : ''; ?> />
+ <input type="checkbox" name="stm_show_email" id="stm_show_email" <?php checked( ! empty( $stm_show_email ) ); ?> />