Facebook for WooCommerce - Version 2.0.3

Version Description

Download this release

Release Info

Developer SkyVerge
Plugin Icon Facebook for WooCommerce
Version 2.0.3
Comparing to
See all releases

Code changes from version 2.0.2 to 2.0.3

changelog.txt CHANGED
@@ -1,5 +1,10 @@
1
  *** Facebook for WooCommerce Changelog ***
2
 
 
 
 
 
 
3
  2020.09.25 - version 2.0.2
4
  * Tweak - Allow simple and variable products with zero/empty price to sync to Facebook
5
  * Tweak - Use the bundle price for Product Bundles products with individually priced items
1
  *** Facebook for WooCommerce Changelog ***
2
 
3
+ 2020.10.02 - version 2.0.3
4
+ * Tweak - Pixel events now can include advanced matching information
5
+ * Fix - Send contents parameter for ViewContent event using the correct format
6
+ * Fix - Remove duplicate visibility meta entries from postmeta table
7
+
8
  2020.09.25 - version 2.0.2
9
  * Tweak - Allow simple and variable products with zero/empty price to sync to Facebook
10
  * Tweak - Use the bundle price for Product Bundles products with individually priced items
class-wc-facebookcommerce.php CHANGED
@@ -11,6 +11,7 @@
11
  use SkyVerge\WooCommerce\Facebook\API;
12
  use SkyVerge\WooCommerce\Facebook\Lifecycle;
13
  use SkyVerge\WooCommerce\Facebook\Utilities\Background_Handle_Virtual_Products_Variations;
 
14
  use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
15
 
16
  if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
@@ -21,7 +22,7 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
21
 
22
 
23
  /** @var string the plugin version */
24
- const VERSION = '2.0.2';
25
 
26
  /** @var string for backwards compatibility TODO: remove this in v2.0.0 {CW 2020-02-06} */
27
  const PLUGIN_VERSION = self::VERSION;
@@ -57,6 +58,9 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
57
  /** @var Background_Handle_Virtual_Products_Variations instance */
58
  protected $background_handle_virtual_products_variations;
59
 
 
 
 
60
  /** @var \SkyVerge\WooCommerce\Facebook\Products\Sync products sync handler */
61
  private $products_sync_handler;
62
 
@@ -114,6 +118,8 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
114
  require_once __DIR__ . '/includes/fbproductfeed.php';
115
  require_once __DIR__ . '/facebook-commerce-messenger-chat.php';
116
  require_once __DIR__ . '/includes/Events/Event.php';
 
 
117
 
118
  $this->product_feed = new \SkyVerge\WooCommerce\Facebook\Products\Feed();
119
  $this->products_sync_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync();
@@ -133,6 +139,14 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
133
  require_once __DIR__ . '/includes/Utilities/Background_Handle_Virtual_Products_Variations.php';
134
 
135
  $this->background_handle_virtual_products_variations = new Background_Handle_Virtual_Products_Variations();
 
 
 
 
 
 
 
 
136
  }
137
 
138
  $this->connection_handler = new \SkyVerge\WooCommerce\Facebook\Handlers\Connection( $this );
@@ -498,6 +512,19 @@ if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
498
  }
499
 
500
 
 
 
 
 
 
 
 
 
 
 
 
 
 
501
  /**
502
  * Gets the products sync handler.
503
  *
11
  use SkyVerge\WooCommerce\Facebook\API;
12
  use SkyVerge\WooCommerce\Facebook\Lifecycle;
13
  use SkyVerge\WooCommerce\Facebook\Utilities\Background_Handle_Virtual_Products_Variations;
14
+ use SkyVerge\WooCommerce\Facebook\Utilities\Background_Remove_Duplicate_Visibility_Meta;
15
  use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
16
 
17
  if ( ! class_exists( 'WC_Facebookcommerce' ) ) :
22
 
23
 
24
  /** @var string the plugin version */
25
+ const VERSION = '2.0.3';
26
 
27
  /** @var string for backwards compatibility TODO: remove this in v2.0.0 {CW 2020-02-06} */
28
  const PLUGIN_VERSION = self::VERSION;
58
  /** @var Background_Handle_Virtual_Products_Variations instance */
59
  protected $background_handle_virtual_products_variations;
60
 
61
+ /** @var Background_Remove_Duplicate_Visibility_Meta job handler instance */
62
+ protected $background_remove_duplicate_visibility_meta;
63
+
64
  /** @var \SkyVerge\WooCommerce\Facebook\Products\Sync products sync handler */
65
  private $products_sync_handler;
66
 
118
  require_once __DIR__ . '/includes/fbproductfeed.php';
119
  require_once __DIR__ . '/facebook-commerce-messenger-chat.php';
120
  require_once __DIR__ . '/includes/Events/Event.php';
121
+ require_once __DIR__ . '/includes/Events/Normalizer.php';
122
+ require_once __DIR__ . '/includes/Events/AAMSettings.php';
123
 
124
  $this->product_feed = new \SkyVerge\WooCommerce\Facebook\Products\Feed();
125
  $this->products_sync_handler = new \SkyVerge\WooCommerce\Facebook\Products\Sync();
139
  require_once __DIR__ . '/includes/Utilities/Background_Handle_Virtual_Products_Variations.php';
140
 
141
  $this->background_handle_virtual_products_variations = new Background_Handle_Virtual_Products_Variations();
142
+
143
+ }
144
+
145
+ if ( 'yes' !== get_option( 'wc_facebook_background_remove_duplicate_visibility_meta_complete', 'no' ) ) {
146
+
147
+ require_once __DIR__ . '/includes/Utilities/Background_Remove_Duplicate_Visibility_Meta.php';
148
+
149
+ $this->background_remove_duplicate_visibility_meta = new Background_Remove_Duplicate_Visibility_Meta();
150
  }
151
 
152
  $this->connection_handler = new \SkyVerge\WooCommerce\Facebook\Handlers\Connection( $this );
512
  }
513
 
514
 
515
+ /**
516
+ * Gets the background remove duplicate visibility meta data handler instance.
517
+ *
518
+ * @since 2.0.3
519
+ *
520
+ * @return Background_Remove_Duplicate_Visibility_Meta
521
+ */
522
+ public function get_background_remove_duplicate_visibility_meta_instance() {
523
+
524
+ return $this->background_remove_duplicate_visibility_meta;
525
+ }
526
+
527
+
528
  /**
529
  * Gets the products sync handler.
530
  *
facebook-commerce-events-tracker.php CHANGED
@@ -29,10 +29,15 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
29
 
30
  /** @var Event search event instance */
31
  private $search_event;
 
 
 
 
32
 
33
-
34
- public function __construct( $user_info ) {
35
  $this->pixel = new WC_Facebookcommerce_Pixel( $user_info );
 
 
36
 
37
  add_action( 'wp_head', array( $this, 'apply_filters' ) );
38
 
@@ -170,6 +175,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
170
  'content_type' => $content_type,
171
  'contents' => $contents,
172
  ],
 
173
  ];
174
 
175
  $event = new Event( $event_data );
@@ -270,6 +276,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
270
  'value' => Framework\SV_WC_Helper::number_format( $total_value ),
271
  'currency' => get_woocommerce_currency(),
272
  ],
 
273
  ];
274
 
275
  $this->search_event = new Event( $event_data );
@@ -329,19 +336,22 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
329
  'content_name' => $product->get_title(),
330
  'content_ids' => wp_json_encode( \WC_Facebookcommerce_Utils::get_fb_content_ids( $product ) ),
331
  'content_type' => $content_type,
332
- 'contents' => [
333
  [
334
- 'id' => \WC_Facebookcommerce_Utils::get_fb_retailer_id( $product ),
335
- 'quantity' => 1,
 
 
336
  ]
337
- ],
338
  'content_category' => $categories['name'],
339
  'value' => $product->get_price(),
340
  'currency' => get_woocommerce_currency(),
341
  ],
 
342
  ];
343
 
344
- $event = new \SkyVerge\WooCommerce\Facebook\Events\Event( $event_data );
345
 
346
  $this->send_api_event( $event );
347
 
@@ -385,6 +395,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
385
  'value' => $this->get_cart_total(),
386
  'currency' => get_woocommerce_currency(),
387
  ],
 
388
  ];
389
 
390
  $event = new SkyVerge\WooCommerce\Facebook\Events\Event( $event_data );
@@ -617,6 +628,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
617
  'value' => $this->get_cart_total(),
618
  'currency' => get_woocommerce_currency(),
619
  ],
 
620
  ];
621
 
622
  // if there is only one item in the cart, send its first category
@@ -715,7 +727,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
715
  $contents[] = $content;
716
  }
717
  }
718
-
719
  $event_data = [
720
  'event_name' => $event_name,
721
  'custom_data' => [
@@ -726,6 +738,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
726
  'value' => $order->get_total(),
727
  'currency' => get_woocommerce_currency(),
728
  ],
 
729
  ];
