Skip to content

Commit

Permalink
Merge branch 'develop' into feature/donation-summary-hook-store
Browse files Browse the repository at this point in the history
  • Loading branch information
jonwaldstein authored Dec 23, 2024
2 parents b1fa053 + 76d4f29 commit 5af8277
Show file tree
Hide file tree
Showing 15 changed files with 144 additions and 79 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# Bin files
/bin/*
!/bin/.gitkeep
!/bin/strauss-installar.sh

# Numerous always-ignore extensions
.diff
Expand Down
Empty file removed bin/.gitkeep
Empty file.
41 changes: 41 additions & 0 deletions bin/strauss-installar.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/bin/bash

# Function to get the installed version of strauss
get_installed_version() {
local version_output
version_output=$(php ./bin/strauss.phar --version)
echo "$version_output" | sed -n -e 's/^.*strauss //p'
}

# Function to check if the latest release version is not installed
is_update_needed() {
local latest_release=$1
local current_version

if [[ ! -f ./bin/strauss.phar ]]; then
return 0
fi

current_version=$(get_installed_version)
[[ "$current_version" != "$latest_release" ]]
}

# Function to download and install the latest release
download_and_install() {
local latest_release=$1
rm -f ./bin/strauss.phar
curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/"$latest_release"/strauss.phar
echo "$latest_release" > ./bin/strauss-version.txt
}

# Main script execution
main() {
local latest_release
latest_release="0.20.1" # strauss release version
if is_update_needed "$latest_release"; then
echo "Updating strauss to $latest_release ..."
download_and_install "$latest_release"
fi
}

main
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,10 @@
"test": "./vendor/bin/phpunit --colors --stop-on-failure",
"unreleased": "./vendor/bin/since-unreleased.sh",
"strauss": [
"test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.14.0/strauss.phar",
"bin/strauss-installar.sh",
"vendor/stellarwp/validation/bin/set-domain domain=give",
"@php bin/strauss.phar"
"@php bin/strauss.phar",
"@composer dump-autoload"
],
"post-install-cmd": [
"@strauss",
Expand Down
4 changes: 2 additions & 2 deletions give.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* Description: The most robust, flexible, and intuitive way to accept donations on WordPress.
* Author: GiveWP
* Author URI: https://givewp.com/
* Version: 3.19.0
* Version: 3.19.2
* Requires at least: 6.5
* Requires PHP: 7.2
* Text Domain: give
Expand Down Expand Up @@ -411,7 +411,7 @@ private function setup_constants()
{
// Plugin version.
if (!defined('GIVE_VERSION')) {
define('GIVE_VERSION', '3.19.0');
define('GIVE_VERSION', '3.19.2');
}

// Plugin Root File.
Expand Down
2 changes: 1 addition & 1 deletion includes/country-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2111,7 +2111,7 @@ function give_get_indonesian_states_list() {
* @link https://en.wikipedia.org/wiki/ISO_3166-2:IN
* @link https://www.iso.org/obp/ui/#iso:code:3166:IN
*
* @unreleased Changed subdivision code for Odisha (OD)
* @since 3.19.1 Changed subdivision code for Odisha (OD)
* @since 2.11.0 Renamed Indian state of Orissa to Odisha (#5826)
* @since 1.0
*
Expand Down
2 changes: 1 addition & 1 deletion includes/payments/actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ function give_refresh_thismonth_stat_transients( $payment_ID ) {
* Add support to get all payment meta.
* Note: only use for internal purpose
*
* @unreleased change $donor_data['address'] to array instead of false
* @since 3.19.0 change $donor_data['address'] to array instead of false
* @since 2.0
*
* @param $check
Expand Down
11 changes: 10 additions & 1 deletion readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Tags: donation, donate, recurring donations, fundraising, crowdfunding
Requires at least: 6.5
Tested up to: 6.7
Requires PHP: 7.2
Stable tag: 3.19.0
Stable tag: 3.19.2
License: GPLv3
License URI: http://www.gnu.org/licenses/gpl-3.0.html

Expand Down Expand Up @@ -266,6 +266,15 @@ You can report security bugs through the Patchstack Vulnerability Disclosure Pro
10. Use almost any payment gateway integration with GiveWP through our add-ons or by creating your own add-on.

== Changelog ==
= 3.19.2: December 17th, 2024 =
* Fix: Resolved an issue with the custom donation amount field where using certain languages like Swedish were resulting in additional zero values being added

= 3.19.1: December 17th, 2024 =
* Fix: Resolved an issue with PayPal where some fields were not being validated properly before processing the donation
* Fix: Resolved an issue with PayPal and emails with a plus sign trying to connect to GiveWP
* Fix: Updated the format of the donation count in the multi form goal progress stats
* Change: Updated subdivision ISO code for Odisha, India to OD (Open source submission by @sorensd)

= 3.19.0: December 5th, 2024 =
* New: Added support to the donor dashboard for managing recurring donations from our Blink Payment Gateway add-on
* Fix: Resolved a compatability issue with loading translations on WordPress 6.7
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,20 @@ import {__} from '@wordpress/i18n';
const generateRequestErrors = (values: Record<string, any>, errors: object[], setError: UseFormSetError<any>) => {
Object.entries(errors).forEach(([field, value]) => {
if (Object.keys(values).includes(field)) {
setError(field, {message: Array.isArray(value) ? value[0] : value});
const fieldElement: HTMLInputElement = document.querySelector('input[name="' + field + '"]');
const canFocus = fieldElement && fieldElement.type !== 'hidden';

setError(field, {message: Array.isArray(value) ? value[0] : value}, {shouldFocus: canFocus});

if (!canFocus) {
// In fields that aren't inputs by default or are hidden inputs, we need to use this workaround because the "shouldFocus" option will not work in these cases.
if (!fieldElement) {
const fieldElementContainer = document.querySelector('.givewp-fields-' + field); //E.g: <div class="givewp-fields-giftAid">content...</div>
fieldElementContainer?.scrollIntoView({behavior: 'smooth'});
} else {
fieldElement.parentElement.scrollIntoView({behavior: 'smooth'}); // E.g: <input type="hidden" name="state">
}
}
} else if (field === 'gateway_error') {
setError('FORM_ERROR', {message: Array.isArray(value) ? value[0] : value});
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,33 @@ type CustomAmountProps = {
onValueChange?: (value: string, name?: string, values?: CurrencyInputOnChangeValues) => void;
};

const formatter = new Intl.NumberFormat(navigator.language);
const groupSeparator = formatter.format(1000).replace(/[0-9]/g, '');
const decimalSeparator = formatter.format(1.1).replace(/[0-9]/g, '');

/**
* @since 3.0.0
*/
const CustomAmount = (
{defaultValue, fieldError, currency, value, onValueChange}: CustomAmountProps
) => {

return (
<div className={classNames('givewp-fields-amount__input-container', {invalid: fieldError})}>
<CurrencyInput
intlConfig={{
locale: navigator.language,
currency,
}}
disableAbbreviations
decimalSeparator={decimalSeparator}
groupSeparator={
/**
* Replace non-breaking space to avoid conflict with the suffix separator.
* @link https://github.com/cchanxzy/react-currency-input-field/issues/266
*/
groupSeparator.replace(/\u00A0/g, ' ')
}
className="givewp-fields-amount__input givewp-fields-amount__input-custom"
aria-invalid={fieldError ? 'true' : 'false'}
id="amount-custom"
Expand All @@ -36,7 +50,7 @@ const CustomAmount = (
defaultValue={defaultValue}
value={value}
decimalsLimit={2}
onValueChange={(value) => onValueChange(value !== undefined ? value : '')}
onValueChange={(value) => {onValueChange(value !== undefined ? value : '')}}
/>
</div>
);
Expand Down
17 changes: 17 additions & 0 deletions src/MultiFormGoals/ProgressBar/Model.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,23 @@ public function getDonationCount(): int
return $results->count;
}

/**
* Get formatted number of donations
*
* @since 3.19.1
*/
public function getFormattedDonationCount(): string
{
return give_format_amount(
$this->getDonationCount(),
[
'sanitize' => false,
'decimal' => false,
'currency' => false,
]
);
}

/**
* Get formatted total remaining (ex: $75)
*
Expand Down
5 changes: 4 additions & 1 deletion src/MultiFormGoals/resources/views/progressbar.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
/**
* Multi-Form Goals block/shortcode template
* Styles for this template are defined in 'blocks/multi-form-goals/common.scss'
*
* @since 3.19.1 Format the donation count
*
* @var Give\MultiFormGoals\ProgressBar\Model $this
*/

Expand Down Expand Up @@ -32,7 +35,7 @@
</div>
<div part="stat-count" class="give-progress-bar-block__stat">
<div part="stat-count-value"><?php
echo esc_html($this->getDonationCount()); ?></div>
echo esc_html($this->getFormattedDonationCount()); ?></div>
<div part="stat-count-label"><?php
echo _n('donation', 'donations', $this->getDonationCount(), 'give'); ?></div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Give\PaymentGateways\Gateways\PayPalCommerce;

use Exception;
use Give\DonationForms\Actions\GenerateDonationFormValidationRouteUrl;
use Give\Framework\Support\Scripts\Concerns\HasScriptAssetFile;
use Give\Helpers\Language;
use Give\PaymentGateways\PayPalCommerce\Models\MerchantDetail;
Expand Down Expand Up @@ -51,7 +53,9 @@ public function enqueueScript(int $formId)
}

