Changeset 3722918
- Timestamp:
- 10/01/2026 10:50:25 AM (3 weeks ago)
- Location:
- wp-flashy-marketing-automation
- Files:
-
- 10 edited
- 1 copied
-
tags/2.0.14 (copied) (copied from wp-flashy-marketing-automation/trunk )
-
tags/2.0.14/core/classes/Flashy_Export.php (modified) (5 diffs)
-
tags/2.0.14/core/classes/Flashy_Products_Feed.php (modified) (1 diff)
-
tags/2.0.14/core/snippets/tracking.php (modified) (1 diff)
-
tags/2.0.14/flashy.php (modified) (9 diffs)
-
tags/2.0.14/readme.txt (modified) (1 diff)
-
trunk/core/classes/Flashy_Export.php (modified) (5 diffs)
-
trunk/core/classes/Flashy_Products_Feed.php (modified) (1 diff)
-
trunk/core/snippets/tracking.php (modified) (1 diff)
-
trunk/flashy.php (modified) (9 diffs)
-
trunk/readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
wp-flashy-marketing-automation/tags/2.0.14/core/classes/Flashy_Export.php
r2959482 r3722918 90 90 "tags" => $product['tags'], 91 91 "sku" => $product['sku'], 92 "gtin" => isset($product['gtin']) ? $product['gtin'] : '', 92 93 "created_at" => $product['created_at'], 93 94 "updated_at" => $product['updated_at'] … … 242 243 $prefix = ( isset($args['prefix']) ) ? $args['prefix'] : ""; 243 244 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 ); 245 250 246 251 $default = array( … … 262 267 'exclude_product_categories' => '', // array of categories id's 263 268 'exclude_sale_items' => true, // bool, 264 'description' => '' 269 'description' => '', 270 'contact' => null, // ['email' => ..., 'phone' => ...] restrict the coupon to matching store customers (contact-only coupons) 265 271 ); 266 272 267 273 $merged = array_merge( $default, $args ); 268 274 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 { 269 305 $coupon = new WC_Coupon(); 270 306 … … 290 326 $coupon->set_description( $merged['description'] ); 291 327 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 292 337 // Create, publish and save coupon (data) 293 338 $coupon->save(); 294 339 340 if( !$coupon->get_id() ) { 341 throw new \RuntimeException( "WooCommerce did not persist the coupon" ); 342 } 343 295 344 return array( 296 345 "data" => $merged['coupon_code'], 297 "success" => true 346 "success" => true, 347 "environment" => $this->environment(), 298 348 ); 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 ) ); 299 404 } 300 405 … … 330 435 } 331 436 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); 335 440 336 441 if( !empty(wc_get_coupon_id_by_code($code)) ) 337 442 { 338 return $this->getUniqueCode($prefix );443 return $this->getUniqueCode($prefix, $length, $charset); 339 444 } 340 445 341 446 return $code; 342 447 } 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 } 343 479 } -
wp-flashy-marketing-automation/tags/2.0.14/core/classes/Flashy_Products_Feed.php
r2959482 r3722918 115 115 "tags" => $this->childFieldsCheck("tags", $product, $parent), 116 116 "sku" => $product->get_sku(), 117 "gtin" => method_exists($product, 'get_global_unique_id') ? (string) $product->get_global_unique_id() : '', 117 118 "created_at" => $product->get_date_created()->getTimestamp(), 118 119 "updated_at" => $product->get_date_modified()->getTimestamp(), -
wp-flashy-marketing-automation/tags/2.0.14/core/snippets/tracking.php
r3578462 r3722918 13 13 if(isset($flashy_id) && $flashy_id != '') { ?> 14 14 <script> 15 window.flashyMetadata = {"platform": "WordPress","version": "2.0.1 3"};15 window.flashyMetadata = {"platform": "WordPress","version": "2.0.14"}; 16 16 console.log("Flashy Init", flashyMetadata); 17 17 </script> -
wp-flashy-marketing-automation/tags/2.0.14/flashy.php
r3578462 r3722918 4 4 Plugin URI: https://flashy.app 5 5 Description: Wordpress plugin for flashy.app to sync products, orders and customers and track events. 6 Version: 2.0.1 36 Version: 2.0.14 7 7 Author: Flashy 8 8 Author URI: https://flashy.app … … 641 641 // Flashy Actions 642 642 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 } 643 651 } 644 652 … … 668 676 { 669 677 $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") . ")"); 670 681 } 671 682 … … 673 684 { 674 685 $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"); 675 727 } 676 728 … … 692 744 { 693 745 $this->load_flashy_hooks(); 746 747 if( flashy_diagnostics_enabled() && !empty($this->actions) ) 748 flashy_log("Flushing actions: " . json_encode(array_keys($this->actions))); 694 749 695 750 $list_id = get_option('flashy_list_id'); … … 766 821 flashy_log($e->getTraceAsString(), true); 767 822 } 823 824 if( flashy_diagnostics_enabled() && !empty($this->actions) ) 825 flashy_log("Flush complete"); 768 826 } 769 827 … … 2674 2732 } 2675 2733 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 */ 2738 function 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 2676 2748 function flashy_log($contents, $force = false) 2677 2749 { … … 2684 2756 $log = apply_filters('flashy/get_info', 'path') . "/error.log"; 2685 2757 2686 $current = file_get_contents($log);2687 2688 2758 if( gettype($contents) == "array" || gettype($contents) == "object" ) 2689 2759 $contents = json_encode($contents); 2690 2760 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); 2694 2772 } 2695 2773 … … 2700 2778 $content = "[" . date('Y-m-d H:i:s') . "] Reset Log \n"; 2701 2779 2702 file_put_contents($log, $content );2780 file_put_contents($log, $content, LOCK_EX); 2703 2781 } 2704 2782 -
wp-flashy-marketing-automation/tags/2.0.14/readme.txt
r3578462 r3722918 34 34 = COLLECT MORE SUBSCRIBERS ON CHECK & SIGNUP PAGE = 35 35 Add 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 36 42 37 43 = 2.0.13 = -
wp-flashy-marketing-automation/trunk/core/classes/Flashy_Export.php
r2959482 r3722918 90 90 "tags" => $product['tags'], 91 91 "sku" => $product['sku'], 92 "gtin" => isset($product['gtin']) ? $product['gtin'] : '', 92 93 "created_at" => $product['created_at'], 93 94 "updated_at" => $product['updated_at'] … … 242 243 $prefix = ( isset($args['prefix']) ) ? $args['prefix'] : ""; 243 244 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 ); 245 250 246 251 $default = array( … … 262 267 'exclude_product_categories' => '', // array of categories id's 263 268 'exclude_sale_items' => true, // bool, 264 'description' => '' 269 'description' => '', 270 'contact' => null, // ['email' => ..., 'phone' => ...] restrict the coupon to matching store customers (contact-only coupons) 265 271 ); 266 272 267 273 $merged = array_merge( $default, $args ); 268 274 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 { 269 305 $coupon = new WC_Coupon(); 270 306 … … 290 326 $coupon->set_description( $merged['description'] ); 291 327 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 292 337 // Create, publish and save coupon (data) 293 338 $coupon->save(); 294 339 340 if( !$coupon->get_id() ) { 341 throw new \RuntimeException( "WooCommerce did not persist the coupon" ); 342 } 343 295 344 return array( 296 345 "data" => $merged['coupon_code'], 297 "success" => true 346 "success" => true, 347 "environment" => $this->environment(), 298 348 ); 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 ) ); 299 404 } 300 405 … … 330 435 } 331 436 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); 335 440 336 441 if( !empty(wc_get_coupon_id_by_code($code)) ) 337 442 { 338 return $this->getUniqueCode($prefix );443 return $this->getUniqueCode($prefix, $length, $charset); 339 444 } 340 445 341 446 return $code; 342 447 } 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 } 343 479 } -
wp-flashy-marketing-automation/trunk/core/classes/Flashy_Products_Feed.php
r2959482 r3722918 115 115 "tags" => $this->childFieldsCheck("tags", $product, $parent), 116 116 "sku" => $product->get_sku(), 117 "gtin" => method_exists($product, 'get_global_unique_id') ? (string) $product->get_global_unique_id() : '', 117 118 "created_at" => $product->get_date_created()->getTimestamp(), 118 119 "updated_at" => $product->get_date_modified()->getTimestamp(), -
wp-flashy-marketing-automation/trunk/core/snippets/tracking.php
r3578462 r3722918 13 13 if(isset($flashy_id) && $flashy_id != '') { ?> 14 14 <script> 15 window.flashyMetadata = {"platform": "WordPress","version": "2.0.1 3"};15 window.flashyMetadata = {"platform": "WordPress","version": "2.0.14"}; 16 16 console.log("Flashy Init", flashyMetadata); 17 17 </script> -
wp-flashy-marketing-automation/trunk/flashy.php
r3578462 r3722918 4 4 Plugin URI: https://flashy.app 5 5 Description: Wordpress plugin for flashy.app to sync products, orders and customers and track events. 6 Version: 2.0.1 36 Version: 2.0.14 7 7 Author: Flashy 8 8 Author URI: https://flashy.app … … 641 641 // Flashy Actions 642 642 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 } 643 651 } 644 652 … … 668 676 { 669 677 $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") . ")"); 670 681 } 671 682 … … 673 684 { 674 685 $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"); 675 727 } 676 728 … … 692 744 { 693 745 $this->load_flashy_hooks(); 746 747 if( flashy_diagnostics_enabled() && !empty($this->actions) ) 748 flashy_log("Flushing actions: " . json_encode(array_keys($this->actions))); 694 749 695 750 $list_id = get_option('flashy_list_id'); … … 766 821 flashy_log($e->getTraceAsString(), true); 767 822 } 823 824 if( flashy_diagnostics_enabled() && !empty($this->actions) ) 825 flashy_log("Flush complete"); 768 826 } 769 827 … … 2674 2732 } 2675 2733 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 */ 2738 function 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 2676 2748 function flashy_log($contents, $force = false) 2677 2749 { … … 2684 2756 $log = apply_filters('flashy/get_info', 'path') . "/error.log"; 2685 2757 2686 $current = file_get_contents($log);2687 2688 2758 if( gettype($contents) == "array" || gettype($contents) == "object" ) 2689 2759 $contents = json_encode($contents); 2690 2760 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); 2694 2772 } 2695 2773 … … 2700 2778 $content = "[" . date('Y-m-d H:i:s') . "] Reset Log \n"; 2701 2779 2702 file_put_contents($log, $content );2780 file_put_contents($log, $content, LOCK_EX); 2703 2781 } 2704 2782 -
wp-flashy-marketing-automation/trunk/readme.txt
r3578462 r3722918 34 34 = COLLECT MORE SUBSCRIBERS ON CHECK & SIGNUP PAGE = 35 35 Add 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 36 42 37 43 = 2.0.13 =
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)