Plugin Directory

Changeset 3205976


Ignore:
Timestamp:
12/10/2024 10:42:07 PM (16 months ago)
Author:
acteamintegrations
Message:

Version 2.8.0

Location:
activecampaign-for-woocommerce/trunk
Files:
2 added
39 edited

Legend:

Unmodified
Added
Removed
  • activecampaign-for-woocommerce/trunk/CHANGELOG.txt

    r3104234 r3205976  
    33**ActiveCampaign for WooCommerce**
    44
     5= 2.8.0 2024-12-10 =
     6* Feature - Product sync now has the option to directly pull products from the database
     7* Enhancement - Product sync will show the number of products available to sync for debugging purposes
     8* Bugfix - Fatal errors thrown by PHP 8.2 resolved
     9* Bugfix - Orders from WooCommerce sometimes synced to the wrong contact
     10* Bugfix - Products missing from product sync with some plugin customizations
     11* Bugfix - Edge case where some orders would convert to subscriptions and vanish from the store
     12
     13= 2.7.11 2024-11-13 =
     14* Bugfix - URL correction for setup
     15* Bugfix - Order created date fix
     16* Bugfix - Abandoned cart int fix
     17
     18= 2.7.10 2024-10-28 =
     19* Bugfix - Solving various issues with order update
     20* Bugfix - Abandoned cart created date error resolved
     21
     22= 2.7.9 2024-10-16 =
     23* Bugfix - Issue with our order action event has been resolved
     24
     25= 2.7.8 2024-10-15 =
     26* Bugfix - WooCommerce hook for stripe added to the order sync
     27* Bugfix - Order status changes should not get lost if done quickly
     28* Bugfix - Added debug display items for product sync
     29* Bugfix - Fixed product sync issue related to gathering records due to WC updates
     30
     31= 2.7.7 2024-09-11 =
     32* Enhancement - WooCommerce checkout blocks supported for abandoned cart
     33* Fix - Order pages no longer cause errors in the AC block
     34* Fix - Various issues due to WooCommerce changes
     35
     36= 2.7.6 2024-07-30 =
     37* Enhancement - Orders through Stripe will trigger the order updated hook
     38* Fix - WooCommerce Order with Stripe payment not updating correct status
     39* Fix - Product sync throws error on isVisible field
     40
     41= 2.7.5 2024-07-19 =
     42* Fix - Grammar tokens issue resolved
     43* Fix - Fetch parent category if variation has none set or is "uncategorized"
     44
     45= 2.7.4 2024-06-26 =
     46* Enhancement - New product sync option in settings for product description selection between full or short description
     47
    548= 2.7.3 2024-06-17 =
    6 * Fix for WCS not always returning all records in historical sync
    7 * Better error handling for bad records sent to ActiveCampaign
    8 * WooCommerce 9.0.0 compatibility updates
     49* Update - WooCommerce 9.0.0 compatibility updates
     50* Tweak - Better error handling for bad records sent to ActiveCampaign
     51* Fix - WCS not always returning all records in historical sync
    952
    1053= 2.7.2 2024-06-10 =
  • activecampaign-for-woocommerce/trunk/README.txt

    r3189047 r3205976  
    33Tags: marketing, ecommerce, woocommerce, email, activecampaign, abandoned cart
    44Requires at least: 6.0
    5 Tested up to: 6.7.0
    6 Stable tag: 2.7.11
     5Tested up to: 6.7.1
     6Stable tag: 2.8.0
    77Requires PHP: 7.4
    88License: GPLv2 or later
     
    6868
    6969= WooCommerce Compatibility =
    70 * Tested up to version: 9.4.1
     70* Tested up to version: 9.4.3
    7171* Minimal version requirement: 7.4.0
    7272* HPOS Compatible
     
    9494
    9595== Changelog ==
     96
     97= 2.8.0 2024-12-10 =
     98* Feature - Product sync now has the option to directly pull products from the database
     99* Enhancement - Product sync will show the number of products available to sync for debugging purposes
     100* Bugfix - Fatal errors thrown by PHP 8.2 resolved
     101* Bugfix - Orders from WooCommerce sometimes synced to the wrong contact
     102* Bugfix - Products missing from product sync with some plugin customizations
     103* Bugfix - Edge case where some orders would convert to subscriptions and vanish from the store
    96104
    97105= 2.7.11 2024-11-13 =
  • activecampaign-for-woocommerce/trunk/ac_vendor/autoload.php

    r3189047 r3205976  
    55require_once __DIR__ . '/composer/autoload_real.php';
    66
    7 return ComposerAutoloaderInitdd516b1c42b8adb957397bd81974f415::getLoader();
     7return ComposerAutoloaderInitd69e46321af071c131c0b9948fe62b79::getLoader();
  • activecampaign-for-woocommerce/trunk/ac_vendor/composer/autoload_classmap.php

    r3089566 r3205976  
    291291    'Activecampaign_For_Woocommerce_Ac_Features' => $baseDir . '/includes/features/class-activecampaign-for-woocommerce-ac-features.php',
    292292    'Activecampaign_For_Woocommerce_Ac_Features_Repository' => $baseDir . '/includes/repositories/class-activecampaign-for-woocommerce-ac-features-repository.php',
     293    'Activecampaign_For_Woocommerce_Ac_Tracking_Repository' => $baseDir . '/includes/repositories/class-activecampaign-for-woocommerce-ac-tracking-repository.php',
    293294    'Activecampaign_For_Woocommerce_Activator' => $baseDir . '/includes/class-activecampaign-for-woocommerce-activator.php',
    294295    'Activecampaign_For_Woocommerce_Add_Accepts_Marketing_To_Customer_Meta_Command' => $baseDir . '/includes/commands/class-activecampaign-for-woocommerce-add-accepts-marketing-to-customer-meta-command.php',
  • activecampaign-for-woocommerce/trunk/ac_vendor/composer/autoload_real.php

    r3189047 r3205976  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInitdd516b1c42b8adb957397bd81974f415
     5class ComposerAutoloaderInitd69e46321af071c131c0b9948fe62b79
    66{
    77    private static $loader;
     
    2525        require __DIR__ . '/platform_check.php';
    2626
    27         spl_autoload_register(array('ComposerAutoloaderInitdd516b1c42b8adb957397bd81974f415', 'loadClassLoader'), true, true);
     27        spl_autoload_register(array('ComposerAutoloaderInitd69e46321af071c131c0b9948fe62b79', 'loadClassLoader'), true, true);
    2828        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
    29         spl_autoload_unregister(array('ComposerAutoloaderInitdd516b1c42b8adb957397bd81974f415', 'loadClassLoader'));
     29        spl_autoload_unregister(array('ComposerAutoloaderInitd69e46321af071c131c0b9948fe62b79', 'loadClassLoader'));
    3030
    3131        $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
     
    3333            require __DIR__ . '/autoload_static.php';
    3434
    35             call_user_func(\Composer\Autoload\ComposerStaticInitdd516b1c42b8adb957397bd81974f415::getInitializer($loader));
     35            call_user_func(\Composer\Autoload\ComposerStaticInitd69e46321af071c131c0b9948fe62b79::getInitializer($loader));
    3636        } else {
    3737            $map = require __DIR__ . '/autoload_namespaces.php';
     
    5454
    5555        if ($useStaticLoader) {
    56             $includeFiles = Composer\Autoload\ComposerStaticInitdd516b1c42b8adb957397bd81974f415::$files;
     56            $includeFiles = Composer\Autoload\ComposerStaticInitd69e46321af071c131c0b9948fe62b79::$files;
    5757        } else {
    5858            $includeFiles = require __DIR__ . '/autoload_files.php';
    5959        }
    6060        foreach ($includeFiles as $fileIdentifier => $file) {
    61             composerRequiredd516b1c42b8adb957397bd81974f415($fileIdentifier, $file);
     61            composerRequired69e46321af071c131c0b9948fe62b79($fileIdentifier, $file);
    6262        }
    6363
     
    6666}
    6767
    68 function composerRequiredd516b1c42b8adb957397bd81974f415($fileIdentifier, $file)
     68function composerRequired69e46321af071c131c0b9948fe62b79($fileIdentifier, $file)
    6969{
    7070    if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
  • activecampaign-for-woocommerce/trunk/ac_vendor/composer/autoload_static.php

    r3189047 r3205976  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInitdd516b1c42b8adb957397bd81974f415
     7class ComposerStaticInitd69e46321af071c131c0b9948fe62b79
    88{
    99    public static $files = array (
     
    374374        'Activecampaign_For_Woocommerce_Ac_Features' => __DIR__ . '/../..' . '/includes/features/class-activecampaign-for-woocommerce-ac-features.php',
    375375        'Activecampaign_For_Woocommerce_Ac_Features_Repository' => __DIR__ . '/../..' . '/includes/repositories/class-activecampaign-for-woocommerce-ac-features-repository.php',
     376        'Activecampaign_For_Woocommerce_Ac_Tracking_Repository' => __DIR__ . '/../..' . '/includes/repositories/class-activecampaign-for-woocommerce-ac-tracking-repository.php',
    376377        'Activecampaign_For_Woocommerce_Activator' => __DIR__ . '/../..' . '/includes/class-activecampaign-for-woocommerce-activator.php',
    377378        'Activecampaign_For_Woocommerce_Add_Accepts_Marketing_To_Customer_Meta_Command' => __DIR__ . '/../..' . '/includes/commands/class-activecampaign-for-woocommerce-add-accepts-marketing-to-customer-meta-command.php',
     
    487488    {
    488489        return \Closure::bind(function () use ($loader) {
    489             $loader->prefixLengthsPsr4 = ComposerStaticInitdd516b1c42b8adb957397bd81974f415::$prefixLengthsPsr4;
    490             $loader->prefixDirsPsr4 = ComposerStaticInitdd516b1c42b8adb957397bd81974f415::$prefixDirsPsr4;
    491             $loader->classMap = ComposerStaticInitdd516b1c42b8adb957397bd81974f415::$classMap;
     490            $loader->prefixLengthsPsr4 = ComposerStaticInitd69e46321af071c131c0b9948fe62b79::$prefixLengthsPsr4;
     491            $loader->prefixDirsPsr4 = ComposerStaticInitd69e46321af071c131c0b9948fe62b79::$prefixDirsPsr4;
     492            $loader->classMap = ComposerStaticInitd69e46321af071c131c0b9948fe62b79::$classMap;
    492493
    493494        }, null, ClassLoader::class);
  • activecampaign-for-woocommerce/trunk/activecampaign-for-woocommerce.php

    r3189047 r3205976  
    1717 * Plugin URI:           https://www.activecampaign.com/
    1818 * Description:          Add Abandoned Cart functionality to your WooCommerce store, synchronize order & customer information using ActiveCampaign.
    19  * Version:              2.7.11
     19 * Version:              2.8.0
    2020 * WC requires at least: 7.4.0
    21  * WC tested up to:      9.4.1
     21 * WC tested up to:      9.4.3
    2222 * Requires at least:    6.0
    2323 * Requires PHP:         7.4
  • activecampaign-for-woocommerce/trunk/admin/class-activecampaign-for-woocommerce-admin-product-sync.php

    r3169593 r3205976  
    6666            );
    6767
    68             $data['products']     = $this->get_products_by_offset( -1, 15, true );
     68            $data['products']     = $this->get_all_product_ids_direct(); // Get the source
     69            $data['products_wc']  = $this->get_products_by_offset( -1, 15, true ); // works but does not have all records
    6970            $data['event_status'] = wp_get_scheduled_event( ACTIVECAMPAIGN_FOR_WOOCOMMERCE_RUN_PRODUCT_SYNC_NAME );
    7071            $data['page_url']     = esc_url( admin_url( 'admin.php?page=' . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_PLUGIN_NAME_SNAKE . '_product_sync&activesync=1' ) );
     
    8990        delete_option( ACTIVECAMPAIGN_FOR_WOOCOMMERCE_PRODUCT_SYNC_STOP_CHECK_NAME );
    9091        do_action( 'activecampaign_for_woocommerce_run_sync_connection' );
    91 
    9292        do_action( 'activecampaign_for_woocommerce_build_product_sync_schedules' );
    9393    }
  • activecampaign-for-woocommerce/trunk/admin/class-activecampaign-for-woocommerce-admin.php

    r3189047 r3205976  
    1818use Activecampaign_For_Woocommerce_AC_Contact_Repository as Contact_Repository;
    1919use Activecampaign_For_Woocommerce_Synced_Status_Interface as Synced_Status;
     20use Activecampaign_For_Woocommerce_Api_Client as Api_Client;
     21use Activecampaign_For_Woocommerce_Ac_Tracking_Repository as AC_Tracking;
    2022
    2123/**
    2224 * The admin-specific functionality of the plugin.
    23  *
     25 * AC_User
    2426 * Defines the plugin name, version, and two examples hooks for how to
    2527 * enqueue the admin-specific stylesheet and JavaScript.
     
    9496
    9597    /**
     98     * The class for the API client to connect to AC.
     99     *
     100     * @var Activecampaign_For_Woocommerce_Api_Client The client.
     101     */
     102    private $api_client;
     103
     104    /**
    96105     * Initialize the class and set its properties.
    97106     *
     
    105114     * @since    1.0.0
    106115     */
    107     public function __construct( $plugin_name, $version, Validator $validator, Admin_Settings_Updated $event, Connection_Repository $connection_repository, Contact_Repository $contact_repository ) {
     116    public function __construct( $plugin_name, $version, Validator $validator, Admin_Settings_Updated $event, Connection_Repository $connection_repository, Contact_Repository $contact_repository, Api_Client $api_client ) {
    108117        $this->plugin_name           = $plugin_name;
    109118        $this->version               = $version;
     
    112121        $this->connection_repository = $connection_repository;
    113122        $this->contact_repository    = $contact_repository;
     123        $this->api_client            = $api_client;
    114124    }
    115125
     
    841851        $api_url_changing = $this->api_url_is_changing( $data, $current_settings );
    842852
     853        if (
     854            isset( $current_settings['browse_tracking'] ) &&
     855            in_array( $current_settings['browse_tracking'], [ 1, '1' ] ) &&
     856            (
     857                ! isset( $current_settings['tracking_id'] ) ||
     858                empty( $current_settings['tracking_id'] )
     859            )
     860        ) {
     861            $tracking_id         = $this->activecampaign_fetch_accountid();
     862            $data['tracking_id'] = $tracking_id;
     863        }
     864
    843865        if ( $current_settings ) {
    844866            $data = array_merge( $current_settings, $data );
     
    13881410        wp_send_json_success( 'Entitlement ready for refresh' );
    13891411    }
     1412
     1413
     1414    /**
     1415     * Gets the tracking/account ID from AC.
     1416     *
     1417     * @return string tracking ID returned.
     1418     */
     1419    private function activecampaign_fetch_accountid() {
     1420        $logger = new Logger();
     1421
     1422        try {
     1423            $ac_user     = new AC_Tracking( $this->api_client );
     1424            $tracking_id = $ac_user->find_sitetracking_code();
     1425
     1426            // $result = $this->api_client->get( 'user/me' )->execute();
     1427
     1428            return $tracking_id;
     1429        } catch ( Throwable $t ) {
     1430            $logger->warning(
     1431                'Could not fetch tracking ID from ActiveCampaign.',
     1432                [
     1433                    'message' => $t->getMessage(),
     1434                    'code'    => 'ADMIN_1435',
     1435                ]
     1436            );
     1437        }
     1438    }
    13901439}
  • activecampaign-for-woocommerce/trunk/admin/scripts/activecampaign-for-woocommerce-product-sync.js

    r2810439 r3205976  
    66            $('.sync-run-status').hide();
    77            $('#activecampaign-run-product-wait').show();
    8             // $('#activecampaign-run-product-sync').addClass('disabled');
    98            $('#activecampaign-product-sync-run-shortly').show();
    109
    1110            var batchLimit = 20;
     11            var syncDirectMode = 0;
     12
     13            if($('.activecampaign-product-sync-direct-mode:checked').val() === '1') {
     14                syncDirectMode = 1;
     15            }
    1216
    1317            if($('#activecampaign-product-sync-limit').find(":selected").text()) {
     
    2024                'action': action,
    2125                'batchLimit': batchLimit,
     26                'syncDirectMode': syncDirectMode,
    2227                'activecampaign_for_woocommerce_settings_nonce_field': $('#activecampaign_for_woocommerce_nonce_field').val()
    2328            });
  • activecampaign-for-woocommerce/trunk/admin/trait-activecampaign-for-woocommerce-admin-utilities.php

    r3151035 r3205976  
    196196            }
    197197
     198            if ( ! isset( $current_options['browse_tracking'] ) ) {
     199                $options_to_be_saved['browse_tracking'] = '0';
     200            }
     201
    198202            if ( ! isset( $current_options['ac_debug'] ) ) {
    199203                $options_to_be_saved['ac_debug']        = '0';
  • activecampaign-for-woocommerce/trunk/admin/views/activecampaign-for-woocommerce-admin-display.php

    r3189047 r3205976  
    3737$activecampaign_for_woocommerce_debug_excess                  = 0;
    3838$activecampaign_for_woocommerce_desc_select                   = '0';
     39$activecampaign_for_woocommerce_browse_tracking               = '0';
    3940
    4041if ( is_array( $activecampaign_for_woocommerce_options ) ) {
     
    150151    }
    151152    $activecampaign_for_woocommerce_custom_email_field = esc_html( sanitize_text_field( $activecampaign_for_woocommerce_custom_email_field ) );
     153
     154    if ( isset( $activecampaign_for_woocommerce_settings['browse_tracking'] ) ) {
     155        $activecampaign_for_woocommerce_browse_tracking = $activecampaign_for_woocommerce_settings['browse_tracking'];
     156    }
     157    $activecampaign_for_woocommerce_browse_tracking = esc_html( sanitize_text_field( $activecampaign_for_woocommerce_browse_tracking ) );
    152158}
    153159
     
    180186    ),
    181187);
     188
    182189?>
    183190<?php settings_errors(); ?>
     191<style>
     192    .helptext {
     193        padding-left: 23px;
     194        font-style: italic;
     195    }
     196</style>
    184197<div id="activecampaign-for-woocommerce-app">
    185198    <?php
     
    241254                    </a>
    242255                    <div>
    243                     <div id="activecampaign-manual-mode-container">
    244                         or, <span id="activecampaign-manual-mode">manually configure the API</span>
    245                     </div>
     256                        <div id="activecampaign-manual-mode-container">
     257                            or, <span id="activecampaign-manual-mode">manually configure the API</span>
     258                        </div>
    246259                    </div>
    247260                </div>
     
    322335                    </span><?php esc_html_e( 'ActiveCampaign Configurations', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    323336                </label>
    324                     <div id="activecampaign_store" class="accordion-content">
     337                <div id="activecampaign_store" class="accordion-content">
     338                    <div>
    325339                        <div>
    326                             <div>
    327                                 <?php
    328                                 wp_nonce_field( 'activecampaign_for_woocommerce_settings_form', 'activecampaign_for_woocommerce_settings_nonce_field' );
    329                                 ?>
    330                                 <section id="activecampaign_connection_list">
    331                                     <div>
    332                                         <div id="activecampaign_connection_modal" class="hidden">
    333                                             <div class="modal-content">
    334                                                 <div class="notice notice-success inline" style="display:none;">
    335                                                     Connection Status
    336                                                 </div>
    337                                                 <input type="hidden" id="connection_id" name="connection_id" value="">
    338                                                 <label>Site URL <small>(Your WordPress Address URL: <?php echo esc_html( site_url() ); ?>)</small></label>
    339                                                 <input type="text" id="connection_external_id" name="connection_external_id" value="">
    340                                                 <label>Integration Name <small>(Used to identify your stores in ActiveCampaign. By default this is your Site Title.)</small></label>
    341                                                 <input type="text" id="connection_integration_name" name="connection_integration_name" value="">
    342                                                 <label>Store URL <small>(Your main store page: <?php echo esc_html( get_permalink( wc_get_page_id( 'shop' ) ) ); ?>)</small></label>
    343                                                 <input type="text" id="connection_integration_link" name="connection_integration_link" value="">
    344                                                 <input type="hidden" id="connection_integration_logo" name="connection_integration_logo" placeholder="Using default WooCommerce logo" value="">
    345                                                 <div class="activecampaign-block-inputs">
    346                                                     <a href="#" id="activecampaign-send-update-connection-button"
    347                                                        data-value="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
    348                                                        class="activecampaign-for-woocommerce button secondary" style="display:none;">
     340                            <?php
     341                            wp_nonce_field( 'activecampaign_for_woocommerce_settings_form', 'activecampaign_for_woocommerce_settings_nonce_field' );
     342                            ?>
     343                            <section id="activecampaign_connection_list">
     344                                <div>
     345                                    <div id="activecampaign_connection_modal" class="hidden">
     346                                        <div class="modal-content">
     347                                            <div class="notice notice-success inline" style="display:none;">
     348                                                Connection Status
     349                                            </div>
     350                                            <input type="hidden" id="connection_id" name="connection_id" value="">
     351                                            <label>Site URL <small>(Your WordPress Address URL: <?php echo esc_html( site_url() ); ?>)</small></label>
     352                                            <input type="text" id="connection_external_id" name="connection_external_id" value="">
     353                                            <label>Integration Name <small>(Used to identify your stores in ActiveCampaign. By default this is your Site Title.)</small></label>
     354                                            <input type="text" id="connection_integration_name" name="connection_integration_name" value="">
     355                                            <label>Store URL <small>(Your main store page: <?php echo esc_html( get_permalink( wc_get_page_id( 'shop' ) ) ); ?>)</small></label>
     356                                            <input type="text" id="connection_integration_link" name="connection_integration_link" value="">
     357                                            <input type="hidden" id="connection_integration_logo" name="connection_integration_logo" placeholder="Using default WooCommerce logo" value="">
     358                                            <div class="activecampaign-block-inputs">
     359                                                <a href="#" id="activecampaign-send-update-connection-button"
     360                                                   data-value="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
     361                                                   class="activecampaign-for-woocommerce button secondary" style="display:none;">
    349362                                    <span>
    350363                                        <?php esc_html_e( 'Update connection', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    351364                                    </span>
    352                                                     </a>
    353                                                     <a href="#" id="activecampaign-send-create-connection-button"
    354                                                        data-value="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
    355                                                        class="activecampaign-for-woocommerce button secondary" style="display:none;">
     365                                                </a>
     366                                                <a href="#" id="activecampaign-send-create-connection-button"
     367                                                   data-value="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
     368                                                   class="activecampaign-for-woocommerce button secondary" style="display:none;">
    356369                                    <span>
    357370                                        <?php esc_html_e( 'Create new connection', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    358371                                    </span>
    359                                                     </a>
    360                                                     <a href="#" id="activecampaign-cancel-connection-button"
    361                                                        data-value="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
    362                                                        class="activecampaign-for-woocommerce button secondary">
     372                                                </a>
     373                                                <a href="#" id="activecampaign-cancel-connection-button"
     374                                                   data-value="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
     375                                                   class="activecampaign-for-woocommerce button secondary">
    363376                                    <span>
    364377                                        Cancel
    365378                                    </span>
    366                                                     </a>
    367                                                 </div>
     379                                                </a>
    368380                                            </div>
    369381                                        </div>
    370                                         <div>
    371                                             <h2 style="float:left;">WooCommerce Connections</h2>
    372                                             <div style="float:right">
    373                                                 <a href="#" id="activecampaign-new-connection-button"
    374                                                    data-value="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
    375                                                    class="activecampaign-for-woocommerce">
     382                                    </div>
     383                                    <div>
     384                                        <h2 style="float:left;">WooCommerce Connections</h2>
     385                                        <div style="float:right">
     386                                            <a href="#" id="activecampaign-new-connection-button"
     387                                               data-value="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>"
     388                                               class="activecampaign-for-woocommerce">
    376389                        <span>
    377390                            <?php esc_html_e( 'Create a new connection', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    378391                        </span>
    379                                                 </a>
    380                                             </div>
    381                                             <table class="wp-list-table widefat striped table-view-list comments">
    382                                                 <thead>
    383                                                 <tr>
    384                                                     <th scope="col" >
    385                                                         Connection ID
    386                                                     </th>
    387                                                     <th scope="col">
    388                                                         Site URL
    389                                                     </th>
    390                                                     <th scope="col">
    391                                                         Integration Name
    392                                                     </th>
    393                                                     <th scope="col">
    394                                                         Store URL
    395                                                     </th>
    396                                                     <th scope="col">
    397                                                         Options
    398                                                     </th>
    399                                                     <th scope="col">
    400                                                         Status
    401                                                     </th>
    402                                                 </tr>
    403                                                 </thead>
    404 
    405                                                 <tbody id="the-connection-list" data-wp-lists="list:connection">
    406                                                 <tr><td colspan="6">Loading...</td></tr>
    407                                                 </tbody>
    408 
    409                                                 <tbody id="the-extra-comment-list" data-wp-lists="list:comment" style="display: none;">
    410                                                 <tr class="no-items"><td class="colspanchange" colspan="5">No comments found.</td></tr> </tbody>
    411                                             </table>
     392                                            </a>
    412393                                        </div>
     394                                        <table class="wp-list-table widefat striped table-view-list comments">
     395                                            <thead>
     396                                            <tr>
     397                                                <th scope="col" >
     398                                                    Connection ID
     399                                                </th>
     400                                                <th scope="col">
     401                                                    Site URL
     402                                                </th>
     403                                                <th scope="col">
     404                                                    Integration Name
     405                                                </th>
     406                                                <th scope="col">
     407                                                    Store URL
     408                                                </th>
     409                                                <th scope="col">
     410                                                    Options
     411                                                </th>
     412                                                <th scope="col">
     413                                                    Status
     414                                                </th>
     415                                            </tr>
     416                                            </thead>
     417
     418                                            <tbody id="the-connection-list" data-wp-lists="list:connection">
     419                                            <tr><td colspan="6">Loading...</td></tr>
     420                                            </tbody>
     421
     422                                            <tbody id="the-extra-comment-list" data-wp-lists="list:comment" style="display: none;">
     423                                            <tr class="no-items"><td class="colspanchange" colspan="5">No comments found.</td></tr> </tbody>
     424                                        </table>
    413425                                    </div>
    414                                 </section>
    415                             </div>
    416                             <?php if ( $this->verify_ac_features( 'abandon' ) ) : ?>
    417                                 <h2>
    418                                     <?php esc_html_e( 'Abandoned Cart', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    419                                 </h2>
    420                                 <p>
    421                                     <?php esc_html_e( 'How long should the store will wait before considering a cart abandoned to send to ActiveCampaign?', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    422                                 </p>
    423                                 <p>
    424                                     <?php esc_html_e( 'For example a 1 hour setting would wait until 1 hour after the last activity on the cart and then queue the cart for abandoned cart sync to ActiveCampaign. This relies on a cron job that runs hourly. It may be longer before an abandoned cart goes from ready to synced depending on your cron frequency.', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    425                                 </p>
    426                                 <label>
    427                                     <?php esc_html_e( 'Select wait time:', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    428                                 </label>
    429                                 <?php foreach ( $activecampaign_for_woocommerce_ab_cart_options as $activecampaign_for_woocommerce_ab_cart_options_value => $activecampaign_for_woocommerce_ab_cart_options_option ) : ?>
    430                                     <label class="radio">
    431                                         <input type="radio"
    432                                                id="abcart_wait<?php echo esc_html( $activecampaign_for_woocommerce_ab_cart_options_value ); ?>"
    433                                                name="abcart_wait"
    434                                                value="<?php echo esc_html( $activecampaign_for_woocommerce_ab_cart_options_value ); ?>"
    435                                             <?php
    436                                             if ( (string) $activecampaign_for_woocommerce_ab_cart_options_value === $activecampaign_for_woocommerce_abcart_wait ) {
    437                                                 echo 'checked';
    438                                             }
    439                                             ?>
    440                                         >
    441                                         <?php echo esc_html( $activecampaign_for_woocommerce_ab_cart_options_option ); ?>
    442                                     </label>
    443                                 <?php endforeach; ?>
    444                             <?php endif; ?>
    445                         </div>
    446                         <hr/>
    447                         <div>
     426                                </div>
     427                            </section>
     428                        </div>
     429                        <?php if ( $this->verify_ac_features( 'abandon' ) ) : ?>
    448430                            <h2>
    449                                 <?php esc_html_e( 'Opt-in Checkbox', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     431                                <?php esc_html_e( 'Abandoned Cart', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    450432                            </h2>
    451433                            <p>
    452                                 <?php esc_html_e( 'Configure what text should appear next to the opt-in checkbox, and whether that checkbox should be visible and checked by default.', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     434                                <?php esc_html_e( 'How long should the store will wait before considering a cart abandoned to send to ActiveCampaign?', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    453435                            </p>
    454                             <div>
    455                                 <label for="optin_checkbox_text">
    456                                     <?php esc_html_e( 'Checkbox text:', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    457                                 </label>
    458                                 <input type="text" name="optin_checkbox_text" id="optin_checkbox_text"
    459                                        value="<?php echo esc_html( $activecampaign_for_woocommerce_optin_checkbox_text ); ?>">
    460                             </div>
    461                             <h3>
    462                                 <?php esc_html_e( 'Checkbox display options:', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    463                             </h3>
    464                             <?php foreach ( $activecampaign_for_woocommerce_checkbox_display_options as $activecampaign_for_woocommerce_checkbox_display_options_value => $activecampaign_for_woocommerce_checkbox_display_options_option ) : ?>
    465                                 <label class="radio"
    466                                        for="checkbox_display_option_<?php echo esc_html( $activecampaign_for_woocommerce_checkbox_display_options_value ); ?>">
     436                            <p>
     437                                <?php esc_html_e( 'For example a 1 hour setting would wait until 1 hour after the last activity on the cart and then queue the cart for abandoned cart sync to ActiveCampaign. This relies on a cron job that runs hourly. It may be longer before an abandoned cart goes from ready to synced depending on your cron frequency.', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     438                            </p>
     439                            <label>
     440                                <?php esc_html_e( 'Select wait time:', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     441                            </label>
     442                            <?php foreach ( $activecampaign_for_woocommerce_ab_cart_options as $activecampaign_for_woocommerce_ab_cart_options_value => $activecampaign_for_woocommerce_ab_cart_options_option ) : ?>
     443                                <label class="radio">
    467444                                    <input type="radio"
    468                                            id="checkbox_display_option_<?php echo esc_html( $activecampaign_for_woocommerce_checkbox_display_options_value ); ?>"
    469                                            name="checkbox_display_option"
    470                                            value="<?php echo esc_html( $activecampaign_for_woocommerce_checkbox_display_options_value ); ?>"
     445                                           id="abcart_wait<?php echo esc_html( $activecampaign_for_woocommerce_ab_cart_options_value ); ?>"
     446                                           name="abcart_wait"
     447                                           value="<?php echo esc_html( $activecampaign_for_woocommerce_ab_cart_options_value ); ?>"
    471448                                        <?php
    472                                         if ( $activecampaign_for_woocommerce_checkbox_display_options_value === $activecampaign_for_woocommerce_optin_checkbox_display_option ) {
    473                                             echo esc_html( 'checked' );
     449                                        if ( (string) $activecampaign_for_woocommerce_ab_cart_options_value === $activecampaign_for_woocommerce_abcart_wait ) {
     450                                            echo 'checked';
    474451                                        }
    475452                                        ?>
    476453                                    >
    477                                     <?php echo esc_html( $activecampaign_for_woocommerce_checkbox_display_options_option ); ?>
     454                                    <?php echo esc_html( $activecampaign_for_woocommerce_ab_cart_options_option ); ?>
    478455                                </label>
    479456                            <?php endforeach; ?>
    480                         </div>
    481                         <hr/>
    482                         <?php if ( $this->verify_ac_features( 'abandon' ) ) : ?>
     457                        <?php endif; ?>
     458                    </div>
     459                    <hr/>
     460                    <div>
     461                        <h2>
     462                            <?php esc_html_e( 'Opt-in Checkbox', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     463                        </h2>
     464                        <p>
     465                            <?php esc_html_e( 'Configure what text should appear next to the opt-in checkbox, and whether that checkbox should be visible and checked by default.', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     466                        </p>
     467                        <div>
     468                            <label for="optin_checkbox_text">
     469                                <?php esc_html_e( 'Checkbox text:', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     470                            </label>
     471                            <input type="text" name="optin_checkbox_text" id="optin_checkbox_text"
     472                                   value="<?php echo esc_html( $activecampaign_for_woocommerce_optin_checkbox_text ); ?>">
     473                        </div>
     474                        <h3>
     475                            <?php esc_html_e( 'Checkbox display options:', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     476                        </h3>
     477                        <?php foreach ( $activecampaign_for_woocommerce_checkbox_display_options as $activecampaign_for_woocommerce_checkbox_display_options_value => $activecampaign_for_woocommerce_checkbox_display_options_option ) : ?>
     478                            <label class="radio"
     479                                   for="checkbox_display_option_<?php echo esc_html( $activecampaign_for_woocommerce_checkbox_display_options_value ); ?>">
     480                                <input type="radio"
     481                                       id="checkbox_display_option_<?php echo esc_html( $activecampaign_for_woocommerce_checkbox_display_options_value ); ?>"
     482                                       name="checkbox_display_option"
     483                                       value="<?php echo esc_html( $activecampaign_for_woocommerce_checkbox_display_options_value ); ?>"
     484                                    <?php
     485                                    if ( $activecampaign_for_woocommerce_checkbox_display_options_value === $activecampaign_for_woocommerce_optin_checkbox_display_option ) {
     486                                        echo esc_html( 'checked' );
     487                                    }
     488                                    ?>
     489                                >
     490                                <?php echo esc_html( $activecampaign_for_woocommerce_checkbox_display_options_option ); ?>
     491                            </label>
     492                        <?php endforeach; ?>
     493                    </div>
     494                    <hr/>
     495                    <?php if ( $this->verify_ac_features( 'abandon' ) ) : ?>
     496                        <div>
     497                            <h2>
     498                                <?php esc_html_e( 'Historical Sync Options', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     499                            </h2>
    483500                            <div>
    484                                 <h2>
    485                                     <?php esc_html_e( 'Historical Sync Options', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    486                                 </h2>
    487                                 <div>
    488                                     Change these settings according to your hosting capabilities. Lower numbers will take longer but consume less resources.
    489                                 </div>
    490                                 <div>
    491                                     <label>Runs Per Batch: <span class="help"> (ex: Every time the sync runs 10 batch groups of 50 will run)</span></label>
    492                                     <input type="number" name="sync_batch_runs" id="sync_batch_runs" min="1" max="40"
    493                                            value="<?php echo esc_html( $activecampaign_for_woocommerce_sync_batch_runs ); ?>">
    494                                 </div>
    495                                 <div>
    496                                     <label>Bulk Sync Batch Limit: <span class="help">(num of records synced to ActiveCampaign at a time)</span></label>
    497                                     <input type="number" name="sync_batch_limit" id="sync_batch_limit" min="1" max="50"
    498                                            value="<?php echo esc_html( $activecampaign_for_woocommerce_sync_batch_limit ); ?>"> Max 50
    499                                 </div>
     501                                Change these settings according to your hosting capabilities. Lower numbers will take longer but consume less resources.
    500502                            </div>
    501                         <?php endif; ?>
    502                         <hr/>
    503                         <?php if ( $this->verify_ac_features( 'product' ) ) : ?>
    504503                            <div>
    505                                 <h2>
    506                                     <?php esc_html_e( 'Product Sync Options', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    507                                 </h2>
    508                                 <label>
    509                                     <?php esc_html_e( 'Product Description:', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
    510                                 </label>
    511                                 <label class="radio">
    512                                     <input type="radio" id="ac_desc_select0" name="ac_desc_select" value="0"
    513                                         <?php
    514                                         if ( '0' === $activecampaign_for_woocommerce_desc_select ) {
    515                                             echo 'checked';
    516                                         }
    517                                         ?>
    518                                     > Use full description only
    519                                     <div style="padding-left: 23px;font-style:italic;">
    520                                         My product descriptions can be assumed to be readable in a small email content block
    521                                     </div>
    522                                 </label>
    523                                 <label class="radio">
    524                                     <input type="radio" id="ac_desc_select1" name="ac_desc_select" value="1"
    525                                         <?php
    526                                         if ( '1' === $activecampaign_for_woocommerce_desc_select ) {
    527                                             echo 'checked';
    528                                         }
    529                                         ?>
    530                                     > Use short description only
    531 
    532                                     <div style="padding-left: 23px;font-style:italic;">
    533                                         (Will sync with description empty if short description is not included)<br/>
    534                                         My full length descriptions are too long for a small email content block, I need the short description
    535                                     </div>
    536                                 </label>
    537                                 <label class="radio">
    538                                     <input type="radio" id="ac_desc_select2" name="ac_desc_select" value="2"
    539                                         <?php
    540                                         if ( '2' === $activecampaign_for_woocommerce_desc_select ) {
    541                                             echo 'checked';
    542                                         }
    543                                         ?>
    544                                     > Use short description but fall back to full description. <small>[Suggested]</small>
    545                                     <div style="padding-left: 23px;font-style:italic;">
    546                                         (If the short description is not included it will fall back to the full description.)<br/>
    547                                         I prefer the short description, but don’t want anything showing up empty
    548                                     </div>
    549                                 </label>
     504                                <label>Runs Per Batch: <span class="help"> (ex: Every time the sync runs 10 batch groups of 100 will run)</span></label>
     505                                <input type="number" name="sync_batch_runs" id="sync_batch_runs" min="1" max="40"
     506                                       value="<?php echo esc_html( $activecampaign_for_woocommerce_sync_batch_runs ); ?>">
    550507                            </div>
    551                         <?php endif; ?>
    552                     </div>
     508                            <div>
     509                                <label>Bulk Sync Batch Limit: <span class="help">(num of records synced to ActiveCampaign at a time)</span></label>
     510                                <input type="number" name="sync_batch_limit" id="sync_batch_limit" min="1" max="50"
     511                                       value="<?php echo esc_html( $activecampaign_for_woocommerce_sync_batch_limit ); ?>"> Max 50
     512                            </div>
     513                        </div>
     514                    <?php endif; ?>
     515                    <hr/>
     516                    <?php if ( $this->verify_ac_features( 'product' ) ) : ?>
     517                        <div>
     518                            <h2>
     519                                <?php esc_html_e( 'Product Sync Options', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     520                            </h2>
     521                            <label>
     522                                <?php esc_html_e( 'Product Description:', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     523                            </label>
     524                            <label class="radio">
     525                                <input type="radio" id="ac_desc_select0" name="ac_desc_select" value="0"
     526                                    <?php
     527                                    if ( '0' === $activecampaign_for_woocommerce_desc_select ) {
     528                                        echo 'checked';
     529                                    }
     530                                    ?>
     531                                > Use full description only
     532                                <div style="padding-left: 23px;font-style:italic;">
     533                                    My product descriptions can be assumed to be readable in a small email content block
     534                                </div>
     535                            </label>
     536                            <label class="radio">
     537                                <input type="radio" id="ac_desc_select1" name="ac_desc_select" value="1"
     538                                    <?php
     539                                    if ( '1' === $activecampaign_for_woocommerce_desc_select ) {
     540                                        echo 'checked';
     541                                    }
     542                                    ?>
     543                                > Use short description only
     544
     545                                <div style="padding-left: 23px;font-style:italic;">
     546                                    (Will sync with description empty if short description is not included)<br/>
     547                                    My full length descriptions are too long for a small email content block, I need the short description
     548                                </div>
     549                            </label>
     550                            <label class="radio">
     551                                <input type="radio" id="ac_desc_select2" name="ac_desc_select" value="2"
     552                                    <?php
     553                                    if ( '2' === $activecampaign_for_woocommerce_desc_select ) {
     554                                        echo 'checked';
     555                                    }
     556                                    ?>
     557                                > Use short description but fall back to full description. <small>[Suggested]</small>
     558                                <div style="padding-left: 23px;font-style:italic;">
     559                                    (If the short description is not included it will fall back to the full description.)<br/>
     560                                    I prefer the short description, but don’t want anything showing up empty
     561                                </div>
     562                            </label>
     563                        </div>
     564                    <?php endif; ?>
     565                    <?php if ( $this->verify_ac_features( 'browsetracking' ) ) : ?>
     566                        <div>
     567                            <h2>
     568                                <?php esc_html_e( 'Tracking &amp; Browse Abandonment', ACTIVECAMPAIGN_FOR_WOOCOMMERCE_LOCALIZATION_DOMAIN ); ?>
     569                            </h2>
     570                            <label class="radio">
     571                                <input type="radio" id="browse_tracking1" name="browse_tracking" value="1"
     572                                    <?php
     573                                    if ( '1' === $activecampaign_for_woocommerce_browse_tracking ) {
     574                                        echo 'checked';
     575                                    }
     576                                    ?>
     577                                > Enabled (Track by default)
     578                                <p class="helptext">
     579                                    This option will track all known contacts by default, and will not provide an additional tracking consent notice to your contacts.
     580                                </p>
     581                            </label>
     582                            <label class="radio">
     583                                <input type="radio" id="browse_tracking2" name="browse_tracking" value="2"
     584                                    <?php
     585                                    if ( '2' === $activecampaign_for_woocommerce_browse_tracking ) {
     586                                        echo 'checked';
     587                                    }
     588                                    ?>
     589                                > Enabled (Do not track by default)
     590                                <p class="helptext">
     591                                    This option will not track all known contacts by default.
     592                                    Your contacts will only be tracked after they confirm tracking consent.
     593                                    You must develop a tracking consent notice, and connect it to this plugin, to use this option. You can call the hook [activecampaign_for_woocommerce_load_sitetracking] to then load the tracking.
     594                                </p>
     595                            </label>
     596                            <label class="radio">
     597                                <input type="radio" id="browse_tracking0" name="browse_tracking" value="0"
     598                                    <?php
     599                                    if ( '0' === $activecampaign_for_woocommerce_browse_tracking ) {
     600                                        echo 'checked';
     601                                    }
     602                                    ?>
     603                                > Off
     604                            </label>
     605                        </div>
     606                    <?php endif; ?>
     607                </div>
    553608            </section>
    554609
  • activecampaign-for-woocommerce/trunk/admin/views/activecampaign-for-woocommerce-product-sync.php

    r3169593 r3205976  
    4646                            </div>
    4747                            <div class="mb-500">
    48                                 There are <?php echo esc_html( count( $activecampaign_for_woocommerce_product_sync_data['products'] ) ); ?> products available to sync.
    49                             </div>
    50 
    51                             <div class="mb-500">
    5248                                <button type="button" id="activecampaign-run-product-sync" class="activecampaign-for-woocommerce button button-primary" style="padding: 0 10px">
    5349                                    <?php
     
    6864                            </div>
    6965                            <div>
     66                                <div class="mb-500">
     67                                    <label>If these values match please choose the safe option.</label><br/>
     68                                    <input type="radio" class="activecampaign-product-sync-direct-mode" name="activecampaign-product-sync-direct-mode" value="0" checked /> <?php echo esc_html( count( $activecampaign_for_woocommerce_product_sync_data['products_wc'] ) ); ?> records via WooCommerce safe methods<br/>
     69                                    <input type="radio" class="activecampaign-product-sync-direct-mode" name="activecampaign-product-sync-direct-mode" value="1" /> <?php echo esc_html( count( $activecampaign_for_woocommerce_product_sync_data['products'] ) ); ?> records via direct data pull<br/>
     70                                </div>
    7071                                <div>
    7172                                    <label>Batch Limit: </label>
  • activecampaign-for-woocommerce/trunk/includes/abandoned_carts/class-activecampaign-for-woocommerce-run-abandonment-sync-command.php

    r3177307 r3205976  
    712712            if ( $synced_to_ac ) {
    713713                // Update the record to show we've synced so we don't sync it again
    714 
    715                 $wpdb->update(
    716                     $wpdb->prefix . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_TABLE_NAME,
    717                     array(
     714                if ($order_ac->get_email() !== $customer->email ) {
     715                    // The emails don't match!
     716                    $this->logger->warning(
     717                        'The returned email does not match. This could cause an issue with this contact record. Do not save customer ID in this case.',
     718                        [
     719                            'ac_email'       => $order_ac->get_email(),
     720                            'customer_email' => $customer->email,
     721                        ]
     722                    );
     723                    $ab_data_save = array(
     724                        'synced_to_ac'   => self::STATUS_ABANDONED_CART_AUTO_SYNCED,
     725                        'abandoned_date' => $this->calculate_abandoned_date( $abc_order ),
     726                        'ac_order_id'    => self::validate_object( $order_ac, 'get_id' ) ? $order_ac->get_id() : null,
     727                        'ac_customer_id' => null,
     728                    );
     729                } else {
     730                    $ab_data_save = array(
    718731                        'synced_to_ac'   => self::STATUS_ABANDONED_CART_AUTO_SYNCED,
    719732                        'abandoned_date' => $this->calculate_abandoned_date( $abc_order ),
    720733                        'ac_order_id'    => self::validate_object( $order_ac, 'get_id' ) ? $order_ac->get_id() : null,
    721734                        'ac_customer_id' => self::validate_object( $order_ac, 'get_customerid' ) ? $order_ac->get_customerid() : null,
    722                     ),
     735                    );
     736                }
     737
     738                $wpdb->update(
     739                    $wpdb->prefix . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_TABLE_NAME,
     740                    $ab_data_save,
    723741                    array(
    724742                        'id' => $abc_order->id,
     
    10111029
    10121030        if ( isset( $cart->last_access_time ) && ( ! isset( $cart->abandoned_date ) || empty( $cart->abandoned_date ) ) ) {
    1013             try {
     1031
    10141032                $now = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
    10151033
    1016                 if ( ! isset( $this->expire_time ) || empty( $this->expire_time ) ) {
    1017                     $this->expire_time = 1;
    1018                 }
     1034                // 1 hour is the default
     1035            if ( ! isset( $this->expire_time ) || empty( $this->expire_time ) ) {
     1036                $this->expire_time = 1;
     1037            }
    10191038
    10201039                $expire_datetime = new DateTime( 'now -' . $this->expire_time . ' hours', new DateTimeZone( 'UTC' ) );
    10211040                $ab_date         = new DateTime( $cart->last_access_time . ' + ' . $this->expire_time . ' hours', new DateTimeZone( 'UTC' ) );
    10221041
    1023                 $diff = $expire_datetime->diff( $ab_date, true );
    1024                 $i    = 0 + ( $diff->days * 24 );
    1025                 $i   += $diff->hours;
    1026 
     1042                $i        = 0;
     1043                $hourdiff = 0;
     1044
     1045            try {
     1046                $diff           = $expire_datetime->diff( $ab_date, true );
     1047                $hours_in_days  = $diff->format( '%d' ) * 24; // get number of hours in days
     1048                $hours_in_hours = $diff->format( '%h' ); // add number of hours in hours
     1049
     1050                if ( ! empty( $hours_in_days ) ) {
     1051                    $i += intval( $hours_in_days );
     1052                }
     1053
     1054                if ( ! empty( $hours_in_hours ) ) {
     1055                    $i += intval( $hours_in_hours );
     1056                }
     1057            } catch ( Throwable $t ) {
     1058                // cannot use this method on this install
     1059                $this->logger->debug(
     1060                    'Primary time diff in hours could not be calculated for the abandoned cart.',
     1061                    [
     1062                        'cartid'           => $cart->id,
     1063                        'message'          => $t->getMessage(),
     1064                        'trace'            => $t->getTrace(),
     1065                        'last_access_time' => $cart->last_access_time,
     1066                    ]
     1067                );
     1068            }
     1069
     1070            try {
     1071                // secondary method to check
     1072                $hourdiff = round( ( strtotime( $cart->last_access_time + $this->expire_time ) - strtotime( $expire_datetime->format( 'Y-m-d H:i:s' ) ) ) / 3600, 0 );
     1073            } catch ( Throwable $t ) {
     1074                // cannot use this method
     1075                $this->logger->debug(
     1076                    'Secondary time diff in hours could not be calculated for the abandoned cart.',
     1077                    [
     1078                        'cartid'           => $cart->id,
     1079                        'message'          => $t->getMessage(),
     1080                        'trace'            => $t->getTrace(),
     1081                        'last_access_time' => $cart->last_access_time,
     1082                    ]
     1083                );
     1084            }
     1085            try {
    10271086                // calc_abandoned_date is calculated by the DB
    10281087                if ( ! empty( $cart->calc_abandoned_date ) && empty( $cart->abandoned_date ) ) {
     
    10311090                } elseif ( empty( $cart->calc_abandoned_date ) && empty( $cart->abandoned_date ) ) {
    10321091                    // If the DB somehow fails to calculate the date
    1033                     if ( intval( $i ) >= $this->expire_time ) {
     1092                    if ( $i >= $this->expire_time || $hourdiff >= $this->expire_time ) {
    10341093                        // If the expiration and abandonment difference is more than the expire time
    10351094                        return $ab_date->format( 'Y-m-d H:i:s e' );
  • activecampaign-for-woocommerce/trunk/includes/abandoned_carts/trait-activecampaign-for-woocommerce-abandoned-cart-utilities.php

    r3189047 r3205976  
    128128        $logger        = new Logger();
    129129        if ( isset( $order ) && ! empty( $order ) ) {
    130             $customer_id = $customer_util->get_customer_id( $order );
     130            $customer_id = $customer_util->get_wc_customer_id( $order );
    131131        }
    132132
     
    154154    public function delete_abandoned_cart_by_customer() {
    155155        $customer_util = new Customer_Utilities();
    156         $customer_id   = $customer_util->get_customer_id();
     156        $customer_id   = $customer_util->get_wc_customer_id();
    157157        $logger        = new Logger();
    158158
  • activecampaign-for-woocommerce/trunk/includes/api-client/class-activecampaign-for-woocommerce-api-client.php

    r3089566 r3205976  
    163163        'ecom/graphql',
    164164        'account/entitlements',
     165        'user/me',
     166        'siteTracking/code',
     167        'account/info',
    165168    );
    166169
     
    696699        }
    697700
     701        if (
     702            (
     703                'siteTracking/code' === $this->endpoint ||
     704                'siteTracking\/code' === $this->endpoint
     705            )
     706        ) {
     707            $this->logger->debug_calls(
     708                'SiteTracking Code Response',
     709                array(
     710                    'endpoint'             => $this->endpoint,
     711                    'method'               => $this->method,
     712                    'response_status_code' => self::validate_object( $response, 'getStatusCode' ) ? $response->getStatusCode() : null,
     713                    'response_headers'     => self::validate_object( $response, 'getHeaders' ) ? $response->getHeaders() : null,
     714                    'response_body'        => self::validate_object( $response, 'getBody' ) ? $response->getBody() : null,
     715                    'response_contents'    => self::validate_object( $response, 'getBody' ) ? $response->getBody()->getContents() : null,
     716                    'response_string'      => self::validate_object( $response, 'getBody' ) ? $response->getBody()->__toString() : null,
     717                )
     718            );
     719
     720            if ( self::validate_object( $response->getBody(), '__toString' ) ) {
     721                return $response->getBody()->__toString();
     722            }
     723        }
     724
    698725        return $response;
    699726    }
  • activecampaign-for-woocommerce/trunk/includes/class-activecampaign-for-woocommerce.php

    r3169593 r3205976  
    506506     */
    507507    private function define_admin_commands() {
    508         if ( $this->verify_ac_features( 'historical' ) ) {
     508        if ( $this->is_configured() && $this->is_connected() && $this->verify_ac_features( 'historical' ) ) {
    509509            $this->define_historical_sync_commands();
    510510        }
    511         if ( $this->verify_ac_features( 'product' ) ) {
     511
     512        if ( $this->is_configured() && $this->is_connected() && $this->verify_ac_features( 'product' ) ) {
    512513            $this->define_product_sync();
    513514        }
     
    610611            'woocommerce_order_edit_status',
    611612            $this->order_events,
    612             'execute_order_edit_status',
     613            'execute_order_edit_status_event',
    613614            20,
    614615            2
     
    674675            'execute',
    675676            1,
    676             1
     677            2
    677678        );
    678679
     
    914915        );
    915916
     917        $this->loader->add_action(
     918            'activecampaign_for_woocommerce_miscat_order_to_subscription_historical',
     919            $this->subscription_events,
     920            'trigger_historical_order_to_historical_subscription',
     921            2,
     922            2
     923        );
     924
    916925        // $this->loader->add_action(
    917926        // 'woocommerce_subscription_payment_complete',
     
    947956
    948957        $this->define_subscription_commands();
     958
     959        $this->loader->add_action(
     960            'activecampaign_for_woocommerce_load_sitetracking',
     961            $this->admin,
     962            'activecampaign_load_sitetracking'
     963        );
    949964
    950965        // custom hook for hourly abandoned cart
  • activecampaign-for-woocommerce/trunk/includes/config/activecampaign-for-woocommerce-class-factories.php

    r3049374 r3205976  
    137137        $event = new Activecampaign_For_Woocommerce_Admin_Settings_Updated_Event();
    138138
    139         return new Admin( $plugin_name, $version, $validator, $event, $connection_repository, $contact_repository );
     139        return new Admin( $plugin_name, $version, $validator, $event, $connection_repository, $contact_repository, $api_client );
    140140    },
    141141
  • activecampaign-for-woocommerce/trunk/includes/config/activecampaign-for-woocommerce-global-constants.php

    r3189047 r3205976  
    2626 */
    2727if ( ! defined( 'ACTIVECAMPAIGN_FOR_WOOCOMMERCE_VERSION' ) ) {
    28     define( 'ACTIVECAMPAIGN_FOR_WOOCOMMERCE_VERSION', '2.7.11' );
     28    define( 'ACTIVECAMPAIGN_FOR_WOOCOMMERCE_VERSION', '2.8.0' );
    2929}
    3030
  • activecampaign-for-woocommerce/trunk/includes/customers/class-activecampaign-for-woocommerce-customer-utilities.php

    r2968938 r3205976  
    133133
    134134    /**
    135      * Returns a customer ID if we can find one.
     135     * Returns a WooCommerce customer ID if we can find one.
    136136     *
    137137     * @param     WC_Order|null $order The order object.
     
    139139     * @return bool|string
    140140     */
    141     public function get_customer_id( $order = null ) {
     141    public function get_wc_customer_id( $order = null ) {
    142142        if ( is_null( $order ) && self::validate_object( wc()->session, 'get_customer_id' ) && ! empty( wc()->session->get_customer_id() ) ) {
    143143            return wc()->session->get_customer_id();
  • activecampaign-for-woocommerce/trunk/includes/features/class-activecampaign-for-woocommerce-ac-features.php

    r3151035 r3205976  
    5353        'ecom-product-catalog',
    5454        'ecom-recurring-payments',
     55        'ecom-browse-abandonment',
    5556    ];
    5657
  • activecampaign-for-woocommerce/trunk/includes/features/trait-activecampaign-for-woocommerce-features-checker.php

    r3089566 r3205976  
    4545        $logger   = new Logger();
    4646        $features = array(
    47             'historical' => 'ecom-historical-sync',
    48             'abandon'    => 'ecom-core',
    49             'activesync' => 'ecom-core',
    50             'recurring'  => 'ecom-recurring-payments',
    51             'product'    => 'ecom-product-catalog',
    52             'ecommerce'  => 'ecommerce',
     47            'historical'     => 'ecom-historical-sync',
     48            'abandon'        => 'ecom-core',
     49            'activesync'     => 'ecom-core',
     50            'recurring'      => 'ecom-recurring-payments',
     51            'product'        => 'ecom-product-catalog',
     52            'ecommerce'      => 'ecommerce',
     53            'browsetracking' => 'ecom-browse-abandonment',
    5354        );
    5455
  • activecampaign-for-woocommerce/trunk/includes/models/class-activecampaign-for-woocommerce-ac-contact.php

    r2966088 r3205976  
    117117    private $tags;
    118118
     119    public function __construct() {
     120
     121        // Start completely empty
     122        $this->id         = null;
     123        $this->externalid = '';
     124        $this->email      = '';
     125        $this->first_name = '';
     126        $this->last_name  = '';
     127        $this->phone      = '';
     128    }
     129
    119130    /**
    120131     * Returns a connection id.
     
    304315     * Creates the contact model from an order object.
    305316     *
    306      * @param     WC_Order $order The WC Order.
     317     * @param     WC_Order $wc_order_or_subscription The WC Order or Subscription.
    307318     *
    308319     * @return bool
    309320     */
    310     public function create_ecom_contact_from_order( $order ) {
     321    public function create_ecom_contact_from_order( $wc_order_or_subscription ) {
    311322        $logger = new Logger();
    312         if ( isset( $order ) && self::validate_object( $order, 'get_id' ) && $order->get_id() ) {
    313             $customer = null;
    314             if ( $order->get_customer_id() ) {
     323        if ( isset( $wc_order_or_subscription ) && self::validate_object( $wc_order_or_subscription, 'get_id' ) && $wc_order_or_subscription->get_id() ) {
     324            $wc_customer = null;
     325            if ( $wc_order_or_subscription->get_customer_id() ) {
    315326                try {
    316327                    // Use the customer information
    317                     $customer = new WC_Customer( $order->get_customer_id(), false );
    318 
    319                     if ( $customer->get_id() ) {
    320                         $this->externalid = $customer->get_id();
    321                     }
    322 
    323                     if ( $customer->get_email() ) {
    324                         $this->email = $customer->get_email();
    325                     } elseif ( $customer->get_billing_email() ) {
    326                         $this->email = $customer->get_billing_email();
    327                     }
    328 
    329                     if ( $customer->get_first_name() ) {
    330                         $this->first_name = $customer->get_first_name();
    331                     } elseif ( $customer->get_billing_first_name() ) {
    332                         $this->first_name = $customer->get_billing_first_name();
    333                     }
    334 
    335                     if ( $customer->get_last_name() ) {
    336                         $this->last_name = $customer->get_last_name();
    337                     } elseif ( $customer->get_billing_last_name() ) {
    338                         $this->last_name = $customer->get_billing_last_name();
    339                     }
    340 
    341                     if ( $customer->get_billing_phone() ) {
    342                         $this->phone = $customer->get_billing_phone();
     328                    $wc_customer = new WC_Customer( $wc_order_or_subscription->get_customer_id(), false );
     329
     330                    if ( $wc_customer->get_id() ) {
     331                        // Note this is for WC customer ID specifically.
     332                        $this->externalid = $wc_customer->get_id();
     333                    }
     334
     335                    if ( $wc_customer->get_email() ) {
     336                        $this->email = $wc_customer->get_email();
     337                    } elseif ( $wc_customer->get_billing_email() ) {
     338                        $this->email = $wc_customer->get_billing_email();
     339                    }
     340
     341                    if ( $wc_customer->get_first_name() ) {
     342                        $this->first_name = $wc_customer->get_first_name();
     343                    } elseif ( $wc_customer->get_billing_first_name() ) {
     344                        $this->first_name = $wc_customer->get_billing_first_name();
     345                    }
     346
     347                    if ( $wc_customer->get_last_name() ) {
     348                        $this->last_name = $wc_customer->get_last_name();
     349                    } elseif ( $wc_customer->get_billing_last_name() ) {
     350                        $this->last_name = $wc_customer->get_billing_last_name();
     351                    }
     352
     353                    if ( $wc_customer->get_billing_phone() ) {
     354                        $this->phone = $wc_customer->get_billing_phone();
    343355                    }
    344356
     
    354366            }
    355367
    356             if ( ! $customer || ! $order->get_customer_id() || ! $customer->get_email() ) {
     368            if ( ! $wc_customer || ! $wc_order_or_subscription->get_customer_id() || ! $wc_customer->get_email() ) {
    357369                try {
    358370                    $this->externalid = 0;
    359                     if ( self::validate_object( $order, 'get_billing_email' ) ) {
    360                         $this->email      = $order->get_billing_email();
    361                         $this->first_name = $order->get_billing_first_name();
    362                         $this->last_name  = $order->get_billing_last_name();
    363                         $this->phone      = $order->get_billing_phone();
     371                    if ( self::validate_object( $wc_order_or_subscription, 'get_billing_email' ) ) {
     372                        $this->email      = $wc_order_or_subscription->get_billing_email();
     373                        $this->first_name = $wc_order_or_subscription->get_billing_first_name();
     374                        $this->last_name  = $wc_order_or_subscription->get_billing_last_name();
     375                        $this->phone      = $wc_order_or_subscription->get_billing_phone();
    364376
    365377                        return true;
     
    369381                        'AC Contact: There was a problem preparing data for a record.',
    370382                        [
    371                             'customer_email' => self::validate_object( $order, 'get_billing_email' ) ? $order->get_billing_email() : null,
     383                            'customer_email' => self::validate_object( $wc_order_or_subscription, 'get_billing_email' ) ? $wc_order_or_subscription->get_billing_email() : null,
    372384                            'message'        => $t->getMessage(),
    373385                        ]
  • activecampaign-for-woocommerce/trunk/includes/models/factories/class-activecampaign-for-woocommerce-ecom-order-factory.php

    r2966088 r3205976  
    6262     */
    6363    public function from_woocommerce( $cart, $customer ) {
    64         $order = new Ecom_Order();
    65         $logger = new Logger();
     64        $ecom_order = new Ecom_Order();
     65        $logger     = new Logger();
    6666
    6767        try {
     
    6969                $date = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
    7070
    71                 $order->set_id( $this->get_ac_id() );
     71                $ecom_order->set_id( $this->get_ac_id() );
    7272
    7373                $external_id = $this->generate_externalcheckoutid(
     
    7575                    $customer->get_email()
    7676                );
    77                 $order->set_externalcheckoutid( $external_id );
    78                 $order->set_source( '1' );
    79                 $order->set_email( $customer->get_email() );
    80                 $order->set_total_price( $this->get_cart_total( $cart ) );
    81                 $order->set_currency( $this->get_woocommerce_currency() );
    82                 $order->set_connectionid( $this->admin->get_connection_storage()['connection_id'] );
    83                 $order->set_customerid( $this->get_ac_customer_id() );
    84                 $order->set_order_date( $date->format( DATE_ATOM ) );
    85                 $order->set_order_url( wc_get_cart_url() );
     77                $ecom_order->set_externalcheckoutid( $external_id );
     78                $ecom_order->set_source( '1' );
     79                $ecom_order->set_email( $customer->get_email() );
     80                $ecom_order->set_total_price( $this->get_cart_total( $cart ) );
     81                $ecom_order->set_currency( $this->get_woocommerce_currency() );
     82                $ecom_order->set_connectionid( $this->admin->get_connection_storage()['connection_id'] );
     83                $ecom_order->set_customerid( $this->get_ac_customer_id() );
     84                $ecom_order->set_order_date( $date->format( DATE_ATOM ) );
     85                $ecom_order->set_order_url( wc_get_cart_url() );
    8686            }
    8787        } catch ( Throwable $t ) {
     
    103103
    104104            if ( count( $products ) > 0 ) {
    105                 array_walk( $products, [ $order, 'push_order_product' ] );
     105                array_walk( $products, [ $ecom_order, 'push_order_product' ] );
    106106            } else {
    107107                $logger->warning(
     
    127127        }
    128128
    129         return $order;
     129        return $ecom_order;
    130130    }
    131131
  • activecampaign-for-woocommerce/trunk/includes/orders/class-activecampaign-for-woocommerce-cofe-order-builder.php

    r3189047 r3205976  
    9696     * @param     int                 $source The source.
    9797     *
    98      * @return Activecampaign_For_Woocommerce_Cofe_Ecom_Order|null
     98     * @return Activecampaign_For_Woocommerce_Cofe_Ecom_Order|int|null
    9999     */
    100100    public function setup_cofe_order_from_table( $wc_order, $source = 0 ) {
     
    116116                function_exists( 'wcs_is_subscription' ) && wcs_is_subscription( $wc_order->get_id() )
    117117            ) {
     118                $wc_subscription = wcs_get_subscription( $wc_order->get_id() );
    118119                $logger->warning(
    119120                    'This record was improperly triggered by WooCommerce as an order but is a subscription. It will be processed as a subscription instead.',
    120121                    [
    121                         'order_id' => $wc_order->get_id(),
     122                        'order_id'   => self::validate_object( $wc_order, 'get_id' ) ? $wc_order->get_id() : null,
     123                        'source'   => $source,
    122124                    ]
    123125                );
    124126
    125                 $wc_subscription = wcs_get_subscription( $wc_order->get_id() );
    126 
    127                 if ( ! empty( $wc_subscription->get_id() ) ) {
    128                     $subscription_id = $wc_subscription->get_id();
    129                     do_action( 'activecampaign_for_woocommerce_miscat_order_to_subscription', [ $subscription_id ] );
    130 
    131                     return null;
     127                $wc_subscription    = wcs_get_subscription( $wc_order->get_id() );
     128                $wc_subscription_id = $wc_subscription->get_id();
     129
     130                if ( ! empty( $wc_subscription_id ) ) {
     131                    if ( 0 === $source ) {
     132                        do_action( 'activecampaign_for_woocommerce_miscat_order_to_subscription_historical', [ $wc_subscription_id ] );
     133                    } else {
     134                        do_action( 'activecampaign_for_woocommerce_miscat_order_to_subscription', [ $wc_subscription_id ] );
     135                    }
     136
     137                    return 30; // 30 is the designator for subscription status block
    132138                }
    133139            }
  • activecampaign-for-woocommerce/trunk/includes/orders/class-activecampaign-for-woocommerce-new-order-created-event.php

    r3169593 r3205976  
    256256
    257257            if ( ! isset( $customer_data['id'] ) || empty( $customer_data['id'] ) ) {
    258                 $found_customer_id = $customer_utilities->get_customer_id( $wc_order );
     258                $found_customer_id = $customer_utilities->get_wc_customer_id( $wc_order );
    259259                if ( isset( $found_customer_id ) && ! empty( $found_customer_id ) ) {
    260                     $customer_data['id'] = $customer_utilities->get_customer_id( $wc_order );
     260                    $customer_data['id'] = $customer_utilities->get_wc_customer_id( $wc_order );
    261261                }
    262262            }
    263263
    264264            if ( empty( $customer_data['id'] ) ) {
    265                 $customer_data['id'] = 0;
     265                $customer_data['id'] = null;
    266266            }
    267267
     
    293293
    294294            if ( isset( $stored_row->wc_order_id ) && ! empty( $stored_row->wc_order_id ) ) {
     295                $this->schedule_sync_job( $order_id );
    295296                return;
    296297            }
     
    307308            if ( isset( $stored_row->wc_order_id ) && ! empty( $stored_row->wc_order_id ) ) {
    308309                // If we've saved the order we do not need to save again to stop redundant events
     310                $this->schedule_sync_job( $order_id );
    309311                return;
    310312            }
     
    516518            if ( ! wp_get_scheduled_event( ACTIVECAMPAIGN_FOR_WOOCOMMERCE_RUN_NEW_ORDER_SYNC_NAME, [ 'row_id' => $row_id ] ) ) {
    517519                wp_schedule_single_event(
    518                     time() + 30,
     520                    time() + 10,
    519521                    ACTIVECAMPAIGN_FOR_WOOCOMMERCE_RUN_NEW_ORDER_SYNC_NAME,
    520522                    [
     
    528530                [
    529531                    'row_id'       => $row_id,
    530                     'current_time' => time() + 30,
    531                     'schedule'     => wp_get_scheduled_event( ACTIVECAMPAIGN_FOR_WOOCOMMERCE_RUN_NEW_ORDER_SYNC_NAME, [ 'id' => $row_id ] ),
     532                    'current_time' => time() + 10,
     533                    'schedule'     => wp_get_scheduled_event( ACTIVECAMPAIGN_FOR_WOOCOMMERCE_RUN_NEW_ORDER_SYNC_NAME, [ 'row_id' => $row_id ] ),
    532534                ]
    533535            );
  • activecampaign-for-woocommerce/trunk/includes/orders/class-activecampaign-for-woocommerce-new-order-sync-job.php

    r3169593 r3205976  
    398398
    399399                try {
    400                     if ( isset( $prep_order->ac_customer_id ) && ! empty( $prep_order->ac_customer_id ) ) {
    401                         $ac_customer_id = $prep_order->ac_customer_id;
    402                     } else {
     400                    $extract_email = $this->extract_email_from_order( $wc_order );
     401                    if ( ! empty( $extract_email ) ) {
     402                        $ac_customer_id = $this->get_ac_customer_id( $extract_email );
     403                    } elseif ( isset( $prep_order->customer_email ) && ! empty( $prep_order->customer_email ) ) {
    403404                        $ac_customer_id = $this->get_ac_customer_id( $prep_order->customer_email );
    404405                    }
     
    450451                try {
    451452                    // RECOVERED
    452                     if ( isset( $unsynced_recovered_order->ac_customer_id ) && ! empty( $unsynced_recovered_order->ac_customer_id ) ) {
    453                         $ac_customer_id = $unsynced_recovered_order->ac_customer_id;
    454                     } else {
     453                    $extract_email = $this->extract_email_from_order( $wc_order );
     454                    if ( ! empty( $extract_email ) ) {
     455                        $ac_customer_id = $this->get_ac_customer_id( $extract_email );
     456                    } elseif ( isset( $unsynced_recovered_order->customer_email ) && ! empty( $unsynced_recovered_order->customer_email ) ) {
    455457                        $ac_customer_id = $this->get_ac_customer_id( $unsynced_recovered_order->customer_email );
    456458                    }
     
    514516            // Data for cofe order sync
    515517            $ecom_order = $cofe_order_builder->setup_cofe_order_from_table( $wc_order, 1 );
    516             if ( ! is_null( $status ) ) {
     518
     519            if ( ! is_null( $status ) && ! is_null( $ecom_order ) ) {
    517520                $ecom_order->set_wc_status( $status );
    518521            }
     522
    519523            if ( is_null( $ecom_order ) ) {
    520524                $this->logger->warning( 'Setup COFE order returned null. Something may have gone wrong or the data may not be missing/incompatible with AC.' );
     525
     526                return false;
     527            } elseif (30 === $ecom_order ) {
     528                $this->logger->debug(
     529                    'Ecom order builder returned miscat. This order is actually a subscription.',
     530                    [
     531                        'order_id' => ! empty( $wc_order->get_id() ) ? $wc_order->get_id() : null,
     532                    ]
     533                );
     534
    521535                return false;
    522536            }
  • activecampaign-for-woocommerce/trunk/includes/orders/class-activecampaign-for-woocommerce-order-action-events.php

    r3177307 r3205976  
    8686
    8787        if ( isset( $order_id ) && ! empty( $order_id ) ) {
     88            $post_type = get_post_type( $order_id );
     89
    8890            $logger->debug_excess(
    8991                'Order update triggered',
    9092                [
    91                     'order' => $order_id,
    92                 ]
    93             );
    94 
    95             $post_type = get_post_type( $order_id );
    96 
    97             // If it's a subscription, route through sub update
    98             if ( 'shop_subscription' === $post_type ) {
    99                 $wc_subscription = $this->get_wc_subscription( $order_id );
    100 
    101                 if ( $this->check_update_validity( $wc_subscription ) ) {
    102                     do_action( 'activecampaign_for_woocommerce_route_order_update_to_subscription', [ $wc_subscription ] );
    103                 }
    104 
     93                    'order'     => $order_id,
     94                    'post_type' => $post_type,
     95                ]
     96            );
     97
     98            if ($this->check_if_subscription_and_reroute( $order_id, $post_type ) ) {
    10599                return;
    106100            }
     
    162156
    163157        if ( isset( $order_id ) && ! empty( $order_id ) ) {
     158            $post_type = get_post_type( $order_id );
     159
    164160            $logger->debug_excess(
    165161                'Order status update triggered',
     
    168164                    'order_status' => $from_status,
    169165                    'new_status'   => $to_status,
    170                 ]
    171             );
    172 
    173             $post_type = get_post_type( $order_id );
    174 
    175             // If it's a subscription, route through subscription update.
    176             if ( 'shop_subscription' === $post_type ) {
    177                 $wc_subscription = $this->get_wc_subscription( $order_id );
    178 
    179                 do_action( 'activecampaign_for_woocommerce_route_order_update_to_subscription', [ $wc_subscription ] );
     166                    'post_type'    => $post_type,
     167                ]
     168            );
     169
     170            if ($this->check_if_subscription_and_reroute( $order_id, $post_type ) ) {
    180171                return;
    181172            }
     
    228219    }
    229220
    230     public function execute_order_edit_status( $order_id, $new_status ) {
     221    /**
     222     * Executes the code based on an order status edit action event.
     223     *
     224     * @param string|int $order_id The order id.
     225     * @param string     $new_status The new updated status.
     226     *
     227     * @return void
     228     */
     229    public function execute_order_edit_status_event( $order_id, $new_status ) {
    231230        $wc_order = $this->get_wc_order( $order_id );
    232231
    233232        if ( self::validate_object( $wc_order, 'get_data' ) ) {
    234233            set_transient( 'acforwc_order_updated_hook', wp_date( DATE_ATOM ), 604800 );
     234
     235            $post_type = get_post_type( $order_id );
     236            if ($this->check_if_subscription_and_reroute( $order_id, $post_type ) ) {
     237                return;
     238            }
    235239
    236240            if ( ! wp_get_scheduled_event(
     
    406410     */
    407411    private function check_update_validity( $wc_order ) {
    408         $logger = new Logger();
    409         $last_synced      = $wc_order->get_meta( 'ac_order_last_synced_time' );
    410         $last_status      = $wc_order->get_meta( 'ac_last_synced_status' );
    411         $ac_datahash      = $wc_order->get_meta( 'ac_datahash' );
     412        $logger      = new Logger();
     413        $last_synced = $wc_order->get_meta( 'ac_order_last_synced_time' );
     414        $last_status = $wc_order->get_meta( 'ac_last_synced_status' );
     415        $ac_datahash = $wc_order->get_meta( 'ac_datahash' );
    412416        try {
    413417            $current_datahash = md5( wp_json_encode( $wc_order->get_data() ) );
     
    460464        return true;
    461465    }
     466
     467    private function check_if_subscription_and_reroute( $order_id, $post_type ) {
     468        $logger = new Logger();
     469
     470        try {
     471                // If it's a subscription, route through sub update
     472            if (
     473                    'shop_subscription' === $post_type ||
     474                    'shop_order_placehold' === $post_type ||
     475                    (
     476                        function_exists( 'wcs_is_subscription' ) &&
     477                        wcs_is_subscription( $order_id )
     478                    )
     479                ) {
     480                $wc_subscription = $this->get_wc_subscription( $order_id );
     481                $subscription_id = $wc_subscription->get_id();
     482
     483                if ( wcs_is_subscription( $subscription_id ) ) {
     484                    $logger->debug(
     485                        'Order update accidentally triggered from subscription. Routing order to subscription instead.',
     486                        array(
     487                            'order_id'                 => $order_id,
     488                            'subscription_id'          => $subscription_id,
     489                            'subscription item count'  => $wc_subscription->get_item_count(),
     490                            'is_subscription on order' => wcs_is_subscription( $order_id ),
     491                            'is_subscription on subscription' => wcs_is_subscription( $subscription_id ),
     492                        )
     493                    );
     494
     495                    if ( $this->check_update_validity( $wc_subscription ) ) {
     496                        do_action( 'activecampaign_for_woocommerce_route_order_update_to_subscription', [ $wc_subscription ] );
     497                    }
     498
     499                    return true;
     500                }
     501            }
     502        } catch (Throwable $t ) {
     503            $logger->warning(
     504                'Something went wrong validating post type as shop_subscription',
     505                [
     506                    'message' => $t->getMessage(),
     507                ]
     508            );
     509        }
     510
     511        return false;
     512    }
    462513}
  • activecampaign-for-woocommerce/trunk/includes/orders/historical/class-activecampaign-for-woocommerce-historical-sync-runner-cofe.php

    r3122277 r3205976  
    206206                    '%d' // where format
    207207                );
    208             } else {
     208            } else if (false === $sync_response ) {
    209209                $wpdb->update(
    210210                    ( $wpdb->prefix . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_TABLE_NAME ), // table
     
    393393
    394394                if ( is_null( $cofe_ecom_order ) ) {
    395                     $this->logger->debug( 'Ecom order builder returned null. Something may have gone wrong with the sync.' );
     395                    $this->logger->debug(
     396                        'Ecom order builder returned null. Something may have gone wrong with the sync or the order may have been miscategorized.',
     397                        [
     398                            'order_id' => isset( $order_id ) ? $order_id : null,
     399                        ]
     400                    );
     401
    396402                    $this->add_incompatible_order_to_status( $order_id );
    397403                    $this->mark_order_as_historical_incompatible( $order_id );
     404                    unset( $order_ids[ $k ] );
     405                    continue;
     406                } elseif (30 === $cofe_ecom_order ) {
     407                    $this->logger->debug(
     408                        'Ecom order builder returned miscat. This order is actually a subscription.',
     409                        [
     410                            'order_id' => isset( $order_id ) ? $order_id : null,
     411                        ]
     412                    );
     413
    398414                    unset( $order_ids[ $k ] );
    399415                    continue;
     
    442458                    }
    443459                }
     460            }
     461
     462            if ( false === $r ) {
     463                return null;
    444464            }
    445465        }
     
    481501                    self::wpdb_update_in(
    482502                        ( $wpdb->prefix . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_TABLE_NAME ), // table
    483                         array( 'synced_to_ac' => self::STATUS_HISTORICAL_SYNC_PREP ), // data
     503                        array( 'synced_to_ac' => self::STATUS_HISTORICAL_SYNC_QUEUE ), // data
    484504                        array( 'wc_order_id' => $order_ids ), // where
    485505                        array( '%d' ), // format
  • activecampaign-for-woocommerce/trunk/includes/orders/trait-activecampaign-for-woocommerce-order-data-gathering.php

    r3049374 r3205976  
    475475        return get_site_url();
    476476    }
     477
     478    /**
     479     * Extract the email from an order.
     480     *
     481     * @param WC_Order $wc_order The WC Order.
     482     *
     483     * @return mixed|null
     484     */
     485    public function extract_email_from_order( $wc_order ) {
     486        if ( self::validate_object( $wc_order, 'get_billing_email' ) && $wc_order->get_billing_email() && ! empty( $wc_order->get_billing_email() ) ) {
     487            return $wc_order->get_billing_email();
     488        } elseif ( self::validate_object( $wc_order, 'get_user' ) && $wc_order->get_user() && ! empty( $wc_order->get_user()->user_email ) ) {
     489            // If we can't find the billing email for whatever reason look for the user email.
     490            return $wc_order->get_user()->user_email;
     491        } else {
     492            return null;
     493        }
     494    }
    477495}
  • activecampaign-for-woocommerce/trunk/includes/orders/trait-activecampaign-for-woocommerce-synced-status-handler.php

    r3104234 r3205976  
    364364                    self::STATUS_HISTORICAL_SYNC_PREP,
    365365                    self::STATUS_HISTORICAL_SYNC_QUEUE,
     366                    self::STATUS_SYNC_INCOMPATIBLE,
    366367                    self::STATUS_SUBSCRIPTION_HISTORICAL_SYNC_FINISH,
    367368                    self::STATUS_SUBSCRIPTION_HISTORICAL_SYNC_PREP,
    368369                    self::STATUS_SUBSCRIPTION_HISTORICAL_SYNC_QUEUE,
    369370                    self::STATUS_SUBSCRIPTION_INCOMPATIBLE,
     371                    self::STATUS_SUBSCRIPTION_EXPIRED,
     372                    self::STATUS_SUBSCRIPTION_FAILED_SYNC,
     373                    self::STATUS_SUBSCRIPTION_FAILED_BILLING,
     374                    self::STATUS_FAIL,
     375                    self::STATUS_SYNCED,
    370376                ]
    371377            );
     
    374380            $delete_count = $wpdb->query(
    375381                'DELETE FROM ' . $wpdb->prefix . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_TABLE_NAME .
    376                 ' WHERE (order_date < "' . $expire_2week . '" AND synced_to_ac IN (' . $synced_to_ac_implode . ') ) OR (order_date < "' . $expire_4week . '" AND synced_to_ac = 1) OR (order_date IS NULL AND abandoned_date IS NULL AND last_access_time IS NULL)'
     382                ' WHERE (synced_to_ac IN (' . $synced_to_ac_implode . ') ) OR (order_date < "' . $expire_4week . '" AND synced_to_ac = 0) OR (order_date IS NULL AND abandoned_date IS NULL AND last_access_time IS NULL)'
    377383            );
    378384
  • activecampaign-for-woocommerce/trunk/includes/products/class-activecampaign-for-woocommerce-product-sync-job.php

    r3169593 r3205976  
    5757     */
    5858    private $batch_limit;
     59
     60    /**
     61     * Direct mode enabled. 1 = enabled = uses direct DB access.
     62     *
     63     * @var int
     64     */
     65    private $direct_mode;
     66
    5967    /**
    6068     * Activecampaign_For_Woocommerce_Product_Sync_Job constructor.
     
    7179        $this->start_record            = 0;
    7280        $this->batch_limit             = 20;
     81        $this->direct_mode             = 0;
    7382    }
    7483
     
    100109                'batch_limit'  => $this->batch_limit,
    101110                'start_record' => $this->start_record,
     111                'direct_mode'  => $this->direct_mode,
    102112            )
    103113        );
     
    245255        $offset = 0;
    246256
    247         $wc_product_ids = $this->get_products_by_offset( $this->batch_limit, $offset, true );
    248 
     257        if ($this->direct_mode ) {
     258            $wc_product_ids = $this->get_products_direct_by_offset( $this->batch_limit, $offset, true );
     259        } else {
     260            $wc_product_ids = $this->get_products_by_offset( $this->batch_limit, $offset, true );
     261        }
    249262        while ( $wc_product_ids ) {
    250263            $this->schedule_background_product_sync( $offset, $this->batch_limit );
    251264
    252265            $offset += count( $wc_product_ids );
    253 
    254             $wc_product_ids = $this->get_products_by_offset( $this->batch_limit, $offset, true );
    255         }
    256 
     266            if ($this->direct_mode ) {
     267                $wc_product_ids = $this->get_products_direct_by_offset( $this->batch_limit, $offset, true );
     268            } else {
     269                $wc_product_ids = $this->get_products_by_offset( $this->batch_limit, $offset, true );
     270            }
     271        }
     272
     273        $status = $this->add_args_to_status( $args );
    257274    }
    258275
     
    301318                $this->start_record = $args[0]->start_record;
    302319            }
     320            if ( ! empty( $data->direct_mode ) || 1 === $data->direct_mode || '1' === $data->direct_mode ) {
     321                $this->direct_mode = $args[0]->direct_mode;
     322            }
    303323        }
    304324
     
    309329            if ( ! empty( $data['start_record'] ) || 0 === $data['start_record'] || '0' === $data['start_record'] ) {
    310330                $this->start_record = $data['start_record'];
     331            }
     332            if ( ! empty( $data['direct_mode'] ) || 1 === $data['direct_mode'] || '1' === $data['direct_mode'] ) {
     333                $this->direct_mode = $data['direct_mode'];
    311334            }
    312335        }
     
    324347                $this->start_record = $_post['startRecord'];
    325348            }
     349            if ( isset( $_post['syncDirectMode'] ) && ! empty( $_post['syncDirectMode'] ) ) {
     350                $this->direct_mode = $_post['syncDirectMode'];
     351            }
    326352        }
    327353
    328354        $status->start_record = $this->start_record;
    329355        $status->batch_limit  = $this->batch_limit;
     356        $status->direct_mode  = $this->direct_mode;
    330357
    331358        Sync_Status::update_status( ACTIVECAMPAIGN_FOR_WOOCOMMERCE_PRODUCT_SYNC_RUNNING_STATUS_NAME, $status );
     
    347374                'start_record' => (int) $offset,
    348375                'batch_limit'  => (int) $batch_limit,
     376                'direct_mode'  => (int) $this->direct_mode,
    349377            ],
    350378        ];
     
    435463            $limit  = $this->batch_limit;
    436464
    437             $wc_products = $this->get_products_by_offset( $limit, $offset, false );
     465            if ($this->direct_mode ) {
     466                $wc_products = $this->get_products_direct_by_offset( $limit, $offset, false );
     467            } else {
     468                $wc_products = $this->get_products_by_offset( $limit, $offset, false );
     469            }
    438470        } else {
    439471            $wc_products = $products_list;
     
    579611                $p_data = Ecom_Cofe_Product::product_array_for_cofe( $product, $connection_id, $parent );
    580612                if ( ! is_null( $p_data ) ) {
    581                     $product_data[] = $p_data;
     613                    $product_data[ $p_data['storePrimaryId'] ] = $p_data;
    582614                }
    583615            }
  • activecampaign-for-woocommerce/trunk/includes/products/class-activecampaign-for-woocommerce-sync-status.php

    r3169593 r3205976  
    2626        $status_name = 'none',
    2727        $is_halted = false,
    28         $is_cancelled = false
     28        $is_cancelled = false,
     29        $direct_mode = false
    2930    ) {
    3031        $this->start_record    = $start_record; // Required
     
    4041        $this->is_halted       = $is_halted; // Required
    4142        $this->is_cancelled    = $is_cancelled; // Required
     43        $this->direct_mode     = $direct_mode;
    4244    }
    4345
     
    5355            $data['failed_id_array'],
    5456            $data['is_running'],
    55             $data['status_name']
     57            $data['status_name'],
     58            $data['direct_mode']
    5659        );
    5760    }
     
    153156    public $failed_order_id_array;
    154157
     158    /**
     159     * @var false|mixed
     160     */
     161    public $direct_mode;
    155162
    156163    /**
  • activecampaign-for-woocommerce/trunk/includes/repositories/class-activecampaign-for-woocommerce-cofe-order-repository.php

    r3122277 r3205976  
    175175                    'message' => $t->getMessage(),
    176176                    'code'    => $t->getCode(),
    177                     'ac_code' => 'COR_195',
     177                    'ac_code' => 'COR_172',
    178178                    'trace'   => $logger->clean_trace( $t->getTrace() ),
    179179                ]
     
    211211                    'message' => $t->getMessage(),
    212212                    'code'    => $t->getCode(),
    213                     'ac_code' => 'COR_195',
     213                    'ac_code' => 'COR_209',
    214214                    'trace'   => $logger->clean_trace( $t->getTrace() ),
    215215                ]
  • activecampaign-for-woocommerce/trunk/includes/subscriptions/class-activecampaign-for-woocommerce-new-subscription-sync-job.php

    r3169593 r3205976  
    311311
    312312                try {
    313                     if ( isset( $prep_order->ac_customer_id ) && ! empty( $prep_order->ac_customer_id ) ) {
    314                         $ac_customer_id = $prep_order->ac_customer_id;
    315                     } else {
     313                    $extract_email = $this->extract_email_from_order( $wc_order );
     314                    if ( ! empty( $extract_email ) ) {
     315                        $ac_customer_id = $this->get_ac_customer_id( $extract_email );
     316                    } elseif ( isset( $prep_order->customer_email ) && ! empty( $prep_order->customer_email ) ) {
    316317                        $ac_customer_id = $this->get_ac_customer_id( $prep_order->customer_email );
    317318                    }
     
    361362                try {
    362363                    // RECOVERED
    363                     if ( isset( $unsynced_recovered_order->ac_customer_id ) && ! empty( $unsynced_recovered_order->ac_customer_id ) ) {
    364                         $ac_customer_id = $unsynced_recovered_order->ac_customer_id;
    365                     } else {
     364                    $extract_email = $this->extract_email_from_order( $wc_order );
     365                    if ( ! empty( $extract_email ) ) {
     366                        $ac_customer_id = $this->get_ac_customer_id( $extract_email );
     367                    } elseif ( isset( $unsynced_recovered_order->customer_email ) && ! empty( $unsynced_recovered_order->customer_email ) ) {
    366368                        $ac_customer_id = $this->get_ac_customer_id( $unsynced_recovered_order->customer_email );
    367369                    }
  • activecampaign-for-woocommerce/trunk/includes/subscriptions/class-activecampaign-for-woocommerce-subscription-events.php

    r3089566 r3205976  
    7373    // $logger = new Logger();
    7474    // if ( isset( $wc_order ) && self::validate_object( $wc_order, 'get_id' ) ) {
    75     // $logger->dev( 'Triggered the execute_subscription_created_for_order action. Look into removal of this. Is there any case where we need this?', [ $wc_order->get_id() ] );
    7675    // } else {
    77     // $logger->dev( 'Triggered the execute_subscription_created_for_order action but it carries no order. Look into removal of this. Is there any case where we need this?' );
    7876    // }
    7977    // }
     
    108106                ]
    109107            );
    110 
    111             $order_id = $wc_subscription->get_id(); // This is actually the ID for a subscription but it's handled as an order.
    112             // phpcs:disable
    113             $stored_row = $wpdb->get_row(
    114                 $wpdb->prepare(
    115                     'SELECT id, wc_order_id, synced_to_ac FROM ' . $wpdb->prefix . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_TABLE_NAME . '
    116                     WHERE wc_order_id = %d LIMIT 1',
    117                     [ $order_id ]
    118                 ),
    119                 'ARRAY_A'
    120             );
    121             // phpcs:enable
    122108
    123109            if ( isset( $subscription_id ) && null !== $subscription_id && ! empty( $subscription_id ) ) {
     
    164150        try {
    165151            $order_id = $wc_subscription->get_id(); // This is actually the ID for a subscription but it's handled as an order.
    166             // phpcs:disable
    167             $stored_row = $wpdb->get_row(
    168                 $wpdb->prepare(
    169                     'SELECT id, wc_order_id, synced_to_ac FROM ' . $wpdb->prefix . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_TABLE_NAME . '
    170                     WHERE wc_order_id = %d LIMIT 1',
    171                     [ $order_id ]
    172                 ),
    173                 'ARRAY_A'
    174             );
    175             // phpcs:enable
    176 
     152            $this->update_status( $wc_subscription, 0 );
    177153            if ( isset( $subscription_id ) && null !== $subscription_id && ! empty( $subscription_id ) ) {
    178154                if ( ! wp_get_scheduled_event( ACTIVECAMPAIGN_FOR_WOOCOMMERCE_RUN_NEW_ORDER_SYNC_NAME, [ 'wc_order_id' => $subscription_id ] ) ) {
     
    195171    }
    196172
    197 
    198 
    199     /**
    200      * TODO: Action for moving an order record to a subscription record
    201      *
     173    /**
     174     * Triggers and order routed to subscription method. Action for moving an order record to a subscription record.
     175     *
     176     * @param string|array $subscription_id The subscription ID.
     177     */
     178    public function trigger_order_to_subscription( $subscription_id ) {
     179        if (is_array( $subscription_id ) && ! empty( $subscription_id[0] ) ) {
     180            $wc_subscription = $this->get_wc_subscription_object( $subscription_id[0] );
     181        } else {
     182            $wc_subscription = $this->get_wc_subscription_object( $subscription_id );
     183        }
     184
     185        if (self::validate_object( $wc_subscription, 'get_id' ) && wcs_is_subscription( $wc_subscription ) && ! empty( $wc_subscription->get_id() ) ) {
     186            $this->update_status( $wc_subscription, 0 );
     187            $this->execute_woocommerce_subscription_status_updated( $wc_subscription );
     188        } else {
     189            $logger = new Logger();
     190            $logger->debug(
     191                'The trigger_order_to_subscription method failed to establish a subscription object',
     192                [
     193                    'subscription_id' => $subscription_id,
     194                    'wc_subscription' => $wc_subscription,
     195                    'is subscription' => wcs_is_subscription( $wc_subscription ),
     196                ]
     197            );
     198        }
     199    }
     200
     201    /**
     202     * Triggers historical sync subscription.
     203     *
     204     * @action activecampaign_for_woocommerce_miscat_order_to_subscription_historical
    202205     * @param string $subscription_id
    203      */
    204     public function trigger_order_to_subscription( $subscription_id ) {
     206     *
     207     * @return void
     208     */
     209    public function trigger_historical_order_to_historical_subscription( $subscription_id ) {
     210        if (is_array( $subscription_id ) ) {
     211            $subscription_id = $subscription_id[0];
     212        }
    205213        $wc_subscription = $this->get_wc_subscription_object( $subscription_id );
    206         $this->execute_woocommerce_subscription_status_updated( $wc_subscription );
    207     }
    208 
     214        if (self::validate_object( $wc_subscription, 'get_id' ) && ! empty( $wc_subscription->get_id() ) ) {
     215            $this->update_status( $wc_subscription, 1 );
     216            $this->execute_woocommerce_subscription_status_updated( $wc_subscription );
     217        } else {
     218            $logger = new Logger();
     219            $logger->debug(
     220                'This historical order to subscription does not appear to be valid.',
     221                [
     222                    'subscription_id' => $subscription_id,
     223                ]
     224            );
     225        }
     226    }
     227
     228    /**
     229     * Update the DB status to subscription.
     230     *
     231     * @param WC_Subscription $wc_subscription The subscription object.
     232     * @param int             $historical Default to not historical.
     233     *
     234     * @return void
     235     */
     236    public function update_status( $wc_subscription, $historical = 0 ) {
     237        $logger = new Logger();
     238        global $wpdb;
     239        $order_id = $wc_subscription->get_id(); // This is actually the ID for a subscription but it's handled as an order.
     240        // phpcs:disable
     241        $stored_row = $wpdb->get_row(
     242            $wpdb->prepare(
     243                'SELECT id, wc_order_id, synced_to_ac FROM ' . $wpdb->prefix . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_TABLE_NAME . '
     244                    WHERE wc_order_id = %d LIMIT 1',
     245                [ $order_id ]
     246            ),
     247            'ARRAY_A'
     248        );
     249        // phpcs:enable
     250
     251        if ( isset( $stored_row['id'] ) && ! empty( $stored_row['id'] ) ) {
     252            $stored_id                  = $stored_row['id'];
     253            $stored_row['synced_to_ac'] = 0 === $historical ? self::STATUS_SUBSCRIPTION_UNSYNCED : self::STATUS_SUBSCRIPTION_HISTORICAL_SYNC_PREP;
     254
     255            $wpdb->update(
     256                $wpdb->prefix . ACTIVECAMPAIGN_FOR_WOOCOMMERCE_TABLE_NAME,
     257                $stored_row,
     258                [
     259                    'id' => $stored_id,
     260                ]
     261            );
     262        }
     263    }
     264
     265    /**
     266     * @param WC_Subscription|string|int|object $subscription The subscription object or id.
     267     *
     268     * @return false|WC_Subscription
     269     */
    209270    private function get_wc_subscription_object( $subscription ) {
    210         if ( isset( $subscription ) && ! empty( $subscription ) ) {
     271        if (
     272            isset( $subscription ) &&
     273            self::validate_object( $subscription, 'get_id' ) &&
     274            wcs_is_subscription( $subscription )
     275        ) {
     276            return $subscription;
     277        }
     278
     279        if (
     280            isset( $subscription ) &&
     281            ! empty( $subscription )
     282        ) {
    211283            $wc_subscription = wcs_get_subscription( $subscription );
    212284
    213             if ( ! empty( $wc_subscription->get_id() ) ) {
     285            if (
     286                ! empty( $wc_subscription ) &&
     287                 self::validate_object( $wc_subscription, 'get_id' ) &&
     288                 ! empty( $wc_subscription->get_id() )
     289            ) {
    214290                return $wc_subscription;
    215291            }
  • activecampaign-for-woocommerce/trunk/includes/traits/class-activecampaign-for-woocommerce-interacts-with-api-trait.php

    r3151035 r3205976  
    701701        }
    702702    }
     703
     704    private function get_result_code_from_api(
     705        Activecampaign_For_Woocommerce_Api_Client $client,
     706        callable $response_massager = null
     707    ) {
     708        $client->set_filters( [] );
     709        $client->with_body( '' );
     710        $logger = new Logger();
     711        $result = $client
     712            ->get( self::ENDPOINT_NAME_PLURAL )
     713            ->execute();
     714
     715        if ( $result ) {
     716            try {
     717                $matches = [];
     718                if ( preg_match( '/\'setAccount\', \'(\d*)\'\)/', $result, $matches ) !== false && ! empty( $matches[1] ) ) {
     719                    return $matches[1];
     720                }
     721
     722                if ( ! is_object( $result ) || ! self::validate_object( $result, 'getBody' ) ) {
     723                    $logger->debug(
     724                        'Result from API may not have a body. Could be an error.',
     725                        [
     726                            'result'        => $result,
     727                            'client_body'   => self::validate_object( $client, 'getBody' ) ? $client->get_body() : null,
     728                            'resource_name' => self::RESOURCE_NAME,
     729                            'endpoint_name' => self::ENDPOINT_NAME,
     730                        ]
     731                    );
     732                } else {
     733                    $resources_array = json_decode( $result->getBody(), true );
     734
     735                    if ( count( $resources_array[ self::RESOURCE_NAME_PLURAL ] ) < 1 ) {
     736                        $logger->debug_excess(
     737                            'Activecampaign_For_Woocommerce_Interacts_With_Api: The resource was not found. This may not be an error.',
     738                            [
     739                                'resource_name' => self::RESOURCE_NAME,
     740                                'endpoint_name' => self::ENDPOINT_NAME,
     741                                'client_body'   => self::validate_object( $client, 'getBody' ) ? $client->get_body() : null,
     742                                'response'      => $result->getBody() instanceof StreamInterface
     743                                    ? $result->getBody()->getContents()
     744                                    : null,
     745                                'code'          => 404,
     746                            ]
     747                        );
     748                    }
     749
     750                    if ( $response_massager ) {
     751                        $resources_array = $response_massager( $resources_array );
     752                    }
     753
     754                    return $resources_array[ self::RESOURCE_NAME_PLURAL ];
     755                }
     756            } catch ( Throwable $t ) {
     757                $logger->debug(
     758                    'Activecampaign_For_Woocommerce_Interacts_With_Api: Resource thrown error.',
     759                    [
     760                        'result'      => $result,
     761                        'client_body' => self::validate_object( $client, 'getBody' ) ? $client->get_body() : null,
     762                        'code'        => $t->getCode(),
     763                    ]
     764                );
     765            }
     766        }
     767    }
    703768}
  • activecampaign-for-woocommerce/trunk/includes/traits/trait-activecampaign-for-woocommerce-arg-data-gathering.php

    r3169593 r3205976  
    2121 */
    2222trait Activecampaign_For_Woocommerce_Arg_Data_Gathering {
     23
    2324    /**
    2425     * Checks both post and get for values. WC seems to pass nonce as GET but fields pass as POST.
     
    122123        // Do not include groups for now.
    123124        $logger = new Logger();
     125
    124126        try {
    125127            $safe_product_types = self::get_cofe_safe_product_types(); // This may be causing an issue with some 3rd party plugins due to custom product types.
     
    163165            );
    164166        }
     167
    165168        return null;
    166169    }
    167170
    168 
    169 
     171    /**
     172     * Get product data directly from the database bypassing WooCommerce functions.
     173     *
     174     * @param int|string $limit The limit.
     175     * @param int|string $offset The offset.
     176     * @param bool       $return_id_only Return only IDs or not.
     177     *
     178     * @return array
     179     */
     180    public function get_products_direct_by_offset( $limit, $offset, $return_id_only = true ) {
     181        global $wpdb;
     182
     183        try {
     184            $product_ids = $wpdb->get_col(
     185                $wpdb->prepare(
     186                    "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish' LIMIT %d OFFSET %d",
     187                    array( $limit, $offset )
     188                )
     189            );
     190        } catch ( Throwable $t ) {
     191            $logger = new Logger();
     192            $logger->warning(
     193                'There was an issue getting products for the product sync',
     194                [
     195                    'message'        => $t->getMessage(),
     196                    'return_id_only' => $return_id_only,
     197                ]
     198            );
     199        }
     200        try {
     201            if ($return_id_only ) {
     202                return $product_ids;
     203            } else {
     204                $products = array();
     205
     206                foreach ($product_ids as $product_id ) {
     207                                $products[] = wc_get_product( $product_id );
     208                }
     209
     210                return $products;
     211            }
     212        } catch ( Throwable $t ) {
     213            $logger = new Logger();
     214            $logger->warning(
     215                'There was an issue getting products for the product sync',
     216                [
     217                    'message'        => $t->getMessage(),
     218                    'return_id_only' => $return_id_only,
     219                ]
     220            );
     221        }
     222
     223        return null;
     224    }
     225
     226    /**
     227     * Gets all product data directly from the database.
     228     *
     229     * @return array WC_Products array
     230     */
     231    public function get_all_products_direct() {
     232        global $wpdb;
     233        $product_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish'" );
     234
     235        $products = array();
     236        foreach ($product_ids as $product_id ) {
     237            $products[] = wc_get_product( $product_id );
     238        }
     239
     240        return $products;
     241    }
     242
     243    /**
     244     * Gets all product IDs directly from the database.
     245     *
     246     * @return array
     247     */
     248    public function get_all_product_ids_direct() {
     249        global $wpdb;
     250        $product_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'product' AND post_status = 'publish'" );
     251
     252        return $product_ids;
     253    }
     254
     255    /**
     256     * Fetch the safe product types. These are going to blacklist the below items.
     257     *
     258     * @return int[]|string[]
     259     */
    170260    public static function get_cofe_safe_product_types() {
    171         $product_types = wc_get_product_types();
     261        $product_types           = wc_get_product_types();
     262        $product_types_blacklist = array( 'grouped', 'draft' );
    172263
    173264        // Blacklist certain types that cause conflicts & duplicates
    174         if ( isset( $product_types['grouped'] ) ) {
    175             unset( $product_types['grouped'] ); // Grouped products are bundles of existing single products. These cause duplicate records.
    176         }
    177 
    178         if ( isset( $product_types['draft'] ) ) {
    179             unset( $product_types['draft'] ); // Never sync drafts
     265        foreach ( $product_types_blacklist as $product_type ) {
     266            if ( isset( $product_types[ $product_type ] ) ) {
     267                unset( $product_types[ $product_type ] ); // Never sync this type
     268            }
    180269        }
    181270
  • activecampaign-for-woocommerce/trunk/public/class-activecampaign-for-woocommerce-public.php

    r2975700 r3205976  
    165165            wp_enqueue_script( $this->plugin_name );
    166166        }
     167
     168        try {
     169            $options = $this->admin->get_local_settings();
     170
     171            if (
     172                isset( $options['browse_tracking'] ) &&
     173                in_array( $options['browse_tracking'], [ 1, '1' ], true ) &&
     174                isset( $options['tracking_id'] )
     175            ) {
     176                $this->activecampaign_frontend_sitetracking_scripts( $options['tracking_id'] );
     177            }
     178        } catch ( Throwable $t ) {
     179            $this->logger->warning(
     180                'Activecampaign_For_Woocommerce_Public: There was an issue with enabling site tracking.',
     181                [
     182                    'message' => $t->getMessage(),
     183                    'ac_code' => 'PUB_180',
     184                ]
     185            );
     186        }
    167187    }
    168188
     
    330350                [
    331351                    'message' => $t->getMessage(),
     352                    'ac_code' => 'PUB_350',
    332353                ]
    333354            );
     
    336357        return false;
    337358    }
     359
     360    /**
     361     * Hook to load the site tracking script. Can be called from any place on the site.
     362     * Call `activecampaign_for_woocommerce_load_sitetracking` to load this hook.
     363     *
     364     * @action activecampaign_for_woocommerce_load_sitetracking
     365     */
     366    public function activecampaign_load_sitetracking() {
     367        try {
     368            $options = $this->admin->get_local_settings();
     369
     370            if (
     371                isset( $options['browse_tracking'] ) &&
     372                in_array( $options['browse_tracking'], [ 1, '1', 2, '2' ], true ) &&
     373                isset( $options['tracking_id'] )
     374            ) {
     375                $this->activecampaign_frontend_sitetracking_scripts( $options['tracking_id'] );
     376            }
     377        } catch ( Throwable $t ) {
     378            $this->logger->warning(
     379                'Activecampaign_For_Woocommerce_Public: There was an issue with loading site tracking.',
     380                [
     381                    'message' => $t->getMessage(),
     382                    'ac_code' => 'PUB_380',
     383                ]
     384            );
     385        }
     386    }
     387
     388    /**
     389     * Loads in the site tracking script.
     390     *
     391     * @param string $tracking_id the tracking ID to use.
     392     */
     393    public function activecampaign_frontend_sitetracking_scripts( $tracking_id ) {
     394        $ac_forms_settings = get_option( 'settings_activecampaign' ); // This is the setting from the other AC plugin
     395
     396        if (
     397            isset( $ac_forms_settings['activecampaign_site_tracking_default'], $ac_forms_settings['site_tracking'] ) &&
     398            in_array( $ac_forms_settings['site_tracking'], [ '1', 1 ] )
     399        ) {
     400            // Don't perform this stuff, the other plugin will do it
     401            return;
     402        }
     403
     404        wp_register_script(
     405            'activecampaign-for-woocommerce-site-tracking',
     406            plugins_url( '/js/site_tracking.js', __FILE__ ),
     407            array( 'jquery' ),
     408            $this->version,
     409            true
     410        );
     411
     412        unset( $ac_forms_settings['api_url'] );
     413        unset( $ac_forms_settings['api_key'] );
     414        $current_user = wp_get_current_user();
     415        $user_email   = '';
     416        if ( isset( $current_user->data->user_email ) ) {
     417            $user_email = $current_user->data->user_email;
     418        }
     419
     420        // any data we need to access in JavaScript.
     421        if ( empty( $tracking_id ) || ! empty( $ac_forms_settings['tracking_actid'] ) ) {
     422            $tracking_id = $ac_forms_settings['tracking_actid'];
     423        }
     424
     425        $data = array(
     426            'ac_settings' => array(
     427                'tracking_actid'        => $tracking_id,
     428                'site_tracking_default' => 1,
     429                'site_tracking'         => 1,
     430            ),
     431            'user_email'  => $user_email,
     432        );
     433
     434        if ( isset( $ac_forms_settings['activecampaign_site_tracking_default'] ) ) {
     435            $data['ac_settings']['site_tracking_default'] = (int) $ac_forms_settings['activecampaign_site_tracking_default'];
     436        }
     437
     438        wp_localize_script( 'activecampaign-for-woocommerce-site-tracking', 'php_data', $data );
     439        wp_enqueue_script( 'activecampaign-for-woocommerce-site-tracking' );
     440
     441    }
     442
    338443}
Note: See TracChangeset for help on using the changeset viewer.