730
 
731
  $event = new Event( $event_data );
@@ -772,6 +785,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
772
  'value' => $subscription->get_total(),
773
  'currency' => get_woocommerce_currency(),
774
  ],
 
775
  ];
776
 
777
  $event = new Event( $event_data );
@@ -831,6 +845,7 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
831
  * @return bool
832
  */
833
  protected function send_api_event( Event $event ) {
 
834
 
835
  try {
836
 
@@ -958,6 +973,48 @@ if ( ! class_exists( 'WC_Facebookcommerce_EventsTracker' ) ) :
958
  return WC()->cart ? WC()->cart->total : 0;
959
  }
960
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
961
 
962
  }
963
 
29
 
30
  /** @var Event search event instance */
31
  private $search_event;
32
+ /** @var array with events tracked */
33
+ private $tracked_events;
34
+ /** @var AAMSettings aam settings instance, used to filter advanced matching fields*/
35
+ private $aam_settings;
36
 
37
+ public function __construct( $user_info, $aam_settings ) {
 
38
  $this->pixel = new WC_Facebookcommerce_Pixel( $user_info );
39
+ $this->aam_settings = $aam_settings;
40
+ $this->tracked_events = array();
41
 
42
  add_action( 'wp_head', array( $this, 'apply_filters' ) );
43
 
175
  'content_type' => $content_type,
176
  'contents' => $contents,
177
  ],
178
+ 'user_data' => $this->pixel->get_user_info()
179
  ];
180
 
181
  $event = new Event( $event_data );
276
  'value' => Framework\SV_WC_Helper::number_format( $total_value ),
277
  'currency' => get_woocommerce_currency(),
278
  ],
279
+ 'user_data' => $this->pixel->get_user_info()
280
  ];
281
 
282
  $this->search_event = new Event( $event_data );
336
  'content_name' => $product->get_title(),
337
  'content_ids' => wp_json_encode( \WC_Facebookcommerce_Utils::get_fb_content_ids( $product ) ),
338
  'content_type' => $content_type,
339
+ 'contents' => wp_json_encode(
340
  [
341
+ [
342
+ 'id' => \WC_Facebookcommerce_Utils::get_fb_retailer_id( $product ),
343
+ 'quantity' => 1,
344
+ ]
345
  ]
346
+ ),
347
  'content_category' => $categories['name'],
348
  'value' => $product->get_price(),
349
  'currency' => get_woocommerce_currency(),
350
  ],
351
+ 'user_data' => $this->pixel->get_user_info(),
352
  ];
353
 
354
+ $event = new Event( $event_data );
355
 
356
  $this->send_api_event( $event );
357
 
395
  'value' => $this->get_cart_total(),
396
  'currency' => get_woocommerce_currency(),
397
  ],
398
+ 'user_data' => $this->pixel->get_user_info(),
399
  ];
400
 
401
  $event = new SkyVerge\WooCommerce\Facebook\Events\Event( $event_data );
628
  'value' => $this->get_cart_total(),
629
  'currency' => get_woocommerce_currency(),
630
  ],
631
+ 'user_data' => $this->pixel->get_user_info()
632
  ];
633
 
634
  // if there is only one item in the cart, send its first category
727
  $contents[] = $content;
728
  }
729
  }
730
+ // Advanced matching information is extracted from the order
731
  $event_data = [
732
  'event_name' => $event_name,
733
  'custom_data' => [
738
  'value' => $order->get_total(),
739
  'currency' => get_woocommerce_currency(),
740
  ],
741
+ 'user_data' => $this->get_user_data_from_billing_address($order)
742
  ];
743
 
744
  $event = new Event( $event_data );
785
  'value' => $subscription->get_total(),
786
  'currency' => get_woocommerce_currency(),
787
  ],
788
+ 'user_data' => $this->pixel->get_user_info()
789
  ];
790
 
791
  $event = new Event( $event_data );
845
  * @return bool
846
  */
847
  protected function send_api_event( Event $event ) {
848
+ $this->tracked_events[] = $event;
849
 
850
  try {
851
 
973
  return WC()->cart ? WC()->cart->total : 0;
974
  }
975
 
976
+ /**
977
+ * Gets advanced matching information from a given order
978
+ *
979
+ * @since 2.0.3
980
+ *
981
+ * @return array
982
+ */
983
+ private function get_user_data_from_billing_address($order) {
984
+ if($this->aam_settings == null || !$this->aam_settings->get_enable_automatic_matching() ){
985
+ return array();
986
+ }
987
+ $user_data= array();
988
+ $user_data['fn'] = $order->get_billing_first_name();
989
+ $user_data['ln'] = $order->get_billing_last_name();
990
+ $user_data['em'] = $order->get_billing_email();
991
+ // get_user_id() returns 0 if the current user is a guest
992
+ $user_data['external_id'] = $order->get_user_id() === 0 ? null : strval($order->get_user_id());
993
+ $user_data['zp'] = $order->get_billing_postcode();
994
+ $user_data['st'] = $order->get_billing_state();
995
+ // We can use country as key because this information is for CAPI events only
996
+ $user_data['country'] = $order->get_billing_country();
997
+ $user_data['ct'] = $order->get_billing_city();
998
+ $user_data['ph'] = $order->get_billing_phone();
999
+ // The fields contain country, so we do not need to add a condition
1000
+ foreach ($user_data as $field => $value) {
1001
+ if( $value === null || $value === '' ||
1002
+ !in_array($field, $this->aam_settings->get_enabled_automatic_matching_fields())
1003
+ ){
1004
+ unset($user_data[$field]);
1005
+ }
1006
+ }
1007
+ return $user_data;
1008
+ }
1009
+
1010
+ /**
1011
+ * Gets the events tracked by this object
1012
+ *
1013
+ * @return array
1014
+ */
1015
+ public function get_tracked_events(){
1016
+ return $this->tracked_events;
1017
+ }
1018
 
1019
  }
1020
 
facebook-commerce-pixel-event.php CHANGED
@@ -415,11 +415,13 @@ if ( ! class_exists( 'WC_Facebookcommerce_Pixel' ) ) :
415
  }
416
 
417
  if ( ! empty( $event_id ) ) {
418
-
419
  $event = sprintf(
420
  "/* %s Facebook Integration Event Tracking */\n" .
 
421
  "fbq('%s', '%s', %s, %s);",
422
  WC_Facebookcommerce_Utils::getIntegrationName(),
 
 
423
  esc_js( $method ),
424
  esc_js( $event_name ),
425
  json_encode( self::build_params( $params, $event_name ), JSON_PRETTY_PRINT | JSON_FORCE_OBJECT ),
@@ -430,8 +432,11 @@ if ( ! class_exists( 'WC_Facebookcommerce_Pixel' ) ) :
430
 
431
  $event = sprintf(
432
  "/* %s Facebook Integration Event Tracking */\n" .
 
433
  "fbq('%s', '%s', %s);",
434
  WC_Facebookcommerce_Utils::getIntegrationName(),
 
 
435
  esc_js( $method ),
436
  esc_js( $event_name ),
437
  json_encode( self::build_params( $params, $event_name ), JSON_PRETTY_PRINT | JSON_FORCE_OBJECT )
@@ -626,7 +631,14 @@ if ( ! class_exists( 'WC_Facebookcommerce_Pixel' ) ) :
626
  return '';
627
  }
628
 
629
-
 
 
 
 
 
 
 
630
  }
631
 
632
  endif;
415
  }
416
 
417
  if ( ! empty( $event_id ) ) {
 
418
  $event = sprintf(
419
  "/* %s Facebook Integration Event Tracking */\n" .
420
+ "fbq('set', 'agent', '%s', '%s');\n".
421
  "fbq('%s', '%s', %s, %s);",
422
  WC_Facebookcommerce_Utils::getIntegrationName(),
423
+ Event::get_platform_identifier(),
424
+ self::get_pixel_id(),
425
  esc_js( $method ),
426
  esc_js( $event_name ),
427
  json_encode( self::build_params( $params, $event_name ), JSON_PRETTY_PRINT | JSON_FORCE_OBJECT ),
432
 
433
  $event = sprintf(
434
  "/* %s Facebook Integration Event Tracking */\n" .
435
+ "fbq('set', 'agent', '%s', '%s');\n".
436
  "fbq('%s', '%s', %s);",
437
  WC_Facebookcommerce_Utils::getIntegrationName(),
438
+ Event::get_platform_identifier(),
439
+ self::get_pixel_id(),
440
  esc_js( $method ),
441
  esc_js( $event_name ),
442
  json_encode( self::build_params( $params, $event_name ), JSON_PRETTY_PRINT | JSON_FORCE_OBJECT )
631
  return '';
632
  }
633
 
634
+ /**
635
+ * Gets the logged in user info
636
+ *
637
+ * @return string[]
638
+ */
639
+ public function get_user_info(){
640
+ return $this->user_info;
641
+ }
642
  }
643
 
644
  endif;
facebook-commerce.php CHANGED
@@ -12,6 +12,7 @@ use SkyVerge\WooCommerce\Facebook\Admin;
12
  use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
13
  use SkyVerge\WooCommerce\Facebook\Products;
14
  use SkyVerge\WooCommerce\Facebook\Products\Feed;
 
15
 
16
  if ( ! defined( 'ABSPATH' ) ) {
17
  exit; // Exit if accessed directly
@@ -412,8 +413,9 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
412
  add_action( 'wc_facebook_generate_product_catalog_feed', [ $this, 'handle_generate_product_catalog_feed' ] );
413
 
414
  if ( $this->get_facebook_pixel_id() ) {
415
- $user_info = WC_Facebookcommerce_Utils::get_user_info( $this->is_advanced_matching_enabled() );
416
- $this->events_tracker = new WC_Facebookcommerce_EventsTracker( $user_info );
 
417
  }
418
 
419
  // initialize the messenger chat features
@@ -423,6 +425,48 @@ class WC_Facebookcommerce_Integration extends WC_Integration {
423
  ] );
424
  }
