Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/trunk' into feat/epic-ia-trunk-r…
Browse files Browse the repository at this point in the history
…asacc
  • Loading branch information
jaredrethman committed Dec 9, 2024
2 parents 61c9e15 + f2c8502 commit 1ff052b
Show file tree
Hide file tree
Showing 25 changed files with 928 additions and 24 deletions.
28 changes: 28 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,31 @@
# [5.9.0](https://github.com/Automattic/newspack-plugin/compare/v5.8.2...v5.9.0) (2024-12-09)


### Bug Fixes

* **emails:** account for false order value ([#3590](https://github.com/Automattic/newspack-plugin/issues/3590)) ([a2e4042](https://github.com/Automattic/newspack-plugin/commit/a2e404287c7bdeba44689b1a98df9644322d4a71))
* **ras-acc:** correct My Account custom font sizing clash ([#3588](https://github.com/Automattic/newspack-plugin/issues/3588)) ([080f1ce](https://github.com/Automattic/newspack-plugin/commit/080f1ce9e3ac102bdc475b1e5fac4016d48dee2a))
* **ras-acc:** make helper text size more specific ([#3584](https://github.com/Automattic/newspack-plugin/issues/3584)) ([5bcc688](https://github.com/Automattic/newspack-plugin/commit/5bcc68812937ea979b9d28a08ca95e71fb19a341))
* **ras-acc:** re-add recaptcha to the WooCommerce checkout ([#3605](https://github.com/Automattic/newspack-plugin/issues/3605)) ([07f46b3](https://github.com/Automattic/newspack-plugin/commit/07f46b3bfd7581a6e1e05490e1b2df06677ae59e))
* undefined var ([#3585](https://github.com/Automattic/newspack-plugin/issues/3585)) ([00d8bc7](https://github.com/Automattic/newspack-plugin/commit/00d8bc7f4db78602e948a4ba7dfe5dad2b606672))
* **woocommerce-emails:** use the default email payload if there are no donation products ([#3545](https://github.com/Automattic/newspack-plugin/issues/3545)) ([60c21f3](https://github.com/Automattic/newspack-plugin/commit/60c21f31641a9bbc906d4cc4319fa7d418f8fdf1))


### Features

* mark perfmatters as a required plugin ([#3578](https://github.com/Automattic/newspack-plugin/issues/3578)) ([f20291c](https://github.com/Automattic/newspack-plugin/commit/f20291c7899e99c5d52b8663a10a8e57b7ff1029))
* **ras-acc:** add reader account creation and login improvements ([#3582](https://github.com/Automattic/newspack-plugin/issues/3582)) ([b66de08](https://github.com/Automattic/newspack-plugin/commit/b66de08dcf0a901063577c715257d7ffecd9908d))
* **reader-data:** add a CLI command to align reader membership data ([#3548](https://github.com/Automattic/newspack-plugin/issues/3548)) ([8e49bf0](https://github.com/Automattic/newspack-plugin/commit/8e49bf0a2c9e74958f80de13a52b5fa720e87949))
* **subscriptions:** add setting to reattempt payment after final retry ([#3560](https://github.com/Automattic/newspack-plugin/issues/3560)) ([553c3ac](https://github.com/Automattic/newspack-plugin/commit/553c3ac4327691b3f1826a7de6e3bd5f3d335ccf))
* **woocommerce:** remove internal metadata from REST API response ([6b659a6](https://github.com/Automattic/newspack-plugin/commit/6b659a6afb38d235cf36e116a655352523a09725))

## [5.8.2](https://github.com/Automattic/newspack-plugin/compare/v5.8.1...v5.8.2) (2024-12-09)


### Bug Fixes

* **esp-sync:** schedule second sync upon subscription reactivation, just in case ([#3603](https://github.com/Automattic/newspack-plugin/issues/3603)) ([9334295](https://github.com/Automattic/newspack-plugin/commit/93342955db2f70afa9feac6eb8fa349f3703fd72))

## [5.8.1](https://github.com/Automattic/newspack-plugin/compare/v5.8.0...v5.8.1) (2024-11-26)


Expand Down
70 changes: 70 additions & 0 deletions includes/class-recaptcha.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ public static function init() {
\add_action( 'rest_api_init', [ __CLASS__, 'register_api_endpoints' ] );
\add_action( 'wp_enqueue_scripts', [ __CLASS__, 'register_scripts' ] );

// Add reCAPTCHA to the Woo checkout form.
\add_action( 'woocommerce_review_order_before_submit', [ __CLASS__, 'add_recaptcha_v2_to_checkout' ] );
\add_action( 'woocommerce_checkout_after_customer_details', [ __CLASS__, 'add_recaptcha_v3_to_checkout' ] );

// Verify reCAPTCHA on checkout submission.
\add_action( 'woocommerce_checkout_process', [ __CLASS__, 'verify_recaptcha_on_checkout' ] );
}
Expand Down Expand Up @@ -435,6 +439,72 @@ public static function verify_captcha() {
return true;
}

/**
* Render a container for the reCAPTCHA v2 checkbox widget.
*/
public static function render_recaptcha_v2_container() {
if ( ! self::can_use_captcha( 'v2' ) || ( method_exists( 'Newspack_Blocks\Modal_Checkout', 'is_modal_checkout' ) && \Newspack_Blocks\Modal_Checkout::is_modal_checkout() ) ) {
return;
}
?>
<div id="<?php echo \esc_attr( 'newspack-recaptcha-' . uniqid() ); ?>" class="grecaptcha-container"></div>
<?php
}

/**
* Add reCAPTCHA v2 to Woo checkout.
*/
public static function add_recaptcha_v2_to_checkout() {
self::render_recaptcha_v2_container();
}

/**
* Add reCAPTCHA v3 to Woo checkout.
*/
public static function add_recaptcha_v3_to_checkout() {
if ( ! self::can_use_captcha( 'v3' ) || ( method_exists( 'Newspack_Blocks\Modal_Checkout', 'is_modal_checkout' ) && \Newspack_Blocks\Modal_Checkout::is_modal_checkout() ) ) {
return;
}
$site_key = self::get_site_key();
?>
<script src="<?php echo \esc_url( self::get_script_url() ); ?>"></script>
<script>
grecaptcha.ready( function() {
var field;
function refreshToken() {
grecaptcha.execute(
'<?php echo \esc_attr( $site_key ); ?>',
{ action: 'checkout' }
).then( function( token ) {
if ( field ) {
field.value = token;
}
} );
}
setInterval( refreshToken, 30000 );
( function( $ ) {
if ( ! $ ) { return; }
$( document ).on( 'updated_checkout', refreshToken );
$( document.body ).on( 'checkout_error', refreshToken );
} )( jQuery );
grecaptcha.execute(
'<?php echo \esc_attr( $site_key ); ?>',
{ action: 'checkout' }
).then( function( token ) {
field = document.createElement('input');
field.type = 'hidden';
field.name = 'g-recaptcha-response';
field.value = token;
var form = document.querySelector('form.checkout');
if ( form ) {
form.appendChild( field );
}
} );
} );
</script>
<?php
}

/**
* Verify reCAPTCHA on checkout submission.
*/
Expand Down
2 changes: 2 additions & 0 deletions includes/cli/class-initializer.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public static function init() {
include_once NEWSPACK_ABSPATH . 'includes/cli/class-ras.php';
include_once NEWSPACK_ABSPATH . 'includes/cli/class-ras-esp-sync.php';
include_once NEWSPACK_ABSPATH . 'includes/cli/class-co-authors-plus.php';
include_once NEWSPACK_ABSPATH . 'includes/cli/class-woocommerce-subscriptions.php';
}

/**
Expand Down Expand Up @@ -66,5 +67,6 @@ public static function register_comands() {
'schedule_author_term_backfill',
]
);
WP_CLI::add_command( 'newspack migrate-expired-subscriptions', [ 'Newspack\CLI\WooCommerce_Subscriptions', 'migrate_expired_subscriptions' ] );
}
}
8 changes: 7 additions & 1 deletion includes/cli/class-ras-esp-sync.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,15 @@ class RAS_ESP_Sync extends Reader_Activation\ESP_Sync {
* Log to WP CLI.
*
* @param string $message The message to log.
* @param array $data Optional. Additional data to log.
*/
protected static function log( $message ) {
protected static function log( $message, $data = [] ) {
WP_CLI::log( $message );
if ( ! empty( $data ) ) {
WP_CLI::log(
wp_json_encode( $data )
);
}
}

/**
Expand Down
184 changes: 184 additions & 0 deletions includes/cli/class-woocommerce-subscriptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<?php
/**
* WooCommerce Subscriptions Integration CLI commands.
*
* @package Newspack
*/

namespace Newspack\CLI;

use WP_CLI;
use Newspack\Woocommerce_Subscriptions as WooCommerce_Subscriptions_Integration;

defined( 'ABSPATH' ) || exit;

/**
* WooCommerce Subscriptions Integration CLI commands.
*/
class WooCommerce_Subscriptions {
/**
* Flag for live mode.
*
* @var bool
*/
private static $live = false;

/**
* Flag for verbose output.
*
* @var bool
*/
private static $verbose = false;

/**
* Subscription ids to process.
*
* @var bool|array
*/
private static $ids = false;

/**
* Migrate status of on-hold WooCommerce subscriptions that have failed all payment retries to expired.
*
* ## OPTIONS
*
* [--live]
* : Run the command in live mode, updating the subscriptions.
*
* [--verbose]
* : Produce more output.
*
* [--ids]
* : Comma-separated list of subscription IDs. If provided, only ubscriptions with these IDs will be processed.
*
* @param array $args Positional arguments.
* @param array $assoc_args Assoc arguments.
*
* @return void
*/
public function migrate_expired_subscriptions( $args, $assoc_args ) {
WP_CLI::line( '' );
if ( ! WooCommerce_Subscriptions_Integration::is_enabled() ) {
WP_CLI::error( 'WooCommerce Subscriptions Integration is not enabled.' );
WP_CLI::line( '' );
return;
}
self::$ids = isset( $assoc_args['ids'] ) ? explode( ',', $assoc_args['ids'] ) : false;
self::$live = isset( $assoc_args['live'] ) ? true : false;
self::$verbose = isset( $assoc_args['verbose'] ) ? true : false;
$updated = 0;
$page = 1;
$per_page = 25;
$subscriptions = self::get_subscriptions( $page );
if ( empty( $subscriptions ) ) {
WP_CLI::success( 'No on-hold subscriptions to process.' );
WP_CLI::line( '' );
return;
}
WP_CLI::line( 'Processing subscriptions in ' . ( self::$live ? 'live' : 'dry run' ) . ' mode...' );
WP_CLI::line( '' );
while ( ! empty( $subscriptions ) ) {
foreach ( $subscriptions as $subscription ) {
$id = $subscription->get_id();
if ( self::$verbose ) {
WP_CLI::line( 'Processing subscription ' . $id . '...' );
}
// A pending retry indicates the subscription is awaiting payment retry.
if ( $subscription->get_date( 'payment_retry' ) > 0 ) {
if ( self::$verbose ) {
WP_CLI::line( 'Subscription is awaiting payment retry. Moving to next subscription...' );
WP_CLI::line( '' );
}
continue;
}
$renewal_order = $subscription->get_last_order(
'all',
[ 'renewal' ],
[
'completed',
'processing',
'refunded',
]
);
// No failed or pending renewal orders indicates the subscription was likely manually placed on hold.
if ( empty( $renewal_order ) ) {
if ( self::$verbose ) {
WP_CLI::line( 'Subscription has no pending renewal orders. Moving to next subscription...' );
WP_CLI::line( '' );
}
continue;
}
$last_retry = \WCS_Retry_Manager::store()->get_last_retry_for_order( wcs_get_objects_property( $renewal_order, 'id' ) );
// No retries indicates the subscription was likely manually placed on hold.
if ( empty( $last_retry ) ) {
if ( self::$verbose ) {
WP_CLI::line( 'No retries scheduled. Moving to next subscription...' );
WP_CLI::line( '' );
}
continue;
}
// A non failed status indicates the retry was either manually cancelled
// or was successful at one point but likely placed on hold for some other reason.
if ( 'failed' !== $last_retry->get_status() ) {
if ( self::$verbose ) {
WP_CLI::line( 'Last retry does not have a failed status. Moving to next subscription...' );
WP_CLI::line( '' );
}
continue;
} else {
if ( self::$verbose ) {
WP_CLI::line( 'Updating subscription status to expired...' );
}
if ( self::$live ) {
$subscription->update_status( 'expired', __( 'Subscription status updated by Newspack CLI command.', 'newspack-plugin' ) );
$subscription->set_end_date( $last_retry->get_date() );
$subscription->save();
}
++$updated;
}
if ( self::$verbose ) {
WP_CLI::line( 'Finished processing subscription ' . $id );
WP_CLI::line( '' );
}
}
$subscriptions = self::get_subscriptions( ++$page );
}
WP_CLI::success( 'Finished processing subscriptions. ' . $updated . ' subscriptions updated.' );
if ( ! self::$live ) {
WP_CLI::warning( 'Dry run. Use --live flag to process live subscriptions.' );
}
WP_CLI::line( '' );
}

/**
* Get subscriptions to process.
*
* @param int $page Page number.
*
* @return array
*/
private static function get_subscriptions( $page = 1 ) {
$subscriptions = [];
if ( false !== self::$ids ) {
while ( ! empty( self::$ids ) ) {
$id = array_shift( self::$ids );
if ( ! is_numeric( $id ) ) {
continue;
}
$subscription = wcs_get_subscription( $id );
if ( $subscription ) {
$subscriptions[] = $subscription;
}
}
} else {
$subscriptions = wcs_get_subscriptions(
[
'paged' => $page,
'subscriptions_per_page' => 25,
'subscription_status' => 'on-hold',
]
);
}
return $subscriptions;
}
}
19 changes: 19 additions & 0 deletions includes/data-events/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,25 @@ When a non-donation subscription status changes, or when there's a subscription
| `user_id` | `int` |
| `email` | `string` |
| `subscription_id` | `int` |
| `product_ids` | `array` |
| `amount` | `float` |
| `currency` | `string` |
| `recurrence` | `string` |
| `status_before` | `string` |
| `status_after` | `string` |
| `user_first_name` | `string` |
| `user_last_name` | `string` |

### `subscription_renewal_attempt`

When a subscription of any type (donation or non-donation) renews, a renewal order gets created for it in Woo. This indicates a renewal attempt (at this point the order might still succeed or fail when collecting payment). We can trigger actions based on the renewal attempt, such as a scheduled contact sync to the ESP.

| Name | Type |
| ----------------- | -------- |
| `user_id` | `int` |
| `email` | `string` |
| `order_id` | `int` |
| `subscription_id` | `int` |
| `amount` | `float` |
| `currency` | `string` |
| `recurrence` | `string` |
Expand Down
Loading

0 comments on commit 1ff052b

Please sign in to comment.