Plugin Directory

Changeset 3722918


Ignore:
Timestamp:
10/01/2026 10:50:25 AM (3 weeks ago)
Author:
flashyapp
Message:

Update to version 2.0.14 from GitHub

Location:
wp-flashy-marketing-automation
Files:
10 edited
1 copied

Legend:

Unmodified
Added
Removed
  • wp-flashy-marketing-automation/tags/2.0.14/core/classes/Flashy_Export.php

    r2959482 r3722918  
    9090                    "tags" => $product['tags'],
    9191                    "sku" => $product['sku'],
     92                    "gtin" => isset($product['gtin']) ? $product['gtin'] : '',
    9293                    "created_at" => $product['created_at'],
    9394                    "updated_at" => $product['updated_at']
    … …  
    242243        $prefix = ( isset($args['prefix']) ) ? $args['prefix'] : "";
    243244
    244         $code = $this->getUniqueCode($prefix);
     245        $code = $this->getUniqueCode(
     246            $prefix,
     247            isset($args['code_length']) ? (int) $args['code_length'] : 6,
     248            isset($args['code_charset']) ? $args['code_charset'] : null
     249        );
    245250
    246251        $default = array(
    … …  
    262267            'exclude_product_categories' => '', // array of categories id's
    263268            'exclude_sale_items' => true, // bool,
    264             'description' => ''
     269            'description' => '',
     270            'contact' => null, // ['email' => ..., 'phone' => ...] restrict the coupon to matching store customers (contact-only coupons)
    265271        );
    266272
    267273        $merged = array_merge( $default, $args );
    268274
     275        try {
     276            return $this->saveCoupon( $merged );
     277        }
     278        catch( \Throwable $e ) {
     279            return array(
     280                "success" => false,
     281                "error" => $e->getMessage(),
     282                "exception" => get_class( $e ),
     283                "environment" => $this->environment(),
     284            );
     285        }
     286    }
     287
     288    /**
     289     * Versions + supported args, so Flashy can tell whether a store runs a plugin that honours `contact` / `code_charset`.
     290     */
     291    private function environment()
     292    {
     293        global $woocommerce;
     294
     295        return array(
     296            "woocommerce" => isset($woocommerce) ? $woocommerce->version : null,
     297            "wordpress" => get_bloginfo( 'version' ),
     298            "php" => phpversion(),
     299            "supports" => array( "contact", "code_length", "code_charset", "description" ),
     300        );
     301    }
     302
     303    private function saveCoupon( $merged )
     304    {
    269305        $coupon = new WC_Coupon();
    270306
    … …  
    290326        $coupon->set_description( $merged['description'] );
    291327
     328        if( !empty($merged['contact']) && is_array($merged['contact']) ) {
     329            $emails = $this->findCustomerEmails( $merged['contact'] );
     330
     331            // No matching customer in the store -> leave the coupon unrestricted
     332            if( count($emails) > 0 ) {
     333                $coupon->set_email_restrictions( $emails );
     334            }
     335        }
     336
    292337        // Create, publish and save coupon (data)
    293338        $coupon->save();
    294339
     340        if( !$coupon->get_id() ) {
     341            throw new \RuntimeException( "WooCommerce did not persist the coupon" );
     342        }
     343
    295344        return array(
    296345            "data" => $merged['coupon_code'],
    297             "success" => true
     346            "success" => true,
     347            "environment" => $this->environment(),
    298348        );
     349    }
     350
     351    /**
     352     * Emails of every store customer matching the contact's email or phone.
     353     * Empty when no customer exists, so the caller leaves the coupon unrestricted.
     354     */
     355    public function findCustomerEmails( $contact )
     356    {
     357        $email = isset($contact['email']) ? sanitize_email( strtolower( trim( $contact['email'] ) ) ) : '';
     358        $phone = isset($contact['phone']) ? preg_replace( '/\D+/', '', (string) $contact['phone'] ) : '';
     359
     360        $users = array();
     361
     362        if( $email !== '' ) {
     363            $by_email = get_user_by( 'email', $email );
     364
     365            if( $by_email ) {
     366                $users[] = $by_email;
     367            }
     368
     369            $users = array_merge( $users, get_users( array(
     370                'meta_key' => 'billing_email',
     371                'meta_value' => $email,
     372                'meta_compare' => '=',
     373                'number' => 50,
     374                'fields' => 'all',
     375            ) ) );
     376        }
     377
     378        // Match on the last 9 digits so local (05x) and international (972 5x) formats both hit
     379        if( strlen( $phone ) >= 9 ) {
     380            $users = array_merge( $users, get_users( array(
     381                'meta_key' => 'billing_phone',
     382                'meta_value' => substr( $phone, -9 ),
     383                'meta_compare' => 'LIKE',
     384                'number' => 50,
     385                'fields' => 'all',
     386            ) ) );
     387        }
     388
     389        $emails = array();
     390
     391        foreach( $users as $user ) {
     392            $candidates = array( $user->user_email, get_user_meta( $user->ID, 'billing_email', true ) );
     393
     394            foreach( $candidates as $candidate ) {
     395                $candidate = sanitize_email( strtolower( trim( (string) $candidate ) ) );
     396
     397                if( $candidate !== '' ) {
     398                    $emails[] = $candidate;
     399                }
     400            }
     401        }
     402
     403        return array_values( array_unique( $emails ) );
    299404    }
    300405
    … …  
    330435        }
    331436
    332     private function getUniqueCode($prefix)
    333     {
    334         $code = $prefix . wp_generate_password(6, false);
     437    private function getUniqueCode($prefix, $length = 6, $charset = null)
     438    {
     439        $code = $prefix . $this->randomCode($length, $charset);
    335440
    336441        if( !empty(wc_get_coupon_id_by_code($code)) )
    337442        {
    338             return $this->getUniqueCode($prefix);
     443            return $this->getUniqueCode($prefix, $length, $charset);
    339444        }
    340445
    341446        return $code;
    342447    }
     448
     449    /**
     450     * @param int $length 6..12
     451     * @param string|null $charset numbers | letters | alphanumeric (null keeps the legacy wp_generate_password format)
     452     */
     453    private function randomCode($length = 6, $charset = null)
     454    {
     455        $length = min(12, max(6, (int) $length));
     456
     457        $pools = array(
     458            'numbers' => '0123456789',
     459            'letters' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
     460            'alphanumeric' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
     461        );
     462
     463        if( $charset === null || !isset($pools[$charset]) )
     464        {
     465            return wp_generate_password($length, false);
     466        }
     467
     468        $pool = $pools[$charset];
     469
     470        $code = '';
     471
     472        for( $i = 0; $i < $length; $i++ )
     473        {
     474            $code .= $pool[ wp_rand(0, strlen($pool) - 1) ];
     475        }
     476
     477        return $code;
     478    }
    343479}
  • wp-flashy-marketing-automation/tags/2.0.14/core/classes/Flashy_Products_Feed.php

    r2959482 r3722918  
    115115            "tags" => $this->childFieldsCheck("tags", $product, $parent),
    116116            "sku" => $product->get_sku(),
     117            "gtin" => method_exists($product, 'get_global_unique_id') ? (string) $product->get_global_unique_id() : '',
    117118            "created_at" => $product->get_date_created()->getTimestamp(),
    118119            "updated_at" => $product->get_date_modified()->getTimestamp(),
  • wp-flashy-marketing-automation/tags/2.0.14/core/snippets/tracking.php

    r3578462 r3722918  
    1313        if(isset($flashy_id) && $flashy_id != '') { ?>
    1414            <script>
    15                 window.flashyMetadata = {"platform": "WordPress","version": "2.0.13"};
     15                window.flashyMetadata = {"platform": "WordPress","version": "2.0.14"};
    1616                console.log("Flashy Init", flashyMetadata);
    1717            </script>
  • wp-flashy-marketing-automation/tags/2.0.14/flashy.php

    r3578462 r3722918  
    44Plugin URI: https://flashy.app
    55Description: Wordpress plugin for flashy.app to sync products, orders and customers and track events.
    6 Version: 2.0.13
     6Version: 2.0.14
    77Author: Flashy
    88Author URI: https://flashy.app
    … …  
    641641                // Flashy Actions
    642642                add_action('shutdown', array($this, 'run_flashy_actions'), 10, 0);
     643
     644                // diagnostics only: bracket the shutdown chain, so a third-party shutdown callback that
     645                // exits or fatals before our flush (killing every later callback with it) is visible in the log
     646                if( flashy_diagnostics_enabled() )
     647                {
     648                        add_action('shutdown', array($this, 'shutdown_probe_start'), PHP_INT_MIN, 0);
     649                        add_action('shutdown', array($this, 'shutdown_probe_end'), PHP_INT_MAX, 0);
     650                }
    643651        }
    644652
    … …  
    668676        {
    669677                $this->actions[$action] = $data;
     678
     679                if( flashy_diagnostics_enabled() )
     680                        flashy_log("Queued action: " . $action . " (flush hooked: " . (has_action('shutdown', array($this, 'run_flashy_actions')) !== false ? "yes" : "no") . ")");
    670681        }
    671682
    … …  
    673684        {
    674685                $this->hooks[$func] = $data;
     686
     687                if( flashy_diagnostics_enabled() )
     688                        flashy_log("Queued hook: " . $func);
     689        }
     690
     691        function shutdown_probe_start()
     692        {
     693                if( empty($this->actions) && empty($this->hooks) )
     694                        return;
     695
     696                flashy_log("Shutdown chain started; pending: " . json_encode(array_keys($this->actions + $this->hooks)));
     697
     698                global $wp_filter;
     699
     700                if( isset($wp_filter['shutdown']) )
     701                {
     702                        $callbacks = array();
     703
     704                        foreach( $wp_filter['shutdown']->callbacks as $priority => $fns )
     705                        {
     706                                foreach( $fns as $fn )
     707                                {
     708                                        $f = $fn['function'];
     709
     710                                        if( is_array($f) )
     711                                                $callbacks[] = $priority . ":" . (is_object($f[0]) ? get_class($f[0]) : $f[0]) . "::" . $f[1];
     712                                        else if( is_string($f) )
     713                                                $callbacks[] = $priority . ":" . $f;
     714                                        else
     715                                                $callbacks[] = $priority . ":" . (is_object($f) ? get_class($f) : "callable");
     716                                }
     717                        }
     718
     719                        flashy_log("Shutdown callbacks: " . json_encode($callbacks));
     720                }
     721        }
     722
     723        function shutdown_probe_end()
     724        {
     725                if( !empty($this->actions) || !empty($this->hooks) )
     726                        flashy_log("Shutdown chain completed");
    675727        }
    676728
    … …  
    692744        {
    693745                $this->load_flashy_hooks();
     746
     747                if( flashy_diagnostics_enabled() && !empty($this->actions) )
     748                        flashy_log("Flushing actions: " . json_encode(array_keys($this->actions)));
    694749
    695750                $list_id = get_option('flashy_list_id');
    … …  
    766821                        flashy_log($e->getTraceAsString(), true);
    767822                }
     823
     824                if( flashy_diagnostics_enabled() && !empty($this->actions) )
     825                        flashy_log("Flush complete");
    768826        }
    769827
    … …  
    26742732}
    26752733
     2734/**
     2735 * Shutdown diagnostics are active in dev/local environments, or on any site where the
     2736 * flashy_log_state option is turned on — so a customer site can be debugged without code changes.
     2737 */
     2738function flashy_diagnostics_enabled()
     2739{
     2740        static $enabled = null;
     2741
     2742        if( $enabled === null )
     2743                $enabled = flashy_get_environment() !== false || get_option('flashy_log_state') === 'true';
     2744
     2745        return $enabled;
     2746}
     2747
    26762748function flashy_log($contents, $force = false)
    26772749{
    … …  
    26842756        $log = apply_filters('flashy/get_info', 'path') . "/error.log";
    26852757
    2686         $current = file_get_contents($log);
    2687 
    26882758        if( gettype($contents) == "array" || gettype($contents) == "object" )
    26892759                $contents = json_encode($contents);
    26902760
    2691         $current .= "[" . date('Y-m-d H:i:s') . "] " . $contents . "\n";
    2692 
    2693         file_put_contents($log, $current);
     2761        // stable per-request id so concurrent requests can be told apart in the log
     2762        static $request_id = null;
     2763
     2764        if( $request_id === null )
     2765                $request_id = substr(md5(uniqid('', true)), 0, 6);
     2766
     2767        $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : php_sapi_name();
     2768
     2769        $line = "[" . date('Y-m-d H:i:s') . "][" . getmypid() . ":" . $request_id . "][" . $uri . "] " . $contents . "\n";
     2770
     2771        file_put_contents($log, $line, FILE_APPEND | LOCK_EX);
    26942772}
    26952773
    … …  
    27002778    $content = "[" . date('Y-m-d H:i:s') . "] Reset Log \n";
    27012779
    2702     file_put_contents($log, $content);
     2780    file_put_contents($log, $content, LOCK_EX);
    27032781}
    27042782
  • wp-flashy-marketing-automation/tags/2.0.14/readme.txt

    r3578462 r3722918  
    3434= COLLECT MORE SUBSCRIBERS ON CHECK & SIGNUP PAGE =
    3535Add a checkbox on the pages you want to collect consent from your visitor who wants to accept marketing.
     36
     37= 2.0.14 =
     38* New Feature: Contact-only coupons - restrict a generated coupon to a specific customer
     39* New Feature: Control the length and characters of generated coupon codes
     40* New Feature: Sync product GTIN (global unique ID) with Flashy
     41* Improvement: More reliable debug logging
    3642
    3743= 2.0.13 =
  • wp-flashy-marketing-automation/trunk/core/classes/Flashy_Export.php

    r2959482 r3722918  
    9090                    "tags" => $product['tags'],
    9191                    "sku" => $product['sku'],
     92                    "gtin" => isset($product['gtin']) ? $product['gtin'] : '',
    9293                    "created_at" => $product['created_at'],
    9394                    "updated_at" => $product['updated_at']
    … …  
    242243        $prefix = ( isset($args['prefix']) ) ? $args['prefix'] : "";
    243244
    244         $code = $this->getUniqueCode($prefix);
     245        $code = $this->getUniqueCode(
     246            $prefix,
     247            isset($args['code_length']) ? (int) $args['code_length'] : 6,
     248            isset($args['code_charset']) ? $args['code_charset'] : null
     249        );
    245250
    246251        $default = array(
    … …  
    262267            'exclude_product_categories' => '', // array of categories id's
    263268            'exclude_sale_items' => true, // bool,
    264             'description' => ''
     269            'description' => '',
     270            'contact' => null, // ['email' => ..., 'phone' => ...] restrict the coupon to matching store customers (contact-only coupons)
    265271        );
    266272
    267273        $merged = array_merge( $default, $args );
    268274
     275        try {
     276            return $this->saveCoupon( $merged );
     277        }
     278        catch( \Throwable $e ) {
     279            return array(
     280                "success" => false,
     281                "error" => $e->getMessage(),
     282                "exception" => get_class( $e ),
     283                "environment" => $this->environment(),
     284            );
     285        }
     286    }
     287
     288    /**
     289     * Versions + supported args, so Flashy can tell whether a store runs a plugin that honours `contact` / `code_charset`.
     290     */
     291    private function environment()
     292    {
     293        global $woocommerce;
     294
     295        return array(
     296            "woocommerce" => isset($woocommerce) ? $woocommerce->version : null,
     297            "wordpress" => get_bloginfo( 'version' ),
     298            "php" => phpversion(),
     299            "supports" => array( "contact", "code_length", "code_charset", "description" ),
     300        );
     301    }
     302
     303    private function saveCoupon( $merged )
     304    {
    269305        $coupon = new WC_Coupon();
    270306
    … …  
    290326        $coupon->set_description( $merged['description'] );
    291327
     328        if( !empty($merged['contact']) && is_array($merged['contact']) ) {
     329            $emails = $this->findCustomerEmails( $merged['contact'] );
     330
     331            // No matching customer in the store -> leave the coupon unrestricted
     332            if( count($emails) > 0 ) {
     333                $coupon->set_email_restrictions( $emails );
     334            }
     335        }
     336
    292337        // Create, publish and save coupon (data)
    293338        $coupon->save();
    294339
     340        if( !$coupon->get_id() ) {
     341            throw new \RuntimeException( "WooCommerce did not persist the coupon" );
     342        }
     343
    295344        return array(
    296345            "data" => $merged['coupon_code'],
    297             "success" => true
     346            "success" => true,
     347            "environment" => $this->environment(),
    298348        );
     349    }
     350
     351    /**
     352     * Emails of every store customer matching the contact's email or phone.
     353     * Empty when no customer exists, so the caller leaves the coupon unrestricted.
     354     */
     355    public function findCustomerEmails( $contact )
     356    {
     357        $email = isset($contact['email']) ? sanitize_email( strtolower( trim( $contact['email'] ) ) ) : '';
     358        $phone = isset($contact['phone']) ? preg_replace( '/\D+/', '', (string) $contact['phone'] ) : '';
     359
     360        $users = array();
     361
     362        if( $email !== '' ) {
     363            $by_email = get_user_by( 'email', $email );
     364
     365            if( $by_email ) {
     366                $users[] = $by_email;
     367            }
     368
     369            $users = array_merge( $users, get_users( array(
     370                'meta_key' => 'billing_email',
     371                'meta_value' => $email,
     372                'meta_compare' => '=',
     373                'number' => 50,
     374                'fields' => 'all',
     375            ) ) );
     376        }
     377
     378        // Match on the last 9 digits so local (05x) and international (972 5x) formats both hit
     379        if( strlen( $phone ) >= 9 ) {
     380            $users = array_merge( $users, get_users( array(
     381                'meta_key' => 'billing_phone',
     382                'meta_value' => substr( $phone, -9 ),
     383                'meta_compare' => 'LIKE',
     384                'number' => 50,
     385                'fields' => 'all',
     386            ) ) );
     387        }
     388
     389        $emails = array();
     390
     391        foreach( $users as $user ) {
     392            $candidates = array( $user->user_email, get_user_meta( $user->ID, 'billing_email', true ) );
     393
     394            foreach( $candidates as $candidate ) {
     395                $candidate = sanitize_email( strtolower( trim( (string) $candidate ) ) );
     396
     397                if( $candidate !== '' ) {
     398                    $emails[] = $candidate;
     399                }
     400            }
     401        }
     402
     403        return array_values( array_unique( $emails ) );
    299404    }
    300405
    … …  
    330435        }
    331436
    332     private function getUniqueCode($prefix)
    333     {
    334         $code = $prefix . wp_generate_password(6, false);
     437    private function getUniqueCode($prefix, $length = 6, $charset = null)
     438    {
     439        $code = $prefix . $this->randomCode($length, $charset);
    335440
    336441        if( !empty(wc_get_coupon_id_by_code($code)) )
    337442        {
    338             return $this->getUniqueCode($prefix);
     443            return $this->getUniqueCode($prefix, $length, $charset);
    339444        }
    340445
    341446        return $code;
    342447    }
     448
     449    /**
     450     * @param int $length 6..12
     451     * @param string|null $charset numbers | letters | alphanumeric (null keeps the legacy wp_generate_password format)
     452     */
     453    private function randomCode($length = 6, $charset = null)
     454    {
     455        $length = min(12, max(6, (int) $length));
     456
     457        $pools = array(
     458            'numbers' => '0123456789',
     459            'letters' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
     460            'alphanumeric' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
     461        );
     462
     463        if( $charset === null || !isset($pools[$charset]) )
     464        {
     465            return wp_generate_password($length, false);
     466        }
     467
     468        $pool = $pools[$charset];
     469
     470        $code = '';
     471
     472        for( $i = 0; $i < $length; $i++ )
     473        {
     474            $code .= $pool[ wp_rand(0, strlen($pool) - 1) ];
     475        }
     476
     477        return $code;
     478    }
    343479}
  • wp-flashy-marketing-automation/trunk/core/classes/Flashy_Products_Feed.php

    r2959482 r3722918  
    115115            "tags" => $this->childFieldsCheck("tags", $product, $parent),
    116116            "sku" => $product->get_sku(),
     117            "gtin" => method_exists($product, 'get_global_unique_id') ? (string) $product->get_global_unique_id() : '',
    117118            "created_at" => $product->get_date_created()->getTimestamp(),
    118119            "updated_at" => $product->get_date_modified()->getTimestamp(),
  • wp-flashy-marketing-automation/trunk/core/snippets/tracking.php

    r3578462 r3722918  
    1313        if(isset($flashy_id) && $flashy_id != '') { ?>
    1414            <script>
    15                 window.flashyMetadata = {"platform": "WordPress","version": "2.0.13"};
     15                window.flashyMetadata = {"platform": "WordPress","version": "2.0.14"};
    1616                console.log("Flashy Init", flashyMetadata);
    1717            </script>
  • wp-flashy-marketing-automation/trunk/flashy.php

    r3578462 r3722918  
    44Plugin URI: https://flashy.app
    55Description: Wordpress plugin for flashy.app to sync products, orders and customers and track events.
    6 Version: 2.0.13
     6Version: 2.0.14
    77Author: Flashy
    88Author URI: https://flashy.app
    … …  
    641641                // Flashy Actions
    642642                add_action('shutdown', array($this, 'run_flashy_actions'), 10, 0);
     643
     644                // diagnostics only: bracket the shutdown chain, so a third-party shutdown callback that
     645                // exits or fatals before our flush (killing every later callback with it) is visible in the log
     646                if( flashy_diagnostics_enabled() )
     647                {
     648                        add_action('shutdown', array($this, 'shutdown_probe_start'), PHP_INT_MIN, 0);
     649                        add_action('shutdown', array($this, 'shutdown_probe_end'), PHP_INT_MAX, 0);
     650                }
    643651        }
    644652
    … …  
    668676        {
    669677                $this->actions[$action] = $data;
     678
     679                if( flashy_diagnostics_enabled() )
     680                        flashy_log("Queued action: " . $action . " (flush hooked: " . (has_action('shutdown', array($this, 'run_flashy_actions')) !== false ? "yes" : "no") . ")");
    670681        }
    671682
    … …  
    673684        {
    674685                $this->hooks[$func] = $data;
     686
     687                if( flashy_diagnostics_enabled() )
     688                        flashy_log("Queued hook: " . $func);
     689        }
     690
     691        function shutdown_probe_start()
     692        {
     693                if( empty($this->actions) && empty($this->hooks) )
     694                        return;
     695
     696                flashy_log("Shutdown chain started; pending: " . json_encode(array_keys($this->actions + $this->hooks)));
     697
     698                global $wp_filter;
     699
     700                if( isset($wp_filter['shutdown']) )
     701                {
     702                        $callbacks = array();
     703
     704                        foreach( $wp_filter['shutdown']->callbacks as $priority => $fns )
     705                        {
     706                                foreach( $fns as $fn )
     707                                {
     708                                        $f = $fn['function'];
     709
     710                                        if( is_array($f) )
     711                                                $callbacks[] = $priority . ":" . (is_object($f[0]) ? get_class($f[0]) : $f[0]) . "::" . $f[1];
     712                                        else if( is_string($f) )
     713                                                $callbacks[] = $priority . ":" . $f;
     714                                        else
     715                                                $callbacks[] = $priority . ":" . (is_object($f) ? get_class($f) : "callable");
     716                                }
     717                        }
     718
     719                        flashy_log("Shutdown callbacks: " . json_encode($callbacks));
     720                }
     721        }
     722
     723        function shutdown_probe_end()
     724        {
     725                if( !empty($this->actions) || !empty($this->hooks) )
     726                        flashy_log("Shutdown chain completed");
    675727        }
    676728
    … …  
    692744        {
    693745                $this->load_flashy_hooks();
     746
     747                if( flashy_diagnostics_enabled() && !empty($this->actions) )
     748                        flashy_log("Flushing actions: " . json_encode(array_keys($this->actions)));
    694749
    695750                $list_id = get_option('flashy_list_id');
    … …  
    766821                        flashy_log($e->getTraceAsString(), true);
    767822                }
     823
     824                if( flashy_diagnostics_enabled() && !empty($this->actions) )
     825                        flashy_log("Flush complete");
    768826        }
    769827
    … …  
    26742732}
    26752733
     2734/**
     2735 * Shutdown diagnostics are active in dev/local environments, or on any site where the
     2736 * flashy_log_state option is turned on — so a customer site can be debugged without code changes.
     2737 */
     2738function flashy_diagnostics_enabled()
     2739{
     2740        static $enabled = null;
     2741
     2742        if( $enabled === null )
     2743                $enabled = flashy_get_environment() !== false || get_option('flashy_log_state') === 'true';
     2744
     2745        return $enabled;
     2746}
     2747
    26762748function flashy_log($contents, $force = false)
    26772749{
    … …  
    26842756        $log = apply_filters('flashy/get_info', 'path') . "/error.log";
    26852757
    2686         $current = file_get_contents($log);
    2687 
    26882758        if( gettype($contents) == "array" || gettype($contents) == "object" )
    26892759                $contents = json_encode($contents);
    26902760
    2691         $current .= "[" . date('Y-m-d H:i:s') . "] " . $contents . "\n";
    2692 
    2693         file_put_contents($log, $current);
     2761        // stable per-request id so concurrent requests can be told apart in the log
     2762        static $request_id = null;
     2763
     2764        if( $request_id === null )
     2765                $request_id = substr(md5(uniqid('', true)), 0, 6);
     2766
     2767        $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : php_sapi_name();
     2768
     2769        $line = "[" . date('Y-m-d H:i:s') . "][" . getmypid() . ":" . $request_id . "][" . $uri . "] " . $contents . "\n";
     2770
     2771        file_put_contents($log, $line, FILE_APPEND | LOCK_EX);
    26942772}
    26952773
    … …  
    27002778    $content = "[" . date('Y-m-d H:i:s') . "] Reset Log \n";
    27012779
    2702     file_put_contents($log, $content);
     2780    file_put_contents($log, $content, LOCK_EX);
    27032781}
    27042782
  • wp-flashy-marketing-automation/trunk/readme.txt

    r3578462 r3722918  
    3434= COLLECT MORE SUBSCRIBERS ON CHECK & SIGNUP PAGE =
    3535Add a checkbox on the pages you want to collect consent from your visitor who wants to accept marketing.
     36
     37= 2.0.14 =
     38* New Feature: Contact-only coupons - restrict a generated coupon to a specific customer
     39* New Feature: Control the length and characters of generated coupon codes
     40* New Feature: Sync product GTIN (global unique ID) with Flashy
     41* Improvement: More reliable debug logging
    3642
    3743= 2.0.13 =
Note: See TracChangeset for help on using the changeset viewer.