Commit 688eaf8e authored by Michael Iseard's avatar Michael Iseard
Browse files

Rework settings page and asset loading

parent 65c74d43
......@@ -6,4 +6,11 @@
- https://blog.cloudflare.com/using-the-cloudflare-api-to-report-spam-on-yo/
- Make Kudos form a separate block
- Integrate diagnostics with Site Health
- https://kinsta.com/blog/wordpress-5-8/#block-api-enhancements
\ No newline at end of file
- https://kinsta.com/blog/wordpress-5-8/#block-api-enhancements
- Deprecated settings
- _kudos_return_message_enable
- _kudos_custom_return_enable
- Remove files
- CustomReturnPanel.jsx
\ No newline at end of file
......@@ -265,6 +265,28 @@ class Admin {
$this->table->prepare_items();
}
/**
* Register assets for enqueuing in the block editor.
*/
public function register_block_editor_assets() {
wp_register_style(
'kudos-donations-public',
Assets::get_asset_url( '/public/kudos-public.css' ),
[],
$this->version
);
$editor_js = Assets::get_script( '/blocks/kudos-button/index.js' );
wp_register_script(
'kudos-donations-editor',
$editor_js['url'],
$editor_js['dependencies'],
$editor_js['version'],
true
);
}
/**
* Assets specific to the Settings page.
*/
......@@ -309,7 +331,7 @@ class Admin {
*/
private function table_page_assets(): string {
$handle = $this->plugin_name . '-table';
$handle = $this->plugin_name . '-table';
$table_js = Assets::get_script( '/admin/kudos-admin-table.js' );
wp_enqueue_script(
......
......@@ -116,7 +116,7 @@ class Front {
*
* @return string
*/
public function get_kudos_root_styles(): string {
public function get_root_styles(): string {
$theme_colours = apply_filters( 'kudos_theme_colors', Settings::get_setting( 'theme_colors' ) );
......@@ -128,30 +128,28 @@ class Front {
$secondary_darker = Utils::color_luminance( $secondary, '-0.09' );
return "
:root {
--kudos-theme-primary: $primary;
--kudos-theme-primary-dark: $primary_dark;
--kudos-theme-primary-darker: $primary_darker;
--kudos-theme-secondary: $secondary;
--kudos-theme-secondary-dark: $secondary_dark;
--kudos-theme-secondary-darker: $secondary_darker;
}
:root {
--kudos-theme-primary: $primary;
--kudos-theme-primary-dark: $primary_dark;
--kudos-theme-primary-darker: $primary_darker;
--kudos-theme-secondary: $secondary;
--kudos-theme-secondary-dark: $secondary_dark;
--kudos-theme-secondary-darker: $secondary_darker;
}
";
}
/**
* Register the JavaScript for the public-facing side of the plugin.
* This is necessary in order to localize the script with variables.
*/
public function enqueue_scripts() {
public function register_scripts() {
$handle = $this->plugin_name . '-public';
$public_js = Assets::get_script( '/public/kudos-public.js' );
wp_enqueue_script(
$handle,
wp_register_script(
'kudos-donations-public',
$public_js['url'],
$public_js['dependencies'],
$public_js['version'],
......@@ -159,7 +157,7 @@ class Front {
);
wp_localize_script(
$handle,
'kudos-donations-public',
'kudos',
[
'_wpnonce' => wp_create_nonce( 'wp_rest' ),
......@@ -167,7 +165,21 @@ class Front {
]
);
wp_set_script_translations( $handle, 'kudos-donations', KUDOS_PLUGIN_DIR . '/languages' );
wp_set_script_translations( 'kudos-donations-public', 'kudos-donations', KUDOS_PLUGIN_DIR . '/languages' );
}
/**
* Register the public facing styles.
*/
public function register_styles() {
wp_register_style(
'kudos-donations-public',
Assets::get_asset_url( '/public/kudos-public.css' ),
[],
$this->version
);
}
......@@ -177,34 +189,46 @@ class Front {
public function enqueue_root_styles() {
// Output root styles.
if ( function_exists( 'register_block_style' ) ) {
register_block_style(
'iseardmedia/kudos-button',
[
'name' => 'kudos-button',
'label' => __( 'Kudos Button', 'kudos-donations' ),
'is_default' => true,
'inline_style' => $this->get_kudos_root_styles(),
]
);
}
// Failsafe.
echo "<style>";
echo $this->get_kudos_root_styles();
echo "</style>";
register_block_style(
'iseardmedia/kudos-button',
[
'name' => 'kudos-button',
'label' => __( 'Kudos Button', 'kudos-donations' ),
'is_default' => true,
'inline_style' => $this->get_root_styles(),
]
);
}
/**
* Creates and registers the [kudos] shortcode and block.
* Registers the button shortcode and block.
*/
public function register_kudos() {
// Add shortcode.
$this->enqueue_root_styles();
$this->register_button_block();
// If setting is not enabled the shortcode assets and registration will be skipped.
if(Settings::get_setting('enable_shortcode')) {
$this->register_button_shortcode();
}
}
/**
* Register the kudos button shortcode.
*/
private function register_button_shortcode() {
// Enqueue necessary resources.
add_action('wp_enqueue_scripts', function () {
wp_enqueue_script('kudos-donations-public');
wp_enqueue_style('kudos-donations-public');
});
// Register actual shortcode.
add_shortcode(
'kudos',
function ( $atts ) {
$atts = shortcode_atts(
[
'button_label' => __( 'Donate now', 'kudos-donations' ),
......@@ -215,15 +239,62 @@ class Front {
$atts,
'kudos'
);
return $this->kudos_render_callback( $atts );
}
);
}
/**
* Register the Kudos button block.
*/
private function register_button_block() {
// Register kudos button block.
register_block_type_from_metadata( KUDOS_PLUGIN_DIR . '/dist/blocks/kudos-button/',
register_block_type( 'iseardmedia/kudos-button',
[
'render_callback' => [ $this, 'kudos_render_callback' ],
"render_callback" => [ $this, "kudos_render_callback" ],
"category" => "widgets",
"title" => "Kudos Button",
"description" => "Adds a Kudos donate button or form to your post or page.",
"keywords" => [
"kudos",
"button",
"donate",
],
"supports" => [
"align" => true,
"customClassName" => true,
"typography" => [
"fontSize" => false,
],
],
"example" => [
"attributes" => [
"label" => "Donate now!",
"alignment" => "center",
],
],
"attributes" => [
"button_label" => [
"type" => "string",
"default" => "Donate now",
],
"campaign_id" => [
"type" => "string",
"default" => "default",
],
"alignment" => [
"type" => "string",
"default" => "none",
],
"type" => [
"type" => "string",
"default" => "button",
],
],
"editor_script" => "kudos-donations-editor",
"editor_style" => "kudos-donations-public",
"script" => "kudos-donations-public",
"style" => "kudos-donations-public",
] );
}
......@@ -253,7 +324,6 @@ class Front {
// Create the form based on campaign id.
$form = $this->create_form( $atts['campaign_id'], $id );
// If type is form then stop and return form.
if ( isset( $atts['type'] ) && $atts['type'] === 'form' ) {
return $this->render_wrapper( $form, $alignment );
......@@ -361,7 +431,6 @@ class Front {
// Add additional funds if any.
if ( ! empty( $campaign['additional_funds'] ) ) {
$atts['campaign_stats']['total'] += $campaign['additional_funds'];
}
......
......@@ -189,6 +189,11 @@ class Settings {
'default' => null,
'sanitize_callback' => 'esc_url_raw',
],
'completed_payment' => [
'type' => 'string',
'default' => 'message',
'show_in_rest' => true,
],
'return_message_enable' => [
'type' => 'boolean',
'show_in_rest' => true,
......@@ -232,6 +237,12 @@ class Settings {
'default' => false,
'sanitize_callback' => 'rest_sanitize_boolean',
],
'enable_shortcode' => [
'type' => 'boolean',
'show_in_rest' => true,
'default' => true,
'sanitize_callback' => 'rest_sanitize_boolean',
],
'donate_modal_in_footer' => [
'type' => 'boolean',
'show_in_rest' => true,
......
......@@ -11,7 +11,7 @@ class Utils {
*/
public static function get_return_url(): string {
$use_custom = get_option( '_kudos_custom_return_enable' );
$use_custom = get_option( '_kudos_completed_payment' ) === 'url';
$custom_url = esc_url( get_option( '_kudos_custom_return_url' ) );
if ( $use_custom && $custom_url ) {
......
......@@ -56,14 +56,14 @@ class KudosDonations {
*/
public function __construct( $container, $version, $plugin_name ) {
$this->container = $container;
$this->version = $version;
$this->container = $container;
$this->version = $version;
$this->plugin_name = $plugin_name;
}
/**
* Run the loader to execute all of the hooks with WordPress.
* Run the loader to execute all the hooks with WordPress.
*/
public function run() {
......@@ -77,7 +77,7 @@ class KudosDonations {
}
/**
* Register all of the hooks related to the admin area functionality
* Register all the hooks related to the admin area functionality
* of the plugin.
*
* @access private
......@@ -88,15 +88,15 @@ class KudosDonations {
add_action( 'admin_menu', [ $plugin_admin, 'add_menu_pages' ], 11 );
add_action( 'admin_init', [ $plugin_admin, 'admin_actions' ] );
add_action( 'admin_init', [ $plugin_admin, 'register_settings' ] );
add_action( 'rest_api_init', [ $plugin_admin, 'register_settings' ] );
add_action( 'kudos_remove_secret_action', [ $plugin_admin, 'remove_secret_action' ], 10, 2 );
add_action( 'kudos_check_log', [$plugin_admin, 'clear_log'] );
add_action( 'kudos_check_log', [ $plugin_admin, 'clear_log' ] );
add_action( 'enqueue_block_editor_assets', [ $plugin_admin, 'register_block_editor_assets' ] );
}
/**
* Register all of the hooks related to the public-facing functionality
* Register all the hooks related to the public-facing functionality
* of the plugin.
*
* @access private
......@@ -105,8 +105,8 @@ class KudosDonations {
$plugin_public = $this->container->get( 'Front' );
add_action( 'wp_enqueue_scripts', [ $plugin_public, 'enqueue_scripts' ] );
add_action( 'enqueue_block_assets', [ $plugin_public, 'enqueue_root_styles' ] );
add_action( 'wp_enqueue_scripts', [ $plugin_public, 'register_scripts' ] );
add_action( 'wp_enqueue_scripts', [ $plugin_public, 'register_styles' ] );
add_action( 'init', [ $plugin_public, 'register_kudos' ] );
add_action( 'wp_footer', [ $plugin_public, 'handle_query_variables' ], 1000 );
......@@ -168,7 +168,7 @@ class KudosDonations {
if ( $db_version !== KUDOS_VERSION ) {
$this->container->get( 'ActivatorService' )
->activate( $db_version );
->activate( $db_version );
}
}
......
......@@ -43,7 +43,7 @@ class PaymentService {
) {
$vendor = $this::get_current_vendor_class();
$this->vendor = new $vendor($mapper_service, $logger_service);
$this->vendor = new $vendor( $mapper_service, $logger_service );
$this->mapper_service = $mapper_service;
$this->mailer_service = $mailer_service;
$this->logger = $logger_service;
......@@ -81,7 +81,7 @@ class PaymentService {
}
/**
* Check the vendor api key key associated with the mode. Sends a JSON response.
* Check the vendor api key associated with the mode. Sends a JSON response.
*/
public function check_api_keys() {
......@@ -132,12 +132,6 @@ class PaymentService {
*/
public function process_transaction( string $order_id ): bool {
// Bail if no order ID.
if ( null === $order_id ) {
return false;
}
$mapper = $this->mapper_service;
$mailer = $this->mailer_service;
// Get transaction.
......@@ -149,8 +143,8 @@ class PaymentService {
// Get donor.
/** @var DonorEntity $donor */
$donor = $this->mapper_service
->get_repository(DonorEntity::class)
->get_one_by([ 'customer_id' => $transaction->customer_id ]);
->get_repository( DonorEntity::class )
->get_one_by( [ 'customer_id' => $transaction->customer_id ] );
if ( $donor->email ) {
// Send email - email setting is checked in mailer.
......@@ -180,7 +174,7 @@ class PaymentService {
$values = $request->get_json_params();
// Check if bot filling form.
if($this->is_bot($values)) {
if ( $this->is_bot( $values ) ) {
wp_send_json_error( [ 'message' => __( 'Request invalid.', 'kudos-donations' ) ] );
}
......@@ -209,10 +203,10 @@ class PaymentService {
// Search for existing donor based on email and mode.
/** @var DonorEntity $donor */
$donor = $mapper->get_repository( DonorEntity::class )
->get_one_by( [
'email' => $email,
'mode' => $this->vendor->get_api_mode(),
] );
->get_one_by( [
'email' => $email,
'mode' => $this->vendor->get_api_mode(),
] );
// Create new donor if none found.
if ( empty( $donor->customer_id ) ) {
......@@ -281,7 +275,7 @@ class PaymentService {
// Get subscription entity from supplied row id.
/** @var SubscriptionEntity $subscription */
$subscription = $mapper
->get_repository(SubscriptionEntity::class)
->get_repository( SubscriptionEntity::class )
->get_one_by( [ 'id' => $id ] );
// Cancel subscription with vendor.
......@@ -398,7 +392,7 @@ class PaymentService {
$mapper->save( $transaction );
// Add order id query arg to return url if option to show message enabled.
if ( get_option( '_kudos_return_message_enable' ) ) {
if ( get_option( '_kudos_completed_payment' ) === 'message' ) {
$redirect_url = add_query_arg(
[
'kudos_action' => 'order_complete',
......@@ -428,24 +422,26 @@ class PaymentService {
*
* @return bool
*/
public function is_bot($values): bool {
public function is_bot( $values ): bool {
$timeDiff = abs($values['timestamp'] - time());
$timeDiff = abs( $values['timestamp'] - time() );
// Check if form completed too quickly.
if($timeDiff < 4) {
if ( $timeDiff < 4 ) {
$this->logger->info( 'Bot detected, rejecting form.', [
'reason' => 'Form completed too quickly',
'time_taken' => $timeDiff
'reason' => 'Form completed too quickly',
'time_taken' => $timeDiff,
] );
return true;
}
// Check if honeypot field completed.
if ( ! empty( $values['donation'] ) ) {
$this->logger->info( 'Bot detected, rejecting form.', array_merge(['reason' => 'Honeypot field completed'], $values) );
$this->logger->info( 'Bot detected, rejecting form.',
array_merge( [ 'reason' => 'Honeypot field completed' ], $values ) );
return true;
}
return false;
}
......
......@@ -54,11 +54,15 @@ class MollieVendor implements VendorInterface {
* @var \Kudos\Service\MapperService
*/
private $mapper;
/**
* @var array
*/
private $api_keys;
/**
* Mollie constructor.
*/
public function __construct(MapperService $mapper_service, LoggerService $logger_service) {
public function __construct( MapperService $mapper_service, LoggerService $logger_service ) {
$this->logger = $logger_service;
$this->mapper = $mapper_service;
......@@ -66,8 +70,12 @@ class MollieVendor implements VendorInterface {
$settings = Settings::get_setting( 'vendor_mollie' );
$this->api_client = new MollieApiClient();
$this->api_mode = $settings['mode'] ?? '';
$this->api_key = $settings[ $this->api_mode . '_key' ] ?? '';
$this->api_mode = $settings['mode'] ?? '';
$this->api_key = $settings[ $this->api_mode . '_key' ] ?? '';
$this->api_keys = [
'test' => $settings['test_key'] ?? '',
'live' => $settings['live_key'] ?? '',
];
if ( $this->api_key ) {
try {
......@@ -83,7 +91,7 @@ class MollieVendor implements VendorInterface {
}
/**
* Check the Mollie api key key associated with the mode. Sends a JSON response.
* Check the Mollie api keys for both test and live keys. Sends a JSON response.
*/
public function check_api_keys() {
......@@ -93,65 +101,57 @@ class MollieVendor implements VendorInterface {
'recurring' => false,
] );
$mode = $this->api_mode;
$api_key = $this->api_key;
$modes = [ "test", "live" ];
$api_keys = $this->api_keys;
// Check that the api key corresponds to the mode.
if ( substr( $api_key, 0, 4 ) !== $mode ) {
wp_send_json_error(
[
/* translators: %s: API mode */
'message' => sprintf( __( '%1$s API key should begin with %2$s', 'kudos-donations' ),
ucfirst( $mode ),
$mode . '_' ),
'setting' => Settings::get_setting( 'vendor_mollie' ),
]
);
}
// Test the api key.
$result = $this->refresh_api_connection( $api_key );
// Check that the api key corresponds to each mode.
foreach ( $modes as $mode ) {
$api_key = $api_keys[ $mode ];
if ( substr( $api_key, 0, 5 ) !== $mode . "_" ) {
wp_send_json_error(
[
/* translators: %s: API mode */
'message' => sprintf( __( '%1$s API key should begin with %2$s', 'kudos-donations' ),
ucfirst( $mode ),
$mode . '_' ),
'setting' => Settings::get_setting( 'vendor_mollie' ),
]
);
}
// Update settings.
// Test the api key.
if ( ! $this->refresh_api_connection( $api_key ) ) {
wp_send_json_error(
[
/* translators: %s: API mode */
'message' => sprintf( __( 'Error connecting with Mollie, please check the %s API key and try again.',
'kudos-donations' ),
ucfirst( $mode ) ),
'setting' => Settings::get_setting( 'vendor_mollie' ),
]
);
}
}
// Update vendor settings.
Settings::update_array( 'vendor_mollie',
[
'connected' => $result,
'recurring' => $this->can_use_recurring(),
'connected' => true,
'payment_methods' => array_map( function ( $method ) {
return [
'id' => $method->id,
'status' => $method->status,
'maximumAmount' => (array) $method->maximumAmount,
];
},
(array) $this->get_payment_methods() ),
] );
// Send result as JSON response.
if ( $result ) {
// Update vendor settings.
Settings::update_array( 'vendor_mollie',
[
'recurring' => $this->can_use_recurring(),
'payment_methods' => array_map( function ( $method ) {
return [
'id' => $method->id,
'status' => $method->status,
'maximumAmount' => (array) $method->maximumAmount,
];
},
(array) $this->get_payment_methods() ),
] );
wp_send_json_success(
[
'message' =>