425
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
426
  public function load_background_sync_process() {
427
  // Attempt to load background processing (Woo 3.x.x only)
428
  include_once 'includes/fbbackground.php';
12
  use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
13
  use SkyVerge\WooCommerce\Facebook\Products;
14
  use SkyVerge\WooCommerce\Facebook\Products\Feed;
15
+ use SkyVerge\WooCommerce\Facebook\Events\AAMSettings;
16
 
17
  if ( ! defined( 'ABSPATH' ) ) {
18
  exit; // Exit if accessed directly
413
  add_action( 'wc_facebook_generate_product_catalog_feed', [ $this, 'handle_generate_product_catalog_feed' ] );
414
 
415
  if ( $this->get_facebook_pixel_id() ) {
416
+ $aam_settings = $this->load_aam_settings_of_pixel();
417
+ $user_info = WC_Facebookcommerce_Utils::get_user_info( $aam_settings );
418
+ $this->events_tracker = new WC_Facebookcommerce_EventsTracker( $user_info, $aam_settings );
419
  }
420
 
421
  // initialize the messenger chat features
425
  ] );
426
  }
427
 
428
+ /**
429
+ * Returns the Automatic advanced matching of this pixel
430
+ *
431
+ * @since 2.0.3
432
+ *
433
+ * @return AAMSettings
434
+ */
435
+ private function load_aam_settings_of_pixel() {
436
+ $installed_pixel = $this->get_facebook_pixel_id();
437
+ // If no pixel is installed, reading the DB is not needed
438
+ if(!$installed_pixel ){
439
+ return null;
440
+ }
441
+ $config_key = 'wc_facebook_aam_settings';
442
+ $saved_value = get_transient( $config_key );
443
+ $refresh_interval = 20*MINUTE_IN_SECONDS;
444
+ $aam_settings = null;
445
+ // If wc_facebook_aam_settings is present in the DB
446
+ // it is converted into an AAMSettings object
447
+ if( $saved_value !== false ){
448
+ $cached_aam_settings = new AAMSettings(json_decode($saved_value, true));
449
+ // This condition is added because
450
+ // it is possible that the AAMSettings saved do not belong to the current
451
+ // installed pixel
452
+ // because the admin could have changed the connection to Facebook
453
+ // during the refresh interval
454
+ if($cached_aam_settings->get_pixel_id() == $installed_pixel){
455
+ $aam_settings = $cached_aam_settings;
456
+ }
457
+ }
458
+ // If the settings are not present or invalid
459
+ // they are fetched from Facebook domain
460
+ // and cached in WP database if they are not null
461
+ if(!$aam_settings){
462
+ $aam_settings = AAMSettings::build_from_pixel_id( $installed_pixel );
463
+ if($aam_settings){
464
+ set_transient($config_key, strval($aam_settings), $refresh_interval);
465
+ }
466
+ }
467
+ return $aam_settings;
468
+ }
469
+
470
  public function load_background_sync_process() {
471
  // Attempt to load background processing (Woo 3.x.x only)
472
  include_once 'includes/fbbackground.php';
facebook-for-woocommerce.php CHANGED
@@ -10,7 +10,7 @@
10
  * Description: Grow your business on Facebook! Use this official plugin to help sell more of your products using Facebook. After completing the setup, you'll be ready to create ads that promote your products and you can also create a shop section on your Page where customers can browse your products on Facebook.
11
  * Author: Facebook
12
  * Author URI: https://www.facebook.com/
13
- * Version: 2.0.2
14
  * Text Domain: facebook-for-woocommerce
15
  * WC requires at least: 3.5.0
16
  * WC tested up to: 4.5.2
10
  * Description: Grow your business on Facebook! Use this official plugin to help sell more of your products using Facebook. After completing the setup, you'll be ready to create ads that promote your products and you can also create a shop section on your Page where customers can browse your products on Facebook.
11
  * Author: Facebook
12
  * Author URI: https://www.facebook.com/
13
+ * Version: 2.0.3
14
  * Text Domain: facebook-for-woocommerce
15
  * WC requires at least: 3.5.0
16
  * WC tested up to: 4.5.2
i18n/languages/facebook-for-woocommerce.pot CHANGED
@@ -2,10 +2,10 @@
2
  # This file is distributed under the same license as the Facebook for WooCommerce package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Facebook for WooCommerce 2.0.2\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://woocommerce.com/my-account/marketplace-ticket-form/\n"
8
- "POT-Creation-Date: 2020-09-26 00:08:41+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
@@ -13,7 +13,7 @@ msgstr ""
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
 
16
- #: class-wc-facebookcommerce.php:187
17
  #. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
18
  #. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
19
  msgid ""
@@ -21,7 +21,7 @@ msgid ""
21
  "Facebook for WooCommerce connection. Please %3$sclick here%4$s to reconnect!"
22
  msgstr ""
23
 
24
- #: class-wc-facebookcommerce.php:202
25
  #. translators: Placeholders %1$s - opening link HTML tag, %2$s - closing link
26
  #. HTML tag
27
  msgid ""
@@ -29,7 +29,7 @@ msgid ""
29
  "under %1$sWooCommerce > Facebook%2$s."
30
  msgstr ""
31
 
32
- #: class-wc-facebookcommerce.php:217
33
  #. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
34
  #. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
35
  msgid ""
@@ -37,7 +37,7 @@ msgid ""
37
  "configuration, %3$scomplete the setup steps%4$s."
38
  msgstr ""
39
 
40
- #: class-wc-facebookcommerce.php:245
41
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
42
  #. <a> tag, %4$s - </a> tag
43
  msgid ""
@@ -46,7 +46,7 @@ msgid ""
46
  "Connection%4$s area."
47
  msgstr ""
48
 
49
- #: class-wc-facebookcommerce.php:262
50
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
51
  #. <a> tag, %4$s - </a> tag
52
  msgid ""
@@ -55,7 +55,7 @@ msgid ""
55
  "products."
56
  msgstr ""
57
 
58
- #: class-wc-facebookcommerce.php:315
59
  msgid "Cannot create the API instance because the access token is missing."
60
  msgstr ""
61
 
@@ -63,69 +63,69 @@ msgstr ""
63
  msgid "Facebook for WooCommerce"
64
  msgstr ""
65
 
66
- #: facebook-commerce.php:215
67
  msgid "Facebook Commerce and Dynamic Ads (Pixel) Extension"
68
  msgstr ""
69
 
70
- #: facebook-commerce.php:589
71
  msgid "Facebook ID:"
72
  msgstr ""
73
 
74
- #: facebook-commerce.php:597
75
  msgid "Variant IDs:"
76
  msgstr ""
77
 
78
- #: facebook-commerce.php:615
79
  msgid "Reset Facebook metadata"
80
  msgstr ""
81
 
82
- #: facebook-commerce.php:620
83
  msgid "Delete product(s) on Facebook"
84
  msgstr ""
85
 
86
- #: facebook-commerce.php:628
87
  msgid "This product is not yet synced to Facebook."
88
  msgstr ""
89
 
90
- #: facebook-commerce.php:1374
91
  msgid "Nothing to update for product group for %1$s"
92
  msgstr ""
93
 
94
- #: facebook-commerce.php:1640
95
  #. translators: Placeholders %1$s - original error message from Facebook API
96
  msgid "There was an issue connecting to the Facebook API: %1$s"
97
  msgstr ""
98
 
99
- #: facebook-commerce.php:1977
100
  msgid "Your connection has expired."
101
  msgstr ""
102
 
103
- #: facebook-commerce.php:1977
104
  msgid ""
105
  "Please click Manage connection > Advanced Options > Update Token to refresh "
106
  "your connection to Facebook."
107
  msgstr ""
108
 
109
- #: facebook-commerce.php:1984
110
  #. translators: Placeholders %s - error message
111
  msgid "There was an error trying to sync the products to Facebook. %s"
112
  msgstr ""
113
 
114
- #: facebook-commerce.php:2007 facebook-commerce.php:2180
115
  msgid "Product sync is disabled."
116
  msgstr ""
117
 
118
- #: facebook-commerce.php:2014 facebook-commerce.php:2187
119
  msgid "The plugin is not configured or the Catalog ID is missing."
120
  msgstr ""
121
 
122
- #: facebook-commerce.php:2037
123
  msgid ""
124
  "A product sync is in progress. Please wait until the sync finishes before "
125
  "starting a new one."
126
  msgstr ""
127
 
128
- #: facebook-commerce.php:2049 facebook-commerce.php:2201
129
  msgid ""
130
  "We've detected that your Facebook Product Catalog is no longer valid. This "
131
  "may happen if it was deleted, but could also be a temporary error. If the "
@@ -133,33 +133,33 @@ msgid ""
133
  "and setup the plugin again."
134
  msgstr ""
135
 
136
- #: facebook-commerce.php:2225
137
  msgid "We couldn't create the feed or upload the product information."
138
  msgstr ""
139
 
140
- #: facebook-commerce.php:2692
141
  msgid "Hi! We're here to answer any questions you may have."
142
  msgstr ""
143
 
144
- #: facebook-commerce.php:3036
145
  msgid "Facebook for WooCommerce error:"
146
  msgstr ""
147
 
148
- #: facebook-commerce.php:3118
149
  msgid ""
150
  "There was an error trying to retrieve information about the Facebook page: "
151
  "%s"
152
  msgstr ""
153
 
154
- #: facebook-commerce.php:3169
155
  msgid "Get started with Messenger Customer Chat"
156
  msgstr ""
157
 
158
- #: facebook-commerce.php:3170
159
  msgid "Get started with Instagram Shopping"
160
  msgstr ""
161
 
162
- #: facebook-commerce.php:3405
163
  #. translators: Placeholders %1$s - original error message from Facebook API
164
  msgid "There was an issue connecting to the Facebook API: %s"
165
  msgstr ""
2
  # This file is distributed under the same license as the Facebook for WooCommerce package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Facebook for WooCommerce 2.0.3\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://woocommerce.com/my-account/marketplace-ticket-form/\n"
8
+ "POT-Creation-Date: 2020-10-02 23:23:52+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
15
 
16
+ #: class-wc-facebookcommerce.php:201
17
  #. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
18
  #. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
19
  msgid ""
21
  "Facebook for WooCommerce connection. Please %3$sclick here%4$s to reconnect!"
22
  msgstr ""
23
 
24
+ #: class-wc-facebookcommerce.php:216
25
  #. translators: Placeholders %1$s - opening link HTML tag, %2$s - closing link
26
  #. HTML tag
27
  msgid ""
29
  "under %1$sWooCommerce > Facebook%2$s."
30
  msgstr ""
31
 
32
+ #: class-wc-facebookcommerce.php:231
33
  #. translators: Placeholders %1$s - opening strong HTML tag, %2$s - closing
34
  #. strong HTML tag, %3$s - opening link HTML tag, %4$s - closing link HTML tag
35
  msgid ""
37
  "configuration, %3$scomplete the setup steps%4$s."
38
  msgstr ""
39
 
40
+ #: class-wc-facebookcommerce.php:259
41
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
42
  #. <a> tag, %4$s - </a> tag
43
  msgid ""
46
  "Connection%4$s area."
47
  msgstr ""
48
 
49
+ #: class-wc-facebookcommerce.php:276
50
  #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
51
  #. <a> tag, %4$s - </a> tag
52
  msgid ""
55
  "products."
56
  msgstr ""
57
 
58
+ #: class-wc-facebookcommerce.php:329
59
  msgid "Cannot create the API instance because the access token is missing."
60
  msgstr ""
61
 
63
  msgid "Facebook for WooCommerce"
64
  msgstr ""
65
 
66
+ #: facebook-commerce.php:216
67
  msgid "Facebook Commerce and Dynamic Ads (Pixel) Extension"
68
  msgstr ""
69
 
70
+ #: facebook-commerce.php:633
71
  msgid "Facebook ID:"
72
  msgstr ""
73
 
74
+ #: facebook-commerce.php:641
75
  msgid "Variant IDs:"
76
  msgstr ""
77
 
78
+ #: facebook-commerce.php:659
79
  msgid "Reset Facebook metadata"
80
  msgstr ""
81
 
82
+ #: facebook-commerce.php:664
83
  msgid "Delete product(s) on Facebook"
84
  msgstr ""
85
 
86
+ #: facebook-commerce.php:672
87
  msgid "This product is not yet synced to Facebook."
88
  msgstr ""
89
 
90
+ #: facebook-commerce.php:1418
91
  msgid "Nothing to update for product group for %1$s"
92
  msgstr ""
93
 
94
+ #: facebook-commerce.php:1684
95
  #. translators: Placeholders %1$s - original error message from Facebook API
96
  msgid "There was an issue connecting to the Facebook API: %1$s"
97
  msgstr ""
98
 
99
+ #: facebook-commerce.php:2021
100
  msgid "Your connection has expired."
101
  msgstr ""
102
 
103
+ #: facebook-commerce.php:2021
104
  msgid ""
105
  "Please click Manage connection > Advanced Options > Update Token to refresh "
106
  "your connection to Facebook."
107
  msgstr ""
108
 
109
+ #: facebook-commerce.php:2028
110
  #. translators: Placeholders %s - error message
111
  msgid "There was an error trying to sync the products to Facebook. %s"
112
  msgstr ""
113
 
114
+ #: facebook-commerce.php:2051 facebook-commerce.php:2224
115
  msgid "Product sync is disabled."
116
  msgstr ""
117
 
118
+ #: facebook-commerce.php:2058 facebook-commerce.php:2231
119
  msgid "The plugin is not configured or the Catalog ID is missing."
120
  msgstr ""
121
 
122
+ #: facebook-commerce.php:2081
123
  msgid ""
124
  "A product sync is in progress. Please wait until the sync finishes before "
125
  "starting a new one."
126
  msgstr ""
127
 
128
+ #: facebook-commerce.php:2093 facebook-commerce.php:2245
129
  msgid ""
130
  "We've detected that your Facebook Product Catalog is no longer valid. This "
131
  "may happen if it was deleted, but could also be a temporary error. If the "
133
  "and setup the plugin again."
134
  msgstr ""
135
 
136
+ #: facebook-commerce.php:2269
137
  msgid "We couldn't create the feed or upload the product information."
138
  msgstr ""
139
 
140
+ #: facebook-commerce.php:2736
141
  msgid "Hi! We're here to answer any questions you may have."
142
  msgstr ""
143
 
144
+ #: facebook-commerce.php:3080
145
  msgid "Facebook for WooCommerce error:"
146
  msgstr ""
147
 
148
+ #: facebook-commerce.php:3162
149
  msgid ""
150
  "There was an error trying to retrieve information about the Facebook page: "
151
  "%s"
152
  msgstr ""
153
 
154
+ #: facebook-commerce.php:3213
155
  msgid "Get started with Messenger Customer Chat"
156
  msgstr ""
157
 
158
+ #: facebook-commerce.php:3214
159
  msgid "Get started with Instagram Shopping"
160
  msgstr ""
161
 
162
+ #: facebook-commerce.php:3449
163
  #. translators: Placeholders %1$s - original error message from Facebook API
164
  msgid "There was an issue connecting to the Facebook API: %s"
165
  msgstr ""
includes/Events/AAMSettings.php ADDED
@@ -0,0 +1,170 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4
+ *
5
+ * This source code is licensed under the license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @package FacebookCommerce
9
+ */
10
+
11
+ namespace SkyVerge\WooCommerce\Facebook\Events;
12
+
13
+ defined( 'ABSPATH' ) or exit;
14
+
15
+ /**
16
+ * Base Automatic advanced matching settings object
17
+ *
18
+ */
19
+ class AAMSettings {
20
+
21
+ /** @var bool is enable automatic matching enabled for this pixel */
22
+ private $enable_automatic_matching;
23
+
24
+ /** @var string[] advanced matching fields to extract when $enable_automatic_matching is true*/
25
+ private $enabled_automatic_matching_fields;
26
+
27
+ /** @var string pixel id associated with this settings*/
28
+ private $pixel_id;
29
+
30
+ const SIGNALS_JSON_CONFIG_PATH = 'signals/config/json';
31
+
32
+ const CONNECT_FACEBOOK_DOMAIN = 'https://connect.facebook.net/';
33
+
34
+ /**
35
+ * AAMSettings constructor
36
+ *
37
+ * @since 2.0.3
38
+ *
39
+ * @param array $data
40
+ */
41
+ public function __construct( $data = array() ) {
42
+ $this->enable_automatic_matching = isset($data['enableAutomaticMatching']) ? $data['enableAutomaticMatching'] : null;
43
+ $this->enabled_automatic_matching_fields = isset($data['enabledAutomaticMatchingFields']) ? $data['enabledAutomaticMatchingFields'] : null;
44
+ $this->pixel_id = isset($data['pixelId']) ? $data['pixelId'] : null;
45
+ }
46
+
47
+
48
+ /**
49
+ * Gets the URL used to retrieve the advanced matching settings for the given pixel ID.
50
+ *
51
+ * @since 2.0.3
52
+ *
53
+ * @param string $pixel_id pixel ID
54
+ * @return string
55
+ */
56
+ public static function get_url( $pixel_id ){
57
+
58
+ return self::CONNECT_FACEBOOK_DOMAIN.self::SIGNALS_JSON_CONFIG_PATH.'/'.$pixel_id;
59
+ }
60
+
61
+ /**
62
+ * Factory method that builds an AAMSettings object given a pixel id
63
+ * by sending a request to connect.facebook.net domain
64
+ *
65
+ * @since 2.0.3
66
+ *
67
+ * @param string $pixel_id
68
+ */
69
+ public static function build_from_pixel_id( $pixel_id ){
70
+ $url = self::get_url($pixel_id);
71
+ $response = wp_remote_get($url);
72
+ if ( is_wp_error( $response ) ) {
73
+ return null;
74
+ }
75
+ else{
76
+ $response_body = json_decode( wp_remote_retrieve_body( $response ), true );
77
+ if (!array_key_exists('errorMessage', $response_body)){
78
+ $response_body['matchingConfig']['pixelId'] = $pixel_id;
79
+ return new AAMSettings($response_body['matchingConfig']);
80
+ }
81
+ }
82
+ return null;
83
+ }
84
+
85
+ /**
86
+ * Gets enable automatic matching flag
87
+ *
88
+ * @since 2.0.3
89
+ *
90
+ * @return bool
91
+ */
92
+ public function get_enable_automatic_matching(){
93
+ return $this->enable_automatic_matching;
94
+ }
95
+
96
+ /**
97
+ * Gets enabled automatic matching fields array
98
+ *
99
+ * @since 2.0.3
100
+ *
101
+ * @return string[]
102
+ */
103
+ public function get_enabled_automatic_matching_fields(){
104
+ return $this->enabled_automatic_matching_fields;
105
+ }
106
+
107
+ /**
108
+ * Gets the pixel id
109
+ *
110
+ * @since 2.0.3
111
+ *
112
+ * @return string
113
+ */
114
+ public function get_pixel_id(){
115
+ return $this->pixel_id;
116
+ }
117
+
118
+ /**
119
+ * Sets the enable automatic matching flag
120
+ *
121
+ * @since 2.0.3
122
+ *
123
+ * @return AAMSettings
124
+ */
125
+ public function set_enable_automatic_matching($enable_automatic_matching){
126
+ $this->enable_automatic_matching = $enable_automatic_matching;
127
+ return $this;
128
+ }
129
+
130
+ /**
131
+ * Sets the enabled automatic matching fields flag
132
+ *
133
+ * @since 2.0.3
134
+ *
135
+ * @return AAMSettings
136
+ */
137
+ public function set_enabled_automatic_matching_fields($enabled_automatic_matching_fields){
138
+ $this->enabled_automatic_matching_fields = $enabled_automatic_matching_fields;
139
+ return $this;
140
+ }
141
+
142
+ /**
143
+ * Sets the pixel id
144
+ *
145
+ * @since 2.0.3
146
+ *
147
+ * @return AAMSettings
148
+ */
149
+ public function set_pixel_id($pixel_id){
150
+ $this->pixel_id = $pixel_id;
151
+ return $this;
152
+ }
153
+
154
+ /**
155
+ * Returns the json string representing this object
156
+ *
157
+ * @since 2.0.3
158
+ *
159
+ * @return string
160
+ */
161
+ public function __toString(){
162
+ return json_encode(
163
+ array(
164
+ 'enableAutomaticMatching' => $this->enable_automatic_matching,
165
+ 'enabledAutomaticMatchingFields' => $this->enabled_automatic_matching_fields,
166
+ 'pixelId' => $this->pixel_id
167
+ )
168
+ );
169
+ }
170
+ }
includes/Events/Event.php CHANGED
@@ -109,15 +109,47 @@ class Event {
109
  * @param array $data user data
110
  */
111
  protected function prepare_user_data( $data ) {
112
-
113
  $this->data['user_data'] = wp_parse_args( $data, [
114
  'client_ip_address' => $this->get_client_ip(),
115
  'client_user_agent' => $this->get_client_user_agent(),
116
  'click_id' => $this->get_click_id(),
117
  'browser_id' => $this->get_browser_id(),
118
  ] );
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  }
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
  /**
123
  * Generates a UUIDv4 unique ID for the event.
@@ -328,5 +360,4 @@ class Event {
328
  return ! empty( $this->data['custom_data'] ) ? $this->data['custom_data'] : [];
329
  }
330
 
331
-
332
  }
109
  * @param array $data user data
110
  */
111
  protected function prepare_user_data( $data ) {
 
112
  $this->data['user_data'] = wp_parse_args( $data, [
113
  'client_ip_address' => $this->get_client_ip(),
114
  'client_user_agent' => $this->get_client_user_agent(),
115
  'click_id' => $this->get_click_id(),
116
  'browser_id' => $this->get_browser_id(),
117
  ] );
118
+
119
+ // Country key is not the same in pixel and CAPI events, see:
120
+ // https://developers.facebook.com/docs/facebook-pixel/advanced/advanced-matching
121
+ // https://developers.facebook.com/docs/marketing-api/conversions-api/parameters
122
+ if(array_key_exists('cn', $this->data['user_data'])){
123
+ $country = $this->data['user_data']['cn'];
124
+ $this->data['user_data']['country'] = $country;
125
+ unset($this->data['user_data']['cn']);
126
+ }
127
+
128
+ $this->data['user_data'] = Normalizer::normalize_array( $this->data['user_data'], false );
129
+
130
+ $this->data['user_data'] = $this->hash_pii_data( $this->data['user_data'] );
131
  }
132
 
133
+ /**
134
+ * Hashes the user data
135
+ *
136
+ * @see https://developers.facebook.com/docs/marketing-api/server-side-api/parameters/user-data
137
+ *
138
+ * @since 2.0.3
139
+ *
140
+ * @param array $user_data user data
141
+ *
142
+ * @return array
143
+ */
144
+ protected function hash_pii_data( $user_data ){
145
+ $keys_to_hash = ['em', 'fn', 'ln', 'ph', 'ct', 'st', 'zp', 'country', 'external_id'];
146
+ foreach( $keys_to_hash as $key ){
147
+ if(array_key_exists($key, $user_data)){
148
+ $user_data[$key] = hash('sha256', $user_data[$key], false);
149
+ }
150
+ }
151
+ return $user_data;
152
+ }
153
 
154
  /**
155
  * Generates a UUIDv4 unique ID for the event.
360
  return ! empty( $this->data['custom_data'] ) ? $this->data['custom_data'] : [];
361
  }
362
 
 
363
  }
includes/Events/Normalizer.php ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4
+ *
5
+ * This source code is licensed under the license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @package FacebookCommerce
9
+ */
10
+
11
+ namespace SkyVerge\WooCommerce\Facebook\Events;
12
+
13
+ use InvalidArgumentException;
14
+
15
+ defined( 'ABSPATH' ) or exit;
16
+
17
+ /**
18
+ * Normalizer class.
19
+ *
20
+ */
21
+ class Normalizer {
22
+
23
+ /**
24
+ * Normalizes $data according to its type
25
+ *
26
+ * @since 2.0.3
27
+ *
28
+ * @param string $field to be normalized.
29
+ * @param string $data value to be normalized
30
+ * @return string
31
+ * @throws InvalidArgumentException
32
+ */
33
+ public static function normalize($field, $data) {
34
+ if ($data == null || strlen($data) == 0) {
35
+ return null;
36
+ }
37
+
38
+ $data = trim(strtolower($data));
39
+ $normalized_data = $data;
40
+
41
+ switch ($field) {
42
+ case 'em':
43
+ $normalized_data = Normalizer::normalizeEmail($data);
44
+ break;
45
+
46
+ case 'ph':
47
+ $normalized_data = Normalizer::normalizePhone($data);
48
+ break;
49
+
50
+ case 'zp':
51
+ $normalized_data = Normalizer::normalizeZipCode($data);
52
+ break;
53
+
54
+ case 'ct':
55
+ $normalized_data = Normalizer::normalizeCity($data);
56
+ break;
57
+
58
+ case 'st':
59
+ $normalized_data = Normalizer::normalizeState($data);
60
+ break;
61
+
62
+ case 'country':
63
+ $normalized_data = Normalizer::normalizeCountry($data);
64
+ break;
65
+
66
+ case 'cn':
67
+ $normalized_data = Normalizer::normalizeCountry($data);
68
+ break;
69
+
70
+ default:
71
+ }
72
+
73
+ return $normalized_data;
74
+ }
75
+
76
+ /**
77
+ * Normalizes an array containing user data
78
+ *
79
+ * @since 2.0.3
80
+ *
81
+ * @param string[] array with user data to be normalized
82
+ * @return string[]
83
+ */
84
+ public static function normalize_array($data, $is_pixel_data){
85
+ // Country is encoded as cn in Pixel events and country in CAPI events
86
+ $keys_to_normalize = ['fn', 'ln', 'em', 'ph', 'zp', 'ct', 'st'];
87
+ if($is_pixel_data){
88
+ $keys_to_normalize[] = 'cn';
89
+ }
90
+ else{
91
+ $keys_to_normalize[] = 'country';
92
+ }
93
+ foreach($keys_to_normalize as $key){
94
+ if(array_key_exists($key, $data)){
95
+ //If the data is invalid, it is erased from the array
96
+ try{
97
+ $data[$key] = self::normalize($key, $data[$key]);
98
+ }
99
+ catch(InvalidArgumentException $e){
100
+ unset($data[$key]);
101
+ }
102
+ }
103
+ }
104
+ return $data;
105
+ }
106
+
107
+ /**
108
+ * Normalizes an email
109
+ *
110
+ * @since 2.0.3
111
+ *
112
+ * @param string $email Email address to be normalized.
113
+ * @return string
114
+ * @throws InvalidArgumentException
115
+ */
116
+ private static function normalizeEmail($email) {
117
+ // Validates email against RFC 822
118
+ $result = filter_var($email, FILTER_SANITIZE_EMAIL);
119
+
120
+ if (!filter_var($result, FILTER_VALIDATE_EMAIL)) {
121
+ throw new InvalidArgumentException('Invalid email format for the passed email: ' . $email . 'Please check the passed email format.');
122
+ }
123
+
124
+ return $result;
125
+ }
126
+
127
+ /**
128
+ * Normalizes a city name
129
+ *
130
+ * @since 2.0.3
131
+ *
132
+ * @param string $city city name to be normalized.
133
+ * @return string
134
+ */
135
+ private static function normalizeCity($city) {
136
+ return trim(preg_replace('/[0-9.\s\-()]/', '', $city));
137
+ }
138
+
139
+ /**
140
+ * Normalizes a state code
141
+ *
142
+ * @since 2.0.3
143
+ *
144
+ * @param string $state state name to be normalized.
145
+ * @return string
146
+ */
147
+ private static function normalizeState($state) {
148
+ return preg_replace('/[^a-z]/', '', $state);
149
+ }
150
+
151
+ /**
152
+ * Normalizes a country code
153
+ *
154
+ * @since 2.0.3
155
+ *
156
+ * @param string $country country code to be normalized(ISO 3166-2).
157
+ * @return string
158
+ * @throws InvalidArgumentException
159
+ */
160
+ private static function normalizeCountry($country) {
161
+ $result = preg_replace('/[^a-z]/i', '', $country);
162
+
163
+ if (strlen($result) != 2) {
164
+ throw new InvalidArgumentException('Invalid country format passed(' . $country . '). Country Code should be a two-letter ISO Country Code');
165
+ }
166
+
167
+ return $result;
168
+ }
169
+
170
+ /**
171
+ * Normalizes a zip code
172
+ *
173
+ * @since 2.0.3
174
+ *
175
+ * @param string $zip postal code to be normalized.
176
+ * @return string
177
+ */
178
+ private static function normalizeZipCode($zip) {
179
+ // Removing the spaces from the zip code. Eg:
180
+ $zip = preg_replace('/[ ]/', '', $zip);
181
+
182
+ // If the code has more than one part, retain the first part.
183
+ $zip = explode('-', $zip)[0];
184
+ return $zip;
185
+ }
186
+
187
+ /**
188
+ * Normalizes a phone number
189
+ *
190
+ * @since 2.0.3
191
+ *
192
+ * @param string $phone phone number to be normalized.
193
+ * @return string
194
+ */
195
+ private static function normalizePhone($phone) {
196
+ $result = trim(preg_replace('/[a-z()-]/', '', $phone));
197
+
198
+ if (Normalizer::isInternationalNumber($result)) {
199
+ $result = preg_replace('/[\-\s+]/', '', $result);
200
+ }
201
+
202
+ return $result;
203
+ }
204
+
205
+ /**
206
+ * Checks if a phone number is international
207
+ *
208
+ * @since 2.0.3
209
+ *
210
+ * @param string $phone_number Phone number to be normalized.
211
+ * @return bool
212
+ */
213
+ private static function isInternationalNumber($phone_number) {
214
+ // Remove spaces and hyphens
215
+ $phone_number = preg_replace('/[\-\s]/', '', $phone_number);
216
+
217
+ // Strip + and up to 2 leading 0s
218
+ $phone_number = preg_replace('/^\+?0{0,2}/', '', $phone_number);
219
+
220
+ if (substr($phone_number, 0, 1) === '0') {
221
+ return false;
222
+ }
223
+
224
+ // International Phone number with country calling code.
225
+ $international_number_regex = '/^\d{1,4}\(?\d{2,3}\)?\d{4,}$/';
226
+
227
+ return preg_match($international_number_regex, $phone_number);
228
+ }
229
+ }
includes/Lifecycle.php CHANGED
@@ -40,6 +40,7 @@ class Lifecycle extends Framework\Plugin\Lifecycle {
40
  '1.10.1',
41
  '1.11.0',
42
  '2.0.0',
 
43
  ];
44
  }
45
 
@@ -266,4 +267,55 @@ class Lifecycle extends Framework\Plugin\Lifecycle {
266
  }
267
 
268
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
  }
