diff --git a/.github/workflows/php-compat.yml b/.github/workflows/php-compat.yml
index f7c3cd58..a5d05804 100644
--- a/.github/workflows/php-compat.yml
+++ b/.github/workflows/php-compat.yml
@@ -4,35 +4,53 @@ on: pull_request
jobs:
php-compatibility:
+ name: PHP compatibility
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- with:
- fetch-depth: 0
+ - name: Checkout repository
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- - name: Setup proper PHP version
- uses: shivammathur/setup-php@9e72090525849c5e82e596468b86eb55e9cc5401 # v2.32.0
+ - name: Prepare PHP
+ uses: woocommerce/grow/prepare-php@da5279aa4d76745ef32970e49b5ef7903a3b457a # v2.2.2
with:
- php-version: 7.4
- tools: composer
-
- - name: Validate composer.json and composer.lock
- run: composer validate --strict --no-check-all
-
- - name: Get composer cache directory
- id: composer-cache
- run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
+ tools: cs2pr
+ install-deps: no
- - name: Cache dependencies
- uses: actions/cache@d4323d4df104b026a6aa633fdb11d772146be0bf # v4.2.2
+ - name: Prepare node
+ uses: woocommerce/grow/prepare-node@da5279aa4d76745ef32970e49b5ef7903a3b457a # v2.2.2
with:
- path: ${{ steps.composer-cache.outputs.dir }}
- key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
- restore-keys: ${{ runner.os }}-composer-
-
- - name: Install dependencies
- run: composer install
-
- - name: Run PHP Compatibility
- run: ./vendor/bin/phpcs --standard=phpcs-compat.xml.dist -p .
+ node-version-file: ".nvmrc"
+ ignore-scripts: "no"
+
+ # The use of WP-Scripts results in PHP files being generated during the npm build step.
+ # In order to ensure PHP Compatibility, the build step must be run in order to ensure all
+ # files in the production release of the plugin are compatible with the target PHP versions.
+ - name: Build production bundle
+ run: npm run build
+
+ # Unzip the newly created zip file to a separate directory.
+ - name: Unzip production bundle
+ run: |
+ mv woocommerce-square.zip ~
+ cd ~
+ mkdir prod
+ unzip woocommerce-square.zip -d prod
+ cd -
+
+ - name: Copy phpcompat sniffs to production directory
+ run: cp phpcs-compat.xml.dist ~/prod/woocommerce-square/phpcs-compat.xml.dist
+
+ # Installed globally to ensure dev dependencies are not included in compatibility sniffs.
+ # At the time of writing no production version of PHPCompatibility/PHP-Compatibility supports
+ # PHP 8.4 so a dev version is used in order to ensure the sniffs that have been created are
+ # included in the checks.
+ - name: Install PHP Compatibility dev-develop globally
+ run: |
+ composer global config --no-plugins allow-plugins.dealerdirect/phpcodesniffer-composer-installer true
+ composer global require --dev phpcompatibility/php-compatibility:dev-develop#8daeec54772a592ad369be23ae02ed593c71e7f1
+
+ - name: Run PHPCompatibility on all files
+ run: |
+ cd ~/prod/woocommerce-square
+ ~/.composer/vendor/bin/phpcs . --standard=phpcs-compat.xml.dist -ps --basepath=.
diff --git a/composer.json b/composer.json
index 79c5d3c0..78d5e6a1 100644
--- a/composer.json
+++ b/composer.json
@@ -27,7 +27,12 @@
"!/vendor",
"!/assets/js/**/*.min.js",
"!/assets/css/**/*.min.css",
- "*.zip"
+ "*.zip",
+ "/vendor/apimatic/*/tests/**",
+ "/vendor/apimatic/*/.*",
+ "/vendor/square/square/tests/**",
+ "/vendor/square/square/doc/**",
+ "/vendor/square/square/.*"
]
},
"extra": {
diff --git a/includes/Admin/Rest/WC_REST_Square_Settings_Controller.php b/includes/Admin/Rest/WC_REST_Square_Settings_Controller.php
index 39f40980..41899cf4 100644
--- a/includes/Admin/Rest/WC_REST_Square_Settings_Controller.php
+++ b/includes/Admin/Rest/WC_REST_Square_Settings_Controller.php
@@ -179,7 +179,7 @@ public function get_settings() {
$filtered_settings['connection_url'] = wc_square()->get_gateway()->get_plugin()->get_connection_handler()->get_connect_url( false );
$filtered_settings['connection_url_wizard'] = wc_square()->get_gateway()->get_plugin()->get_connection_handler()->get_connect_url( false, array( 'from' => 'wizard' ) );
$filtered_settings['connection_url_sandbox'] = wc_square()->get_gateway()->get_plugin()->get_connection_handler()->get_connect_url( true, array( 'from' => 'wizard' ) );
- $filtered_settings['disconnection_url'] = html_entity_decode( wp_nonce_url( $url, $action ) );
+ $filtered_settings['disconnection_url'] = html_entity_decode( wp_nonce_url( $url, $action ), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
// Add locations to the response.
if ( wc_square()->get_settings_handler()->is_connected() ) {
diff --git a/includes/Framework/PaymentGateway/Admin/Payment_Gateway_Admin_Order.php b/includes/Framework/PaymentGateway/Admin/Payment_Gateway_Admin_Order.php
index 24ae335a..bf8e9011 100644
--- a/includes/Framework/PaymentGateway/Admin/Payment_Gateway_Admin_Order.php
+++ b/includes/Framework/PaymentGateway/Admin/Payment_Gateway_Admin_Order.php
@@ -462,7 +462,7 @@ public function ajax_process_capture() {
wp_send_json_success(
array(
- 'message' => html_entity_decode( wp_strip_all_tags( $result['message'] ) ), // ensure any HTML tags are removed and the currency symbol entity is decoded
+ 'message' => html_entity_decode( wp_strip_all_tags( $result['message'] ), ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ), // ensure any HTML tags are removed and the currency symbol entity is decoded
)
);
diff --git a/includes/Framework/PaymentGateway/Payment_Gateway.php b/includes/Framework/PaymentGateway/Payment_Gateway.php
index 266ba081..1651c02f 100644
--- a/includes/Framework/PaymentGateway/Payment_Gateway.php
+++ b/includes/Framework/PaymentGateway/Payment_Gateway.php
@@ -3621,7 +3621,7 @@ public function get_authorization_time_window() {
* @param \WC_Order $order Optional. The order being charged
* @return bool
*/
- public function perform_credit_card_charge( \WC_Order $order = null ) {
+ public function perform_credit_card_charge( ?\WC_Order $order = null ) {
assert( $this->supports_credit_card_charge() );
@@ -3652,7 +3652,7 @@ public function perform_credit_card_charge( \WC_Order $order = null ) {
* @param \WC_Order $order Optional. The order being authorized
* @return bool
*/
- public function perform_credit_card_authorization( \WC_Order $order = null ) {
+ public function perform_credit_card_authorization( ?\WC_Order $order = null ) {
assert( $this->supports_credit_card_authorization() );
@@ -3677,7 +3677,7 @@ public function perform_credit_card_authorization( \WC_Order $order = null ) {
* @param \WC_Order $order Optional. The order being charged
* @return bool
*/
- public function perform_charge( \WC_Order $order = null ) {
+ public function perform_charge( ?\WC_Order $order = null ) {
assert( $this->supports_charge() );
@@ -3708,7 +3708,7 @@ public function perform_charge( \WC_Order $order = null ) {
* @param \WC_Order $order Optional. The order being authorized
* @return bool
*/
- public function perform_authorization( \WC_Order $order = null ) {
+ public function perform_authorization( ?\WC_Order $order = null ) {
assert( $this->supports_authorization() );
@@ -4002,12 +4002,12 @@ public function add_debug_message( $message, $type = 'message' ) {
if ( 'message' === $type ) {
- Square_Helper::wc_add_notice( str_replace( "\n", '
', htmlspecialchars( $message ) ), 'notice' );
+ Square_Helper::wc_add_notice( str_replace( "\n", '
', htmlspecialchars( $message, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ) ), 'notice' );
} else {
// defaults to error message
- Square_Helper::wc_add_notice( str_replace( "\n", '
', htmlspecialchars( $message ) ), 'error' );
+ Square_Helper::wc_add_notice( str_replace( "\n", '
', htmlspecialchars( $message, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 ) ), 'error' );
}
}
}
diff --git a/includes/Framework/Square_Helper.php b/includes/Framework/Square_Helper.php
index d4c99380..40c1adaf 100644
--- a/includes/Framework/Square_Helper.php
+++ b/includes/Framework/Square_Helper.php
@@ -98,11 +98,14 @@ public static function str_exists( $haystack, $needle ) {
*/
public static function str_to_ascii( $string ) {
- // strip ASCII chars 32 and under
- $string = filter_var( $string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW );
+ // Remove HTML tags.
+ $string = wp_strip_all_tags( $string );
- // strip ASCII chars 127 and higher
- return filter_var( $string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH );
+ // Encode HTML special characters.
+ $string = htmlspecialchars( $string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
+
+ // strip ASCII chars 32 and under; 127 and higher
+ return filter_var( $string, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH );
}
/**
diff --git a/includes/Gateway/API.php b/includes/Gateway/API.php
index 680f0ed1..1012b11e 100644
--- a/includes/Gateway/API.php
+++ b/includes/Gateway/API.php
@@ -731,7 +731,7 @@ public function retrieve_gift_card_by_gan( $gan = '' ) {
*
* @throws \Exception
*/
- public function search_orders( $location_ids = array(), $start_time, $limit = 100, $cursor = '', $end_time = '' ) {
+ public function search_orders( $location_ids, $start_time, $limit = 100, $cursor = '', $end_time = '' ) {
$request = new API\Requests\Orders( $this->client );
diff --git a/includes/Handlers/Product.php b/includes/Handlers/Product.php
index 4fbf1bd5..ee7370ba 100644
--- a/includes/Handlers/Product.php
+++ b/includes/Handlers/Product.php
@@ -1012,7 +1012,7 @@ public static function extract_catalog_item_data( \WC_Product $product, array $v
* * @param bool $is_soft_delete whether or not this item data is for a soft-delete
* @return array
*/
- public static function extract_catalog_item_variation_data( \WC_Product $product, \WC_Product $parent_product = null, $is_soft_delete = false ) {
+ public static function extract_catalog_item_variation_data( \WC_Product $product, ?\WC_Product $parent_product = null, $is_soft_delete = false ) {
if ( ! $product ) {
return null;
diff --git a/includes/Sync/Catalog_Item.php b/includes/Sync/Catalog_Item.php
index b21d346a..b14bb73c 100644
--- a/includes/Sync/Catalog_Item.php
+++ b/includes/Sync/Catalog_Item.php
@@ -78,7 +78,7 @@ public function __construct( $product, $is_soft_delete = false ) {
* @return \Square\Models\CatalogObjectBatch
* @throws \Exception
*/
- public function get_batch( \Square\Models\CatalogObject $catalog_object = null ) {
+ public function get_batch( ?\Square\Models\CatalogObject $catalog_object = null ) {
if ( ! $this->batch ) {
$this->create_batch( $catalog_object );
@@ -122,7 +122,7 @@ protected function is_soft_delete() {
* @param \Square\Models\CatalogObject|null $catalog_object existing catalog object or null to create a new one
* @throws \Exception
*/
- protected function create_batch( \Square\Models\CatalogObject $catalog_object = null ) {
+ protected function create_batch( ?\Square\Models\CatalogObject $catalog_object = null ) {
if ( ! $catalog_object ) {
$catalog_id = Product\Woo_SOR::get_square_item_id( $this->product );
diff --git a/includes/Utilities/String_Utility.php b/includes/Utilities/String_Utility.php
index a4aa0851..dbba4fd5 100644
--- a/includes/Utilities/String_Utility.php
+++ b/includes/Utilities/String_Utility.php
@@ -78,18 +78,21 @@ public static function truncate( $string, $length, $omission = '...' ) {
* @return string
*/
public static function to_ascii( $string ) {
- // strip ASCII chars 32 and under
- $string = filter_var( $string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_LOW );
+ // Remove HTML tags.
+ $string = wp_strip_all_tags( $string );
- // strip ASCII chars 127 and higher
- return filter_var( $string, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH );
+ // Encode HTML special characters.
+ $string = htmlspecialchars( $string, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 );
+
+ // strip ASCII chars 32 and under; 127 and higher
+ return filter_var( $string, FILTER_UNSAFE_RAW, FILTER_FLAG_STRIP_LOW | FILTER_FLAG_STRIP_HIGH );
}
/**
* Returns true if the haystack string starts with needle
*
* Note: case-sensitive
- *
+ *
* See Square_Helper::str_starts_with()
*
* @since 2.2.0
diff --git a/phpcs-compat.xml.dist b/phpcs-compat.xml.dist
index 8a4a8899..51a6d42e 100644
--- a/phpcs-compat.xml.dist
+++ b/phpcs-compat.xml.dist
@@ -1,19 +1,65 @@
-
-
+
-
-
- .
+ WordPress specific ruleset which checks for PHP cross version compatibility.
+
- vendor/
- dist/
- docker/
- build/
- docs/
- node_modules
- tests
- assets
+
+
+ .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
diff --git a/woocommerce-square.php b/woocommerce-square.php
index 682d9560..e0194258 100644
--- a/woocommerce-square.php
+++ b/woocommerce-square.php
@@ -7,7 +7,7 @@
* Requires at least: 6.7
* Tested up to: 6.8
* Requires PHP: 7.4
- * PHP tested up to: 8.3
+ * PHP tested up to: 8.4
*
* Description: Securely accept payments, synchronize sales, and seamlessly manage inventory and product data between WooCommerce and Square POS.
* Author: WooCommerce