class-wc-payments-subscriptions-onboarding-handler.php
9.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
<?php
/**
* Class WC_Payments_Subscriptions_Onboarding_Handler
*
* @package WooCommerce\Payments
*/
defined( 'ABSPATH' ) || exit;
use WCPay\Tracker;
/**
* A class to handle the onboarding of subscriptions products. Created subscription products will be set to draft until
* onboarding is completed.
*/
class WC_Payments_Subscriptions_Onboarding_Handler {
use WC_Payments_Subscriptions_Utilities;
/**
* Option for holding an array of product id's to publish post onboarding.
*
* @const string
*/
const WCPAY_SUBSCRIPTION_AUTO_PUBLISH_PRODUCTS = 'wcpay_subscription_onboarding_products';
/**
* The account service instance.
*
* @var WC_Payments_Account
*/
private $account;
/**
* Constructor
*
* @param WC_Payments_Account $account account service instance.
*/
public function __construct( WC_Payments_Account $account ) {
// This action is triggered on product save but after other required subscriptions logic is triggered.
add_action( 'woocommerce_admin_process_product_object', [ $this, 'product_save' ] );
add_action( 'woocommerce_payments_account_refreshed', [ $this, 'account_data_refreshed' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_modal_scripts_and_styles' ] );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_toast_script' ] );
add_filter( 'woocommerce_subscriptions_admin_pointer_script_parameters', [ $this, 'filter_admin_pointer_script_parameters' ] );
$this->account = $account;
}
/**
* Sets the account service instance reference on the class.
*
* @param WC_Payments_Account $account account service instance.
*/
public function set_account( WC_Payments_Account $account ) {
$this->account = $account;
}
/**
* Convert subscriptions to drafts when using WCPay (without subscriptions) and onboarding is not complete.
* This should be triggered just prior to a $product->save() call so no need to call product->save()
*
* @param WC_Product $product Subscriptions Product.
*/
public function product_save( WC_Product $product ) {
if ( $this->account->is_stripe_connected() ) {
return;
}
// If Subscriptions plugin is installed we don't need to do this check.
if ( $this->is_subscriptions_plugin_active() ) {
return;
}
// Skip products which have already been scheduled or aren't subscriptions.
if ( ! WC_Subscriptions_Product::is_subscription( $product ) ) {
return;
}
// We can skip if the post is not yet marked as published.
if ( 'publish' !== $product->get_status() ) {
return;
}
// Change the default WP saved post URL to correctly reflect the draft status and to add our saved-as-draft flag.
add_filter(
'redirect_post_location',
function() use ( $product ) {
return add_query_arg(
[
'message' => 10, // Post saved as draft message.
'wcpay-subscription-saved-as-draft' => 1,
],
get_edit_post_link( $product->get_id(), 'url' )
);
}
);
$this->convert_subscription_to_draft( $product );
}
/**
* Convert a product to a draft and save the id in an array, so we can auto-publish once onboarding is complete.
*
* @param WC_Product $product Product to convert to draft.
*/
private function convert_subscription_to_draft( WC_Product $product ) {
// Force into draft status.
$product->set_status( 'draft' );
$product->save();
$auto_publish_ids = get_option( self::WCPAY_SUBSCRIPTION_AUTO_PUBLISH_PRODUCTS, [] );
$auto_publish_ids[] = $product->get_id();
// Save and prevent duplicates from multiple updates.
update_option( self::WCPAY_SUBSCRIPTION_AUTO_PUBLISH_PRODUCTS, array_unique( $auto_publish_ids ) );
Tracker::track_admin( 'wcpay_subscriptions_account_not_connected_save_product' );
}
/**
* Method to handle when account data is refreshed and onboarding may have been completed
*/
public function account_data_refreshed() {
if ( ! $this->account->is_stripe_connected() ) {
return;
}
$products = get_option( self::WCPAY_SUBSCRIPTION_AUTO_PUBLISH_PRODUCTS, [] );
if ( [] === $products ) {
return;
}
foreach ( $products as $product_id ) {
$product = wc_get_product( $product_id );
if ( ! $product || ! WC_Subscriptions_Product::is_subscription( $product ) ) {
continue;
}
if ( 'draft' !== $product->get_status() ) {
continue;
}
$product->set_status( 'publish' );
$product->save();
}
// clear auto-published products from option.
delete_option( self::WCPAY_SUBSCRIPTION_AUTO_PUBLISH_PRODUCTS );
}
/**
* Enqueues the admin scripts needed on the add/edit product screen when the
* merchant attempts to publish a subscription product prior to completing
* WCPay onboarding.
*
* @param string $hook_suffix The current admin page.
*/
public function enqueue_modal_scripts_and_styles( $hook_suffix ) {
global $post;
if ( ! in_array( $hook_suffix, [ 'post.php', 'post-new.php' ], true ) ) {
return;
}
if ( ! $post || 'product' !== $post->post_type ) {
return;
}
if ( empty( $_GET['wcpay-subscription-saved-as-draft'] ) || 1 !== (int) $_GET['wcpay-subscription-saved-as-draft'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
if ( $this->is_subscriptions_plugin_active() ) {
return;
}
if ( $this->account->is_stripe_connected() ) {
return;
}
$script_src_url = plugins_url( 'dist/subscription-product-onboarding-modal.js', WCPAY_PLUGIN_FILE );
$script_asset_path = WCPAY_ABSPATH . 'dist/subscription-product-onboarding-modal.asset.php';
$script_asset = file_exists( $script_asset_path ) ? require $script_asset_path : [ 'dependencies' => [] ];
wp_register_script(
'wcpay-subscription-product-onboarding-modal',
$script_src_url,
$script_asset['dependencies'],
WC_Payments::get_file_version( 'dist/subscription-product-onboarding-modal.js' ),
true
);
wp_localize_script(
'wcpay-subscription-product-onboarding-modal',
'wcpaySubscriptionProductOnboardingModal',
[
'connectUrl' => WC_Payments_Account::get_connect_url( 'WC_SUBSCRIPTIONS_PUBLISH_PRODUCT_' . $post->ID ),
'pluginScope' => ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '6.5', '>=' ) ) ? 'woocommerce-admin' : 'woocommerce',
]
);
wp_register_style(
'wcpay-subscription-product-onboarding-modal',
plugins_url( 'dist/subscription-product-onboarding-modal.css', WCPAY_PLUGIN_FILE ),
[],
WC_Payments::get_file_version( 'dist/subscription-product-onboarding-modal.css' )
);
wp_enqueue_script( 'wcpay-subscription-product-onboarding-modal' );
wp_enqueue_style( 'wcpay-subscription-product-onboarding-modal' );
}
/**
* Enqueues the admin scripts needed on the add/edit product screen when the
* merchant has completed WCPay onboarding and is redirected back to product
* edit page.
*
* @param string $hook_suffix The current admin page.
*/
public function enqueue_toast_script( $hook_suffix ) {
global $post;
if ( ! in_array( $hook_suffix, [ 'post.php', 'post-new.php' ], true ) ) {
return;
}
if ( ! $post || 'product' !== $post->post_type ) {
return;
}
if ( empty( $_GET['wcpay-subscriptions-onboarded'] ) || 1 !== (int) $_GET['wcpay-subscriptions-onboarded'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
if ( $this->is_subscriptions_plugin_active() ) {
return;
}
$script_src_url = plugins_url( 'dist/subscription-product-onboarding-toast.js', WCPAY_PLUGIN_FILE );
$script_asset_path = WCPAY_ABSPATH . 'dist/subscription-product-onboarding-toast.asset.php';
$script_asset = file_exists( $script_asset_path ) ? require $script_asset_path : [ 'dependencies' => [] ];
wp_register_script(
'wcpay-subscription-product-onboarding-toast',
$script_src_url,
$script_asset['dependencies'],
WC_Payments::get_file_version( 'dist/subscription-product-onboarding-toast.js' ),
true
);
wp_localize_script(
'wcpay-subscription-product-onboarding-toast',
'wcpaySubscriptionProductOnboardingToast',
[
'pluginScope' => ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '6.5', '>=' ) ) ? 'woocommerce-admin' : 'woocommerce',
]
);
wp_enqueue_script( 'wcpay-subscription-product-onboarding-toast' );
}
/**
* Modifies the pointer content found on the "Add new product" page
* when WooCommerce Subscriptions is not active.
*
* @param array $pointer_params Array of strings used on the "Add new product" page.
* @return array Potentially modified array of strings used on the "Add new product" page.
*/
public function filter_admin_pointer_script_parameters( $pointer_params ) {
if ( $this->is_subscriptions_plugin_active() ) {
return $pointer_params;
}
// translators: %1$s: <h3> tag, %2$s: </h3> tag, %3$s: <p> tag, %4$s: <em> tag, %5$s: </em> tag, %6$s: <em> tag, %7$s: </em> tag, %8$s: </p> tag.
$pointer_params['typePointerContent'] = sprintf( _x( '%1$sChoose Subscription%2$s%3$sWooCommerce Payments adds two new subscription product types - %4$sSimple subscription%5$s and %6$sVariable subscription%7$s.%8$s', 'used in admin pointer script params in javascript as type pointer content', 'woocommerce-payments' ), '<h3>', '</h3>', '<p>', '<em>', '</em>', '<em>', '</em>', '</p>' );
return $pointer_params;
}
}