40
  '1.10.1',
41
  '1.11.0',
42
  '2.0.0',
43
+ '2.0.3',
44
  ];
45
  }
46
 
267
  }
268
 
269
 
270
+ /**
271
+ * Upgrades to version 2.0.3
272
+ *
273
+ * @since 2.0.3
274
+ */
275
+ protected function upgrade_to_2_0_3() {
276
+
277
+ if ( ! $this->should_create_remove_duplicate_visibility_meta_background_job() ) {
278
+ return;
279
+ }
280
+
281
+ // if an unfinished job is stuck, give the handler a chance to complete it
282
+ if ( $handler = $this->get_plugin()->get_background_handle_virtual_products_variations_instance() ) {
283
+ $handler->dispatch();
284
+ }
285
+
286
+ // create a job to remove duplicate visibility meta data entries
287
+ if ( $handler = $this->get_plugin()->get_background_remove_duplicate_visibility_meta_instance() ) {
288
+
289
+ // create_job() expects an non-empty array of attributes
290
+ $handler->create_job( [ 'created_at' => current_time( 'mysql' ) ] );
291
+ $handler->dispatch();
292
+ }
293
+ }
294
+
295
+
296
+ /**
297
+ * Determines whether we need to run a background job to remove duplicate visibility meta.
298
+ *
299
+ * @since 2.0.3
300
+ *
301
+ * @return bool
302
+ */
303
+ private function should_create_remove_duplicate_visibility_meta_background_job() {
304
+
305
+ // we should try to remove duplicate meta if the virtual product variations job ran
306
+ if ( 'yes' === get_option( 'wc_facebook_background_handle_virtual_products_variations_complete', 'no' ) ) {
307
+ return true;
308
+ }
309
+
310
+ $handler = $this->get_plugin()->get_background_handle_virtual_products_variations_instance();
311
+
312
+ // the virtual product variations job is not marked as complete but there is at least one job in the database
313
+ if ( $handler && $handler->get_jobs() ) {
314
+ return true;
315
+ }
316
+
317
+ return false;
318
+ }
319
+
320
+
321
  }