/**
* @throws \Exception
* @since 3.19.1 Add validate URL
*
* @throws Exception
*/
public function formSettings(int $formId): array
{
Expand All @@ -60,14 +64,15 @@ public function formSettings(int $formId): array
'donationFormId' => $formId,
'donationFormNonce' => wp_create_nonce("give_donation_form_nonce_{$formId}"),
'sdkOptions' => $this->getPayPalSDKOptions($formId),
'validateUrl' => (new GenerateDonationFormValidationRouteUrl())(),
];
}

/**
* List of PayPal query parameters: https://developer.paypal.com/docs/checkout/reference/customize-sdk/#query-parameters
*
* @since 3.0.0
* @throws \Exception
* @throws Exception
*/
private function getPayPalSDKOptions(int $formId): array
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {debounce} from 'react-ace/lib/editorOptions';
import {Flex, TextControl} from '@wordpress/components';
import {CSSProperties, useEffect, useState} from 'react';
import {PayPalSubscriber} from './types';
import handleValidationRequest from '@givewp/forms/app/utilities/handleValidationRequest';

(() => {
/**
Expand Down Expand Up @@ -315,34 +316,6 @@ import {PayPalSubscriber} from './types';
return children;
};

/**
* @since 3.12.2
*/
const getRequiredValidationMessage = () => {
return __('This is a required field', 'give');
};

/**
* @since 3.12.2
*/
const isCityRequired = () => {
return Boolean(document.querySelector('.givewp-fields-text-city .givewp-field-required'));
};

/**
* @since 3.12.2
*/
const isStateRequired = () => {
return Boolean(document.querySelector('.givewp-fields-select-state .givewp-field-required'));
};

/**
* @since 3.12.2
*/
const isZipRequired = () => {
return Boolean(document.querySelector('.givewp-fields-text-zip .givewp-field-required'));
};

const SmartButtonsContainer = () => {
const {useWatch, useFormState} = window.givewp.form.hooks;
const donationType = useWatch({name: 'donationType'});
Expand Down Expand Up @@ -384,9 +357,9 @@ import {PayPalSubscriber} from './types';
return actions.reject();
}

// Validate the form values before proceeding.
const result = await trigger();
if (result === false) {
// Validate the form values in the client side before proceeding.
const isClientValidationSuccessful = await trigger();
if (!isClientValidationSuccessful) {
// Set focus on first invalid field.
for (const fieldName in getValues()) {
if (getFieldState(fieldName).invalid) {
Expand All @@ -397,42 +370,30 @@ import {PayPalSubscriber} from './types';
}

/**
* Depending on the selected country, the city, state, and zip fields can be required or not and there are custom
* validation rules on the server side that check that. However, in this case, these validations are reached later
* when the donation is already created on the PayPal side. This way, we need the conditions below to check it earlier
* and prevent the donation creation on the PayPal side if the required billing address fields are missing.
* Validate the form values in the server side before proceeding - this is important to prevent problems with some blocks.
*
* Ideally, the client-side validations should be enough. However, in some cases, these validations are reached
* later when the donation is already created on the PayPal side. This way, we need the request below to check
* it earlier and prevent the donation creation on the PayPal side if the required fields are missing.
*
* Know cases:
*
* #1 - Billing Address Block: depending on the selected country, the city, state, and zip fields
* can be required or not and there are custom validation rules on the server side that check it.
*
* #2 - Gift Aid Block: when users opt-in to the gift aid checkbox, it will display some
* required fields that should be filled, but as this block is not a group and even so has
* "children" fields, the validation rules for it live only on the server.
*/
if (country) {
if (city.length === 0 && isCityRequired()) {
setError(
'city',
{
type: 'custom',
message: getRequiredValidationMessage(),
},
{shouldFocus: true}
);
return actions.reject();
}

if (state.length === 0 && isStateRequired()) {
setError(
'state',
{
type: 'custom',
message: getRequiredValidationMessage(),
},
{shouldFocus: true}
);
// As the state is a hidden field we need to use this workaround because the "shouldFocus" option does not work in hidden fields.
document.querySelector('.givewp-fields-select-state').scrollIntoView({behavior: 'smooth'});
return actions.reject();
}
const isServerValidationSuccessful = await handleValidationRequest(
payPalDonationsSettings.validateUrl,
getValues(),
setError,
gateway
);

if (postalCode.length === 0 && isZipRequired()) {
setError('zip', {type: 'custom', message: getRequiredValidationMessage()}, {shouldFocus: true});
return actions.reject();
}
if (!isServerValidationSuccessful) {
return actions.reject();
}

orderCreated = true;
Expand Down
Loading

0 comments on commit 5af8277

Please sign in to comment.