🔀 Merge branch 'trunk'

This commit is contained in:
Philipp Stracker 2025-02-07 14:43:18 +01:00
commit 24ada2c2a5
No known key found for this signature in database
9 changed files with 221 additions and 116 deletions

View file

@ -7,6 +7,5 @@
export const STORE_NAME = 'wc/paypal/todos';
export const REST_PATH = '/wc/v3/wc_paypal/todos';
export const REST_PERSIST_PATH = '/wc/v3/wc_paypal/todos';
export const REST_RESET_DISMISSED_TODOS_PATH =
'/wc/v3/wc_paypal/reset-dismissed-todos';
export const REST_COMPLETE_ONCLICK_PATH = '/wc/v3/wc_paypal/complete-onclick';
export const REST_RESET_DISMISSED_TODOS_PATH = '/wc/v3/wc_paypal/todos/reset';
export const REST_COMPLETE_ONCLICK_PATH = '/wc/v3/wc_paypal/todos/complete';

View file

@ -313,10 +313,4 @@ return array(
$capabilities['google_pay'] && ! $gateways['google_pay'] // Enable Google Pay.
);
},
'settings.rest.reset_dismissed_todos' => static function( ContainerInterface $container ): ResetDismissedTodosEndpoint {
return new ResetDismissedTodosEndpoint();
},
'settings.rest.complete_onclick' => static function( ContainerInterface $container ): CompleteOnClickEndpoint {
return new CompleteOnClickEndpoint();
},
);

View file