includes/Utilities/Background_Handle_Virtual_Products_Variations.php CHANGED
@@ -132,11 +132,47 @@ class Background_Handle_Virtual_Products_Variations extends Framework\SV_WP_Back
132
  private function sync_and_hide() {
133
  global $wpdb;
134
 
135
- $rows_inserted = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
 
137
- // get post IDs to update
138
  $sql = "
139
- SELECT DISTINCT( posts.ID )
140
  FROM {$wpdb->posts} AS posts
141
  INNER JOIN {$wpdb->postmeta} AS virtual_meta ON ( posts.ID = virtual_meta.post_id AND virtual_meta.meta_key = '_virtual' AND virtual_meta.meta_value = 'yes' )
142
  LEFT JOIN {$wpdb->postmeta} AS sync_meta ON ( posts.ID = sync_meta.post_id AND sync_meta.meta_key = '_wc_facebook_sync_enabled' )
@@ -147,40 +183,80 @@ class Background_Handle_Virtual_Products_Variations extends Framework\SV_WP_Back
147
  LIMIT 1000
148
  ";
149
 
150
- $post_ids = $wpdb->get_col( $sql );
 
 
 
 
 
 
 
 
 
 
 
 
 
151
 
152
  if ( empty( $post_ids ) ) {
 
 
153
 
154
- facebook_for_woocommerce()->log( 'There are no products or products variations to update.' );
155
 
156
- } else {
 
 
157
 
158
- $values = [];
 
 
 
 
159
 
160
- foreach ( $post_ids as $post_id ) {
161
 
162
- $values[] = "('$post_id', 'fb_visibility', 'no')";
163
- }
 
 
 
 
 
 
 
164
 
165
- $values_str = implode( ',', $values );
166
 
167
- // we need to explicitly insert the metadata and set it to no, because not having it means it is visible
168
- $sql = "
169
- INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value )
170
- VALUES {$values_str}
171
- ";
 
 
 
 
 
172
 
173
- $rows_inserted = $wpdb->query( $sql );
 
 
174
 
175
- if ( false === $rows_inserted ) {
 
 
 
176
 
177
- $message = sprintf( 'There was an error trying to set products and variations meta data. %s', $wpdb->last_error );
178
 
179
- facebook_for_woocommerce()->log( $message );
180
- }
 
 
 
181
  }
