Version Description
06.10.2022
- New: The Pixel Manager has been refactored to be ready for the upcoming WooCommerce High Performance Orders Storage
- Tweak: Some UI improvements
- Tweak: Added GAds Conversion Adjustments feed URL to debug info
- Tweak: Refactor for HPOS
Download this release
Release Info
Developer | alekv |
Plugin | Pixel Manager for WooCommerce – Track Google Analytics, Google Ads, Facebook and more |
Version | 1.24.0 |
Comparing to | |
See all releases |
Code changes from version 1.23.0 to 1.24.0
- classes/admin/class-admin.php +9 -15
- classes/admin/class-ask-for-rating.php +2 -1
- classes/admin/class-debug-info.php +14 -3
- classes/admin/class-environment-check.php +3 -3
- classes/admin/class-order-columns.php +122 -25
- classes/class-helpers.php +20 -1
- classes/class-profit-margin.php +14 -6
- classes/pixels/class-pixel-manager.php +67 -34
- classes/pixels/facebook/class-facebook-pixel-manager.php +1 -1
- classes/pixels/google/class-google-pixel-manager.php +2 -1
- classes/pixels/trait-shop.php +17 -36
- readme.txt +11 -2
- wgact.php +11 -4
classes/admin/class-admin.php
CHANGED
@@ -3,6 +3,7 @@
|
|
3 |
// TODO move script for copying debug info into a proper .js enqueued file, or switch tabs to JavaScript switching and always save all settings at the same time
|
4 |
namespace WCPM\Classes\Admin;
|
5 |
|
|
|
6 |
use WCPM\Classes\Pixels\Google\Google ;
|
7 |
use WCPM\Classes\Pixels\Trait_Shop ;
|
8 |
|
@@ -50,7 +51,7 @@ class Admin
|
|
50 |
|
51 |
protected function if_is_wpm_admin_page()
|
52 |
{
|
53 |
-
$_get =
|
54 |
|
55 |
if ( !empty($_get['page']) && 'wpm' === $_get['page'] ) {
|
56 |
return true;
|
@@ -90,7 +91,7 @@ class Admin
|
|
90 |
public function wpm_admin_css( $hook_suffix )
|
91 |
{
|
92 |
// Only output the css on PMW pages and the order page
|
93 |
-
if ( !(strpos( $hook_suffix, 'page_wpm' ) ||
|
94 |
return;
|
95 |
}
|
96 |
wp_enqueue_style(
|
@@ -101,13 +102,6 @@ class Admin
|
|
101 |
);
|
102 |
}
|
103 |
|
104 |
-
private function is_orders_page()
|
105 |
-
{
|
106 |
-
global $pagenow ;
|
107 |
-
$_get = $this->get_input_vars( INPUT_GET );
|
108 |
-
return 'edit.php' === $pagenow && isset( $_get['post_type'] ) && 'shop_order' === $_get['post_type'];
|
109 |
-
}
|
110 |
-
|
111 |
public function wpm_admin_scripts( $hook_suffix )
|
112 |
{
|
113 |
// Only output the remaining scripts on PMW settings page
|
@@ -348,7 +342,7 @@ class Admin
|
|
348 |
// add the field for the TikTok pixel
|
349 |
add_settings_field(
|
350 |
'wpm_plugin_tiktok_pixel_id',
|
351 |
-
esc_html__( 'TikTok pixel ID', 'woocommerce-google-adwords-conversion-tracking-tag' )
|
352 |
[ $this, 'wpm_option_html_tiktok_pixel_id' ],
|
353 |
'wpm_plugin_options_page',
|
354 |
$section_ids['settings_name']
|
@@ -2254,13 +2248,13 @@ class Admin
|
|
2254 |
// feedUrlElement.setSelectionRange(0, 99999)
|
2255 |
navigator.clipboard.writeText(document.getElementById("pmw_plugin_google_ads_conversion_adjustments_feed").value)
|
2256 |
|
2257 |
-
const pmwCaFeedTooltip
|
2258 |
-
pmwCaFeedTooltip.innerHTML = "Copied feed URL to clipboard"
|
2259 |
}
|
2260 |
|
2261 |
const resetCaCopyButton = () => {
|
2262 |
-
const pmwCaFeedTooltip
|
2263 |
-
pmwCaFeedTooltip.innerHTML = "Copy to clipboard"
|
2264 |
}
|
2265 |
</script>
|
2266 |
<div class="pmwCaTooltip">
|
@@ -2649,7 +2643,7 @@ class Admin
|
|
2649 |
?>'
|
2650 |
/>
|
2651 |
<?php
|
2652 |
-
$this->get_status_icon( !empty($this->options['general']['scroll_tracker_thresholds']) );
|
2653 |
?>
|
2654 |
<?php
|
2655 |
$this->get_documentation_html_by_key( 'scroll_tracker_threshold' );
|
3 |
// TODO move script for copying debug info into a proper .js enqueued file, or switch tabs to JavaScript switching and always save all settings at the same time
|
4 |
namespace WCPM\Classes\Admin;
|
5 |
|
6 |
+
use WCPM\Classes\Helpers ;
|
7 |
use WCPM\Classes\Pixels\Google\Google ;
|
8 |
use WCPM\Classes\Pixels\Trait_Shop ;
|
9 |
|
51 |
|
52 |
protected function if_is_wpm_admin_page()
|
53 |
{
|
54 |
+
$_get = Helpers::get_input_vars( INPUT_GET );
|
55 |
|
56 |
if ( !empty($_get['page']) && 'wpm' === $_get['page'] ) {
|
57 |
return true;
|
91 |
public function wpm_admin_css( $hook_suffix )
|
92 |
{
|
93 |
// Only output the css on PMW pages and the order page
|
94 |
+
if ( !(strpos( $hook_suffix, 'page_wpm' ) || Helpers::is_orders_page()) ) {
|
95 |
return;
|
96 |
}
|
97 |
wp_enqueue_style(
|
102 |
);
|
103 |
}
|
104 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
public function wpm_admin_scripts( $hook_suffix )
|
106 |
{
|
107 |
// Only output the remaining scripts on PMW settings page
|
342 |
// add the field for the TikTok pixel
|
343 |
add_settings_field(
|
344 |
'wpm_plugin_tiktok_pixel_id',
|
345 |
+
esc_html__( 'TikTok pixel ID', 'woocommerce-google-adwords-conversion-tracking-tag' ),
|
346 |
[ $this, 'wpm_option_html_tiktok_pixel_id' ],
|
347 |
'wpm_plugin_options_page',
|
348 |
$section_ids['settings_name']
|
2248 |
// feedUrlElement.setSelectionRange(0, 99999)
|
2249 |
navigator.clipboard.writeText(document.getElementById("pmw_plugin_google_ads_conversion_adjustments_feed").value)
|
2250 |
|
2251 |
+
const pmwCaFeedTooltip = document.getElementById("myPmwCaTooltip")
|
2252 |
+
pmwCaFeedTooltip.innerHTML = "Copied feed URL to clipboard"
|
2253 |
}
|
2254 |
|
2255 |
const resetCaCopyButton = () => {
|
2256 |
+
const pmwCaFeedTooltip = document.getElementById("myPmwCaTooltip")
|
2257 |
+
pmwCaFeedTooltip.innerHTML = "Copy to clipboard"
|
2258 |
}
|
2259 |
</script>
|
2260 |
<div class="pmwCaTooltip">
|
2643 |
?>'
|
2644 |
/>
|
2645 |
<?php
|
2646 |
+
$this->get_status_icon( !empty($this->options['general']['scroll_tracker_thresholds']), true, true );
|
2647 |
?>
|
2648 |
<?php
|
2649 |
$this->get_documentation_html_by_key( 'scroll_tracker_threshold' );
|
classes/admin/class-ask-for-rating.php
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
|
3 |
namespace WCPM\Classes\Admin;
|
4 |
|
|
|
5 |
use WCPM\Classes\Pixels\Trait_Shop;
|
6 |
|
7 |
if (!defined('ABSPATH')) {
|
@@ -51,7 +52,7 @@ class Ask_For_Rating {
|
|
51 |
// server side php ajax handler for the admin rating notice
|
52 |
public function ajax_rating_notice_handler() {
|
53 |
|
54 |
-
$_post =
|
55 |
|
56 |
$set = $_post['set'];
|
57 |
|
2 |
|
3 |
namespace WCPM\Classes\Admin;
|
4 |
|
5 |
+
use WCPM\Classes\Helpers;
|
6 |
use WCPM\Classes\Pixels\Trait_Shop;
|
7 |
|
8 |
if (!defined('ABSPATH')) {
|
52 |
// server side php ajax handler for the admin rating notice
|
53 |
public function ajax_rating_notice_handler() {
|
54 |
|
55 |
+
$_post = Helpers::get_input_vars(INPUT_POST);
|
56 |
|
57 |
$set = $_post['set'];
|
58 |
|
classes/admin/class-debug-info.php
CHANGED
@@ -2,6 +2,8 @@
|
|
2 |
|
3 |
namespace WCPM\Classes\Admin;
|
4 |
|
|
|
|
|
5 |
use WCPM\Classes\Pixels\Trait_Shop ;
|
6 |
use WP_Query ;
|
7 |
|
@@ -346,7 +348,7 @@ class Debug_Info
|
|
346 |
|
347 |
if ( in_array( $order->get_payment_method(), $gateway_ids ) ) {
|
348 |
$analysis[$order->get_payment_method()]['order_count_total']++;
|
349 |
-
if (
|
350 |
$analysis[$order->get_payment_method()]['order_count_measured']++;
|
351 |
}
|
352 |
}
|
@@ -367,8 +369,9 @@ class Debug_Info
|
|
367 |
{
|
368 |
$count = 0;
|
369 |
foreach ( $orders as $order_id ) {
|
|
|
370 |
// Get meta data for post id and meta key _wpm_conversion_pixel_fired
|
371 |
-
if (
|
372 |
$count++;
|
373 |
}
|
374 |
}
|
@@ -586,7 +589,15 @@ class Debug_Info
|
|
586 |
private function generate_pmw_tracked_payment_methods()
|
587 |
{
|
588 |
global $wpdb ;
|
589 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
590 |
set_transient( 'pmw_tracked_payment_methods', $tracked_payment_methods, MONTH_IN_SECONDS );
|
591 |
}
|
592 |
|
2 |
|
3 |
namespace WCPM\Classes\Admin;
|
4 |
|
5 |
+
use Automattic\WooCommerce\Utilities\OrderUtil ;
|
6 |
+
use WCPM\Classes\Pixels\Pixel_Manager ;
|
7 |
use WCPM\Classes\Pixels\Trait_Shop ;
|
8 |
use WP_Query ;
|
9 |
|
348 |
|
349 |
if ( in_array( $order->get_payment_method(), $gateway_ids ) ) {
|
350 |
$analysis[$order->get_payment_method()]['order_count_total']++;
|
351 |
+
if ( $order->meta_exists( '_wpm_conversion_pixel_fired' ) ) {
|
352 |
$analysis[$order->get_payment_method()]['order_count_measured']++;
|
353 |
}
|
354 |
}
|
369 |
{
|
370 |
$count = 0;
|
371 |
foreach ( $orders as $order_id ) {
|
372 |
+
$order = wc_get_order( $order_id );
|
373 |
// Get meta data for post id and meta key _wpm_conversion_pixel_fired
|
374 |
+
if ( $order->meta_exists( '_wpm_conversion_pixel_fired' ) ) {
|
375 |
$count++;
|
376 |
}
|
377 |
}
|
589 |
private function generate_pmw_tracked_payment_methods()
|
590 |
{
|
591 |
global $wpdb ;
|
592 |
+
|
593 |
+
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
594 |
+
// HPOS tables in use
|
595 |
+
$tracked_payment_methods = $wpdb->get_col( "SELECT DISTINCT payment_method FROM {$wpdb->prefix}wc_orders WHERE payment_method <> ''" );
|
596 |
+
} else {
|
597 |
+
// Traditional post tables are in use.
|
598 |
+
$tracked_payment_methods = $wpdb->get_col( "SELECT DISTINCT meta_value FROM {$wpdb->prefix}postmeta WHERE `meta_key` = '_payment_method' AND meta_value != ''" );
|
599 |
+
}
|
600 |
+
|
601 |
set_transient( 'pmw_tracked_payment_methods', $tracked_payment_methods, MONTH_IN_SECONDS );
|
602 |
}
|
603 |
|
classes/admin/class-environment-check.php
CHANGED
@@ -142,7 +142,7 @@ class Environment_Check {
|
|
142 |
'plugin' === $options['type'] &&
|
143 |
isset($options['plugins']) &&
|
144 |
is_array($options['plugins']) &&
|
145 |
-
in_array(
|
146 |
) {
|
147 |
$this->flush_cache_of_all_cache_plugins();
|
148 |
}
|
@@ -399,7 +399,7 @@ class Environment_Check {
|
|
399 |
|
400 |
public function ajax_environment_check_handler() {
|
401 |
|
402 |
-
$_post =
|
403 |
|
404 |
if (isset($_post['set'])) {
|
405 |
|
@@ -655,7 +655,7 @@ class Environment_Check {
|
|
655 |
|
656 |
public function is_hosting_cloudways() {
|
657 |
|
658 |
-
$_server =
|
659 |
|
660 |
if ($_server && array_key_exists('cw_allowed_ip', $_server)) {
|
661 |
return true;
|
142 |
'plugin' === $options['type'] &&
|
143 |
isset($options['plugins']) &&
|
144 |
is_array($options['plugins']) &&
|
145 |
+
in_array(WPM_PLUGIN_BASENAME, $options['plugins'], true)
|
146 |
) {
|
147 |
$this->flush_cache_of_all_cache_plugins();
|
148 |
}
|
399 |
|
400 |
public function ajax_environment_check_handler() {
|
401 |
|
402 |
+
$_post = Helpers::get_input_vars(INPUT_POST);
|
403 |
|
404 |
if (isset($_post['set'])) {
|
405 |
|
655 |
|
656 |
public function is_hosting_cloudways() {
|
657 |
|
658 |
+
$_server = Helpers::get_input_vars(INPUT_SERVER);
|
659 |
|
660 |
if ($_server && array_key_exists('cw_allowed_ip', $_server)) {
|
661 |
return true;
|
classes/admin/class-order-columns.php
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
|
3 |
namespace WCPM\Classes\Admin;
|
4 |
|
|
|
5 |
use WCPM\Classes\Helpers;
|
6 |
|
7 |
if (!defined('ABSPATH')) {
|
@@ -22,30 +23,115 @@ class Order_Columns {
|
|
22 |
|
23 |
private function __construct() {
|
24 |
|
25 |
-
|
26 |
-
add_action('manage_shop_order_posts_custom_column', [$this, 'custom_orders_list_column_content'], 20, 2);
|
27 |
add_action('pre_get_posts', [$this, 'view_pixels_not_fired'], 1000, 1);
|
28 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
}
|
30 |
|
31 |
public function view_pixels_not_fired( $query ) {
|
32 |
-
global $pagenow;
|
33 |
|
34 |
-
|
35 |
-
if (!( isset($query->query_vars['post_type']) && 'shop_order' === $query->query_vars['post_type'] && ( 'edit.php' === $pagenow ) )) {
|
36 |
return;
|
37 |
}
|
38 |
|
39 |
-
if (
|
40 |
return;
|
41 |
}
|
42 |
|
43 |
-
|
44 |
-
|
|
|
45 |
|
|
|
46 |
|
47 |
// Set additional filters for the view
|
48 |
-
if ($
|
49 |
|
50 |
$query->set('post_status', ['wc-completed', 'wc-processing', 'wc-on-hold', 'wc-pending']);
|
51 |
|
@@ -100,22 +186,24 @@ class Order_Columns {
|
|
100 |
]
|
101 |
]));
|
102 |
|
103 |
-
|
104 |
// Add new view with all orders where the conversion pixels have not been fired
|
105 |
-
add_filter('views_edit-shop_order', function ( $views ) use ( $count_missing_pixel_fires, $
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
|
110 |
-
|
|
|
|
|
111 |
|
112 |
-
|
113 |
|
114 |
-
|
115 |
|
116 |
-
|
117 |
}
|
118 |
|
|
|
119 |
public function pmw_order_table_styles() {
|
120 |
wp_add_inline_style(
|
121 |
'woocommerce_admin_styles',
|
@@ -125,6 +213,8 @@ class Order_Columns {
|
|
125 |
|
126 |
public function custom_shop_order_column( $columns ) {
|
127 |
|
|
|
|
|
128 |
function get_list_order_parameter( $list_order ) {
|
129 |
if (is_null($list_order)) {
|
130 |
return '';
|
@@ -135,7 +225,6 @@ class Order_Columns {
|
|
135 |
|
136 |
$_get = Helpers::get_input_vars_sanitized(INPUT_GET);
|
137 |
|
138 |
-
|
139 |
if (!isset($_get['order'])) {
|
140 |
$list_order = 'dsc';
|
141 |
} elseif ('dsc' === $_get['order']) {
|
@@ -159,12 +248,20 @@ class Order_Columns {
|
|
159 |
return $reordered_columns;
|
160 |
}
|
161 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
|
163 |
-
|
164 |
-
switch ($column) {
|
165 |
case 'pmw-monitored':
|
166 |
// Get custom post meta data
|
167 |
-
if (
|
168 |
$text = __('PMW monitored order', 'woocommerce-google-adwords-conversion-tracking-tag');
|
169 |
?>
|
170 |
<div aria-hidden="true" title="<?php esc_html_e($text); ?>" class="pmw-monitored-icon good">
|
@@ -184,7 +281,7 @@ class Order_Columns {
|
|
184 |
|
185 |
case 'pmw-pixels-fired':
|
186 |
// Get custom post meta data
|
187 |
-
if (
|
188 |
$text = __('Order not tracked by PMW', 'woocommerce-google-adwords-conversion-tracking-tag');
|
189 |
?>
|
190 |
<div aria-hidden="true" title="<?php esc_html_e($text); ?>" class="pmw-monitored-icon none">
|
@@ -192,7 +289,7 @@ class Order_Columns {
|
|
192 |
</div>
|
193 |
<?php
|
194 |
|
195 |
-
} elseif (
|
196 |
$text = __('This order was created by a shop manager. Only orders created by customers are analysed.', 'woocommerce-google-adwords-conversion-tracking-tag');
|
197 |
?>
|
198 |
<div aria-hidden="true" title="<?php esc_html_e($text); ?>" class="pmw-monitored-icon none">
|
@@ -200,7 +297,7 @@ class Order_Columns {
|
|
200 |
</div>
|
201 |
<?php
|
202 |
|
203 |
-
} elseif (
|
204 |
$text = __('Conversion pixels fired', 'woocommerce-google-adwords-conversion-tracking-tag');
|
205 |
?>
|
206 |
<div aria-hidden="true" title="<?php esc_html_e($text); ?>" class="pmw-monitored-icon good">
|
2 |
|
3 |
namespace WCPM\Classes\Admin;
|
4 |
|
5 |
+
use WC_Order_Query;
|
6 |
use WCPM\Classes\Helpers;
|
7 |
|
8 |
if (!defined('ABSPATH')) {
|
23 |
|
24 |
private function __construct() {
|
25 |
|
26 |
+
// pre HPOS
|
|
|
27 |
add_action('pre_get_posts', [$this, 'view_pixels_not_fired'], 1000, 1);
|
28 |
|
29 |
+
// pre HPOS and HPOS
|
30 |
+
add_action('manage_shop_order_posts_custom_column', [$this, 'custom_orders_list_column_content'], 20, 2);
|
31 |
+
add_filter('manage_edit-shop_order_columns', [$this, 'custom_shop_order_column'], 20);
|
32 |
+
add_filter('manage_woocommerce_page_wc-orders_columns', [$this, 'custom_shop_order_column'], 20);
|
33 |
+
|
34 |
+
// HPOS only
|
35 |
+
add_action('manage_woocommerce_page_wc-orders_custom_column', [$this, 'custom_orders_list_column_content_order'], 20, 2);
|
36 |
+
add_action('woocommerce_order_list_table_prepare_items_query_args', [$this, 'hpos_view_query_adjustment'], 20);
|
37 |
+
add_filter('views_woocommerce_page_wc-orders', [$this, 'hpos_menu_view'], 20);
|
38 |
+
}
|
39 |
+
|
40 |
+
public function hpos_menu_view( $views ) {
|
41 |
+
|
42 |
+
$count_missing_pixel_fires = count(wc_get_orders([
|
43 |
+
'return' => 'ids',
|
44 |
+
'status' => ['wc-completed', 'wc-processing', 'wc-on-hold', 'wc-pending'],
|
45 |
+
'posts_per_page' => -1,
|
46 |
+
'date_created' => '>' . ( time() - MONTH_IN_SECONDS ),
|
47 |
+
'meta_query' => [
|
48 |
+
[
|
49 |
+
'key' => '_wpm_process_through_wpm',
|
50 |
+
'compare' => 'EXISTS',
|
51 |
+
],
|
52 |
+
[
|
53 |
+
'key' => '_wpm_conversion_pixel_fired',
|
54 |
+
'compare' => 'NOT EXISTS'
|
55 |
+
],
|
56 |
+
],
|
57 |
+
'field_query' => [
|
58 |
+
[
|
59 |
+
'field' => 'created_via',
|
60 |
+
'value' => 'checkout',
|
61 |
+
'compare' => '='
|
62 |
+
]
|
63 |
+
]
|
64 |
+
]));
|
65 |
+
|
66 |
+
|
67 |
+
return $this->get_updated_views_hpos($views, $count_missing_pixel_fires, $this->is_pmw_pixels_not_fired_view());
|
68 |
+
}
|
69 |
+
|
70 |
+
public function get_updated_views_hpos( $views, $count_missing_pixel_fires, $pmw_pixels_not_fired_query ) {
|
71 |
+
|
72 |
+
$query_string = admin_url('admin.php?page=wc-orders');
|
73 |
+
$query_string = add_query_arg('pmw-pixels-not-fired', '', $query_string);
|
74 |
+
|
75 |
+
$class = $pmw_pixels_not_fired_query ? 'current' : '';
|
76 |
+
|
77 |
+
$views['pmw-pixels-not-fired'] = $this->get_pmw_no_pixels_fired_view_html($query_string, $class, $count_missing_pixel_fires);
|
78 |
+
|
79 |
+
return $views;
|
80 |
+
}
|
81 |
+
|
82 |
+
private function get_pmw_no_pixels_fired_view_html( $query_string, $class, $count_missing_pixel_fires ) {
|
83 |
+
return sprintf('<a href="%s" class="%s">%s <span class="count">(%s)</span></a>', $query_string, $class, esc_html__('PMW pixels not fired - 30d', 'woocommerce-google-adwords-conversion-tracking-tag'), $count_missing_pixel_fires);
|
84 |
+
}
|
85 |
+
|
86 |
+
public function hpos_view_query_adjustment( $query_args ) {
|
87 |
+
|
88 |
+
if (!$this->is_pmw_pixels_not_fired_view()) {
|
89 |
+
return $query_args;
|
90 |
+
}
|
91 |
+
|
92 |
+
// checkout, admin, subscription, Vipps Express Checkout
|
93 |
+
$query_args['created_via'] = 'checkout';
|
94 |
+
|
95 |
+
$query_args['status'] = ['wc-completed', 'wc-processing', 'wc-on-hold', 'wc-pending'];
|
96 |
+
$query_args['date_created'] = '>' . ( time() - MONTH_IN_SECONDS );
|
97 |
+
|
98 |
+
$query_args['meta_query'][] = [
|
99 |
+
'key' => '_wpm_process_through_wpm',
|
100 |
+
'compare' => 'EXISTS',
|
101 |
+
];
|
102 |
+
|
103 |
+
$query_args['meta_query'][] = [
|
104 |
+
'key' => '_wpm_conversion_pixel_fired',
|
105 |
+
'compare' => 'NOT EXISTS',
|
106 |
+
];
|
107 |
+
|
108 |
+
return $query_args;
|
109 |
+
}
|
110 |
+
|
111 |
+
|
112 |
+
private function is_pmw_pixels_not_fired_view() {
|
113 |
+
$_get = Helpers::get_input_vars_sanitized(INPUT_GET);
|
114 |
+
return isset($_get['pmw-pixels-not-fired']);
|
115 |
}
|
116 |
|
117 |
public function view_pixels_not_fired( $query ) {
|
|
|
118 |
|
119 |
+
if (!Helpers::is_orders_page()) {
|
|
|
120 |
return;
|
121 |
}
|
122 |
|
123 |
+
if (Helpers::is_wc_hpos_enabled()) {
|
124 |
return;
|
125 |
}
|
126 |
|
127 |
+
if (!$query->is_main_query()) {
|
128 |
+
return;
|
129 |
+
}
|
130 |
|
131 |
+
$is_pmw_pixels_not_fired_view = $this->is_pmw_pixels_not_fired_view();
|
132 |
|
133 |
// Set additional filters for the view
|
134 |
+
if ($is_pmw_pixels_not_fired_view) {
|
135 |
|
136 |
$query->set('post_status', ['wc-completed', 'wc-processing', 'wc-on-hold', 'wc-pending']);
|
137 |
|
186 |
]
|
187 |
]));
|
188 |
|
|
|
189 |
// Add new view with all orders where the conversion pixels have not been fired
|
190 |
+
add_filter('views_edit-shop_order', function ( $views ) use ( $count_missing_pixel_fires, $is_pmw_pixels_not_fired_view ) {
|
191 |
+
return $this->get_updated_views($views, $count_missing_pixel_fires, $is_pmw_pixels_not_fired_view);
|
192 |
+
});
|
193 |
+
}
|
194 |
|
195 |
+
public function get_updated_views( $views, $count_missing_pixel_fires, $pmw_pixels_not_fired_query ) {
|
196 |
+
$query_string = admin_url('edit.php?post_type=shop_order');
|
197 |
+
$query_string = add_query_arg('pmw-pixels-not-fired', '', $query_string);
|
198 |
|
199 |
+
$class = $pmw_pixels_not_fired_query ? 'current' : '';
|
200 |
|
201 |
+
$views['pmw-pixels-not-fired'] = $this->get_pmw_no_pixels_fired_view_html($query_string, $class, $count_missing_pixel_fires);
|
202 |
|
203 |
+
return $views;
|
204 |
}
|
205 |
|
206 |
+
|
207 |
public function pmw_order_table_styles() {
|
208 |
wp_add_inline_style(
|
209 |
'woocommerce_admin_styles',
|
213 |
|
214 |
public function custom_shop_order_column( $columns ) {
|
215 |
|
216 |
+
// error_log('columns: ' . print_r($columns, true));
|
217 |
+
|
218 |
function get_list_order_parameter( $list_order ) {
|
219 |
if (is_null($list_order)) {
|
220 |
return '';
|
225 |
|
226 |
$_get = Helpers::get_input_vars_sanitized(INPUT_GET);
|
227 |
|
|
|
228 |
if (!isset($_get['order'])) {
|
229 |
$list_order = 'dsc';
|
230 |
} elseif ('dsc' === $_get['order']) {
|
248 |
return $reordered_columns;
|
249 |
}
|
250 |
|
251 |
+
public function custom_orders_list_column_content( $column_name, $post_id ) {
|
252 |
+
|
253 |
+
$order = wc_get_order($post_id);
|
254 |
+
|
255 |
+
$this->custom_orders_list_column_content_order($column_name, $order);
|
256 |
+
}
|
257 |
+
|
258 |
+
public function custom_orders_list_column_content_order( $column_name, $order ) {
|
259 |
+
|
260 |
|
261 |
+
switch ($column_name) {
|
|
|
262 |
case 'pmw-monitored':
|
263 |
// Get custom post meta data
|
264 |
+
if ($order->get_meta('_wpm_process_through_wpm', true)) {
|
265 |
$text = __('PMW monitored order', 'woocommerce-google-adwords-conversion-tracking-tag');
|
266 |
?>
|
267 |
<div aria-hidden="true" title="<?php esc_html_e($text); ?>" class="pmw-monitored-icon good">
|
281 |
|
282 |
case 'pmw-pixels-fired':
|
283 |
// Get custom post meta data
|
284 |
+
if (!$order->get_meta('_wpm_process_through_wpm', true)) {
|
285 |
$text = __('Order not tracked by PMW', 'woocommerce-google-adwords-conversion-tracking-tag');
|
286 |
?>
|
287 |
<div aria-hidden="true" title="<?php esc_html_e($text); ?>" class="pmw-monitored-icon none">
|
289 |
</div>
|
290 |
<?php
|
291 |
|
292 |
+
} elseif ($order->get_created_via() !== 'checkout') {
|
293 |
$text = __('This order was created by a shop manager. Only orders created by customers are analysed.', 'woocommerce-google-adwords-conversion-tracking-tag');
|
294 |
?>
|
295 |
<div aria-hidden="true" title="<?php esc_html_e($text); ?>" class="pmw-monitored-icon none">
|
297 |
</div>
|
298 |
<?php
|
299 |
|
300 |
+
} elseif ($order->get_meta('_wpm_conversion_pixel_fired', true)) {
|
301 |
$text = __('Conversion pixels fired', 'woocommerce-google-adwords-conversion-tracking-tag');
|
302 |
?>
|
303 |
<div aria-hidden="true" title="<?php esc_html_e($text); ?>" class="pmw-monitored-icon good">
|
classes/class-helpers.php
CHANGED
@@ -15,7 +15,7 @@ class Helpers {
|
|
15 |
return self::generic_sanitization($input_vars);
|
16 |
}
|
17 |
|
18 |
-
|
19 |
|
20 |
if (is_array($input)) {
|
21 |
array_walk_recursive($input, function ( &$value, $key ) {
|
@@ -40,4 +40,23 @@ class Helpers {
|
|
40 |
|
41 |
return false;
|
42 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
}
|
15 |
return self::generic_sanitization($input_vars);
|
16 |
}
|
17 |
|
18 |
+
public static function generic_sanitization( $input ) {
|
19 |
|
20 |
if (is_array($input)) {
|
21 |
array_walk_recursive($input, function ( &$value, $key ) {
|
40 |
|
41 |
return false;
|
42 |
}
|
43 |
+
|
44 |
+
public static function is_wc_hpos_enabled() {
|
45 |
+
return class_exists('Automattic\WooCommerce\Utilities\OrderUtil') && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled();
|
46 |
+
}
|
47 |
+
|
48 |
+
public static function is_orders_page() {
|
49 |
+
global $pagenow;
|
50 |
+
|
51 |
+
$_get = self::get_input_vars(INPUT_GET);
|
52 |
+
|
53 |
+
return ( 'edit.php' === $pagenow && isset($_get['post_type']) && 'shop_order' === $_get['post_type'] ) || ( isset($_get['page']) && 'wc-orders' === $_get['page'] );
|
54 |
+
}
|
55 |
+
|
56 |
+
public static function get_input_vars( $type ) {
|
57 |
+
|
58 |
+
$input_vars = filter_input_array($type, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
59 |
+
|
60 |
+
return self::generic_sanitization($input_vars);
|
61 |
+
}
|
62 |
}
|
classes/class-profit-margin.php
CHANGED
@@ -112,17 +112,25 @@ class Profit_Margin {
|
|
112 |
|
113 |
// Add Stripe fees
|
114 |
// because Stripe doesn't save the fee on the order fees
|
115 |
-
$order_fees += self::get_fee_by_postmeta_key($order
|
116 |
|
117 |
// Add _paypal_transaction_fee
|
118 |
// because PayPal doesn't save the fee on the order fees
|
119 |
// https://stackoverflow.com/a/56129332/4688612
|
120 |
-
$order_fees += self::get_fee_by_postmeta_key($order
|
121 |
|
122 |
// Add ppcp_paypal_fees
|
123 |
// because PayPal doesn't save the fee on the order fees
|
124 |
-
if (get_post_meta($order->get_id(), '_ppcp_paypal_fees', true)) {
|
125 |
-
$ppcp_paypal_fees = get_post_meta($order->get_id(), '_ppcp_paypal_fees', true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
|
127 |
if (!empty($ppcp_paypal_fees['paypal_fee']['value'])) {
|
128 |
$order_fees += $ppcp_paypal_fees['paypal_fee']['value'];
|
@@ -132,9 +140,9 @@ class Profit_Margin {
|
|
132 |
return $order_fees;
|
133 |
}
|
134 |
|
135 |
-
private static function get_fee_by_postmeta_key( $
|
136 |
|
137 |
-
$fee =
|
138 |
|
139 |
if (empty($fee)) {
|
140 |
return 0;
|
112 |
|
113 |
// Add Stripe fees
|
114 |
// because Stripe doesn't save the fee on the order fees
|
115 |
+
$order_fees += self::get_fee_by_postmeta_key($order, '_stripe_fee');
|
116 |
|
117 |
// Add _paypal_transaction_fee
|
118 |
// because PayPal doesn't save the fee on the order fees
|
119 |
// https://stackoverflow.com/a/56129332/4688612
|
120 |
+
$order_fees += self::get_fee_by_postmeta_key($order, '_paypal_transaction_fee');
|
121 |
|
122 |
// Add ppcp_paypal_fees
|
123 |
// because PayPal doesn't save the fee on the order fees
|
124 |
+
// if (get_post_meta($order->get_id(), '_ppcp_paypal_fees', true)) {
|
125 |
+
// $ppcp_paypal_fees = get_post_meta($order->get_id(), '_ppcp_paypal_fees', true);
|
126 |
+
//
|
127 |
+
// if (!empty($ppcp_paypal_fees['paypal_fee']['value'])) {
|
128 |
+
// $order_fees += $ppcp_paypal_fees['paypal_fee']['value'];
|
129 |
+
// }
|
130 |
+
// }
|
131 |
+
|
132 |
+
if ($order->meta_exists('_ppcp_paypal_fees')) {
|
133 |
+
$ppcp_paypal_fees = $order->get_meta('_ppcp_paypal_fees', true);
|
134 |
|
135 |
if (!empty($ppcp_paypal_fees['paypal_fee']['value'])) {
|
136 |
$order_fees += $ppcp_paypal_fees['paypal_fee']['value'];
|
140 |
return $order_fees;
|
141 |
}
|
142 |
|
143 |
+
private static function get_fee_by_postmeta_key( $order, $postmeta_key ) {
|
144 |
|
145 |
+
$fee = $order->get_meta( $postmeta_key, true);
|
146 |
|
147 |
if (empty($fee)) {
|
148 |
return 0;
|
classes/pixels/class-pixel-manager.php
CHANGED
@@ -4,6 +4,7 @@ namespace WCPM\Classes\Pixels;
|
|
4 |
|
5 |
use WCPM\Classes\Admin\Environment_Check ;
|
6 |
use WCPM\Classes\Admin\Validations ;
|
|
|
7 |
use WCPM\Classes\Http\Facebook_CAPI ;
|
8 |
use WCPM\Classes\Http\Google_MP ;
|
9 |
use WCPM\Classes\Pixels\Facebook\Facebook_Microdata ;
|
@@ -27,8 +28,10 @@ class Pixel_Manager
|
|
27 |
protected $google_active ;
|
28 |
protected $google ;
|
29 |
protected $microdata_product_id ;
|
30 |
-
protected $position = 1 ;
|
31 |
protected $order ;
|
|
|
|
|
|
|
32 |
private static $instance ;
|
33 |
public static function get_instance()
|
34 |
{
|
@@ -167,6 +170,11 @@ class Pixel_Manager
|
|
167 |
return $this->order;
|
168 |
}
|
169 |
|
|
|
|
|
|
|
|
|
|
|
170 |
// https://wordpress.stackexchange.com/a/377954/68337
|
171 |
public function prepare_custom_rest_handlers(
|
172 |
$served,
|
@@ -179,13 +187,12 @@ class Pixel_Manager
|
|
179 |
// error log $request->get_route();
|
180 |
// error_log($request->get_route());
|
181 |
// If $request->get_route() is not /pmw/v1/google-ads/conversion-adjustments then return $served
|
182 |
-
if ( strpos( $request->get_route(),
|
183 |
return $served;
|
184 |
}
|
185 |
// if (strpos($request->get_route(), '/google-ads/conversion-adjustments/') !== 0) {
|
186 |
// return $served;
|
187 |
// }
|
188 |
-
// error_log('prepare_custom_rest_responses - 2');
|
189 |
// Send headers.
|
190 |
// $server->send_header( 'Content-Type', 'text/xml' );
|
191 |
// $server->send_header( 'Content-Type', 'application/xml' );
|
@@ -193,15 +200,14 @@ class Pixel_Manager
|
|
193 |
// $server->send_header('Content-Type', 'text/html');
|
194 |
// Echo the XML that's returned by smg_feed().
|
195 |
// Turn off phpcs because we're echoing the XML.
|
196 |
-
|
197 |
-
echo $result->get_data() ;
|
198 |
// And then exit.
|
199 |
exit;
|
200 |
}
|
201 |
|
202 |
public function register_rest_routes()
|
203 |
{
|
204 |
-
register_rest_route(
|
205 |
'methods' => 'POST',
|
206 |
'callback' => function () {
|
207 |
wp_send_json_success();
|
@@ -210,7 +216,7 @@ class Pixel_Manager
|
|
210 |
return true;
|
211 |
},
|
212 |
] );
|
213 |
-
register_rest_route(
|
214 |
'methods' => 'GET',
|
215 |
'callback' => function () {
|
216 |
wp_send_json_success();
|
@@ -219,18 +225,18 @@ class Pixel_Manager
|
|
219 |
return true;
|
220 |
},
|
221 |
] );
|
222 |
-
register_rest_route(
|
223 |
'methods' => 'POST',
|
224 |
'callback' => [ $this, 'wpm_save_imported_settings' ],
|
225 |
'permission_callback' => function () {
|
226 |
return current_user_can( 'manage_options' );
|
227 |
},
|
228 |
] );
|
229 |
-
register_rest_route(
|
230 |
'methods' => 'POST',
|
231 |
'callback' => function ( $request ) {
|
232 |
$product_ids = $request->get_json_params();
|
233 |
-
$product_ids =
|
234 |
|
235 |
if ( !$product_ids ) {
|
236 |
wp_send_json_error( 'No product ids provided' );
|
@@ -243,7 +249,7 @@ class Pixel_Manager
|
|
243 |
return true;
|
244 |
},
|
245 |
] );
|
246 |
-
register_rest_route(
|
247 |
'methods' => 'POST',
|
248 |
'callback' => function ( $request ) {
|
249 |
$data = $request->get_json_params();
|
@@ -285,12 +291,46 @@ class Pixel_Manager
|
|
285 |
'Adjusted Value Currency'
|
286 |
];
|
287 |
$csv = implode( ',', $title_row ) . PHP_EOL;
|
288 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
$refunds = wc_get_orders( [
|
290 |
'type' => 'shop_order_refund',
|
291 |
'status' => 'completed',
|
292 |
-
'date_after' =>
|
293 |
-
'date_before' =>
|
294 |
] );
|
295 |
// error_log('refunds: ' . print_r($refunds, true));
|
296 |
foreach ( $refunds as $refund ) {
|
@@ -386,7 +426,7 @@ class Pixel_Manager
|
|
386 |
|
387 |
public function capture_ajax_server_to_server_event()
|
388 |
{
|
389 |
-
$_post =
|
390 |
$this->process_server_to_server_event( $_post['data'] );
|
391 |
wp_send_json_success();
|
392 |
}
|
@@ -403,7 +443,7 @@ class Pixel_Manager
|
|
403 |
{
|
404 |
$options = $request->get_params();
|
405 |
// Sanitize nested array $options
|
406 |
-
$options =
|
407 |
// Validate imported options
|
408 |
|
409 |
if ( Validations::validate_imported_options( $options ) ) {
|
@@ -445,18 +485,14 @@ class Pixel_Manager
|
|
445 |
|
446 |
public function wpm_woocommerce_new_order( $order_id )
|
447 |
{
|
|
|
448 |
/**
|
449 |
* All new orders should be marked as long WPM is active,
|
450 |
* so that we know we can process them later through WPM,
|
451 |
* and so that we know we should not touch orders that were
|
452 |
* placed before WPM was active.
|
453 |
*/
|
454 |
-
|
455 |
-
$order_id,
|
456 |
-
'_wpm_process_through_wpm',
|
457 |
-
true,
|
458 |
-
true
|
459 |
-
);
|
460 |
/**
|
461 |
* Set a custom user ID on the order
|
462 |
* because WC sets 0 on all order created
|
@@ -466,12 +502,8 @@ class Pixel_Manager
|
|
466 |
if ( is_user_logged_in() ) {
|
467 |
$user_id = get_current_user_id();
|
468 |
}
|
469 |
-
|
470 |
-
|
471 |
-
'_wpm_customer_user',
|
472 |
-
$user_id,
|
473 |
-
true
|
474 |
-
);
|
475 |
}
|
476 |
|
477 |
// Thanks to: https://gist.github.com/mishterk/6b7a4d6e5a91086a5a9b05ace304b5ce#file-mark-wordpress-scripts-as-async-or-defer-php
|
@@ -1110,7 +1142,7 @@ class Pixel_Manager
|
|
1110 |
|
1111 |
public function ajax_pmw_get_product_ids()
|
1112 |
{
|
1113 |
-
$_post =
|
1114 |
$product_ids = explode( ',', $_post['productIds'] );
|
1115 |
|
1116 |
if ( !$product_ids ) {
|
@@ -1145,7 +1177,7 @@ class Pixel_Manager
|
|
1145 |
|
1146 |
public function ajax_purchase_pixels_fired_handler()
|
1147 |
{
|
1148 |
-
$_post =
|
1149 |
|
1150 |
if ( isset( $_post['order_id'] ) && isset( $_post['source'] ) ) {
|
1151 |
$this->save_conversion_pixels_fired_status( $_post['order_id'], $_post['source'] );
|
@@ -1158,12 +1190,13 @@ class Pixel_Manager
|
|
1158 |
|
1159 |
public function save_conversion_pixels_fired_status( $order_id, $source = 'thankyou_page' )
|
1160 |
{
|
1161 |
-
update_post_meta( $order_id, '_wpm_conversion_pixel_trigger', $source );
|
1162 |
-
update_post_meta( $order_id, '_wpm_conversion_pixel_fired', true );
|
1163 |
-
// Get the time between when the order was created and now and save it in _wpm_conversion_pixel_fired_delay
|
1164 |
$order = wc_get_order( $order_id );
|
|
|
|
|
|
|
1165 |
$time_diff = time() - strtotime( $order->get_date_created() );
|
1166 |
-
|
|
|
1167 |
}
|
1168 |
|
1169 |
public function wpm_front_end_scripts()
|
4 |
|
5 |
use WCPM\Classes\Admin\Environment_Check ;
|
6 |
use WCPM\Classes\Admin\Validations ;
|
7 |
+
use WCPM\Classes\Helpers ;
|
8 |
use WCPM\Classes\Http\Facebook_CAPI ;
|
9 |
use WCPM\Classes\Http\Google_MP ;
|
10 |
use WCPM\Classes\Pixels\Facebook\Facebook_Microdata ;
|
28 |
protected $google_active ;
|
29 |
protected $google ;
|
30 |
protected $microdata_product_id ;
|
|
|
31 |
protected $order ;
|
32 |
+
protected $position = 1 ;
|
33 |
+
protected $rest_namespace = 'pmw/v1' ;
|
34 |
+
protected $gads_conversion_adjustments_route = '/google-ads/conversion-adjustments.csv' ;
|
35 |
private static $instance ;
|
36 |
public static function get_instance()
|
37 |
{
|
170 |
return $this->order;
|
171 |
}
|
172 |
|
173 |
+
public function get_google_ads_conversion_adjustments_endpoint()
|
174 |
+
{
|
175 |
+
return '/wp-json/' . $this->rest_namespace . $this->gads_conversion_adjustments_route;
|
176 |
+
}
|
177 |
+
|
178 |
// https://wordpress.stackexchange.com/a/377954/68337
|
179 |
public function prepare_custom_rest_handlers(
|
180 |
$served,
|
187 |
// error log $request->get_route();
|
188 |
// error_log($request->get_route());
|
189 |
// If $request->get_route() is not /pmw/v1/google-ads/conversion-adjustments then return $served
|
190 |
+
if ( strpos( $request->get_route(), $this->rest_namespace . $this->gads_conversion_adjustments_route ) === false ) {
|
191 |
return $served;
|
192 |
}
|
193 |
// if (strpos($request->get_route(), '/google-ads/conversion-adjustments/') !== 0) {
|
194 |
// return $served;
|
195 |
// }
|
|
|
196 |
// Send headers.
|
197 |
// $server->send_header( 'Content-Type', 'text/xml' );
|
198 |
// $server->send_header( 'Content-Type', 'application/xml' );
|
200 |
// $server->send_header('Content-Type', 'text/html');
|
201 |
// Echo the XML that's returned by smg_feed().
|
202 |
// Turn off phpcs because we're echoing the XML.
|
203 |
+
esc_html_e( $result->get_data() );
|
|
|
204 |
// And then exit.
|
205 |
exit;
|
206 |
}
|
207 |
|
208 |
public function register_rest_routes()
|
209 |
{
|
210 |
+
register_rest_route( $this->rest_namespace, '/test/', [
|
211 |
'methods' => 'POST',
|
212 |
'callback' => function () {
|
213 |
wp_send_json_success();
|
216 |
return true;
|
217 |
},
|
218 |
] );
|
219 |
+
register_rest_route( $this->rest_namespace, '/test/', [
|
220 |
'methods' => 'GET',
|
221 |
'callback' => function () {
|
222 |
wp_send_json_success();
|
225 |
return true;
|
226 |
},
|
227 |
] );
|
228 |
+
register_rest_route( $this->rest_namespace, '/settings/', [
|
229 |
'methods' => 'POST',
|
230 |
'callback' => [ $this, 'wpm_save_imported_settings' ],
|
231 |
'permission_callback' => function () {
|
232 |
return current_user_can( 'manage_options' );
|
233 |
},
|
234 |
] );
|
235 |
+
register_rest_route( $this->rest_namespace, '/products/', [
|
236 |
'methods' => 'POST',
|
237 |
'callback' => function ( $request ) {
|
238 |
$product_ids = $request->get_json_params();
|
239 |
+
$product_ids = Helpers::generic_sanitization( $product_ids );
|
240 |
|
241 |
if ( !$product_ids ) {
|
242 |
wp_send_json_error( 'No product ids provided' );
|
249 |
return true;
|
250 |
},
|
251 |
] );
|
252 |
+
register_rest_route( $this->rest_namespace, '/pixels-fired/', [
|
253 |
'methods' => 'POST',
|
254 |
'callback' => function ( $request ) {
|
255 |
$data = $request->get_json_params();
|
291 |
'Adjusted Value Currency'
|
292 |
];
|
293 |
$csv = implode( ',', $title_row ) . PHP_EOL;
|
294 |
+
$date_before = gmdate( 'Y-m-d H:i:s', strtotime( '-2 days' ) );
|
295 |
+
$date_after = gmdate( 'Y-m-d H:i:s', strtotime( '-4 days' ) );
|
296 |
+
/**
|
297 |
+
* Get all cancelled orders that were cancelled within the last 2 and 4 days
|
298 |
+
* and retract them
|
299 |
+
*/
|
300 |
+
$orders = wc_get_orders( [
|
301 |
+
'limit' => -1,
|
302 |
+
'status' => 'cancelled',
|
303 |
+
'date_modified' => $date_after . '...' . $date_before,
|
304 |
+
] );
|
305 |
+
foreach ( $orders as $order ) {
|
306 |
+
// Get the order ID
|
307 |
+
$order_id = $order->get_id();
|
308 |
+
// Get the modified date
|
309 |
+
$adjustment_time = $order->get_date_modified();
|
310 |
+
$adjustment_time = $adjustment_time->format( 'Y-m-d H:i:s' ) . ' ' . $timezone;
|
311 |
+
// Set adjustment type
|
312 |
+
$adjustment_type = 'RETRACT';
|
313 |
+
$adjusted_value = null;
|
314 |
+
$adjusted_value_currency = null;
|
315 |
+
// Compile new row
|
316 |
+
$row = [
|
317 |
+
$order_id,
|
318 |
+
$conversion_name,
|
319 |
+
$adjustment_time,
|
320 |
+
$adjustment_type,
|
321 |
+
$adjusted_value,
|
322 |
+
$adjusted_value_currency
|
323 |
+
];
|
324 |
+
$csv .= implode( ',', $row ) . PHP_EOL;
|
325 |
+
}
|
326 |
+
/**
|
327 |
+
* Get all refunds from 2 up to 3 days ago
|
328 |
+
*/
|
329 |
$refunds = wc_get_orders( [
|
330 |
'type' => 'shop_order_refund',
|
331 |
'status' => 'completed',
|
332 |
+
'date_after' => $date_after,
|
333 |
+
'date_before' => $date_before,
|
334 |
] );
|
335 |
// error_log('refunds: ' . print_r($refunds, true));
|
336 |
foreach ( $refunds as $refund ) {
|
426 |
|
427 |
public function capture_ajax_server_to_server_event()
|
428 |
{
|
429 |
+
$_post = Helpers::get_input_vars( INPUT_POST );
|
430 |
$this->process_server_to_server_event( $_post['data'] );
|
431 |
wp_send_json_success();
|
432 |
}
|
443 |
{
|
444 |
$options = $request->get_params();
|
445 |
// Sanitize nested array $options
|
446 |
+
$options = Helpers::generic_sanitization( $options );
|
447 |
// Validate imported options
|
448 |
|
449 |
if ( Validations::validate_imported_options( $options ) ) {
|
485 |
|
486 |
public function wpm_woocommerce_new_order( $order_id )
|
487 |
{
|
488 |
+
$order = wc_get_order( $order_id );
|
489 |
/**
|
490 |
* All new orders should be marked as long WPM is active,
|
491 |
* so that we know we can process them later through WPM,
|
492 |
* and so that we know we should not touch orders that were
|
493 |
* placed before WPM was active.
|
494 |
*/
|
495 |
+
$order->add_meta_data( '_wpm_process_through_wpm', true, true );
|
|
|
|
|
|
|
|
|
|
|
496 |
/**
|
497 |
* Set a custom user ID on the order
|
498 |
* because WC sets 0 on all order created
|
502 |
if ( is_user_logged_in() ) {
|
503 |
$user_id = get_current_user_id();
|
504 |
}
|
505 |
+
$order->add_meta_data( '_wpm_customer_user', $user_id, true );
|
506 |
+
$order->save();
|
|
|
|
|
|
|
|
|
507 |
}
|
508 |
|
509 |
// Thanks to: https://gist.github.com/mishterk/6b7a4d6e5a91086a5a9b05ace304b5ce#file-mark-wordpress-scripts-as-async-or-defer-php
|
1142 |
|
1143 |
public function ajax_pmw_get_product_ids()
|
1144 |
{
|
1145 |
+
$_post = Helpers::get_input_vars( INPUT_POST );
|
1146 |
$product_ids = explode( ',', $_post['productIds'] );
|
1147 |
|
1148 |
if ( !$product_ids ) {
|
1177 |
|
1178 |
public function ajax_purchase_pixels_fired_handler()
|
1179 |
{
|
1180 |
+
$_post = Helpers::get_input_vars( INPUT_POST );
|
1181 |
|
1182 |
if ( isset( $_post['order_id'] ) && isset( $_post['source'] ) ) {
|
1183 |
$this->save_conversion_pixels_fired_status( $_post['order_id'], $_post['source'] );
|
1190 |
|
1191 |
public function save_conversion_pixels_fired_status( $order_id, $source = 'thankyou_page' )
|
1192 |
{
|
|
|
|
|
|
|
1193 |
$order = wc_get_order( $order_id );
|
1194 |
+
$order->update_meta_data( '_wpm_conversion_pixel_trigger', $source );
|
1195 |
+
$order->update_meta_data( '_wpm_conversion_pixel_fired', true );
|
1196 |
+
// Get the time between when the order was created and now and save it in _wpm_conversion_pixel_fired_delay
|
1197 |
$time_diff = time() - strtotime( $order->get_date_created() );
|
1198 |
+
$order->update_meta_data( '_wpm_conversion_pixel_fired_delay', $time_diff );
|
1199 |
+
$order->save();
|
1200 |
}
|
1201 |
|
1202 |
public function wpm_front_end_scripts()
|
classes/pixels/facebook/class-facebook-pixel-manager.php
CHANGED
@@ -44,7 +44,7 @@ class Facebook_Pixel_Manager
|
|
44 |
add_action( 'woocommerce_subscription_status_cancelled', [ $this, 'facebook_capi_report_subscription_cancellation__premium_only' ] );
|
45 |
add_action(
|
46 |
'woocommerce_subscription_status_updated',
|
47 |
-
[ $this, '
|
48 |
10,
|
49 |
3
|
50 |
);
|
44 |
add_action( 'woocommerce_subscription_status_cancelled', [ $this, 'facebook_capi_report_subscription_cancellation__premium_only' ] );
|
45 |
add_action(
|
46 |
'woocommerce_subscription_status_updated',
|
47 |
+
[ $this, 'facebook_capi_report_subscription_update__premium_only' ],
|
48 |
10,
|
49 |
3
|
50 |
);
|
classes/pixels/google/class-google-pixel-manager.php
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
|
3 |
namespace WCPM\Classes\Pixels\Google;
|
4 |
|
|
|
5 |
use WCPM\Classes\Http\Google_MP_GA4 ;
|
6 |
use WCPM\Classes\Http\Google_MP_UA ;
|
7 |
use WCPM\Classes\Pixels\Script_Manager ;
|
@@ -47,7 +48,7 @@ class Google_Pixel_Manager
|
|
47 |
{
|
48 |
|
49 |
if ( is_user_logged_in() ) {
|
50 |
-
$user_info = get_user_by( 'id', $this->wpm_get_order_user_id( $order
|
51 |
if ( is_object( $user_info ) ) {
|
52 |
wc_get_logger()->debug( 'Prevented order ID ' . $order->get_id() . ' to be reported through the Measurement Protocol for user ' . $user_info->user_login . ' (roles: ' . implode( ', ', $user_info->roles ) . ')', [
|
53 |
'source' => 'wpm',
|
2 |
|
3 |
namespace WCPM\Classes\Pixels\Google;
|
4 |
|
5 |
+
use WCPM\Classes\Helpers ;
|
6 |
use WCPM\Classes\Http\Google_MP_GA4 ;
|
7 |
use WCPM\Classes\Http\Google_MP_UA ;
|
8 |
use WCPM\Classes\Pixels\Script_Manager ;
|
48 |
{
|
49 |
|
50 |
if ( is_user_logged_in() ) {
|
51 |
+
$user_info = get_user_by( 'id', $this->wpm_get_order_user_id( $order ) );
|
52 |
if ( is_object( $user_info ) ) {
|
53 |
wc_get_logger()->debug( 'Prevented order ID ' . $order->get_id() . ' to be reported through the Measurement Protocol for user ' . $user_info->user_login . ' (roles: ' . implode( ', ', $user_info->roles ) . ')', [
|
54 |
'source' => 'wpm',
|
classes/pixels/trait-shop.php
CHANGED
@@ -8,6 +8,7 @@ use libphonenumber\PhoneNumberUtil ;
|
|
8 |
use WC_Geolocation ;
|
9 |
use WCPM\Classes\Admin\Documentation ;
|
10 |
use WCPM\Classes\Admin\Environment_Check ;
|
|
|
11 |
use WCPM\Classes\Profit_Margin ;
|
12 |
|
13 |
if ( !defined( 'ABSPATH' ) ) {
|
@@ -84,7 +85,7 @@ trait Trait_Shop
|
|
84 |
|
85 |
protected function is_valid_order_key_in_url()
|
86 |
{
|
87 |
-
$_get =
|
88 |
$order_key = null;
|
89 |
// key is for WooCommerce
|
90 |
// wcf-key is for CartFlows
|
@@ -160,7 +161,7 @@ trait Trait_Shop
|
|
160 |
|
161 |
protected function get_order_with_url_order_key()
|
162 |
{
|
163 |
-
$_get =
|
164 |
// key is for WooCommerce
|
165 |
// wcf-key is for CartFlows
|
166 |
|
@@ -409,11 +410,11 @@ trait Trait_Shop
|
|
409 |
return wp_specialchars_decode( $title );
|
410 |
}
|
411 |
|
412 |
-
protected function is_backend_manual_order( $
|
413 |
{
|
414 |
// Only continue if this is a back-end order
|
415 |
|
416 |
-
if (
|
417 |
return true;
|
418 |
} else {
|
419 |
return false;
|
@@ -421,11 +422,11 @@ trait Trait_Shop
|
|
421 |
|
422 |
}
|
423 |
|
424 |
-
protected function is_backend_subscription_renewal_order( $
|
425 |
{
|
426 |
// Only continue if this is a back-end order
|
427 |
|
428 |
-
if (
|
429 |
return true;
|
430 |
} else {
|
431 |
return false;
|
@@ -433,10 +434,10 @@ trait Trait_Shop
|
|
433 |
|
434 |
}
|
435 |
|
436 |
-
protected function was_order_created_while_wpm_was_active( $
|
437 |
{
|
438 |
|
439 |
-
if (
|
440 |
return true;
|
441 |
} else {
|
442 |
return false;
|
@@ -444,10 +445,10 @@ trait Trait_Shop
|
|
444 |
|
445 |
}
|
446 |
|
447 |
-
protected function was_order_created_while_wpm_premium_was_active( $
|
448 |
{
|
449 |
|
450 |
-
if (
|
451 |
return true;
|
452 |
} else {
|
453 |
return false;
|
@@ -455,20 +456,20 @@ trait Trait_Shop
|
|
455 |
|
456 |
}
|
457 |
|
458 |
-
protected function wpm_get_order_user_id( $
|
459 |
{
|
460 |
|
461 |
-
if (
|
462 |
-
return (int)
|
463 |
} else {
|
464 |
-
return (int)
|
465 |
}
|
466 |
|
467 |
}
|
468 |
|
469 |
protected function is_browser_on_shop()
|
470 |
{
|
471 |
-
$_server =
|
472 |
// error_log(print_r($_server, true));
|
473 |
// error_log(print_r($_server['HTTP_HOST'], true));
|
474 |
// error_log('get_site_url(): ' . parse_url(get_site_url(), PHP_URL_HOST));
|
@@ -544,7 +545,7 @@ trait Trait_Shop
|
|
544 |
|
545 |
protected function is_nodedupe_parameter_set()
|
546 |
{
|
547 |
-
$_get =
|
548 |
|
549 |
if ( isset( $_get['nodedupe'] ) ) {
|
550 |
return true;
|
@@ -593,26 +594,6 @@ trait Trait_Shop
|
|
593 |
return filter_var( $email, FILTER_VALIDATE_EMAIL );
|
594 |
}
|
595 |
|
596 |
-
protected function get_input_vars( $type )
|
597 |
-
{
|
598 |
-
$input_vars = filter_input_array( $type, FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
599 |
-
return $this->generic_sanitization( $input_vars );
|
600 |
-
}
|
601 |
-
|
602 |
-
protected function generic_sanitization( $input )
|
603 |
-
{
|
604 |
-
|
605 |
-
if ( is_array( $input ) ) {
|
606 |
-
array_walk_recursive( $input, function ( &$value, $key ) {
|
607 |
-
$value = filter_var( $value, FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
608 |
-
} );
|
609 |
-
} else {
|
610 |
-
$input = filter_var( $input, FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
611 |
-
}
|
612 |
-
|
613 |
-
return $input;
|
614 |
-
}
|
615 |
-
|
616 |
private function get_percentage( $counter, $denominator )
|
617 |
{
|
618 |
return ( $denominator > 0 ? round( $counter / $denominator * 100 ) : 0 );
|
8 |
use WC_Geolocation ;
|
9 |
use WCPM\Classes\Admin\Documentation ;
|
10 |
use WCPM\Classes\Admin\Environment_Check ;
|
11 |
+
use WCPM\Classes\Helpers ;
|
12 |
use WCPM\Classes\Profit_Margin ;
|
13 |
|
14 |
if ( !defined( 'ABSPATH' ) ) {
|
85 |
|
86 |
protected function is_valid_order_key_in_url()
|
87 |
{
|
88 |
+
$_get = Helpers::get_input_vars( INPUT_GET );
|
89 |
$order_key = null;
|
90 |
// key is for WooCommerce
|
91 |
// wcf-key is for CartFlows
|
161 |
|
162 |
protected function get_order_with_url_order_key()
|
163 |
{
|
164 |
+
$_get = Helpers::get_input_vars( INPUT_GET );
|
165 |
// key is for WooCommerce
|
166 |
// wcf-key is for CartFlows
|
167 |
|
410 |
return wp_specialchars_decode( $title );
|
411 |
}
|
412 |
|
413 |
+
protected function is_backend_manual_order( $order )
|
414 |
{
|
415 |
// Only continue if this is a back-end order
|
416 |
|
417 |
+
if ( $order->meta_exists( '_created_via' ) && 'admin' === $order->get_meta( '_created_via', true ) ) {
|
418 |
return true;
|
419 |
} else {
|
420 |
return false;
|
422 |
|
423 |
}
|
424 |
|
425 |
+
protected function is_backend_subscription_renewal_order( $order )
|
426 |
{
|
427 |
// Only continue if this is a back-end order
|
428 |
|
429 |
+
if ( $order->meta_exists( '_created_via' ) && 'subscription' === $order->get_meta( '_created_via', true ) ) {
|
430 |
return true;
|
431 |
} else {
|
432 |
return false;
|
434 |
|
435 |
}
|
436 |
|
437 |
+
protected function was_order_created_while_wpm_was_active( $order )
|
438 |
{
|
439 |
|
440 |
+
if ( $order->meta_exists( '_wpm_process_through_wpm' ) ) {
|
441 |
return true;
|
442 |
} else {
|
443 |
return false;
|
445 |
|
446 |
}
|
447 |
|
448 |
+
protected function was_order_created_while_wpm_premium_was_active( $order )
|
449 |
{
|
450 |
|
451 |
+
if ( $order->meta_exists( '_wpm_premium_active' ) ) {
|
452 |
return true;
|
453 |
} else {
|
454 |
return false;
|
456 |
|
457 |
}
|
458 |
|
459 |
+
protected function wpm_get_order_user_id( $order )
|
460 |
{
|
461 |
|
462 |
+
if ( $order->meta_exists( '_wpm_customer_user' ) ) {
|
463 |
+
return (int) $order->get_meta( '_wpm_customer_user', true );
|
464 |
} else {
|
465 |
+
return (int) $order->get_meta( '_customer_user', true );
|
466 |
}
|
467 |
|
468 |
}
|
469 |
|
470 |
protected function is_browser_on_shop()
|
471 |
{
|
472 |
+
$_server = Helpers::get_input_vars( INPUT_SERVER );
|
473 |
// error_log(print_r($_server, true));
|
474 |
// error_log(print_r($_server['HTTP_HOST'], true));
|
475 |
// error_log('get_site_url(): ' . parse_url(get_site_url(), PHP_URL_HOST));
|
545 |
|
546 |
protected function is_nodedupe_parameter_set()
|
547 |
{
|
548 |
+
$_get = Helpers::get_input_vars( INPUT_GET );
|
549 |
|
550 |
if ( isset( $_get['nodedupe'] ) ) {
|
551 |
return true;
|
594 |
return filter_var( $email, FILTER_VALIDATE_EMAIL );
|
595 |
}
|
596 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
597 |
private function get_percentage( $counter, $denominator )
|
598 |
{
|
599 |
return ( $denominator > 0 ? round( $counter / $denominator * 100 ) : 0 );
|
readme.txt
CHANGED
@@ -4,7 +4,7 @@ Tags: woocommerce, google analytics, google ads, facebook, conversion tracking,
|
|
4 |
Requires at least: 3.7
|
5 |
Tested up to: 6.0
|
6 |
Requires PHP: 7.3
|
7 |
-
Stable tag: 1.
|
8 |
License: GPLv3 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
10 |
|
@@ -86,6 +86,7 @@ Have a look at the full feature list over [here](https://sweetcode.com/docs/wpm/
|
|
86 |
<strong>Premium Features</strong>
|
87 |
|
88 |
* [Automatic Conversion Recovery (ACR)](https://sweetcode.com/docs/wpm/features/acr?utm_source=wordpress.org&utm_medium=wpm-plugin-page&utm_campaign=pixel-manager-for-woocommerce-docs&utm_content=acr)
|
|
|
89 |
* Meta CAPI (Facebook CAPI)
|
90 |
* Meta Microdata Output (Facebook Microdata Output)
|
91 |
* Google Analytics Universal and Google Analytics 4 Enhanced E-Commerce
|
@@ -214,11 +215,19 @@ You can send the link to the front page of your shop too if you think it would b
|
|
214 |
|
215 |
== Changelog ==
|
216 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
= 1.23.0 = 30.09.2022
|
218 |
|
219 |
|
220 |
|
221 |
-
* Tweak: Few styling fixes
|
222 |
|
223 |
= 1.22.1 = 26.09.2022
|
224 |
|
4 |
Requires at least: 3.7
|
5 |
Tested up to: 6.0
|
6 |
Requires PHP: 7.3
|
7 |
+
Stable tag: 1.24.0
|
8 |
License: GPLv3 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
10 |
|
86 |
<strong>Premium Features</strong>
|
87 |
|
88 |
* [Automatic Conversion Recovery (ACR)](https://sweetcode.com/docs/wpm/features/acr?utm_source=wordpress.org&utm_medium=wpm-plugin-page&utm_campaign=pixel-manager-for-woocommerce-docs&utm_content=acr)
|
89 |
+
* Google Ads Conversion Adjustments
|
90 |
* Meta CAPI (Facebook CAPI)
|
91 |
* Meta Microdata Output (Facebook Microdata Output)
|
92 |
* Google Analytics Universal and Google Analytics 4 Enhanced E-Commerce
|
215 |
|
216 |
== Changelog ==
|
217 |
|
218 |
+
= 1.24.0 = 06.10.2022
|
219 |
+
|
220 |
+
* New: The Pixel Manager has been refactored to be ready for the upcoming WooCommerce High Performance Orders Storage
|
221 |
+
* Tweak: Some UI improvements
|
222 |
+
* Tweak: Added GAds Conversion Adjustments feed URL to debug info
|
223 |
+
* Tweak: Refactor for HPOS
|
224 |
+
|
225 |
+
|
226 |
= 1.23.0 = 30.09.2022
|
227 |
|
228 |
|
229 |
|
230 |
+
* Tweak: Few styling fixes in the settings page.
|
231 |
|
232 |
= 1.22.1 = 26.09.2022
|
233 |
|
wgact.php
CHANGED
@@ -10,16 +10,16 @@
|
|
10 |
* Developer URI: https://sweetcode.com
|
11 |
* Text Domain: woocommerce-google-adwords-conversion-tracking-tag
|
12 |
* Domain path: /languages
|
13 |
-
* * Version: 1.
|
14 |
*
|
15 |
* WC requires at least: 3.7
|
16 |
-
* WC tested up to: 6.
|
17 |
*
|
18 |
* License: GNU General Public License v3.0
|
19 |
* License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
20 |
*
|
21 |
**/
|
22 |
-
const WPM_CURRENT_VERSION = '1.
|
23 |
// TODO add option checkbox on uninstall and ask if user wants to delete options from db
|
24 |
|
25 |
if ( !defined( 'ABSPATH' ) ) {
|
@@ -35,6 +35,7 @@ use WCPM\Classes\Admin\Order_Columns ;
|
|
35 |
use WCPM\Classes\Db_Upgrade ;
|
36 |
use WCPM\Classes\Default_Options ;
|
37 |
use WCPM\Classes\Deprecated_Filters ;
|
|
|
38 |
use WCPM\Classes\Pixels\Pixel_Manager ;
|
39 |
use WCPM\Classes\Admin\Ask_For_Rating ;
|
40 |
|
@@ -119,7 +120,7 @@ if ( function_exists( 'wpm_fs' ) ) {
|
|
119 |
define( 'WPM_DB_OPTIONS_NAME', 'wgact_plugin_options' );
|
120 |
define( 'WPM_DB_NOTIFICATIONS_NAME', 'wgact_notifications' );
|
121 |
define( 'WPM_PLUGIN_DIR_PATH', plugin_dir_url( __FILE__ ) );
|
122 |
-
define( '
|
123 |
define( 'WPM_DB_RATINGS', 'wgact_ratings' );
|
124 |
require_once dirname( __FILE__ ) . '/vendor/woocommerce/action-scheduler/action-scheduler.php';
|
125 |
// check if WooCommerce is running
|
@@ -154,6 +155,12 @@ if ( function_exists( 'wpm_fs' ) ) {
|
|
154 |
} );
|
155 |
|
156 |
if ( $this->is_woocommerce_active() ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
157 |
add_action( 'woocommerce_init', [ $this, 'init' ] );
|
158 |
add_action(
|
159 |
'init',
|
10 |
* Developer URI: https://sweetcode.com
|
11 |
* Text Domain: woocommerce-google-adwords-conversion-tracking-tag
|
12 |
* Domain path: /languages
|
13 |
+
* * Version: 1.24.0
|
14 |
*
|
15 |
* WC requires at least: 3.7
|
16 |
+
* WC tested up to: 6.9
|
17 |
*
|
18 |
* License: GNU General Public License v3.0
|
19 |
* License URI: http://www.gnu.org/licenses/gpl-3.0.html
|
20 |
*
|
21 |
**/
|
22 |
+
const WPM_CURRENT_VERSION = '1.24.0' ;
|
23 |
// TODO add option checkbox on uninstall and ask if user wants to delete options from db
|
24 |
|
25 |
if ( !defined( 'ABSPATH' ) ) {
|
35 |
use WCPM\Classes\Db_Upgrade ;
|
36 |
use WCPM\Classes\Default_Options ;
|
37 |
use WCPM\Classes\Deprecated_Filters ;
|
38 |
+
use WCPM\Classes\Helpers ;
|
39 |
use WCPM\Classes\Pixels\Pixel_Manager ;
|
40 |
use WCPM\Classes\Admin\Ask_For_Rating ;
|
41 |
|
120 |
define( 'WPM_DB_OPTIONS_NAME', 'wgact_plugin_options' );
|
121 |
define( 'WPM_DB_NOTIFICATIONS_NAME', 'wgact_notifications' );
|
122 |
define( 'WPM_PLUGIN_DIR_PATH', plugin_dir_url( __FILE__ ) );
|
123 |
+
define( 'WPM_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
|
124 |
define( 'WPM_DB_RATINGS', 'wgact_ratings' );
|
125 |
require_once dirname( __FILE__ ) . '/vendor/woocommerce/action-scheduler/action-scheduler.php';
|
126 |
// check if WooCommerce is running
|
155 |
} );
|
156 |
|
157 |
if ( $this->is_woocommerce_active() ) {
|
158 |
+
add_action( 'before_woocommerce_init', function () {
|
159 |
+
if ( Helpers::is_wc_hpos_enabled() && class_exists( 'Automattic\\WooCommerce\\Utilities\\FeaturesUtil' ) ) {
|
160 |
+
// TODO: https://app.asana.com/0/1110999795232049/1203086190142026
|
161 |
+
\Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', WPM_PLUGIN_BASENAME, true );
|
162 |
+
}
|
163 |
+
} );
|
164 |
add_action( 'woocommerce_init', [ $this, 'init' ] );
|
165 |
add_action(
|
166 |
'init',
|