@ -64,9 +64,8 @@ class TodosDefinition {
'action' => array(
'type' => 'tab',
'tab' => 'payment_methods',
'section' => 'ppcp-fastlane',
'modal' => 'ppcp-fastlane-gateway',
'highlight' => 'ppcp-fastlane-gateway',
'section' => 'ppcp-axo-gateway',
'highlight' => 'ppcp-axo-gateway',
),
),
'enable_credit_debit_cards' => array(

View file

@ -1,74 +1,93 @@
<?php
/**
* PayPal Commerce Todos Model
* Todos details class
*
* @package WooCommerce\PayPalCommerce\Settings\Data
*/
declare( strict_types = 1 );
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\Settings\Data;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
/**
* Class TodosModel
*
* Handles the storage and retrieval of task completion states in WordPress options table.
* Provides methods to get and update completion states with proper type casting.
* Handles todos data persistence and state management.
*/
class TodosModel {
/**
* WordPress option name for storing the completion states.
*
* @var string
*/
protected const OPTION_NAME = 'ppcp_todos';
class TodosModel extends AbstractDataModel {
/**
* Retrieves the formatted completion states from WordPress options.
*
* Loads the raw completion states from wp_options table and formats them into a
* standardized array structure with proper type casting.
*
* @return array The formatted completion states array.
* Option key for WordPress storage.
*/
public function get() : array {
$completion_states = get_option( self::OPTION_NAME, array() );
protected const OPTION_KEY = 'ppcp-settings';
return array_map(
/**
* Ensures the task completion states are boolean values.
*
* @param mixed $state value to sanitize, as stored in the DB.
*/
static fn( $state ) => (bool) $state,
$completion_states
/**
* Returns the default structure for settings data.
*
* @return array
*/
protected function get_defaults(): array {
return array(
'dismissedTodos' => array(),
'completedOnClickTodos' => array(),
);
}
/**
* Updates the completion states in WordPress options.
* Gets the dismissed todos.
*
* Converts the provided data array and saves it to wp_options table.
* Throws an exception if update fails.
*
* @param array $states Array of task IDs and their completion states.
* @return void
* @throws RuntimeException When the completion states update fails.
* @return array
*/
public function update( array $states ) : void {
$completion_states = array_map(
static function ( $state ) {
return (bool) $state;
},
$states
public function get_dismissed_todos(): array {
return $this->data['dismissedTodos'] ?? array();
}
/**
* Gets the completed onclick todos.
*
* @return array
*/
public function get_completed_onclick_todos(): array {
return $this->data['completedOnClickTodos'] ?? array();
}
/**
* Updates dismissed todos.
*
* @param array $todo_ids Array of todo IDs to mark as dismissed.
*/
public function update_dismissed_todos( array $todo_ids ): void {
$this->data['dismissedTodos'] = array_unique( $todo_ids );
$this->save();
}
/**
* Updates completed onclick todos.
*
* @param array $todo_ids Array of todo IDs to mark as completed.
*/
public function update_completed_onclick_todos( array $todo_ids ): void {
$this->data['completedOnClickTodos'] = array_unique( $todo_ids );
$this->save();
}
/**
* Resets dismissed todos.
*/
public function reset_dismissed_todos(): void {
$this->data['dismissedTodos'] = array();
$this->save();
}
/**
* Gets current todos data including dismissed and completed states.
*
* @return array The todos data array.
*/
public function get_todos_data(): array {
return array(
'dismissedTodos' => $this->get_dismissed_todos(),
'completedOnClickTodos' => $this->get_completed_onclick_todos(),
);
$result = update_option( self::OPTION_NAME, $completion_states );
if ( ! $result ) {
throw new RuntimeException( 'Failed to update todo completion states' );
}
}
}

View file

@ -21,6 +21,7 @@ namespace WooCommerce\PayPalCommerce\Settings\Endpoint;
use WP_REST_Server;
use WP_REST_Response;
use WP_REST_Request;
use WooCommerce\PayPalCommerce\Settings\Data\TodosModel;
/**
* Class CompleteOnClickEndpoint
@ -36,6 +37,22 @@ class CompleteOnClickEndpoint extends RestEndpoint {
*/
protected $rest_base = 'complete-onclick';
/**
* The todos model instance.
*
* @var TodosModel
*/
protected TodosModel $todos;
/**
* Constructor.
*
* @param TodosModel $todos The todos model instance.
*/
public function __construct( TodosModel $todos ) {
$this->todos = $todos;
}
/**
* Registers the routes for the complete-onclick endpoint.
*
@ -71,26 +88,22 @@ class CompleteOnClickEndpoint extends RestEndpoint {
return $this->return_error( __( 'Todo ID is required.', 'woocommerce-paypal-payments' ) );
}
$settings = get_option( 'ppcp-settings', array() );
try {
$todos_data = $this->todos->get_todos_data();
$completed_todos = $todos_data['completedOnClickTodos'];
if ( ! isset( $settings['completedOnClickTodos'] ) ) {
$settings['completedOnClickTodos'] = array();
}
if ( ! in_array( $todo_id, $settings['completedOnClickTodos'], true ) ) {
$settings['completedOnClickTodos'][] = $todo_id;
$update_result = update_option( 'ppcp-settings', $settings );
if ( ! $update_result ) {
return $this->return_error( __( 'Failed to mark todo as completed on click.', 'woocommerce-paypal-payments' ) );
if ( ! in_array( $todo_id, $completed_todos, true ) ) {
$this->todos->update_completed_onclick_todos( array_merge( $completed_todos, array( $todo_id ) ) );
}
}
return $this->return_success(
array(
'message' => __( 'Todo marked as completed on click successfully.', 'woocommerce-paypal-payments' ),
'todoId' => $todo_id,
)
);
return $this->return_success(
array(
'message' => __( 'Todo marked as completed on click successfully.', 'woocommerce-paypal-payments' ),
'todoId' => $todo_id,
)
);
} catch ( \Exception $e ) {
return $this->return_error( __( 'Failed to mark todo as completed on click.', 'woocommerce-paypal-payments' ) );
}
}
}

View file

@ -15,6 +15,7 @@ namespace WooCommerce\PayPalCommerce\Settings\Endpoint;
use WP_REST_Server;
use WP_REST_Response;
use WP_REST_Request;
use WooCommerce\PayPalCommerce\Settings\Data\TodosModel;
/**
* Class ResetDismissedTodosEndpoint
@ -29,6 +30,22 @@ class ResetDismissedTodosEndpoint extends RestEndpoint {
*/
protected $rest_base = 'reset-dismissed-todos';
/**
* The todos model instance.
*
* @var TodosModel
*/
protected TodosModel $todos;
/**
* Constructor.
*
* @param TodosModel $todos The todos model instance.
*/
public function __construct( TodosModel $todos ) {
$this->todos = $todos;
}
/**
* Registers the REST API route for resetting todos.
*/
@ -54,23 +71,18 @@ class ResetDismissedTodosEndpoint extends RestEndpoint {
* @return WP_REST_Response The response containing reset status.
*/
public function reset_dismissed_todos( WP_REST_Request $request ): WP_REST_Response {
$settings = get_option( 'ppcp-settings', array() );
try {
$this->todos->reset_dismissed_todos();
$settings['dismissedTodos'] = array();
// Clear the completedOnClickTodos for testing purposes.
// $settings['completedOnClickTodos'] = array();.
$update_result = update_option( 'ppcp-settings', $settings );
if ( ! $update_result ) {
return $this->return_error( __( 'Failed to reset dismissed todos.', 'woocommerce-paypal-payments' ) );
return $this->return_success(
array(
'message' => __( 'Dismissed todos reset successfully.', 'woocommerce-paypal-payments' ),
)
);
} catch ( \Exception $e ) {
return $this->return_error(
__( 'Failed to reset dismissed todos.', 'woocommerce-paypal-payments' )
);
}
return $this->return_success(
array(
'message' => __( 'Dismissed todos reset successfully.', 'woocommerce-paypal-payments' ),
)
);
}
}

View file

@ -2,7 +2,7 @@
/**
* REST endpoint to manage the things to do items.
*
* Provides endpoints for retrieving, updating, and resetting todos
* Provides endpoints for retrieving, updating, completing, resetting, and managing todos
* via WP REST API routes.
*
* @package WooCommerce\PayPalCommerce\Settings\Endpoint
@ -75,10 +75,7 @@ class TodosRestEndpoint extends RestEndpoint {
* Registers the REST API routes for todos management.
*/
public function register_routes(): void {
/**
* GET wc/v3/wc_paypal/todos
* POST wc/v3/wc_paypal/todos
*/
// GET/POST /todos - Get todos list and update dismissed todos.
register_rest_route(
$this->namespace,
'/' . $this->rest_base,
@ -95,6 +92,28 @@ class TodosRestEndpoint extends RestEndpoint {
),
)
);
// POST /todos/reset - Reset dismissed todos.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/reset',
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'reset_dismissed_todos' ),
'permission_callback' => array( $this, 'check_permission' ),
)
);
// POST /todos/complete - Mark todo as completed on click.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/complete',
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'complete_onclick' ),
'permission_callback' => array( $this, 'check_permission' ),
)
);
}
/**
@ -103,9 +122,9 @@ class TodosRestEndpoint extends RestEndpoint {
* @return WP_REST_Response The response containing todos data.
*/
public function get_todos(): WP_REST_Response {
$settings = get_option( 'ppcp-settings', array() );
$dismissed_ids = $settings['dismissedTodos'] ?? array();
$completed_onclick_ids = $settings['completedOnClickTodos'] ?? array();
$todos_data = $this->todos->get_todos_data();
$dismissed_ids = $todos_data['dismissedTodos'];
$completed_onclick_ids = $todos_data['completedOnClickTodos'];
$todos = array();
foreach ( $this->todos_definition->get() as $id => $todo ) {
@ -143,21 +162,73 @@ class TodosRestEndpoint extends RestEndpoint {
* @return WP_REST_Response The response containing updated todos or error details.
*/
public function update_todos( WP_REST_Request $request ): WP_REST_Response {
$data = $request->get_json_params();
$settings = get_option( 'ppcp-settings', array() );
$data = $request->get_json_params();
if ( isset( $data['dismissedTodos'] ) ) {
$settings['dismissedTodos'] = array_unique(
is_array( $data['dismissedTodos'] ) ? $data['dismissedTodos'] : array()
);
try {
$dismissed_todos = is_array( $data['dismissedTodos'] ) ? $data['dismissedTodos'] : array();
$this->todos->update_dismissed_todos( $dismissed_todos );
$update_result = update_option( 'ppcp-settings', $settings );
if ( $update_result ) {
return $this->return_success( $settings );
return $this->return_success( $this->todos->get_todos_data() );
} catch ( \Exception $e ) {
return $this->return_error( $e->getMessage() );
}
}
return $this->return_success( $data );
}
/**
* Handles the completion of a todo item via click.
*
* @param WP_REST_Request $request The request instance.
* @return WP_REST_Response The response containing completion status.
*/
public function complete_onclick( WP_REST_Request $request ): WP_REST_Response {
$todo_id = $request->get_param( 'todoId' );
if ( ! $todo_id ) {
return $this->return_error( __( 'Todo ID is required.', 'woocommerce-paypal-payments' ) );
}
try {
$todos_data = $this->todos->get_todos_data();
$completed_todos = $todos_data['completedOnClickTodos'];
if ( ! in_array( $todo_id, $completed_todos, true ) ) {
$this->todos->update_completed_onclick_todos( array_merge( $completed_todos, array( $todo_id ) ) );
}
return $this->return_success(
array(
'message' => __( 'Todo marked as completed on click successfully.', 'woocommerce-paypal-payments' ),
'todoId' => $todo_id,
)
);
} catch ( \Exception $e ) {
return $this->return_error( __( 'Failed to mark todo as completed on click.', 'woocommerce-paypal-payments' ) );
}
}
/**
* Resets all dismissed todos.
*
* @param WP_REST_Request $request The request instance.
* @return WP_REST_Response The response containing reset status.
*/
public function reset_dismissed_todos( WP_REST_Request $request ): WP_REST_Response {
try {
$this->todos->reset_dismissed_todos();
return $this->return_success(
array(
'message' => __( 'Dismissed todos reset successfully.', 'woocommerce-paypal-payments' ),
)
);
} catch ( \Exception $e ) {
return $this->return_error(
__( 'Failed to reset dismissed todos.', 'woocommerce-paypal-payments' )
);
}
}
}

View file

@ -162,10 +162,10 @@ class TodosEligibilityService {
*/
public function get_eligibility_checks(): array {
return array(
'enable_fastlane' => fn() => ! $this->is_fastlane_eligible,
'enable_fastlane' => fn() => $this->is_fastlane_eligible,
'enable_credit_debit_cards' => fn() => $this->is_card_payment_eligible,
'enable_pay_later_messaging' => fn() => ! $this->is_pay_later_messaging_eligible,
'add_pay_later_messaging' => fn() => $this->is_pay_later_messaging_eligible && ! $this->is_pay_later_messaging_ui_eligible,
'enable_pay_later_messaging' => fn() => $this->is_pay_later_messaging_eligible,
'add_pay_later_messaging' => fn() => $this->is_pay_later_messaging_eligible,
'configure_paypal_subscription' => fn() => $this->is_subscription_eligible,
'add_paypal_buttons' => fn() => $this->is_paypal_buttons_eligible,
'register_domain_apple_pay' => fn() => $this->is_apple_pay_domain_eligible,

View file

@ -239,9 +239,7 @@ class SettingsModule implements ServiceModule, ExecutableModule {
'settings' => $container->get( 'settings.rest.settings' ),
'styling' => $container->get( 'settings.rest.styling' ),
'todos' => $container->get( 'settings.rest.todos' ),
'reset_dismissed_todos' => $container->get( 'settings.rest.reset_dismissed_todos' ),
'pay_later_messaging' => $container->get( 'settings.rest.pay_later_messaging' ),
'complete_onclick' => $container->get( 'settings.rest.complete_onclick' ),
);
foreach ( $endpoints as $endpoint ) {