182
 
183
- return (int) $rows_inserted;
184
  }
185
 
186
 
132
  private function sync_and_hide() {
133
  global $wpdb;
134
 
135
+ $results = $this->get_posts_to_update();
136
+
137
+ if ( empty( $results ) ) {
138
+
139
+ facebook_for_woocommerce()->log( 'There are no products or products variations to update.' );
140
+ return 0;
141
+ }
142
+
143
+ $insert = $update = [];
144
+
145
+ foreach ( $results as $result ) {
146
+
147
+ if ( $result->visibility ) {
148
+ $update[] = $result->id;
149
+ } else {
150
+ $insert[] = $result->id;
151
+ }
152
+ }
153
+
154
+ $rows_inserted = $this->set_product_visibility_meta( $insert );
155
+ $rows_updated = $this->update_product_visibility_meta( $update );
156
+
157
+ return $rows_inserted + $rows_updated;
158
+ }
159
+
160
+
161
+ /**
162
+ * Gets the ID and current visibility setting for virtual products that are enabled for sync.
163
+ *
164
+ * The method returns data for products that have visibility set to 'yes' or is not defined.
165
+ * Products that have visibility set to 'no' are ignored.
166
+ *
167
+ * @since 2.0.3
168
+ *
169
+ * @return array|null
170
+ */
171
+ private function get_posts_to_update() {
172
+ global $wpdb;
173
 
 
174
  $sql = "
175
+ SELECT DISTINCT posts.ID id, visibility_meta.meta_value as visibility
176
  FROM {$wpdb->posts} AS posts
177
  INNER JOIN {$wpdb->postmeta} AS virtual_meta ON ( posts.ID = virtual_meta.post_id AND virtual_meta.meta_key = '_virtual' AND virtual_meta.meta_value = 'yes' )
178
  LEFT JOIN {$wpdb->postmeta} AS sync_meta ON ( posts.ID = sync_meta.post_id AND sync_meta.meta_key = '_wc_facebook_sync_enabled' )
183
  LIMIT 1000
184
  ";
185
 
186
+ return $wpdb->get_results( $sql );
187
+ }
188
+
189
+
190
+ /**
191
+ * Adds new visibility meta set to 'no' for the given post IDs.
192
+ *
193
+ * @since 2.0.3
194
+ *
195
+ * @param int[] $post_ids post IDs to update
196
+ * @return int
197
+ */
198
+ private function set_product_visibility_meta( $post_ids ) {
199
+ global $wpdb;
200
 
201
  if ( empty( $post_ids ) ) {
202
+ return 0;
203
+ }
204
 
205
+ $values_str = '';
206
 
207
+ foreach ( $post_ids as $post_id ) {
208
+ $values_str .= "('{$post_id}', 'fb_visibility', 'no')";
209
+ }
210
 
211
+ // we need to explicitly insert the metadata and set it to no, because not having it means it is visible
212
+ $sql = "
213
+ INSERT INTO {$wpdb->postmeta} (post_id, meta_key, meta_value )
214
+ VALUES {$values_str}
215
+ ";
216
 
217
+ $rows_inserted = $wpdb->query( $sql );
218
 
219
+ if ( false === $rows_inserted ) {
220
+
221
+ $message = sprintf( 'There was an error trying to set products and variations meta data. %s', $wpdb->last_error );
222
+
223
+ facebook_for_woocommerce()->log( $message );
224
+ }
225
+
226
+ return (int) $rows_inserted;
227
+ }
228
 
 
229
 
