Plugin Directory

Changeset 3381414


Ignore:
Timestamp:
10/20/2025 03:35:43 PM (4 months ago)
Author:
2wstechnologies
Message:

new release with new design and new features in campaign creation

Location:
insim/trunk
Files:
86 added
8 edited

Legend:

Unmodified
Added
Removed
  • insim/trunk/README.txt

    r3301645 r3381414  
    9292= 3.0.0 =
    9393* Fix bugs in recipient list creation
     94
     95= 4.0 =
     96* Add new criteria to create recipient list
     97* Update the design
     98* Add sms count and message preview in Campaign creation
  • insim/trunk/admin/models/sim-to-shop-campaign-model.php

    r3301630 r3381414  
    232232        private function get_recipient_query($count = false) {
    233233            global $wpdb;
    234        
    235             $query_select = "SELECT * , meta2.meta_value AS billing_phone, meta4.meta_value AS billing_country, meta6.meta_value AS billing_lastname, meta7.meta_value AS billing_firstname"
    236                 . ", (SELECT COUNT(*) FROM $wpdb->posts post LEFT JOIN $wpdb->postmeta meta0 ON (meta0.post_id = post.ID) WHERE post.post_type='shop_order' AND meta0.meta_key='_customer_user' AND meta0.meta_value=wp_users.ID) AS order_nbr";
    237        
     234
     235            $query_select = "SELECT DISTINCT wp_users.ID, wp_users.*, meta2.meta_value AS billing_phone, meta4.meta_value AS billing_country, meta6.meta_value AS billing_lastname, meta7.meta_value AS billing_firstname"
     236                . ", (SELECT COUNT(*) FROM $wpdb->posts post LEFT JOIN $wpdb->postmeta meta0 ON (meta0.post_id = post.ID) WHERE post.post_type='shop_order' AND post.post_status IN ('wc-completed', 'wc-processing', 'wc-on-hold') AND meta0.meta_key='_customer_user' AND meta0.meta_value=wp_users.ID) AS order_nbr";
     237
    238238            if ($count) {
    239                 $query_select = "SELECT COUNT(*) AS total_rows";
     239                $query_select = "SELECT COUNT(DISTINCT wp_users.ID) AS total_rows";
    240240            }
    241241       
     
    274274        // }
    275275
    276         private function execute_recipient_query($query, $count = false, $countryCode = null) {
     276        private function execute_recipient_query($query, $count = false, $countryCodes = null) {
    277277            global $wpdb;
    278278
     
    291291            $mergedResult = $mainResult;
    292292
    293             // Only run the additional query if $countryCode is set and not empty
    294             if (isset($countryCode) && $countryCode !== "") {
     293            // Run additional query for country filters (finds customers from orders who don't have user accounts)
     294            // Only run if we have country codes and it's a single country (to avoid complexity with multiple OR countries)
     295            if (is_array($countryCodes) && count($countryCodes) === 1 && !empty($countryCodes[0])) {
     296                $countryCode = $countryCodes[0];
    295297                $additionalQuery = "
    296298                    SELECT ID,
    297                     CONCAT_WS(' ', 
     299                    CONCAT_WS(' ',
    298300                    (SELECT meta_value FROM $wpdb->postmeta WHERE post_id = p.ID AND meta_key = '_billing_first_name' LIMIT 1),
    299301                    (SELECT meta_value FROM $wpdb->postmeta WHERE post_id = p.ID AND meta_key = '_billing_last_name' LIMIT 1)
     
    318320                }
    319321                $mergedResult = $this->mergeResults($mainResult, $additionalResult);
     322
     323                if (WP_DEBUG) {
     324                    error_log("Additional order query ran for country: " . $countryCode);
     325                }
     326            } else if (is_array($countryCodes) && count($countryCodes) > 1) {
     327                // Multiple countries with OR - skip additional query to avoid complexity
     328                // The main query with DISTINCT should handle everything correctly
     329                if (WP_DEBUG) {
     330                    error_log("Multiple countries detected (" . implode(', ', $countryCodes) . "), skipping additional order query");
     331                }
    320332            }
    321333
    322334            if (WP_DEBUG) {
    323                 error_log("Merged and Unique Result: " . print_r($mergedResult, true));
     335                error_log("Merged and Unique Result count: " . count($mergedResult));
    324336            }
    325337
     
    371383        }
    372384
    373        
    374        
     385        /**
     386         * Build SQL WHERE clause for a single filter
     387         */
     388        private function build_filter_clause($field, $operator, $value, $value2, &$country_keys) {
     389            global $wpdb;
     390
     391            // Sanitize inputs
     392            $value = sanitize_text_field($value);
     393            $value2 = sanitize_text_field($value2);
     394
     395            switch ($field) {
     396                case 'country':
     397                    // Store country_keys as array for execute_recipient_query (used for additional order query)
     398                    if (!is_array($country_keys)) {
     399                        $country_keys = array();
     400                    }
     401                    if (!in_array($value, $country_keys)) {
     402                        $country_keys[] = $value;
     403                    }
     404
     405                    if ($operator === 'is') {
     406                        return "wp_users.ID IN (
     407                            SELECT user_id FROM $wpdb->usermeta
     408                            WHERE (meta_key = 'billing_country' AND meta_value = '" . esc_sql($value) . "')
     409                            OR (meta_key = 'shipping_country' AND meta_value = '" . esc_sql($value) . "')
     410                        )";
     411                    } elseif ($operator === 'is_not') {
     412                        return "wp_users.ID NOT IN (
     413                            SELECT user_id FROM $wpdb->usermeta
     414                            WHERE (meta_key = 'billing_country' AND meta_value = '" . esc_sql($value) . "')
     415                            OR (meta_key = 'shipping_country' AND meta_value = '" . esc_sql($value) . "')
     416                        )";
     417                    }
     418                    break;
     419
     420                case 'registration_date':
     421                    return $this->build_date_clause('wp_users.user_registered', $operator, $value, $value2);
     422
     423                case 'last_login':
     424                    return $this->build_date_clause('meta3.meta_value', $operator, $value, $value2);
     425
     426                case 'order_count':
     427                    $order_count_subquery = "(SELECT COUNT(*) FROM $wpdb->posts post
     428                        LEFT JOIN $wpdb->postmeta meta0 ON (meta0.post_id = post.ID)
     429                        WHERE post.post_type='shop_order'
     430                        AND post.post_status IN ('wc-completed', 'wc-processing', 'wc-on-hold')
     431                        AND meta0.meta_key='_customer_user'
     432                        AND meta0.meta_value=wp_users.ID)";
     433
     434                    if ($operator === 'equals') {
     435                        return "$order_count_subquery = " . intval($value);
     436                    } elseif ($operator === 'greater_than') {
     437                        return "$order_count_subquery > " . intval($value);
     438                    } elseif ($operator === 'less_than') {
     439                        return "$order_count_subquery < " . intval($value);
     440                    } elseif ($operator === 'between' && $value2) {
     441                        return "$order_count_subquery BETWEEN " . intval($value) . " AND " . intval($value2);
     442                    }
     443                    break;
     444
     445                case 'total_spent':
     446                    // Calculate total spent per customer
     447                    $total_spent_subquery = "(SELECT COALESCE(SUM(meta_total.meta_value), 0) FROM $wpdb->posts post
     448                        LEFT JOIN $wpdb->postmeta meta_customer ON (meta_customer.post_id = post.ID AND meta_customer.meta_key = '_customer_user')
     449                        LEFT JOIN $wpdb->postmeta meta_total ON (meta_total.post_id = post.ID AND meta_total.meta_key = '_order_total')
     450                        WHERE post.post_type = 'shop_order'
     451                        AND post.post_status IN ('wc-completed', 'wc-processing')
     452                        AND meta_customer.meta_value = wp_users.ID)";
     453
     454                    if ($operator === 'greater_than') {
     455                        return "$total_spent_subquery > " . floatval($value);
     456                    } elseif ($operator === 'less_than') {
     457                        return "$total_spent_subquery < " . floatval($value);
     458                    } elseif ($operator === 'between' && $value2) {
     459                        return "$total_spent_subquery BETWEEN " . floatval($value) . " AND " . floatval($value2);
     460                    }
     461                    break;
     462
     463                case 'average_order':
     464                    // Calculate average order value per customer
     465                    $avg_order_subquery = "(SELECT COALESCE(AVG(meta_total.meta_value), 0) FROM $wpdb->posts post
     466                        LEFT JOIN $wpdb->postmeta meta_customer ON (meta_customer.post_id = post.ID AND meta_customer.meta_key = '_customer_user')
     467                        LEFT JOIN $wpdb->postmeta meta_total ON (meta_total.post_id = post.ID AND meta_total.meta_key = '_order_total')
     468                        WHERE post.post_type = 'shop_order'
     469                        AND post.post_status IN ('wc-completed', 'wc-processing')
     470                        AND meta_customer.meta_value = wp_users.ID)";
     471
     472                    if ($operator === 'greater_than') {
     473                        return "$avg_order_subquery > " . floatval($value);
     474                    } elseif ($operator === 'less_than') {
     475                        return "$avg_order_subquery < " . floatval($value);
     476                    } elseif ($operator === 'between' && $value2) {
     477                        return "$avg_order_subquery BETWEEN " . floatval($value) . " AND " . floatval($value2);
     478                    }
     479                    break;
     480
     481                case 'last_order_date':
     482                    // Get the most recent order date for the customer
     483                    $last_order_subquery = "(SELECT MAX(post.post_date) FROM $wpdb->posts post
     484                        LEFT JOIN $wpdb->postmeta meta_customer ON (meta_customer.post_id = post.ID AND meta_customer.meta_key = '_customer_user')
     485                        WHERE post.post_type = 'shop_order'
     486                        AND post.post_status IN ('wc-completed', 'wc-processing', 'wc-on-hold')
     487                        AND meta_customer.meta_value = wp_users.ID)";
     488
     489                    return $this->build_date_clause($last_order_subquery, $operator, $value, $value2);
     490
     491                case 'email_domain':
     492                    if ($operator === 'is') {
     493                        return "wp_users.user_email LIKE '%" . esc_sql($value) . "'";
     494                    } elseif ($operator === 'contains') {
     495                        return "wp_users.user_email LIKE '%" . esc_sql($value) . "%'";
     496                    } elseif ($operator === 'not_contains') {
     497                        return "wp_users.user_email NOT LIKE '%" . esc_sql($value) . "%'";
     498                    }
     499                    break;
     500
     501                case 'customer_role':
     502                    if ($operator === 'is') {
     503                        return "meta5.meta_value LIKE '%" . esc_sql($value) . "%'";
     504                    } elseif ($operator === 'is_not') {
     505                        return "meta5.meta_value NOT LIKE '%" . esc_sql($value) . "%'";
     506                    }
     507                    break;
     508            }
     509
     510            return null;
     511        }
     512
     513        /**
     514         * Build date-based WHERE clause
     515         */
     516        private function build_date_clause($field_expression, $operator, $value, $value2) {
     517            global $wpdb;
     518
     519            if ($operator === 'between' && $value && $value2) {
     520                $date1 = date('Y-m-d 00:00:00', strtotime($value));
     521                $date2 = date('Y-m-d 23:59:59', strtotime($value2));
     522                return "DATE($field_expression) BETWEEN '" . esc_sql($date1) . "' AND '" . esc_sql($date2) . "'";
     523            } elseif ($operator === 'before' && $value) {
     524                $date = date('Y-m-d 00:00:00', strtotime($value));
     525                return "DATE($field_expression) < '" . esc_sql($date) . "'";
     526            } elseif ($operator === 'after' && $value) {
     527                $date = date('Y-m-d 23:59:59', strtotime($value));
     528                return "DATE($field_expression) > '" . esc_sql($date) . "'";
     529            } elseif ($operator === 'in_last_days' && $value) {
     530                $days = intval($value);
     531                return "DATE($field_expression) >= DATE_SUB(CURDATE(), INTERVAL $days DAY)";
     532            } elseif ($operator === 'older_than_days' && $value) {
     533                $days = intval($value);
     534                return "DATE($field_expression) < DATE_SUB(CURDATE(), INTERVAL $days DAY)";
     535            }
     536
     537            return null;
     538        }
    375539
    376540        /**
     
    381545            if (WP_DEBUG)
    382546                error_log("Request: " . print_r($_REQUEST, true));
    383             //the query
    384            
     547
     548            // Get base query
    385549            $query = $this->get_recipient_query($count);
    386 
    387550            $query_where = "";
    388             //take parameter into account
    389             $post = sanitize_post($_REQUEST);
    390 
    391             $register_format = $lastvisit_format = '%Y-%m-%d';
    392             //if only year is checked
    393             if (isset($post['sendsms_query_registered_years']))
    394                 $register_format = '%m-%d';
    395             if (isset($post['sendsms_query_connected_years']))
    396                 $lastvisit_format = '%m-%d';
    397 
    398             if ($post['sendsms_query_country'] && !empty($post['sendsms_query_country'])) {
    399                 $country_code = sanitize_text_field($post['sendsms_query_country']);
    400                 $country_data = explode('|', sanitize_text_field($post['sendsms_query_country']));
    401                 $country_key = $country_data[0];
    402                 $country_value = strtoupper($country_data[1]);
    403                 $query_where .= " AND ID IN (
    404                     SELECT user_id FROM $wpdb->usermeta
    405                     WHERE (meta_key = 'billing_country' AND meta_value = '$country_key')
    406                     OR (meta_key = 'shipping_country' AND UPPER(meta_value) = '$country_key')
    407                 )";
    408             }
    409            
    410             if ($post['sendsms_query_registered_from']) {
    411                 $date = strtotime($post['sendsms_query_registered_from'] . ' 00:00:00');
    412                 $date = date_i18n('Y-m-d H:i:s', $date);
    413                 $query_where .= ' AND ( DATE_FORMAT(wp_users.user_registered , \'' . $register_format . '\') >= DATE_FORMAT(\'' . $date . '\', \'' . $register_format . '\') ) ';
    414             }
    415             if ($post['sendsms_query_registered_to']) {
    416                 $date = strtotime($post['sendsms_query_registered_to'] . ' 00:00:00');
    417                 $date = date_i18n('Y-m-d H:i:s', $date);
    418                 $query_where .= ' AND ( DATE_FORMAT(wp_users.user_registered , \'' . $register_format . '\') <= DATE_FORMAT(\'' . $date . '\', \'' . $register_format . '\') ) ';
    419             }
    420             //TODO finish with others parameters
    421             if ($post['sendsms_query_connected_from']) {
    422                 $date = strtotime($post['sendsms_query_connected_from'] . ' 00:00:00');
    423                 $date = date_i18n('Y-m-d H:i:s', $date);
    424                 $query_where .= ' AND ( DATE_FORMAT(meta3.meta_value , \'' . $register_format . '\') >= DATE_FORMAT(\'' . $date . '\', \'' . $lastvisit_format . '\') ) ';
    425             }
    426             if ($post['sendsms_query_connected_to']) {
    427                 $date = strtotime($post['sendsms_query_connected_to'] . ' 00:00:00');
    428                 $date = date_i18n('Y-m-d H:i:s', $date);
    429                 $query_where .= ' AND ( DATE_FORMAT(meta3.meta_value , \'' . $register_format . '\') <= DATE_FORMAT(\'' . $date . '\', \'' . $lastvisit_format . '\') ) ';
    430             }
    431 
    432             //order number
    433             if ((isset($post['sendsms_query_orders_from']) && !empty($post['sendsms_query_orders_from']))
    434                     || (isset($post['sendsms_query_orders_to']) && !empty($post['sendsms_query_orders_to']))
    435                     || (isset($post['sendsms_query_orders_none'])) && !empty($post['sendsms_query_orders_none'])) {
    436                 $query_where .= ' AND (';
    437 
    438                 if ($post['sendsms_query_orders_from']) {
     551            $country_keys = array();
     552
     553            // Check if we have dynamic filters
     554            if (isset($_REQUEST['dynamic_filters']) && !empty($_REQUEST['dynamic_filters'])) {
     555                // NEW: Process dynamic filter structure
     556                $dynamic_filters = json_decode(stripslashes($_REQUEST['dynamic_filters']), true);
     557
     558                if (WP_DEBUG) {
     559                    error_log("Dynamic filters received: " . print_r($dynamic_filters, true));
     560                }
     561
     562                if ($dynamic_filters && isset($dynamic_filters['groups']) && is_array($dynamic_filters['groups'])) {
     563                    $group_clauses = array();
     564                    $group_operators = isset($dynamic_filters['group_operators']) ? $dynamic_filters['group_operators'] : array();
     565
     566                    foreach ($dynamic_filters['groups'] as $group_index => $group) {
     567                        if (!isset($group['filters']) || !is_array($group['filters']) || empty($group['filters'])) {
     568                            continue;
     569                        }
     570
     571                        $filter_clauses = array();
     572
     573                        foreach ($group['filters'] as $filter) {
     574                            $field = isset($filter['field']) ? $filter['field'] : '';
     575                            $operator = isset($filter['operator']) ? $filter['operator'] : '';
     576                            $value = isset($filter['value']) ? $filter['value'] : '';
     577                            $value2 = isset($filter['value2']) ? $filter['value2'] : '';
     578
     579                            if (empty($field) || empty($operator)) {
     580                                continue;
     581                            }
     582
     583                            $clause = $this->build_filter_clause($field, $operator, $value, $value2, $country_keys);
     584                            if ($clause) {
     585                                $filter_clauses[] = $clause;
     586                            }
     587                        }
     588
     589                        // Combine filters within group using AND
     590                        if (!empty($filter_clauses)) {
     591                            $group_clauses[] = '(' . implode(' AND ', $filter_clauses) . ')';
     592                        }
     593                    }
     594
     595                    // Combine groups using their operators (AND/OR)
     596                    if (!empty($group_clauses)) {
     597                        if (count($group_clauses) === 1) {
     598                            $query_where = ' AND ' . $group_clauses[0];
     599                        } else {
     600                            $combined = $group_clauses[0];
     601                            for ($i = 1; $i < count($group_clauses); $i++) {
     602                                $operator_between_groups = isset($group_operators[$i - 1]) ? strtoupper($group_operators[$i - 1]) : 'AND';
     603                                if ($operator_between_groups !== 'AND' && $operator_between_groups !== 'OR') {
     604                                    $operator_between_groups = 'AND';
     605                                }
     606                                $combined .= ' ' . $operator_between_groups . ' ' . $group_clauses[$i];
     607                            }
     608                            $query_where = ' AND (' . $combined . ')';
     609                        }
     610                    }
     611                }
     612            } else {
     613                // LEGACY: Process old-style static filters (for backward compatibility)
     614                $post = sanitize_post($_REQUEST);
     615                $register_format = $lastvisit_format = '%Y-%m-%d';
     616
     617                if (isset($post['sendsms_query_registered_years']))
     618                    $register_format = '%m-%d';
     619                if (isset($post['sendsms_query_connected_years']))
     620                    $lastvisit_format = '%m-%d';
     621
     622                if ($post['sendsms_query_country'] && !empty($post['sendsms_query_country'])) {
     623                    $country_code = sanitize_text_field($post['sendsms_query_country']);
     624                    $country_data = explode('|', sanitize_text_field($post['sendsms_query_country']));
     625                    $country_key = $country_data[0];
     626                    $country_value = strtoupper($country_data[1]);
     627                    $query_where .= " AND ID IN (
     628                        SELECT user_id FROM $wpdb->usermeta
     629                        WHERE (meta_key = 'billing_country' AND meta_value = '$country_key')
     630                        OR (meta_key = 'shipping_country' AND UPPER(meta_value) = '$country_key')
     631                    )";
     632                }
     633
     634                if ($post['sendsms_query_registered_from']) {
     635                    $date = strtotime($post['sendsms_query_registered_from'] . ' 00:00:00');
     636                    $date = date_i18n('Y-m-d H:i:s', $date);
     637                    $query_where .= ' AND ( DATE_FORMAT(wp_users.user_registered , \'' . $register_format . '\') >= DATE_FORMAT(\'' . $date . '\', \'' . $register_format . '\') ) ';
     638                }
     639                if ($post['sendsms_query_registered_to']) {
     640                    $date = strtotime($post['sendsms_query_registered_to'] . ' 00:00:00');
     641                    $date = date_i18n('Y-m-d H:i:s', $date);
     642                    $query_where .= ' AND ( DATE_FORMAT(wp_users.user_registered , \'' . $register_format . '\') <= DATE_FORMAT(\'' . $date . '\', \'' . $register_format . '\') ) ';
     643                }
     644
     645                if ($post['sendsms_query_connected_from']) {
     646                    $date = strtotime($post['sendsms_query_connected_from'] . ' 00:00:00');
     647                    $date = date_i18n('Y-m-d H:i:s', $date);
     648                    $query_where .= ' AND ( DATE_FORMAT(meta3.meta_value , \'' . $register_format . '\') >= DATE_FORMAT(\'' . $date . '\', \'' . $lastvisit_format . '\') ) ';
     649                }
     650                if ($post['sendsms_query_connected_to']) {
     651                    $date = strtotime($post['sendsms_query_connected_to'] . ' 00:00:00');
     652                    $date = date_i18n('Y-m-d H:i:s', $date);
     653                    $query_where .= ' AND ( DATE_FORMAT(meta3.meta_value , \'' . $register_format . '\') <= DATE_FORMAT(\'' . $date . '\', \'' . $lastvisit_format . '\') ) ';
     654                }
     655
     656                if ((isset($post['sendsms_query_orders_from']) && !empty($post['sendsms_query_orders_from']))
     657                        || (isset($post['sendsms_query_orders_to']) && !empty($post['sendsms_query_orders_to']))
     658                        || (isset($post['sendsms_query_orders_none'])) && !empty($post['sendsms_query_orders_none'])) {
     659                    $query_where .= ' AND (';
     660
     661                    if ($post['sendsms_query_orders_from']) {
     662                        if ($post['sendsms_query_orders_to']) {
     663                            $query_where .= ' ( ';
     664                        }
     665                        $query_where .= " (select count(*) from wp_posts post left join wp_postmeta meta0 on (meta0.post_id = post.ID) where post.post_type='shop_order' and meta0.meta_key='_customer_user' and meta0.meta_value=wp_users.ID) >= " . $post['sendsms_query_orders_from'];
     666                    }
    439667                    if ($post['sendsms_query_orders_to']) {
    440                         $query_where .= ' ( ';
    441                     }
    442                     $query_where .= " (select count(*) from wp_posts post left join wp_postmeta meta0 on (meta0.post_id = post.ID) where post.post_type='shop_order' and meta0.meta_key='_customer_user' and meta0.meta_value=wp_users.ID) >= " . $post['sendsms_query_orders_from'];
    443                 }
    444                 if ($post['sendsms_query_orders_to']) {
    445                     if ($post['sendsms_query_orders_from']) {
    446                         $query_where .= ' AND ';
    447                     }
    448                     $query_where .= "(select count(*) from wp_posts post left join wp_postmeta meta0 on (meta0.post_id = post.ID) where post.post_type='shop_order' and meta0.meta_key='_customer_user' and meta0.meta_value=wp_users.ID) <= " . $post['sendsms_query_orders_to'];
    449                     if ($post['sendsms_query_orders_from']) {
    450                         $query_where .= ' ) ';
    451                     }
    452                 }
    453                 if (array_key_exists('sendsms_query_orders_none',$post) && isset($post['sendsms_query_orders_none'])) {                   
    454                     $query_where .= "(select count(*) from wp_posts post left join wp_postmeta meta0 on (meta0.post_id = post.ID) where post.post_type='shop_order' and meta0.meta_key='_customer_user' and meta0.meta_value=wp_users.ID) = 0 ";                   
    455                 }
    456                 $query_where .= ') ';
     668                        if ($post['sendsms_query_orders_from']) {
     669                            $query_where .= ' AND ';
     670                        }
     671                        $query_where .= "(select count(*) from wp_posts post left join wp_postmeta meta0 on (meta0.post_id = post.ID) where post.post_type='shop_order' and meta0.meta_key='_customer_user' and meta0.meta_value=wp_users.ID) <= " . $post['sendsms_query_orders_to'];
     672                        if ($post['sendsms_query_orders_from']) {
     673                            $query_where .= ' ) ';
     674                        }
     675                    }
     676                    if (array_key_exists('sendsms_query_orders_none',$post) && isset($post['sendsms_query_orders_none'])) {
     677                        $query_where .= "(select count(*) from wp_posts post left join wp_postmeta meta0 on (meta0.post_id = post.ID) where post.post_type='shop_order' and meta0.meta_key='_customer_user' and meta0.meta_value=wp_users.ID) = 0 ";
     678                    }
     679                    $query_where .= ') ';
     680                }
    457681            }
    458682
    459683            $query .= " $query_where";
    460             // print_r($query); die();
    461             return $this->execute_recipient_query($query,$count,$country_key);           
     684
     685            // Add LIMIT to prevent server overload (max 3000 results)
     686            if (!$count) {
     687                $query .= " LIMIT 3000";
     688            }
     689
     690            if (WP_DEBUG) {
     691                error_log("Final query: " . $query);
     692            }
     693
     694            return $this->execute_recipient_query($query, $count, $country_keys);
    462695        }
    463696
  • insim/trunk/admin/partials/html-admin-page.php

    r3326386 r3381414  
    4141         if ( null != get_option('setting_change') && get_option('setting_change') == true ) {
    4242            $tabs = array(
     43                'campaigns' => __('SMS Campaigns', 'insim'),
    4344                 'automations' => __('SMS Automations', 'insim'),
    44                
     45   
    4546                //'history' => __('History', 'insim'),
    4647                 'helpdesk' => __('SMS Helpdesk CRM', 'insim'),
    47                  'campaigns' => __('SMS Campaigns (Beta evrsion)', 'insim'),
    4848                 'settings2' => __('Settings', 'insim'),
    4949                 'contact_us' => __('Contact us', 'insim')
     
    5252            $tabs = array(
    5353                'settings' => __('Settings', 'insim'),
     54                'campaigns' => __('SMS Campaigns', 'insim'),
    5455                'automations' => __('SMS Automations', 'insim'),
    5556               
    5657                //'history' => __('History', 'insim'),
    5758                 'helpdesk' => __('SMS Helpdesk CRM', 'insim'),
    58                  'campaigns' => __('SMS Campaigns (Beta version)', 'insim'),
     59                 
    5960                 'contact_us' => __('Contact us', 'insim')
    6061            );
  • insim/trunk/admin/sim-to-shop-admin.php

    r3022860 r3381414  
    112112            //icon of woocommerce
    113113            wp_enqueue_style(ABSPATH . 'wp-content/plugin/woocommerce.assets/css/mixins.css');
    114         }       
     114        }
    115115    }
    116116
     
    123123
    124124        wp_enqueue_script($this->sim_to_shop, plugin_dir_url(__FILE__) . 'js/sim-to-shop-admin.js', array('jquery'), $this->version, false);
    125        
     125
     126        // Enqueue ULTIMATE MODERN filter manager JavaScript
     127        wp_enqueue_script('insim-filter-modern', plugin_dir_url(__FILE__) . 'js/sim-to-shop-filter-manager-modern.js', array('jquery'), $this->version, false);
     128
     129        // Localize script for AJAX
     130        wp_localize_script('insim-filter-modern', 'insimUltimateData', array(
     131            'ajaxUrl' => admin_url('admin-ajax.php'),
     132            'campaignId' => isset($GLOBALS['insim_current_campaign_id']) ? $GLOBALS['insim_current_campaign_id'] : 0
     133        ));
     134
    126135        wp_enqueue_script( 'jquery-ui-datepicker' );
    127        
     136
    128137
    129138        wp_register_style( 'jquery-ui', plugin_dir_url(__FILE__) . 'css/jquery-ui.css');
    130        
    131         wp_enqueue_style( 'jquery-ui' ); 
     139
     140        wp_enqueue_style( 'jquery-ui' );
    132141    }   
    133142
  • insim/trunk/admin/sim-to-shop-generic-campaign-tab.php

    r3301630 r3381414  
    253253
    254254</Style>
    255 <button style ="border-radius: 15px 0 0 0; background-color: #777" class="tablink" onclick=" stp=1;document.getElementById('next_step').style.display = 'block'; document.getElementById('defaultOpen2').style.backgroundColor= '#555';document.getElementById('defaultOpen1').style.backgroundColor= '#777'; 
     255<button style ="border-radius: 15px 0 0 0; background-color: #777" class="tablink" onclick=" stp=1;document.getElementById('next_step').style.display = 'block'; document.getElementById('defaultOpen2').style.backgroundColor= '#555';document.getElementById('defaultOpen1').style.backgroundColor= '#777';
    256256document.getElementById('defaultOpen3').style.backgroundColor= '#555';
    257257document.getElementById('defaultOpen4').style.backgroundColor= '#555';
    258258document.getElementById('postbox-container-2').style.display = 'none';
    259 document.getElementById('sendsms_choose_recipient').style.display = 'block';
    260 document.getElementById('sendsms_recipient').style.display = 'block';
     259document.getElementById('insim-ultimate-filter-container').style.display = 'block';
    261260document.getElementById('sendsms_msg').style.display = 'none';
    262261document.getElementById('sendsms_titleA').style.display = 'none';
     
    274273 " id="defaultOpen1"><div style ="font-size:20px;color:#765f5f;text-align:center;line-height:0; 0;border-radius:50%;background:white; margin-right: 10px; padding: 7px 14px; display: inline;">1</div>Recipients</button>
    275274
    276 <button class="tablink" onclick=" stp=2; document.getElementById('next_step').style.display = 'block';document.getElementById('defaultOpen2').style.backgroundColor= '#777'; 
    277 document.getElementById('defaultOpen1').style.backgroundColor= '#555'; 
    278 document.getElementById('defaultOpen3').style.backgroundColor= '#555'; 
    279 document.getElementById('defaultOpen4').style.backgroundColor= '#555'; 
    280 document.getElementById('postbox-container-2').style.display = 'block'; document.getElementById('sendsms_choose_recipient').style.display = 'none';
    281 document.getElementById('sendsms_recipient').style.display = 'none';
     275<button class="tablink" onclick=" stp=2; document.getElementById('next_step').style.display = 'block';document.getElementById('defaultOpen2').style.backgroundColor= '#777';
     276document.getElementById('defaultOpen1').style.backgroundColor= '#555';
     277document.getElementById('defaultOpen3').style.backgroundColor= '#555';
     278document.getElementById('defaultOpen4').style.backgroundColor= '#555';
     279document.getElementById('postbox-container-2').style.display = 'block';
     280document.getElementById('insim-ultimate-filter-container').style.display = 'none';
    282281document.getElementById('sendsms_titleA').style.display = 'none';
    283282document.getElementById('sendsms_titleB').style.display = 'none';
     
    286285
    287286document.getElementById('url_track').style.display = 'block';
    288 document.getElementById('sendsms_choose_recipient').style.display = 'none';
    289287document.getElementById('meesageLength').style.display = 'block';
     288document.getElementById('sms_preview_container').style.display = 'flex';
     289document.getElementById('sms_metrics').style.display = 'block';
    290290document.getElementById('sendsms_titleB').style.display = 'none';
    291291document.getElementById('cmp_details').style.display = 'none';
     
    304304
    305305            document.getElementById('meesageLength').innerHTML = document.querySelector('[name = \'sendsms_message\']').value.length+`/160`;
     306            if (typeof updateMessageMetrics === 'function') { updateMessageMetrics(); }
    306307            document.querySelector('[name = \'sendsms_message\']').addEventListener('keyup', () => {
    307308                document.getElementById('meesageLength').innerHTML = document.querySelector('[name = \'sendsms_message\']').value.length+`/160`;
     309                if (typeof updateMessageMetrics === 'function') { updateMessageMetrics(); }
    308310            });
    309311
     
    319321document.getElementById('defaultOpen3').style.backgroundColor= '#777';
    320322document.getElementById('postbox-container-2').style.display = 'block';
    321 document.getElementById('sendsms_recipient').style.display = 'none';
     323document.getElementById('insim-ultimate-filter-container').style.display = 'none';
    322324document.getElementById('sendsms_titleA').style.display = 'block';
    323325document.getElementById('sendsms_titleB').style.display = 'block';
    324326
    325327document.getElementById('sendsms_msg').style.display = 'none';
    326 document.getElementById('sendsms_choose_recipient').style.display = 'none';
    327328document.getElementById('url_track').style.display = 'none';
    328329document.getElementById('sendsms_msg2').style.display = 'none';
    329330document.getElementById('meesageLength').style.display = 'none';
     331document.getElementById('sms_preview_container').style.display = 'none';
     332document.getElementById('sms_metrics').style.display = 'none';
    330333document.getElementById('cmp_details').style.display = 'none';
    331334document.getElementById('sendsms_buttons').style.display = 'none';
     
    342345document.getElementById('defaultOpen3').style.backgroundColor= '#555';
    343346document.getElementById('defaultOpen4').style.backgroundColor= '#777';
    344 document.getElementById('sendsms_recipient').style.display = 'none';
     347document.getElementById('insim-ultimate-filter-container').style.display = 'none';
    345348document.getElementById('postbox-container-2').style.display = 'block';
    346349document.getElementById('sendsms_titleA').style.display = 'none';
     
    348351document.getElementById('sendsms_msg2').style.display = 'none';
    349352
    350 document.getElementById('sendsms_choose_recipient').style.display = 'none';
    351353document.getElementById('url_track').style.display = 'none';
    352354document.getElementById('meesageLength').style.display = 'none';
    353355document.getElementById('sendsms_titleB').style.display = 'none';
     356document.getElementById('sms_preview_container').style.display = 'none';
     357document.getElementById('sms_metrics').style.display = 'none';
    354358document.getElementById('cmp_details').style.display = 'block';
    355359document.getElementById('sendsms_buttons').style.display = 'block';
     
    376380                        <input id ="next_step" class="btn btn-lg btn-primary float-right" style ="margin-left: 25px; margin-top: 25px;" type="submit" value ="<?php _e('Next Step', 'insim'); ?>" />
    377381
    378                         <div style = "width: 600px; display: none; margin-top: 40px;" id="postbox-container-2" class="postbox-container"><!-- left column-->
     382                        <div style = "width: 860px; display: none; margin-top: 40px;" id="postbox-container-2" class="postbox-container"><!-- left column-->
    379383                            <div class="postbox">
    380384                                <div class="panel-wrap woocommerce ">
     
    396400                                                <!-- Campaign details -->
    397401                                                <div id= "cmp_details">
    398                                                     <div class="card" style="box-shadow: 5px 5px lightgrey; margin-bottom: 50px;">
    399                                                         <div class="card-header">
    400                                                             <strong>Resume :</strong>
     402                                                    <div class="card" style="box-shadow: 0 6px 18px rgba(0,0,0,0.06); border-radius:14px; overflow:hidden; margin-bottom: 32px; border:1px solid #ececec;">
     403                                                        <div class="card-header" style="background:#f9fafb; padding:14px 16px; border-bottom:1px solid #ececec;">
     404                                                            <strong style="font-size:15px; color:#111827;">Summary</strong>
    401405                                                        </div>
    402                                                         <div class="card-body">
    403                                                             <p  style= "margin-top: 10px;"><span id ="nbrecres" style =" font-size: large;">Number of recipients : </span><?php echo ($this->_campaign->title != '' ? '<span style="background-color: #f7f1f1;">'.$this->_campaign->nb_recipients : '<span style="color: #1930df; background: #f3eeee;">The number will be calculated once the campaign is saved' ) ?></span>
    404                                                             </p>
    405                                                             <br />
    406                                                             <p  style= "margin-top: 10px;"><span style =" font-size: large;">Title : </span><span id ="titleres" style="background-color: #f7f1f1;"></span>
    407                                                             </p>
    408                                                             <br />
    409                                                             <p  style= "margin-top: 10px;"><span  style =" font-size: large;">Message : </span><span id ="msgres" style="background-color: #f7f1f1;"></span>
    410                                                             </p>
    411                                                             <br />
    412                                                             <p  style= "margin-top: 10px;"> <span style =" font-size: large;">Send date : </span><span id ="senddateres" style="background-color: #f7f1f1;"></span>
    413                                                             </p>
     406                                                        <div class="card-body" style="padding:16px;">
     407                                                            <div style="display:flex; gap:16px; flex-wrap:wrap;">
     408                                                                <div style="flex:1 1 230px; min-width:210px; border:1px dashed #e5e7eb; border-radius:10px; padding:12px; background:#ffffff;">
     409                                                                    <div style="font-size:12px; color:#6b7280; margin-bottom:6px;">Recipients</div>
     410                                                                    <div id="cmp_nb_recipients" style="font-size:16px; color:#111827; font-weight:600;">
     411                                                                        <?php echo '<span>'.intval($this->_campaign->nb_recipients).'</span>'; ?>
    414412                                                        </div>
     413                                                                </div>
     414                                                                <div style="flex:1 1 230px; min-width:210px; border:1px dashed #e5e7eb; border-radius:10px; padding:12px; background:#ffffff;">
     415                                                                    <div style="font-size:12px; color:#6b7280; margin-bottom:6px;">Title</div>
     416                                                                    <div id ="titleres" style="font-size:16px; color:#111827; font-weight:600;"></div>
     417                                                                </div>
     418                                                                <div style="flex:1 1 100%; min-width:210px; border:1px dashed #e5e7eb; border-radius:10px; padding:12px; background:#ffffff;">
     419                                                                    <div style="font-size:12px; color:#6b7280; margin-bottom:6px;">Message</div>
     420                                                                    <div id ="msgres" style="font-size:14px; color:#111827; white-space:pre-wrap; word-wrap:break-word;"></div>
     421                                                                </div>
     422                                                                <div style="flex:1 1 230px; min-width:210px; border:1px dashed #e5e7eb; border-radius:10px; padding:12px; background:#ffffff;">
     423                                                                    <div style="font-size:12px; color:#6b7280; margin-bottom:6px;">Send date</div>
     424                                                                    <div id ="senddateres" style="font-size:16px; color:#111827; font-weight:600;"></div>
     425                                                                </div>
     426                                                            </div>
     427                                                        </div>
     428                                                        <!-- Action buttons are already present below; avoid duplicates here. -->
    415429                                                    </div>
    416430                                                    <style>
     
    514528                                                    </div>
    515529                                                </div>
    516                                                 <!-- campaign title -->
    517                                                 <p id="sendsms_titleA" class="form-field form-field-wide">
    518                                                     <label for="sendsms_title"><span style ="font-size: x-large;"><?php _e('Title of the campaign', 'insim') ?></span></label><br/>
    519                                                     <input style="margin-top: 20px;" type="text" id="sendsms_title" name="sendsms_title" maxlength="255" value="<?php echo htmlentities($this->_campaign->title, ENT_QUOTES, 'utf-8'); ?>" />
    520                                                 </p>
     530                                                <!-- campaign title (modern card) -->
     531                                                <div id="sendsms_titleA" class="form-field form-field-wide" style="display:none;">
     532                                                    <div style="padding:16px; border:1px solid #e6e6e6; border-radius:12px; background:#fff; box-shadow:0 2px 8px rgba(0,0,0,0.03); border-top:4px solid #6a5cff;">
     533                                                        <label for="sendsms_title" style="display:block; font-size:14px; font-weight:600; color:#444; margin-bottom:8px;">Titre de la campagne</label>
     534                                                        <input type="text" id="sendsms_title" name="sendsms_title" maxlength="255" value="<?php echo htmlentities($this->_campaign->title, ENT_QUOTES, 'utf-8'); ?>" style="width:100%; max-width:520px; padding:10px 12px; border:1px solid #dcdcdc; border-radius:8px;" />
     535                                                    </div>
     536                                                </div>
    521537
    522538                                                <!-- campaign message-->
    523                                                 <p id ="sendsms_msg" class="form-field form-field-wide">
    524                                                     <label for="sendsms_title"><span style ="font-size: x-large;"><?php _e('Message') ?></span></label><br/>
    525                                                     <br/><span id="sendsms_msg2" style="margin-top: -10px;"><?php _e('Variables you can use : {firstname}, {lastname}', 'insim'); ?></span><br/>                             
    526                                                     <textarea class="form-control" style="margin-top: -10px;"
     539                                                <div id ="sendsms_msg" class="form-field form-field-wide" style="display:none;">
     540                                                    <div style="display:flex; gap:16px; align-items:flex-start;">
     541                                                        <!-- Editor column -->
     542                                                        <div style="flex:1 1 66%; min-width:420px; background:#fff; border:1px solid #e6e6e6; border-radius:12px; padding:14px; box-shadow:0 2px 8px rgba(0,0,0,0.03); border-top:4px solid #6a5cff;">
     543                                                            <label for="sendsms_title" style="display:block; font-size:14px; font-weight:600; color:#444;"><?php _e('Message') ?></label>
     544                                                            <div style="margin:8px 0 6px 0; display:flex; gap:8px; flex-wrap:wrap;">
     545                                                                <button type="button" class="button" style="background:#2271b1; color:#fff; border-color:#1f5f99;" onclick="insertToken('{firstname}')">{firstname}</button>
     546                                                                <button type="button" class="button" style="background:#2271b1; color:#fff; border-color:#1f5f99;" onclick="insertToken('{lastname}')">{lastname}</button>
     547                                                            </div>
     548                                                            <span id="sendsms_msg2" style="display:block; color:#6b7280; font-size:12px;">Variables disponibles : {firstname}, {lastname}</span>
     549                                                            <div style="position:relative; margin-top:6px;">
     550                                                                <textarea class="form-control" style="width:100%; max-width:100%; padding:12px 12px 22px 12px; border:1px solid #dcdcdc; border-radius:8px; min-height:200px;"
    527551                                                    <?php echo ($this->_campaign->status == 0 ? '' : 'readonly') ?>
    528                                                         rows="5" cols="50" name="sendsms_message" ><?php echo htmlentities($this->_campaign->message, ENT_QUOTES, 'utf-8'); ?></textarea> 
    529                                                     <div id = "meesageLength" style="margin-left: 517px; margin-top: -33px; display: block!important;">0/160</div>
    530                                                     <div id ="url_track" style="disply: inline-block; margin-top: 15px;" onclick="clickInsetTrackingUrl();">
     552                                                                    rows="8" cols="50" name="sendsms_message" ><?php echo htmlentities($this->_campaign->message, ENT_QUOTES, 'utf-8'); ?></textarea>
     553                                                                <div id = "meesageLength" style="position:absolute; right:10px; bottom:6px; color:#6b7280; font-size:12px;">0/160</div>
     554                                                            </div>
     555                                                            <div style="display:flex; justify-content:flex-end; align-items:center; margin-top:10px;">
     556                                                                <style>
     557                                                                    .insim-chip{display:inline-flex; align-items:center; gap:6px; padding:6px 10px; border-radius:999px; background:#f1f5ff; color:#1f3a8a; border:1px solid #dbe6ff; font-size:12px; font-weight:600;}
     558                                                                </style>
     559                                                                <div id="sms_metrics" style="display:none; gap:10px;">
     560                                                                    <span class="insim-chip">SMS :<strong id="sms_segments">0</strong></span>
     561                                                                    <span class="insim-chip" style="display:none;">Coût estimé :<strong id="sms_cost_estimate">—</strong></span>
     562                                                                </div>
     563                                                            </div>
     564                                                            <div id ="url_track" style="margin-top: 12px; display:flex; flex-direction:column; gap:8px;" onclick="clickInsetTrackingUrl();">
     565                                                                <span style="font-size:12px; color:#444;"><b>Insert trackable URL</b><sup>(1)</sup> <span style="font-style: oblique; color: #1aadba; font-weight: bold;">PREMIUM option</span><sup>(2)</sup></span>
     566                                                                <div style="display:flex; gap:8px; align-items:center;">
     567                                                                    <input id ="url_tracking_value" style="flex:1; min-width:0; padding:8px 10px; border:1px solid #dcdcdc; border-radius:8px;" type="text" placeholder="https://www.ardary-insim.com/example">
     568                                                                    <button id ="url_tracking" class="button"  <?php echo (get_option('is_premium') == false ? 'disabled title ="You can not use this option until you pay a subscription !"' : ''); ?> style="height:34px; cursor:pointer; white-space:nowrap; background:#2271b1; color:#fff; border-color:#1f5f99;">&nbsp;<?php _e('Insert in message', 'insim'); ?>&nbsp;</button>
     569                                                                </div>
     570                                                                <p id ='url_tracking_alert' style='display: none; color: red; padding-left: 5px;'><b style="font-weight: 900;"></b> You can not use this option until you pay a subscription ! </p>
     571                                                                <p style="margin-bottom: 0px!important; font-size:12px; color:#666;">(1) We create automatically a trackable short URL that allows you to get detailled analytics.</p>
     572                                                                <?php if ( get_option('is_premium') == false){
     573                                                                    echo '<p style="margin-top: 0; font-size:12px; color:#666;">(2) This is a PREMIUM feature. <a href="https://insim.app/" target ="_blank">Get PREMIUM</a>.</p>';
     574                                                                } else {
     575                                                                    echo '<p style="margin-top: 0; font-size:12px; color:#666;">(2) You are currently in the PREMIUM trial period, this feature is available to you.</p>';
     576                                                                  }
     577                                                                ?>
     578                                                            </div>
     579                                                        </div>
     580                                                        <!-- Preview column -->
     581                                                        <div id="sms_preview_container" style="flex:0 0 260px; display:none;">
     582                                                            <div style="margin-top:8px; padding:12px; border:1px solid #e0e0e0; border-radius:16px; background:#f9fafb; box-shadow: 0 2px 8px rgba(0,0,0,0.05);">
     583                                                                <style>
     584                                                                    .telnewsim{border-left:5px solid rgb(86,85,85);border-right:5px solid rgb(86,85,85);border-bottom:5px solid rgb(86,85,85);border-radius:0 0 12px 12px;background-color:#f2eeee;width:228px;height:280px;position:relative;margin:0 auto;}
     585                                                                    .smsnewsim{border-radius:6px;background-color:rgb(29,168,183);color:#fff;position:absolute;top:55px;right:10px;width:180px;padding:6px 8px;max-height:190px;overflow:auto;font-size:12px;line-height:1.4;word-wrap:break-word;white-space:pre-wrap;}
     586                                                                    .bottom-button-wrapper{position:absolute;bottom:-3px;height:12px;width:100%;}
     587                                                                    .bottom-button{height:10px;width:50px;border-radius:20px 20px 0 0;background-color:rgb(86,85,85);margin:0 auto;}
     588                                                                    .top-bar{height:28px;background:#f5f5f7;border-bottom:1px solid #ececec;display:flex;align-items:center;justify-content:center;color:#666;font-size:11px;border-top-left-radius:12px;border-top-right-radius:12px;}
     589                                                                </style>
     590                                                                <div class="telnewsim">
     591                                                                    <div class="top-bar">Preview</div>
     592                                                                    <div class="smsnewsim" id="sms_preview_text"></div>
     593                                                                    <div class="bottom-button-wrapper"><div class="bottom-button"></div></div>
     594                                                                </div>
     595                                                            </div>
     596                                                        </div>
     597                                                    </div>
     598                                                </div>
     599                                                    <div id ="url_track_old" style="display:none;" onclick="clickInsetTrackingUrl();">
    531600                                                        <br><span ><b>Insert trackable URL</b><sup>(1)</sup> <span style="font-style: oblique; color: #1aadba; font-weight: bold;">PREMIUM option</span><sup>(2)</sup></span></br>
    532601                                                        <input id ="url_tracking_value" style="width: 73%; disply: inline-block; margin-top: 15px;" type="text" placeholder="https://www.ardary-insim.com/example">
     
    541610                                                        ?>
    542611                                                    </div>                                                   
    543                                                 </p>
    544612
    545613                                                <!-- campaign date -->
    546                                                 <div style ="margin-top: 70px; display:inline-block;" id="sendsms_titleB" class="form-field form-field-wide"><label for="sendsms_date"><span style ="font-size: x-large;"><?php _e('Send date', 'insim') ?></span></label><br/>
    547                                                     <input style="margin-top: 20px; display: inline-block; width: 42%;" type="text" <?php echo ($this->_campaign->status < 2 ? '' : 'readonly') ?> class="date-picker-field datepicker" name="sendsms_date" id="sendsms_date" maxlength="10" value="<?php echo $this->_campaign->date_send != "0000-00-00 00:00:00" && $this->_campaign->date_send !="" ? date_i18n('Y-m-d', strtotime($this->_campaign->date_send)) : '' ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />
    548                                                     @<input style="margin-top: 20px; display: inline-block; width: 20%" type="text" <?php echo ($this->_campaign->status < 2 ? '' : 'readonly') ?> class="hour" style="width:2.5em" placeholder="<?php _e('h', 'insim') ?>" name="sendsms_date_hour" id="sendsms_date_hour" maxlength="2" size="2" value="<?php echo $this->_campaign->date_send != "0000-00-00 00:00:00" && $this->_campaign->date_send !="" ? date_i18n('H', strtotime($this->_campaign->date_send)) : '' ?>" pattern="\-?\d+(\.\d{0,})?" />
    549                                                     :<input style="margin-top: 20px; display: inline-block; width: 20%;" type="text" <?php echo ($this->_campaign->status < 2 ? '' : 'readonly') ?> class="minute" style="width:2.5em" placeholder="<?php _e('m', 'insim') ?>" name="sendsms_date_minute" id="sendsms_date_minute" maxlength="2" size="2" value="<?php echo $this->_campaign->date_send != "0000-00-00 00:00:00" && $this->_campaign->date_send !="" ? date_i18n('i', strtotime($this->_campaign->date_send)) : '' ?>" pattern="\-?\d+(\.\d{0,})?" />
    550                                                     <br><?php echo __('Time Zone:', 'insim') . ' ' . date_default_timezone_get(); ?>
     614                                                <div style ="margin-top: 20px; display:none;" id="sendsms_titleB" class="form-field form-field-wide">
     615                                                    <div style="padding:16px; border:1px solid #e6e6e6; border-radius:12px; background:#fff; box-shadow: 0 2px 8px rgba(0,0,0,0.03); border-top:4px solid #1eacba;">
     616                                                        <label for="sendsms_date" style="display:block; font-size:14px; font-weight:600; color:#444; margin-bottom:8px;"><?php _e('Send date', 'insim') ?></label>
     617                                                        <div style="display:flex; gap:12px; align-items:center; flex-wrap:wrap;">
     618                                                            <input style="margin-top: 4px; width: 180px; padding:10px 12px; border:1px solid #dcdcdc; border-radius:8px;" type="text" <?php echo ($this->_campaign->status < 2 ? '' : 'readonly') ?> class="date-picker-field datepicker" name="sendsms_date" id="sendsms_date" maxlength="10" value="<?php echo $this->_campaign->date_send != "0000-00-00 00:00:00" && $this->_campaign->date_send !="" ? date_i18n('Y-m-d', strtotime($this->_campaign->date_send)) : '' ?>" pattern="[0-9]{4}-(0[1-9]|1[012])-(0[1-9]|1[0-9]|2[0-9]|3[01])" />
     619                                                            <span style="opacity:.6;">@</span>
     620                                                            <input style="margin-top: 4px; width: 80px; padding:10px 12px; border:1px solid #dcdcdc; border-radius:8px;" type="text" <?php echo ($this->_campaign->status < 2 ? '' : 'readonly') ?> class="hour" placeholder="<?php _e('h', 'insim') ?>" name="sendsms_date_hour" id="sendsms_date_hour" maxlength="2" size="2" value="<?php echo $this->_campaign->date_send != "0000-00-00 00:00:00" && $this->_campaign->date_send !="" ? date_i18n('H', strtotime($this->_campaign->date_send)) : '' ?>" pattern="\-?\d+(\.\d{0,})?" />
     621                                                            <span style="opacity:.6;">:</span>
     622                                                            <input style="margin-top: 4px; width: 80px; padding:10px 12px; border:1px solid #dcdcdc; border-radius:8px;" type="text" <?php echo ($this->_campaign->status < 2 ? '' : 'readonly') ?> class="minute" placeholder="<?php _e('m', 'insim') ?>" name="sendsms_date_minute" id="sendsms_date_minute" maxlength="2" size="2" value="<?php echo $this->_campaign->date_send != "0000-00-00 00:00:00" && $this->_campaign->date_send !="" ? date_i18n('i', strtotime($this->_campaign->date_send)) : '' ?>" pattern="\-?\d+(\.\d{0,})?" />
     623                                                        </div>
     624                                                        <div style="margin-top:8px; color:#666; font-size:12px;"><?php echo __('Time Zone:', 'insim') . ' ' . date_default_timezone_get(); ?></div>
     625                                                    </div>
    551626                                            </div>
    552627
     
    588663        </Style>
    589664       
    590             <div style ="margin-left: 40px; display: inline-block;" id="sendsms_recipient" class="postbox-container postbox">               
     665            <div style ="margin-left: 40px; display: none !important; visibility: hidden !important;" id="sendsms_recipient" class="postbox-container postbox">
    591666                <?php
    592667                $myListTable = new Sim_To_Shop_Recipient_List(array('campaign' => $this->_campaign));
     
    599674                $myListTable->prepare_items();
    600675                $myListTable->display();
    601                 ?>               
     676                ?>
    602677            </div>
    603678            <?php
     
    719794        function output_choose_recipient() {
    720795            if (get_class($this) == 'Sim_To_Shop_Send_Tab' && $this->_campaign->status == 0) {
     796                // Set campaign ID for filter interface
     797                global $insim_current_campaign_id;
     798                $insim_current_campaign_id = $this->_campaign->id_sendsms_campaign;
    721799                ?>
    722800                <div class="poststuff">
    723                     <div id="sendsms_choose_recipient" class="postbox">
     801                    <!-- ULTIMATE MODERN FILTER INTERFACE -->
     802                    <?php include_once(plugin_dir_path(__FILE__) . 'partials/campaign-filter-interface-ultimate.php'); ?>
     803
     804                    <div id="sendsms_choose_recipient" class="postbox" style="display: none !important; visibility: hidden !important; height: 0 !important; overflow: hidden !important;">
    724805                        <style>
    725806                #add_recipient {       
     
    903984                    document.getElementById('sendsms_validate').setAttribute('disabled', 'disabled');
    904985                    document.getElementById('sendsms_validate').setAttribute('title', 'You have to save the modifications first !');
     986                if (typeof updateMessageMetrics === 'function') { updateMessageMetrics(); }
    905987                });
    906988                document.getElementById('url_tracking_value').addEventListener('input', function() {
     
    10391121
    10401122           
     1123            // Message metrics and preview
     1124            function isGsm7(txt){
     1125                try {
     1126                    // Basic heuristic: if all chars are in 0x00-0x7F and not requiring UCS-2
     1127                    return /^[\u0000-\u007F]*$/.test(txt);
     1128                } catch(e){ return true; }
     1129            }
     1130            function computeSegments(txt){
     1131                var gsm7 = isGsm7(txt);
     1132                var perSeg = gsm7 ? 160 : 70;
     1133                // Concatenated segments length: 153 for GSM7, 67 for UCS2
     1134                var concatLen = gsm7 ? 153 : 67;
     1135                var len = txt.length;
     1136                if (len <= perSeg) return {segments: (len>0?1:0), perSeg: perSeg};
     1137                return {segments: Math.ceil(len / concatLen), perSeg: concatLen};
     1138            }
     1139            function formatMoneyFR(n){
     1140                if (isNaN(n)) return '—';
     1141                return (Math.round(n*100)/100).toFixed(2).replace('.', ',') + ' €';
     1142            }
     1143            window.updateMessageMetrics = function(){
     1144                var ta = document.getElementsByName('sendsms_message')[0];
     1145                if (!ta) return;
     1146                var txt = ta.value || '';
     1147                var previewEl = document.getElementById('sms_preview_text');
     1148                if (previewEl){ previewEl.textContent = txt; }
     1149                var seg = computeSegments(txt);
     1150                var segEl = document.getElementById('sms_segments');
     1151                if (segEl){ segEl.textContent = seg.segments; }
     1152                // Auto-cost: use stored recipient count and default per-SMS if not yet priced
     1153                var defaultPerSms = 0.05;
     1154                var recipients = 0;
     1155                var nbRecEl = document.getElementById('nb_recipients');
     1156                if (nbRecEl){
     1157                    var v = nbRecEl.textContent || nbRecEl.innerText || '0';
     1158                    recipients = parseInt(v.replace(/[^0-9]/g,'')||'0',10) || 0;
     1159                }
     1160                // Fallback: if hidden nb_recipients is 0, try reading summary box live
     1161                if (!recipients) {
     1162                    var cmpBox = document.getElementById('cmp_nb_recipients');
     1163                    if (cmpBox){
     1164                        var vv = cmpBox.textContent || cmpBox.innerText || '0';
     1165                        recipients = parseInt(vv.replace(/[^0-9]/g,'')||'0',10) || 0;
     1166                    }
     1167                }
     1168                var estimatedPrice = recipients * seg.segments * defaultPerSms;
     1169                // Prefer dynamic estimate unless a non-zero price already exists from backend computation
     1170                var backendPrice = <?php echo isset($this->_campaign) && $this->_campaign->price ? floatval($this->_campaign->price) : 0; ?>;
     1171                var estimate = backendPrice > 0 ? backendPrice : estimatedPrice;
     1172                var costEl = document.getElementById('sms_cost_estimate');
     1173                if (costEl){ costEl.textContent = formatMoneyFR(estimate); }
     1174                if (typeof console !== 'undefined') {
     1175                    console.log('[inSIM] Metrics update', { smsSegments: seg.segments, recipients, defaultPerSms, backendPrice, estimate });
     1176                }
     1177            };
     1178            updateMessageMetrics();
     1179
     1180            // Token insertion helper
     1181            window.insertToken = function(token){
     1182                var ta = document.getElementsByName('sendsms_message')[0];
     1183                if (!ta) return;
     1184                var start = ta.selectionStart || ta.value.length;
     1185                var end = ta.selectionEnd || ta.value.length;
     1186                var before = ta.value.substring(0, start);
     1187                var after = ta.value.substring(end);
     1188                ta.value = before + token + after;
     1189                // move caret after inserted token
     1190                var pos = start + token.length;
     1191                if (ta.setSelectionRange){ ta.setSelectionRange(pos, pos); }
     1192                ta.focus();
     1193                if (typeof updateMessageMetrics === 'function') { updateMessageMetrics(); }
     1194                // refresh 160 counter
     1195                document.getElementById('meesageLength').innerHTML = ta.value.length+"/160";
     1196            };
     1197           
    10411198        });
    10421199                function changeSendMod(){
  • insim/trunk/admin/sim-to-shop-send-tab.php

    r3301630 r3381414  
    263263                    ORDER BY id_sendsms_recipient ASC
    264264                LIMIT 200');
     265                if (WP_DEBUG) error_log('[inSIM] transmitOWS() fetched recipients size='.(is_array($result)?count($result):0));
    265266                $size = count($result);
    266267                $total_rows = $wpdb->get_var('SELECT FOUND_ROWS()');
     
    321322                        $campaign->date_send = current_time('mysql');
    322323                        $campaign->compute_campaign(1); 
     324                        if (WP_DEBUG) error_log('[inSIM] After compute_campaign nb_recipients='.$campaign->nb_recipients.' price='.$campaign->price);
    323325                        $campaign->status_label = Sim_To_Shop_Admin::get_instance()->get_status($campaign->status);                       
    324326                    } else {
     
    427429            $campaign = new Sim_To_Shop_Campaign(sanitize_key($_REQUEST['id_sendsms_campaign']));
    428430            $result = $campaign->get_recipients_from_query(false);
    429             wp_send_json(array('total_rows' => sizeof($result)));
     431
     432            // Get pagination parameters (default: show first 10)
     433            $page = isset($_REQUEST['page']) ? intval($_REQUEST['page']) : 1;
     434            $per_page = isset($_REQUEST['per_page']) ? intval($_REQUEST['per_page']) : 10;
     435            $offset = ($page - 1) * $per_page;
     436
     437            $total_rows = is_array($result) ? sizeof($result) : 0;
     438
     439            // Debug logging
     440            if (WP_DEBUG) {
     441                error_log('[inSIM AJAX] Query result count: ' . $total_rows);
     442                error_log('[inSIM AJAX] Page: ' . $page . ', Per page: ' . $per_page . ', Offset: ' . $offset);
     443                if ($total_rows > 0 && isset($result[0])) {
     444                    error_log('[inSIM AJAX] First customer sample: ' . print_r($result[0], true));
     445                }
     446            }
     447
     448            // Paginate results
     449            $paginated_result = is_array($result) ? array_slice($result, $offset, $per_page) : array();
     450
     451            // Format customer data for display
     452            $customers = array();
     453            foreach ($paginated_result as $customer) {
     454                // Check both possible field names for order count
     455                $order_count = 0;
     456                if (isset($customer->order_nbr)) {
     457                    $order_count = intval($customer->order_nbr);
     458                } elseif (isset($customer->nb_order)) {
     459                    $order_count = intval($customer->nb_order);
     460                }
     461
     462                $customers[] = array(
     463                    'ID' => isset($customer->ID) ? $customer->ID : '',
     464                    'name' => isset($customer->display_name) ? $customer->display_name : '',
     465                    'display_name' => isset($customer->display_name) ? $customer->display_name : '',
     466                    'user_login' => isset($customer->user_login) ? $customer->user_login : '',
     467                    'email' => isset($customer->user_email) ? $customer->user_email : '',
     468                    'user_email' => isset($customer->user_email) ? $customer->user_email : '',
     469                    'phone' => isset($customer->billing_phone) ? $customer->billing_phone : '',
     470                    'billing_phone' => isset($customer->billing_phone) ? $customer->billing_phone : '',
     471                    'orders_count' => $order_count,
     472                    'country' => isset($customer->billing_country) ? $customer->billing_country : ''
     473                );
     474            }
     475
     476            // Debug logging
     477            if (WP_DEBUG) {
     478                error_log('[inSIM AJAX] Paginated result count: ' . count($paginated_result));
     479                error_log('[inSIM AJAX] Formatted customers count: ' . count($customers));
     480            }
     481
     482            wp_send_json(array(
     483                'total_rows' => $total_rows,
     484                'customers' => $customers,
     485                'page' => $page,
     486                'per_page' => $per_page,
     487                'total_pages' => $total_rows > 0 ? ceil($total_rows / $per_page) : 0
     488            ));
    430489        }
    431490
     
    442501                $campaign->isteam = sanitize_key($post['isteam']);
    443502                $campaign->save();
     503                // Ensure subsequent UI reloads point to the newly created campaign
     504                $_REQUEST['id_sendsms_campaign'] = $campaign->id_sendsms_campaign;
    444505            } else {
    445506                $campaign = new Sim_To_Shop_Campaign(sanitize_key($_REQUEST['id_sendsms_campaign']));
     
    465526                    $recipient->lastname = isset($row->billing_lastname) && $row->billing_lastname != '' ? $row->billing_lastname : $row->display_name;
    466527                    $recipient->lastname = preg_replace('/[0-9]+/', '', $recipient->lastname);
    467                     $phone = Sim_To_Shop_API::convert_phone_to_international($row->billing_phone, $row->billing_country);
     528                    // Use API instance (method is not static)
     529                    $phone = Sim_To_Shop_API::get_instance()->convert_phone_to_international($row->billing_phone, $row->billing_country);
    468530                    $recipient->phone = $phone;
    469531                    $recipient->iso_country = $row->billing_country;
     
    627689                if ($res) {
    628690                    $campaign->compute_campaign();
    629                     wp_send_json(array('campaign' => $campaign, 'recipient' => $recipient));
     691                    wp_send_json(array('campaign' => $campaign, 'recipient' => $recipient, 'id_sendsms_campaign' => $campaign->id_sendsms_campaign));
    630692                } else
    631693                    wp_send_json(array('error' => __('That phone number is already in the list.', 'insim')));
  • insim/trunk/inSIM.php

    r3301645 r3381414  
    1616 * Plugin URI:        https://ardary-insim.com/
    1717 * Description:       This plugin allows to create an automation or a campaign in order to send sms to a list of recipients as you can do with emails and newsletters.
    18  * Version:           3.0.0
     18 * Version:           4.0
    1919 * Author:            2WS Technologies
    2020 * Author URI:        https://ardary-insim.com/
     
    117117            'frompluguin' => true
    118118        ],
    119         'versionPlug' =>'3.0.0',
     119        'versionPlug' =>'4.0',
    120120        'shop_name' =>get_bloginfo(),
    121121        'shop_url' =>home_url(),
     
    153153            'admin_mail' => get_bloginfo('admin_email'),
    154154            'admin_phone' => get_user_meta(get_current_user_id(),'phone_number',true),
    155             'plugin_version' => '3.0.0',
     155            'plugin_version' => '4.0',
    156156            'shop_version' => $versionB,
    157157            'is_multi' => $isMulti
     
    313313        'admin_phone' => get_user_meta(get_current_user_id(),'phone_number',true),
    314314        'shop_url' => home_url(),
    315         'plugin_version' => '3.0.0',
     315        'plugin_version' => '4.0',
    316316        'type' => 'e-shop',
    317317        'name' => 'wooc',
     
    351351        'admin_phone' => get_user_meta(get_current_user_id(),'phone_number',true),
    352352        'shop_url' => home_url(),
    353         'plugin_version' => '3.0.0',
     353        'plugin_version' => '4.0',
    354354        'type' => 'e-shop',
    355355        'name' => 'wooc',
     
    383383
    384384require plugin_dir_path(__FILE__) . 'includes'.DIRECTORY_SEPARATOR.'sim-to-shop.php';
     385
     386// Load new advanced filter system AJAX handlers
     387require_once plugin_dir_path(__FILE__) . 'admin'.DIRECTORY_SEPARATOR.'sim-to-shop-ajax-handlers.php';
    385388
    386389/**
  • insim/trunk/includes/sim-to-shop.php

    r2837412 r3381414  
    184184        $this->loader->add_action('wp_ajax_addRecipientsFromQuery', $plugin_admin, 'action_add_recipients_from_query');
    185185        $this->loader->add_action('wp_ajax_countRecipientFromQuery', $plugin_admin, 'action_count_recipients_from_query');
     186        // NEW: Add modern interface actions with underscores
     187        $this->loader->add_action('wp_ajax_sim_to_shop_add_recipients_from_query', $plugin_admin, 'action_add_recipients_from_query');
     188        $this->loader->add_action('wp_ajax_sim_to_shop_count_recipients_from_query', $plugin_admin, 'action_count_recipients_from_query');
    186189        $this->loader->add_action('wp_ajax__ajax_fetch_custom_list', $plugin_admin, '_ajax_fetch_custom_list_callback');
    187190        $this->loader->add_action('wp_ajax__ajax_fetch_recipient_list', $plugin_admin, '_ajax_fetch_recipient_list_callback');
Note: See TracChangeset for help on using the changeset viewer.