230
+ /**
231
+ * Updates the value of the visibility meta for the given post IDs.
232
+ *
233
+ * @since 2.0.3
234
+ *
235
+ * @param int[] $post_ids post IDs to update
236
+ * @return int
237
+ */
238
+ private function update_product_visibility_meta( $post_ids ) {
239
+ global $wpdb;
240
 
241
+ if ( empty( $post_ids ) ) {
242
+ return 0;
243
+ }
244
 
245
+ $sql = sprintf(
246
+ "UPDATE {$wpdb->postmeta} SET meta_value = 'no' WHERE meta_key = 'fb_visibility' AND post_id IN (%s)",
247
+ implode( ', ', array_map( 'intval', $post_ids ) )
248
+ );
249
 
250
+ $rows_updated = $wpdb->query( $sql );
251
 
252
+ if ( false === $rows_updated ) {
253
+
254
+ $message = sprintf( 'There was an error trying to update products and variations meta data. %s', $wpdb->last_error );
255
+
256
+ facebook_for_woocommerce()->log( $message );
257
  }
258
 
259
+ return (int) $rows_updated;
260
  }
261
 
262
 
includes/Utilities/Background_Remove_Duplicate_Visibility_Meta.php ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved
4
+ *
5
+ * This source code is licensed under the license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ * @package FacebookCommerce
9
+ */
10
+
11
+ namespace SkyVerge\WooCommerce\Facebook\Utilities;
12
+
13
+ defined( 'ABSPATH' ) or exit;
14
+
15
+ use SkyVerge\WooCommerce\PluginFramework\v5_5_4 as Framework;
16
+
17
+
18
+ /**
19
+ * Background job handler to remove duplicate fb_visibility entries from the postmeta table.
20
+ *
21
+ * The background job handler to hide virtual products from the catalog had a bug that allowed it to create many entries for each product.
22
+ *
23
+ * @since 2.0.3
24
+ */
25
+ class Background_Remove_Duplicate_Visibility_Meta extends Framework\SV_WP_Background_Job_Handler {
26
+
27
+
28
+ /**
29
+ * Background job constructor.
30
+ *
31
+ * @since 2.0.3
32
+ */
33
+ public function __construct() {
34
+
35
+ $this->prefix = 'wc_facebook';
36
+ $this->action = 'background_remove_duplicate_visibility_meta';
37
+
38
+ parent::__construct();
39
+ }
40
+
41
+
42
+ /**
43
+ * Processes job.
44
+ *
45
+ * This job continues to update products and product variations meta data until we run out of memory
46
+ * or exceed the time limit. There is no list of items to loop over.
47
+ *
48
+ * @since 2.0.3
49
+ *
50
+ * @param object $job
51
+ * @param int $items_per_batch number of items to process in a single request. Defaults to unlimited.
52
+ * @return object
53
+ */
54
+ public function process_job( $job, $items_per_batch = null ) {
55
+
56
+ // don't do anything until the job used to hide virtual variations is done
57
+ $handler = facebook_for_woocommerce()->get_background_handle_virtual_products_variations_instance();
58
+
59
+ if ( $handler && $handler->get_jobs( [ 'status' => [ 'processing', 'queued' ] ] ) ) {
60
+ return $job;
61
+ }
62
+
63
+ if ( ! isset( $job->total ) ) {
64
+ $job->total = $this->count_remaining_products();
65
+ }
66
+
67
+ if ( ! isset( $job->progress ) ) {
68
+ $job->progress = 0;
69
+ }
70
+
71
+ while ( $job->progress < $job->total ) {
72
+
73
+ $job->progress += $this->remove_duplicates();
74
+
75
+ // update job progress
76
+ $job = $this->update_job( $job );
77
+
78
+ if ( $this->time_exceeded() || $this->memory_exceeded() ) {
79
+ break;
80
+ }
81
+ }
82
+
83
+ // job complete! :)
84
+ if ( $this->count_remaining_products() === 0 ) {
85
+
86
+ update_option( 'wc_facebook_background_remove_duplicate_visibility_meta_complete', 'yes' );
87
+
88
+ $this->complete_job( $job );
89
+ }
90
+
91
+ return $job;
92
+ }
93
+
94
+
95
+ /**
96
+ * Counts the number of virtual products or product variations with sync enabled and visible.
97
+ *
98
+ * @since 2.0.3
99
+ *
100
+ * @return bool
101
+ */
102
+ private function count_remaining_products() {
103
+ global $wpdb;
104
+
105
+ $sql = "
106
+ SELECT COUNT(post_id)
107
+ FROM (
108
+ SELECT post_id, COUNT(meta_key) entries
109
+ FROM {$wpdb->postmeta}
110
+ WHERE meta_key = 'fb_visibility'
111
+ GROUP BY post_id
112
+ HAVING entries > 1
113
+ ) AS duplicate_entries
114
+ ";
115
+
116
+ return (int) $wpdb->get_var( $sql );
117
+ }
118
+
119
+
120
+ /**
121
+ * Removes duplicate visibility meta data entries for products.
122
+ *
123
+ * @since 2.0.3
124
+ *
125
+ * @return int
126
+ */
127
+ private function remove_duplicates() {
128
+ global $wpdb;
129
+
130
+ $results = $this->get_posts_to_update();
131
+
132
+ if ( empty( $results ) ) {
133
+ facebook_for_woocommerce()->log( 'There are no products or products variations with duplicate visibility meta data.' );
134
+ return 0;
135
+ }
136
+
137
+ $products_updated = 0;
138
+
139
+ foreach ( $results as $result ) {
140
+
141
+ $sql = "DELETE FROM wp_postmeta WHERE post_id = %d AND meta_key = 'fb_visibility' AND meta_id != %d";
142
+
143
+ if ( false === $wpdb->query( $wpdb->prepare( $sql, $result->post_id, $result->last_meta_id ) ) ) {
144
+
145
+ facebook_for_woocommerce()->log( sprintf(
146
+ 'There was an error trying to set products and variations meta data. %s',
147
+ $wpdb->last_error
148
+ ) );
149
+
150
+ continue;
151
+ }
152
+
153
+ $products_updated++;
154
+ }
155
+
156
+ return $products_updated;
157
+ }
158
+
159
+
160
+ /**
161
+ * Gets the ID of products that duplicate visibility meta data.
162
+ *
163
+ * The method also returns the number of meta data entries and ID of the last meta data entry for each product.
164
+ *
165
+ * @since 2.0.3
166
+ *
167
+ * @return array|null
168
+ */
169
+ private function get_posts_to_update() {
170
+ global $wpdb;
171
+
172
+ $sql = "
173
+ SELECT post_id, COUNT(meta_key) entries, MAX(meta_id) last_meta_id
174
+ FROM {$wpdb->postmeta}
175
+ WHERE meta_key = 'fb_visibility'
176
+ GROUP BY post_id
177
+ HAVING entries > 1
178
+ ";
179
+
180
+ return $wpdb->get_results( $sql );
181
+ }
182
+
183
+
184
+ /**
185
+ * No-op
186
+ *
187
+ * @since 2.0.3
188
+ */
189
+ protected function process_item( $item, $job ) {
190
+ // void
191
+ }
192
+
193
+
194
+ }
includes/fbutils.php CHANGED
@@ -12,6 +12,8 @@ if ( ! defined( 'ABSPATH' ) ) {
12
  exit;
13
  }
14
 
 
 
15
  if ( ! class_exists( 'WC_Facebookcommerce_Utils' ) ) :
16
 
17
  /**
@@ -204,28 +206,46 @@ if ( ! class_exists( 'WC_Facebookcommerce_Utils' ) ) :
204
  * Returns user info for the current WP user.
205
  *
206
  * @access public
207
- * @param boolean $use_pii
208
  * @return array
209
  */
210
- public static function get_user_info( $use_pii ) {
211
  $current_user = wp_get_current_user();
212
- if ( 0 === $current_user->ID || $use_pii === false ) {
213
- // User not logged in or admin chose not to send PII.
214
  return array();
215
  } else {
216
- return array_filter(
217
- array(
218
- // Keys documented in
219
- // https://developers.facebook.com/docs/facebook-pixel/pixel-with-ads/
220
- // /conversion-tracking#advanced_match
221
- 'em' => $current_user->user_email,
222
- 'fn' => $current_user->user_firstname,
223
- 'ln' => $current_user->user_lastname,
224
- ),
225
- function ( $value ) {
226
- return $value !== null && $value !== '';
227
- }
228
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  }
230
  }
231
 
12
  exit;
13
  }
14
 
15
+ use SkyVerge\WooCommerce\Facebook\Events\Normalizer;
16
+
17
  if ( ! class_exists( 'WC_Facebookcommerce_Utils' ) ) :
18
 
19
  /**
206
  * Returns user info for the current WP user.
207
  *
208
  * @access public
209
+ * @param AAMSettings $aam_settings
210
  * @return array
211
  */
212
+ public static function get_user_info( $aam_settings ) {
213
  $current_user = wp_get_current_user();
214
+ if ( 0 === $current_user->ID || $aam_settings == null || !$aam_settings->get_enable_automatic_matching() ) {
215
+ // User not logged in or pixel not configured with automatic advance matching
216
  return array();
217
  } else {
218
+ // Keys documented in
219
+ // https://developers.facebook.com/docs/facebook-pixel/advanced/advanced-matching
220
+ $user_data = array(
221
+ 'em' => $current_user->user_email,
222
+ 'fn' => $current_user->user_firstname,
223
+ 'ln' => $current_user->user_lastname,
224
+ 'external_id' => strval($current_user->ID),
 
 
 
 
 
225
  );
226
+ $user_id = $current_user->ID;
227
+ $user_data['ct'] = get_user_meta($user_id, 'billing_city', true);
228
+ $user_data['zp'] = get_user_meta($user_id, 'billing_postcode', true);
229
+ $user_data['country'] = get_user_meta($user_id, 'billing_country', true);
230
+ $user_data['st'] = get_user_meta($user_id, 'billing_state', true);
231
+ $user_data['ph'] = get_user_meta($user_id, 'billing_phone', true);
232
+ // Each field that is not present in AAM settings or is empty is deleted from user data
233
+ foreach ($user_data as $field => $value) {
234
+ if( $value === null || $value === ''
235
+ || !in_array($field, $aam_settings->get_enabled_automatic_matching_fields())
236
+ ){
237
+ unset($user_data[$field]);
238
+ }
239
+ }
240
+ // Country is a special case, it is returned as country in AAM settings
241
+ // But used as cn in pixel
242
+ if(array_key_exists('country', $user_data)){
243
+ $country = $user_data['country'];
244
+ $user_data['cn'] = $country;
245
+ unset($user_data['country']);
246
+ }
247
+ $user_data = Normalizer::normalize_array($user_data, true);
248
+ return $user_data;
249
  }
250
  }
251
 
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: facebook, automattic, woothemes
3
  Tags: facebook, shop, catalog, advertise, pixel, product
4
  Requires at least: 4.4
5
- Tested up to: 5.3.2
6
- Stable tag: 2.0.2
7
  Requires PHP: 5.6 or greater
8
  MySQL: 5.6 or greater
9
  License: GPLv2 or later
@@ -39,6 +39,11 @@ When opening a bug on GitHub, please give us as many details as possible.
39
 
40
  == Changelog ==
41
 
 
 
 
 
 
42
  = 2020.09.25 - version 2.0.2 =
43
  * Tweak - Allow simple and variable products with zero/empty price to sync to Facebook
44
  * Tweak - Use the bundle price for Product Bundles products with individually priced items
2
  Contributors: facebook, automattic, woothemes
3
  Tags: facebook, shop, catalog, advertise, pixel, product
4
  Requires at least: 4.4
5
+ Tested up to: 5.5.1
6
+ Stable tag: 2.0.3
7
  Requires PHP: 5.6 or greater
8
  MySQL: 5.6 or greater
9
  License: GPLv2 or later
39
 
40
  == Changelog ==
41
 
42
+ = 2020.10.02 - version 2.0.3 =
43
+ * Tweak - Pixel events now can include advanced matching information
44
+ * Fix - Send contents parameter for ViewContent event using the correct format
45
+ * Fix - Remove duplicate visibility meta entries from postmeta table
46
+
47
  = 2020.09.25 - version 2.0.2 =
48
  * Tweak - Allow simple and variable products with zero/empty price to sync to Facebook
49
  * Tweak - Use the bundle price for Product Bundles products with individually priced items