Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/gls-shipping-for-woocommerce/gls-shipping-for-woocommerce.php
+++ b/gls-shipping-for-woocommerce/gls-shipping-for-woocommerce.php
@@ -3,7 +3,7 @@
/**
* Plugin Name: GLS Shipping for WooCommerce
* Description: Offical GLS Shipping for WooCommerce plugin
- * Version: 1.4.0
+ * Version: 1.4.1
* Author: Inchoo
* License: GPLv2
* License URI: http://www.gnu.org/licenses/gpl-2.0.html
@@ -24,7 +24,7 @@
{
private static $instance;
- private $version = '1.4.0';
+ private $version = '1.4.1';
private function __construct()
{
@@ -173,16 +173,16 @@
}
// Verify nonce
- if (!isset($_GET['nonce']) || !wp_verify_nonce(sanitize_text_field($_GET['nonce']), 'gls_download_label')) {
+ if (!isset($_GET['nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['nonce'])), 'gls_download_label')) {
wp_die(esc_html__('Invalid security token. Please refresh the page and try again.', 'gls-shipping-for-woocommerce'));
}
// Check user permissions
if (!current_user_can('edit_shop_orders')) {
- wp_die(__('You do not have permission to download shipping labels.', 'gls-shipping-for-woocommerce'));
+ wp_die(esc_html__('You do not have permission to download shipping labels.', 'gls-shipping-for-woocommerce'));
}
- $file_id = sanitize_file_name($_GET['gls_download_label']);
+ $file_id = sanitize_file_name(wp_unslash($_GET['gls_download_label']));
$file_path = GLS_LABELS_DIR . '/' . $file_id;
// Security check - ensure file is within labels directory
@@ -190,22 +190,33 @@
$real_labels_dir = realpath(GLS_LABELS_DIR);
if ($real_path === false || strpos($real_path, $real_labels_dir) !== 0) {
- wp_die(__('Invalid file path.', 'gls-shipping-for-woocommerce'));
+ wp_die(esc_html__('Invalid file path.', 'gls-shipping-for-woocommerce'));
}
if (!file_exists($file_path)) {
- wp_die(__('PDF label not found.', 'gls-shipping-for-woocommerce'));
+ wp_die(esc_html__('PDF label not found.', 'gls-shipping-for-woocommerce'));
+ }
+
+ // Serve the file using WP_Filesystem
+ global $wp_filesystem;
+ if (empty($wp_filesystem)) {
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ WP_Filesystem();
+ }
+
+ $file_contents = $wp_filesystem->get_contents($file_path);
+ if (false === $file_contents) {
+ wp_die(esc_html__('Could not read PDF file.', 'gls-shipping-for-woocommerce'));
}
- // Serve the file
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . basename($file_path) . '"');
header('Content-Transfer-Encoding: binary');
- header('Content-Length: ' . filesize($file_path));
+ header('Content-Length: ' . strlen($file_contents));
header('Cache-Control: private, max-age=0, must-revalidate');
header('Pragma: public');
- readfile($file_path);
+ echo $file_contents; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary PDF data
exit;
}
@@ -259,6 +270,7 @@
public function load_textdomain()
{
+ // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound -- Manual loading needed for non-wp.org distribution
load_plugin_textdomain('gls-shipping-for-woocommerce', false, basename(dirname(__FILE__)) . '/languages/');
}
--- a/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-bulk.php
+++ b/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-bulk.php
@@ -113,101 +113,116 @@
}
// Bulk print labels, dont generate for each but just print in single PDF
if ('print_gls_labels' === $doaction) {
- $prepare_data = new GLS_Shipping_API_Data($order_ids);
- $data = $prepare_data->generate_post_fields_multi();
-
- // Send order to GLS API
- $is_multi = true;
- $api = new GLS_Shipping_API_Service();
- $result = $api->send_order($data, $is_multi);
+ try {
+ $prepare_data = new GLS_Shipping_API_Data($order_ids);
+ $data = $prepare_data->generate_post_fields_multi();
+
+ // Send order to GLS API
+ $is_multi = true;
+ $api = new GLS_Shipping_API_Service();
+ $result = $api->send_order($data, $is_multi);
- $body = $result['body'];
- $failed_orders = $result['failed_orders'];
-
- // Check if all orders failed - don't attempt PDF creation if no successful labels
- if (count($failed_orders) >= count($order_ids)) {
- $redirect = add_query_arg(
- array(
- 'bulk_action' => 'print_gls_labels',
- 'gls_labels_printed' => 0,
- 'gls_labels_failed' => count($failed_orders),
- 'failed_orders' => implode(',', array_column($failed_orders, 'order_id')),
- ),
- $redirect
- );
- return $redirect;
- }
-
- $pdf_filename = $this->bulk_create_print_labels($body);
-
- if ($pdf_filename) {
- // Save tracking numbers to order meta
- if (!empty($body['PrintLabelsInfoList'])) {
- // Group tracking codes by order ID to handle multiple parcels per order
- $orders_data = array();
-
- foreach ($body['PrintLabelsInfoList'] as $labelInfo) {
- if (isset($labelInfo['ClientReference'])) {
- $order_id = str_replace('Order:', '', $labelInfo['ClientReference']);
-
- if (!isset($orders_data[$order_id])) {
- $orders_data[$order_id] = array(
- 'tracking_codes' => array(),
- 'parcel_ids' => array()
- );
- }
-
- if (isset($labelInfo['ParcelNumber'])) {
- $orders_data[$order_id]['tracking_codes'][] = $labelInfo['ParcelNumber'];
- }
- if (isset($labelInfo['ParcelId'])) {
- $orders_data[$order_id]['parcel_ids'][] = $labelInfo['ParcelId'];
+ $body = $result['body'];
+ $failed_orders = $result['failed_orders'];
+
+ // Check if all orders failed - don't attempt PDF creation if no successful labels
+ if (count($failed_orders) >= count($order_ids)) {
+ $redirect = add_query_arg(
+ array(
+ 'bulk_action' => 'print_gls_labels',
+ 'gls_labels_printed' => 0,
+ 'gls_labels_failed' => count($failed_orders),
+ 'failed_orders' => implode(',', array_column($failed_orders, 'order_id')),
+ ),
+ $redirect
+ );
+ return $redirect;
+ }
+
+ $pdf_filename = $this->bulk_create_print_labels($body);
+
+ if ($pdf_filename) {
+ // Save tracking numbers to order meta
+ if (!empty($body['PrintLabelsInfoList'])) {
+ // Group tracking codes by order ID to handle multiple parcels per order
+ $orders_data = array();
+
+ foreach ($body['PrintLabelsInfoList'] as $labelInfo) {
+ if (isset($labelInfo['ClientReference'])) {
+ $order_id = str_replace('Order:', '', $labelInfo['ClientReference']);
+
+ if (!isset($orders_data[$order_id])) {
+ $orders_data[$order_id] = array(
+ 'tracking_codes' => array(),
+ 'parcel_ids' => array()
+ );
+ }
+
+ if (isset($labelInfo['ParcelNumber'])) {
+ $orders_data[$order_id]['tracking_codes'][] = $labelInfo['ParcelNumber'];
+ }
+ if (isset($labelInfo['ParcelId'])) {
+ $orders_data[$order_id]['parcel_ids'][] = $labelInfo['ParcelId'];
+ }
}
}
- }
-
- // Now save all tracking codes for each order
- $successful_orders = array();
- foreach ($orders_data as $order_id => $data) {
- $order = wc_get_order($order_id);
- if ($order) {
- if (!empty($data['tracking_codes'])) {
- $order->update_meta_data('_gls_tracking_codes', $data['tracking_codes']);
+
+ // Now save all tracking codes for each order
+ $successful_orders = array();
+ foreach ($orders_data as $order_id => $data) {
+ $order = wc_get_order($order_id);
+ if ($order) {
+ if (!empty($data['tracking_codes'])) {
+ $order->update_meta_data('_gls_tracking_codes', $data['tracking_codes']);
+ }
+ if (!empty($data['parcel_ids'])) {
+ $order->update_meta_data('_gls_parcel_ids', $data['parcel_ids']);
+ }
+
+ // Save just the filename, URL with nonce is generated on display
+ $order->update_meta_data('_gls_print_label', $pdf_filename);
+ $order->save();
+
+ $successful_orders[] = $order_id;
}
- if (!empty($data['parcel_ids'])) {
- $order->update_meta_data('_gls_parcel_ids', $data['parcel_ids']);
- }
-
- // Save just the filename, URL with nonce is generated on display
- $order->update_meta_data('_gls_print_label', $pdf_filename);
- $order->save();
-
- $successful_orders[] = $order_id;
}
+
+ // Fire hook after successful bulk label generation
+ do_action('gls_bulk_labels_generated', $order_ids, $successful_orders, $failed_orders);
}
-
- // Fire hook after successful bulk label generation
- do_action('gls_bulk_labels_generated', $order_ids, $successful_orders, $failed_orders);
- }
- // Add query args to URL for displaying notices and providing PDF link
- $pdf_url = GLS_Shipping_For_Woo::get_label_download_url($pdf_filename);
- $redirect = add_query_arg(
- array(
- 'bulk_action' => 'print_gls_labels',
- 'gls_labels_printed' => count($order_ids) - count($failed_orders),
- 'gls_labels_failed' => count($failed_orders),
- 'gls_pdf_url' => urlencode($pdf_url),
- 'failed_orders' => implode(',', array_column($failed_orders, 'order_id')),
- ),
- $redirect
- );
- } else {
- // Handle error case
+ // Add query args to URL for displaying notices and providing PDF link
+ $pdf_url = GLS_Shipping_For_Woo::get_label_download_url($pdf_filename);
+ $redirect = add_query_arg(
+ array(
+ 'bulk_action' => 'print_gls_labels',
+ 'gls_labels_printed' => count($order_ids) - count($failed_orders),
+ 'gls_labels_failed' => count($failed_orders),
+ 'gls_pdf_url' => urlencode($pdf_url),
+ 'failed_orders' => implode(',', array_column($failed_orders, 'order_id')),
+ ),
+ $redirect
+ );
+ } else {
+ // Handle error case
+ $redirect = add_query_arg(
+ array(
+ 'bulk_action' => 'print_gls_labels',
+ 'gls_labels_printed_error' => 'true',
+ ),
+ $redirect
+ );
+ }
+ } catch (Exception $e) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional error logging for debugging
+ error_log('GLS Bulk Print Labels Error: ' . $e->getMessage());
+
+ // Handle the exception gracefully - redirect with error message
$redirect = add_query_arg(
array(
'bulk_action' => 'print_gls_labels',
'gls_labels_printed_error' => 'true',
+ 'gls_error_message' => urlencode($e->getMessage()),
),
$redirect
);
@@ -226,6 +241,7 @@
// Check if Labels exist and is an array
if (empty($body['Labels']) || !is_array($body['Labels'])) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional error logging for debugging
error_log('GLS Bulk Print: No labels found in API response. This may happen if all orders failed validation.');
return false;
}
@@ -248,17 +264,33 @@
}
// Display admin notice after bulk action
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Display-only notice after redirect, nonce verified in original action
public function gls_bulk_action_admin_notice() {
if (isset($_REQUEST['bulk_action'])) {
- if ('generate_gls_labels' == $_REQUEST['bulk_action']) {
- $generated = intval($_REQUEST['gls_labels_generated']);
- $failed = intval($_REQUEST['gls_labels_failed']);
- $failed_orders = isset($_REQUEST['failed_orders']) ? explode(',', $_REQUEST['failed_orders']) : [];
+ // Sanitize the bulk action parameter
+ $bulk_action = sanitize_text_field(wp_unslash($_REQUEST['bulk_action']));
+
+ if ('generate_gls_labels' === $bulk_action) {
+ $generated = isset($_REQUEST['gls_labels_generated']) ? intval($_REQUEST['gls_labels_generated']) : 0;
+ $failed = isset($_REQUEST['gls_labels_failed']) ? intval($_REQUEST['gls_labels_failed']) : 0;
+
+ // Sanitize failed_orders - only allow integers (order IDs)
+ $failed_orders = array();
+ if (isset($_REQUEST['failed_orders']) && !empty($_REQUEST['failed_orders'])) {
+ $raw_failed_orders = sanitize_text_field(wp_unslash($_REQUEST['failed_orders']));
+ $failed_orders_array = explode(',', $raw_failed_orders);
+ foreach ($failed_orders_array as $order_id) {
+ $sanitized_id = absint(trim($order_id));
+ if ($sanitized_id > 0) {
+ $failed_orders[] = $sanitized_id;
+ }
+ }
+ }
// Prepare success message
$message = sprintf(
+ /* translators: %s: number of generated labels */
_n(
- /* translators: %s: number of generated labels */
'%s GLS label was successfully generated.',
'%s GLS labels were successfully generated.',
$generated,
@@ -266,12 +298,12 @@
),
number_format_i18n($generated)
);
-
+
// Add failure message if any labels failed to generate
if ($failed > 0) {
$message .= ' ' . sprintf(
+ /* translators: %s: number of failed labels */
_n(
- /* translators: %s: number of failed labels */
'%s label failed to generate.',
'%s labels failed to generate.',
$failed,
@@ -279,26 +311,43 @@
),
number_format_i18n($failed)
);
- $message .= ' ' . sprintf(
- /* translators: %s: comma-separated list of order IDs that failed */
- __('Failed order IDs: %s', 'gls-shipping-for-woocommerce'),
- implode(', ', $failed_orders)
- );
+ if (!empty($failed_orders)) {
+ $message .= ' ' . sprintf(
+ /* translators: %s: comma-separated list of order IDs that failed */
+ __('Failed order IDs: %s', 'gls-shipping-for-woocommerce'),
+ esc_html(implode(', ', $failed_orders))
+ );
+ }
}
- // Display the notice
- printf('<div id="message" class="updated notice is-dismissible"><p>' . $message . '</p></div>');
- } elseif ('print_gls_labels' == $_REQUEST['bulk_action']) {
+ // Display the notice with proper escaping
+ printf(
+ '<div id="message" class="updated notice is-dismissible"><p>%s</p></div>',
+ wp_kses_post($message)
+ );
+ } elseif ('print_gls_labels' === $bulk_action) {
if (isset($_REQUEST['gls_labels_printed']) && isset($_REQUEST['gls_pdf_url'])) {
$printed = intval($_REQUEST['gls_labels_printed']);
- $failed = intval($_REQUEST['gls_labels_failed']);
- $pdf_url = urldecode($_REQUEST['gls_pdf_url']);
- $failed_orders = isset($_REQUEST['failed_orders']) ? explode(',', $_REQUEST['failed_orders']) : [];
+ $failed = isset($_REQUEST['gls_labels_failed']) ? intval($_REQUEST['gls_labels_failed']) : 0;
+ $pdf_url = esc_url_raw(urldecode(sanitize_text_field(wp_unslash($_REQUEST['gls_pdf_url']))));
+
+ // Sanitize failed_orders - only allow integers (order IDs)
+ $failed_orders = array();
+ if (isset($_REQUEST['failed_orders']) && !empty($_REQUEST['failed_orders'])) {
+ $raw_failed_orders = sanitize_text_field(wp_unslash($_REQUEST['failed_orders']));
+ $failed_orders_array = explode(',', $raw_failed_orders);
+ foreach ($failed_orders_array as $order_id) {
+ $sanitized_id = absint(trim($order_id));
+ if ($sanitized_id > 0) {
+ $failed_orders[] = $sanitized_id;
+ }
+ }
+ }
// Prepare success message
$message = sprintf(
+ /* translators: %s: number of orders processed */
_n(
- /* translators: %s: number of orders processed */
'GLS label for %s order has been generated. ',
'GLS labels for %s orders have been generated. ',
$printed,
@@ -310,8 +359,8 @@
// Add failure message if any labels failed to generate
if ($failed > 0) {
$message .= sprintf(
+ /* translators: %s: number of failed labels */
_n(
- /* translators: %s: number of failed labels */
'%s label failed to generate. ',
'%s labels failed to generate. ',
$failed,
@@ -319,27 +368,49 @@
),
number_format_i18n($failed)
);
- $message .= sprintf(
- __('Failed order IDs: %s', 'gls-shipping-for-woocommerce'),
- implode(', ', $failed_orders)
- );
+ if (!empty($failed_orders)) {
+ $message .= sprintf(
+ /* translators: %s: comma-separated list of order IDs that failed */
+ __('Failed order IDs: %s', 'gls-shipping-for-woocommerce'),
+ esc_html(implode(', ', $failed_orders))
+ );
+ }
}
-
+
$message .= sprintf(
/* translators: %s: URL to download the PDF file */
__('<br><a href="%s" target="_blank">Click here to download the PDF</a>', 'gls-shipping-for-woocommerce'),
esc_url($pdf_url)
);
- // Display the notice
- printf('<div id="message" class="updated notice is-dismissible"><p>' . $message . '</p></div>');
+ // Display the notice with proper escaping
+ printf(
+ '<div id="message" class="updated notice is-dismissible"><p>%s</p></div>',
+ wp_kses_post($message)
+ );
} elseif (isset($_REQUEST['gls_labels_printed_error'])) {
$message = __('An error occurred while generating the GLS labels PDF.', 'gls-shipping-for-woocommerce');
- printf('<div id="message" class="error notice is-dismissible"><p>' . $message . '</p></div>');
+
+ // Display specific error message if available
+ if (isset($_REQUEST['gls_error_message']) && !empty($_REQUEST['gls_error_message'])) {
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via sanitize_text_field after urldecode
+ $error_detail = sanitize_text_field(urldecode(wp_unslash($_REQUEST['gls_error_message'])));
+ $message .= ' ' . sprintf(
+ /* translators: %s: error message from GLS API */
+ __('Error: %s', 'gls-shipping-for-woocommerce'),
+ $error_detail
+ );
+ }
+
+ printf(
+ '<div id="message" class="error notice is-dismissible"><p>%s</p></div>',
+ esc_html($message)
+ );
}
}
}
}
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
// Enqueue bulk styles
public function admin_enqueue_styles()
@@ -440,9 +511,9 @@
}
}
- // Display the tracking numbers
+ // Display the tracking numbers (each element is already escaped with esc_html())
if (!empty($tracking_numbers)) {
- echo implode(' ', $tracking_numbers);
+ echo wp_kses_post( implode(' ', $tracking_numbers) );
} else {
echo '-';
}
--- a/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-label-migration.php
+++ b/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-label-migration.php
@@ -116,21 +116,24 @@
AutomatticWooCommerceUtilitiesOrderUtil::custom_orders_table_usage_is_enabled()) {
// HPOS enabled
$table = $wpdb->prefix . 'wc_orders_meta';
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name uses $wpdb->prefix + constant
$exists = $wpdb->get_var($wpdb->prepare(
- "SELECT 1 FROM {$table}
- WHERE meta_key = '_gls_print_label'
- AND meta_value LIKE %s
+ "SELECT 1 FROM {$table}
+ WHERE meta_key = '_gls_print_label'
+ AND meta_value LIKE %s
AND meta_value NOT LIKE %s
LIMIT 1",
'%/wp-content/uploads/%',
'%gls_download_label%'
));
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
} else {
// Legacy post meta
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Using $wpdb->postmeta property
$exists = $wpdb->get_var($wpdb->prepare(
- "SELECT 1 FROM {$wpdb->postmeta}
- WHERE meta_key = '_gls_print_label'
- AND meta_value LIKE %s
+ "SELECT 1 FROM {$wpdb->postmeta}
+ WHERE meta_key = '_gls_print_label'
+ AND meta_value LIKE %s
AND meta_value NOT LIKE %s
LIMIT 1",
'%/wp-content/uploads/%',
@@ -156,22 +159,25 @@
AutomatticWooCommerceUtilitiesOrderUtil::custom_orders_table_usage_is_enabled()) {
// HPOS enabled
$table = $wpdb->prefix . 'wc_orders_meta';
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Table name uses $wpdb->prefix + constant
$order_ids = $wpdb->get_col($wpdb->prepare(
- "SELECT order_id FROM {$table}
- WHERE meta_key = '_gls_print_label'
- AND meta_value LIKE %s
+ "SELECT order_id FROM {$table}
+ WHERE meta_key = '_gls_print_label'
+ AND meta_value LIKE %s
AND meta_value NOT LIKE %s
LIMIT %d",
'%/wp-content/uploads/%',
'%gls_download_label%',
$limit
));
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
} else {
// Legacy post meta
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Using $wpdb->postmeta property
$order_ids = $wpdb->get_col($wpdb->prepare(
- "SELECT post_id FROM {$wpdb->postmeta}
- WHERE meta_key = '_gls_print_label'
- AND meta_value LIKE %s
+ "SELECT post_id FROM {$wpdb->postmeta}
+ WHERE meta_key = '_gls_print_label'
+ AND meta_value LIKE %s
AND meta_value NOT LIKE %s
LIMIT %d",
'%/wp-content/uploads/%',
@@ -278,7 +284,7 @@
$order->save();
// Delete old file
- @unlink($old_path);
+ wp_delete_file($old_path);
return true;
}
@@ -330,13 +336,13 @@
continue;
}
foreach ($files as $file) {
- if (@unlink($file)) {
- $deleted_count++;
- }
+ wp_delete_file($file);
+ $deleted_count++;
}
}
if ($deleted_count > 0) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional logging for migration process
error_log("GLS Migration: Cleaned up {$deleted_count} orphaned label files from old uploads folders.");
}
}
@@ -373,7 +379,7 @@
}
// Verify nonce
- if (!wp_verify_nonce(sanitize_text_field($_GET['nonce']), 'gls_old_label_access')) {
+ if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['nonce'])), 'gls_old_label_access')) {
wp_die(esc_html__('Invalid security token.', 'gls-shipping-for-woocommerce'));
}
@@ -403,15 +409,26 @@
wp_die(esc_html__('PDF label file not found.', 'gls-shipping-for-woocommerce'));
}
- // Serve the file
+ // Serve the file using WP_Filesystem
+ global $wp_filesystem;
+ if (empty($wp_filesystem)) {
+ require_once ABSPATH . 'wp-admin/includes/file.php';
+ WP_Filesystem();
+ }
+
+ $file_contents = $wp_filesystem->get_contents($file_path);
+ if (false === $file_contents) {
+ wp_die(esc_html__('Could not read PDF file.', 'gls-shipping-for-woocommerce'));
+ }
+
header('Content-Type: application/pdf');
header('Content-Disposition: inline; filename="' . basename($file_path) . '"');
header('Content-Transfer-Encoding: binary');
- header('Content-Length: ' . filesize($file_path));
+ header('Content-Length: ' . strlen($file_contents));
header('Cache-Control: private, max-age=0, must-revalidate');
header('Pragma: public');
- readfile($file_path);
+ echo $file_contents; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary PDF data
exit;
}
}
--- a/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-order.php
+++ b/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-order.php
@@ -182,7 +182,10 @@
<!-- Service Options (Hidden by default) -->
<div id="gls-services-options" style="display: none; margin-bottom: 15px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; background-color: #f9f9f9;">
- <?php echo $this->render_service_options($order); ?>
+ <?php
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Trusted internal method outputting form fields
+ echo $this->render_service_options($order);
+ ?>
</div>
<button type="button" class="button gls-print-label" order-id="<?php echo esc_attr($order->get_id()); ?>">
@@ -191,11 +194,13 @@
<?php if (!empty($gls_tracking_numbers)) { ?>
<?php foreach ($gls_tracking_numbers as $index => $tracking_number) { ?>
<button type="button" class="button gls-get-status" order-id="<?php echo esc_attr($order->get_id()); ?>" parcel-number="<?php echo esc_attr($tracking_number); ?>" style="margin-top: 10px;">
- <?php
+ <?php
if (count($gls_tracking_numbers) > 1) {
- echo sprintf(esc_html__("Get Parcel Status #%d (%s)", "gls-shipping-for-woocommerce"), $index + 1, esc_html($tracking_number));
+ /* translators: %1$d: parcel index number, %2$s: tracking number */
+ echo esc_html( sprintf(__("Get Parcel Status #%1$d (%2$s)", "gls-shipping-for-woocommerce"), intval($index) + 1, $tracking_number) );
} else {
- echo sprintf(esc_html__("Get Parcel Status (%s)", "gls-shipping-for-woocommerce"), esc_html($tracking_number));
+ /* translators: %s: tracking number */
+ echo esc_html( sprintf(__("Get Parcel Status (%s)", "gls-shipping-for-woocommerce"), $tracking_number) );
}
?>
</button>
@@ -241,7 +246,10 @@
<!-- Service Options (Hidden by default) -->
<div id="gls-services-options-new" style="display: none; margin-bottom: 15px; padding: 10px; border: 1px solid #ddd; border-radius: 4px; background-color: #f9f9f9;">
- <?php echo $this->render_service_options($order); ?>
+ <?php
+ // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Trusted internal method outputting form fields
+ echo $this->render_service_options($order);
+ ?>
</div>
<button type="button" class="button gls-print-label" order-id="<?php echo esc_attr($order->get_id()); ?>">
@@ -313,6 +321,7 @@
return array('success' => true, 'data' => $result);
} catch (Exception $e) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional error logging for debugging
error_log("Failed to generate GLS label for order $order_id: " . $e->getMessage());
return array('success' => false, 'error' => $e->getMessage());
}
@@ -320,15 +329,15 @@
public function generate_label_and_tracking_number()
{
- if (!wp_verify_nonce(sanitize_text_field($_POST['postNonce']), 'import-nonce')) {
+ if (!isset($_POST['postNonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['postNonce'])), 'import-nonce')) {
die('Busted!');
}
- $order_id = sanitize_text_field($_POST['orderId']);
+ $order_id = isset($_POST['orderId']) ? sanitize_text_field(wp_unslash($_POST['orderId'])) : '';
$count = isset($_POST['count']) ? intval($_POST['count']) : null;
$print_position = isset($_POST['printPosition']) ? intval($_POST['printPosition']) : null;
- $cod_reference = isset($_POST['codReference']) ? sanitize_text_field($_POST['codReference']) : null;
- $services = isset($_POST['services']) ? json_decode(stripslashes($_POST['services']), true) : null;
+ $cod_reference = isset($_POST['codReference']) ? sanitize_text_field(wp_unslash($_POST['codReference'])) : null;
+ $services = isset($_POST['services']) ? json_decode(sanitize_text_field(wp_unslash($_POST['services'])), true) : null;
// Use centralized method
$result = $this->generate_single_order_label($order_id, $count, $print_position, $cod_reference, $services);
@@ -408,13 +417,13 @@
public function get_parcel_status()
{
- if (!wp_verify_nonce(sanitize_text_field($_POST['postNonce']), 'import-nonce')) {
+ if (!isset($_POST['postNonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['postNonce'])), 'import-nonce')) {
wp_send_json_error(array('error' => 'Invalid security token'));
wp_die();
}
- $order_id = intval($_POST['orderId']);
- $parcel_number = sanitize_text_field($_POST['parcelNumber']);
+ $order_id = isset($_POST['orderId']) ? intval($_POST['orderId']) : 0;
+ $parcel_number = isset($_POST['parcelNumber']) ? sanitize_text_field(wp_unslash($_POST['parcelNumber'])) : '';
if (empty($order_id) || empty($parcel_number)) {
wp_send_json_error(array('error' => 'Missing order ID or parcel number'));
@@ -579,13 +588,13 @@
*/
public function update_pickup_location()
{
- if (!wp_verify_nonce(sanitize_text_field($_POST['postNonce']), 'import-nonce')) {
+ if (!isset($_POST['postNonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['postNonce'])), 'import-nonce')) {
wp_send_json_error(array('error' => 'Invalid security token'));
wp_die();
}
- $order_id = intval($_POST['orderId']);
- $pickup_info = isset($_POST['pickupInfo']) ? sanitize_text_field(stripslashes($_POST['pickupInfo'])) : '';
+ $order_id = isset($_POST['orderId']) ? intval($_POST['orderId']) : 0;
+ $pickup_info = isset($_POST['pickupInfo']) ? sanitize_text_field(wp_unslash($_POST['pickupInfo'])) : '';
if (empty($order_id) || empty($pickup_info)) {
wp_send_json_error(array('error' => 'Missing order ID or pickup information'));
@@ -607,7 +616,8 @@
$pickup_data = json_decode($pickup_info);
if ($pickup_data) {
$note = sprintf(
- __('GLS pickup location changed to: %s (%s)', 'gls-shipping-for-woocommerce'),
+ /* translators: %1$s: pickup location name, %2$s: pickup location ID */
+ __('GLS pickup location changed to: %1$s (%2$s)', 'gls-shipping-for-woocommerce'),
$pickup_data->name,
$pickup_data->id
);
@@ -634,15 +644,25 @@
return;
}
- // If this is an autosave, our form has not been submitted, so we don't want to do anything.
- if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
- return;
+ // If this is an autosave, our form has not been submitted, so we don't want to do anything.
+ if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
+ return;
+ }
- if (did_action('save_post_shop_order') > 1) return;
+ if (did_action('save_post_shop_order') > 1) {
+ return;
+ }
// Check if this is an order edit page
$screen = get_current_screen();
- if (!$screen || !in_array($screen->id, ['shop_order', 'woocommerce_page_wc-orders'])) {
+ if (!$screen || !in_array($screen->id, array('shop_order', 'woocommerce_page_wc-orders'), true)) {
+ return;
+ }
+
+ // Verify WooCommerce meta box nonce
+ // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Nonce verification only
+ $nonce = isset($_POST['woocommerce_meta_nonce']) ? wp_unslash($_POST['woocommerce_meta_nonce']) : '';
+ if (!wp_verify_nonce($nonce, 'woocommerce_save_data')) {
return;
}
@@ -666,19 +686,19 @@
} elseif (isset($_POST['gls_print_position_new']) && !empty($_POST['gls_print_position_new'])) {
$print_position = intval($_POST['gls_print_position_new']);
}
-
+
if ($print_position !== null) {
$order->update_meta_data('_gls_print_position', $print_position);
}
// Save COD reference if provided (check both possible fields)
$cod_reference = null;
- if (isset($_POST['gls_cod_reference']) && $_POST['gls_cod_reference'] !== '') {
- $cod_reference = sanitize_text_field($_POST['gls_cod_reference']);
- } elseif (isset($_POST['gls_cod_reference_new']) && $_POST['gls_cod_reference_new'] !== '') {
- $cod_reference = sanitize_text_field($_POST['gls_cod_reference_new']);
+ if (isset($_POST['gls_cod_reference']) && !empty($_POST['gls_cod_reference'])) {
+ $cod_reference = sanitize_text_field(wp_unslash($_POST['gls_cod_reference']));
+ } elseif (isset($_POST['gls_cod_reference_new']) && !empty($_POST['gls_cod_reference_new'])) {
+ $cod_reference = sanitize_text_field(wp_unslash($_POST['gls_cod_reference_new']));
}
-
+
if ($cod_reference !== null) {
$order->update_meta_data('_gls_cod_reference', $cod_reference);
}
@@ -703,10 +723,10 @@
// Special handling for select and text fields
if (isset($_POST['gls_express_delivery_service'])) {
- $services['express_delivery_service'] = sanitize_text_field($_POST['gls_express_delivery_service']);
+ $services['express_delivery_service'] = sanitize_text_field(wp_unslash($_POST['gls_express_delivery_service']));
}
if (isset($_POST['gls_sms_service_text'])) {
- $services['sms_service_text'] = sanitize_text_field($_POST['gls_sms_service_text']);
+ $services['sms_service_text'] = sanitize_text_field(wp_unslash($_POST['gls_sms_service_text']));
}
if (!empty($services)) {
--- a/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-pickup-history.php
+++ b/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-pickup-history.php
@@ -71,9 +71,11 @@
'created_at' => current_time('mysql')
);
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- Custom plugin table
$result = $wpdb->insert($this->table_name, $data);
-
+
if ($result === false) {
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional error logging for debugging
error_log('Failed to save pickup history: ' . $wpdb->last_error);
return false;
}
@@ -114,15 +116,20 @@
}
// Get total count
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared -- Table name uses $wpdb->prefix + constant, WHERE uses only hardcoded placeholders
$count_sql = "SELECT COUNT(*) FROM {$this->table_name} {$where_sql}";
if (!empty($where_values)) {
+ // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- SQL has placeholders, values are sanitized
$count_sql = $wpdb->prepare($count_sql, $where_values);
}
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom table with dynamic filtering
$total_items = $wpdb->get_var($count_sql);
// Get records - order by newest first (created_at DESC), then by ID DESC as secondary sort
+ // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name uses $wpdb->prefix + constant, WHERE uses only hardcoded placeholders
$sql = "SELECT * FROM {$this->table_name} {$where_sql} ORDER BY created_at DESC, id DESC LIMIT %d OFFSET %d";
$query_values = array_merge($where_values, array($per_page, $offset));
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom table with prepared placeholders
$records = $wpdb->get_results($wpdb->prepare($sql, $query_values));
// Parse JSON data
@@ -149,10 +156,12 @@
{
global $wpdb;
+ // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name uses $wpdb->prefix + constant
$record = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM {$this->table_name} WHERE id = %d",
$id
));
+ // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
if ($record) {
$record->request_data = json_decode($record->request_data, true);
--- a/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-pickup.php
+++ b/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-pickup.php
@@ -102,7 +102,7 @@
$message = '';
$error = '';
- if (isset($_POST['schedule_pickup']) && wp_verify_nonce($_POST['gls_pickup_nonce'], 'gls_pickup_action')) {
+ if (isset($_POST['schedule_pickup']) && isset($_POST['gls_pickup_nonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['gls_pickup_nonce'])), 'gls_pickup_action')) {
$result = $this->process_pickup_form();
if (is_wp_error($result)) {
$error = $result->get_error_message();
@@ -114,7 +114,7 @@
// Get all addresses (including store fallback as first option)
$all_addresses = GLS_Shipping_Sender_Address_Helper::get_all_addresses_with_store_fallback();
- $current_tab = isset($_GET['tab']) ? $_GET['tab'] : 'schedule';
+ $current_tab = isset($_GET['tab']) ? sanitize_key(wp_unslash($_GET['tab'])) : 'schedule';
?>
<div class="wrap">
@@ -235,6 +235,7 @@
*/
private function render_history_tab()
{
+ // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Display-only pagination/filtering
// Check if viewing details
if (isset($_GET['view_details'])) {
$this->render_pickup_details(intval($_GET['view_details']));
@@ -242,9 +243,11 @@
}
// Get filter parameters
- $search = isset($_GET['search']) ? sanitize_text_field($_GET['search']) : '';
- $status_filter = isset($_GET['status_filter']) ? sanitize_text_field($_GET['status_filter']) : '';
+ $search = isset($_GET['search']) ? sanitize_text_field(wp_unslash($_GET['search'])) : '';
+ $status_filter = isset($_GET['status_filter']) ? sanitize_text_field(wp_unslash($_GET['status_filter'])) : '';
$current_page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
+ // phpcs:enable WordPress.Security.NonceVerification.Recommended
+
$per_page = 20;
// Get history data
@@ -267,7 +270,7 @@
private function render_pickup_details($pickup_id)
{
if (!current_user_can('manage_woocommerce')) {
- wp_die(__('Permission denied.', 'gls-shipping-for-woocommerce'));
+ wp_die(esc_html__('Permission denied.', 'gls-shipping-for-woocommerce'));
}
$history = new GLS_Shipping_Pickup_History();
@@ -289,6 +292,7 @@
<a href="?page=gls-pickup&tab=history" class="button" style="margin-top: 24px;"><?php esc_html_e('← Back to History', 'gls-shipping-for-woocommerce'); ?></a>
</div>
+ <?php /* translators: %d: pickup ID number */ ?>
<h2><?php echo esc_html(sprintf(__('Pickup Details #%d', 'gls-shipping-for-woocommerce'), $pickup->id)); ?></h2>
<div class="pickup-details-container">
@@ -497,6 +501,7 @@
?>
<div class="tablenav bottom">
<div class="tablenav-pages">
+ <?php /* translators: %d: number of items */ ?>
<span class="displaying-num"><?php echo esc_html(sprintf(__('%d items', 'gls-shipping-for-woocommerce'), $data['total'])); ?></span>
<span class="pagination-links">
<?php if ($data['current_page'] > 1): ?>
@@ -540,6 +545,7 @@
/**
* Process pickup form submission
+ * Nonce verified in calling method (render_pickup_page)
*/
private function process_pickup_form()
{
@@ -548,6 +554,7 @@
return new WP_Error('permission_denied', __('Permission denied.', 'gls-shipping-for-woocommerce'));
}
+ // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verified in render_pickup_page() before calling this method
try {
// Get all addresses for validation
$all_addresses = GLS_Shipping_Sender_Address_Helper::get_all_addresses_with_store_fallback();
@@ -565,16 +572,16 @@
return new WP_Error('invalid_package_count', __('Package count must be at least 1.', 'gls-shipping-for-woocommerce'));
}
- $pickup_date_from = sanitize_text_field($_POST['pickup_date_from'] ?? '');
- $pickup_date_to = sanitize_text_field($_POST['pickup_date_to'] ?? '');
-
+ $pickup_date_from = isset($_POST['pickup_date_from']) ? sanitize_text_field(wp_unslash($_POST['pickup_date_from'])) : '';
+ $pickup_date_to = isset($_POST['pickup_date_to']) ? sanitize_text_field(wp_unslash($_POST['pickup_date_to'])) : '';
+
if (empty($pickup_date_from) || empty($pickup_date_to)) {
return new WP_Error('missing_dates', __('Pickup dates are required.', 'gls-shipping-for-woocommerce'));
}
// Combine date and time fields
- $pickup_time_from = !empty($_POST['pickup_time_from']) ? sanitize_text_field($_POST['pickup_time_from']) : '08:00';
- $pickup_time_to = !empty($_POST['pickup_time_to']) ? sanitize_text_field($_POST['pickup_time_to']) : '17:00';
+ $pickup_time_from = !empty($_POST['pickup_time_from']) ? sanitize_text_field(wp_unslash($_POST['pickup_time_from'])) : '08:00';
+ $pickup_time_to = !empty($_POST['pickup_time_to']) ? sanitize_text_field(wp_unslash($_POST['pickup_time_to'])) : '17:00';
$pickup_datetime_from = $pickup_date_from . ' ' . $pickup_time_from;
$pickup_datetime_to = $pickup_date_to . ' ' . $pickup_time_to;
@@ -608,6 +615,7 @@
} catch (Exception $e) {
return new WP_Error('api_error', $e->getMessage());
}
+ // phpcs:enable WordPress.Security.NonceVerification.Missing
}
}
--- a/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-product-restrictions.php
+++ b/gls-shipping-for-woocommerce/includes/admin/class-gls-shipping-product-restrictions.php
@@ -49,6 +49,7 @@
*/
public function save_product_shipping_restriction_field($post_id)
{
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing -- WooCommerce handles nonce verification for product meta
$restrict_parcel_shipping = isset($_POST['_gls_restrict_parcel_shipping']) ? 'yes' : 'no';
update_post_meta($post_id, '_gls_restrict_parcel_shipping', $restrict_parcel_shipping);
}
--- a/gls-shipping-for-woocommerce/includes/api/class-gls-shipping-api-service.php
+++ b/gls-shipping-for-woocommerce/includes/api/class-gls-shipping-api-service.php
@@ -92,21 +92,21 @@
$error_message .= ': ' . esc_html($body['Message']);
}
$this->log_error($error_message, $post_fields);
- throw new Exception($error_message);
+ throw new Exception(esc_html($error_message));
}
// Check for JSON decode errors
if (json_last_error() !== JSON_ERROR_NONE) {
$error_message = 'Invalid JSON response from GLS API: ' . json_last_error_msg();
$this->log_error($error_message, $post_fields);
- throw new Exception($error_message);
+ throw new Exception(esc_html($error_message));
}
// Check for general API errors (authentication, authorization, etc.)
if (isset($body['ErrorCode']) && $body['ErrorCode'] !== 0) {
$error_message = isset($body['ErrorDescription']) ? esc_html($body['ErrorDescription']) : 'Unknown GLS API error';
$this->log_error($error_message, $post_fields);
- throw new Exception($error_message);
+ throw new Exception(esc_html($error_message));
}
$failed_orders = [];
@@ -119,7 +119,7 @@
// If ClientReferenceList is empty, this is likely a general error (like authentication)
if (empty($error['ClientReferenceList'])) {
$this->log_error($error_message, $post_fields);
- throw new Exception($error_message);
+ throw new Exception(esc_html($error_message));
}
// Process order-specific errors
@@ -151,8 +151,8 @@
public function get_parcel_status($parcel_number)
{
- $tracking_api_url = $this->get_api_url('ParcelService', 'GetParcelStatuses');
-
+ $this->api_url = $this->get_api_url('ParcelService', 'GetParcelStatuses');
+
$post_fields = array(
'Username' => $this->get_option("username"),
'Password' => $this->get_password(),
@@ -168,7 +168,7 @@
'data_format' => 'body',
);
- $response = wp_remote_post($tracking_api_url, $params);
+ $response = wp_remote_post($this->api_url, $params);
if (is_wp_error($response)) {
$error_message = esc_html($response->get_error_message());
@@ -196,7 +196,7 @@
$error_message = 'Tracking error: ' . implode(', ', $errors);
// Also log the error with more context
$this->log_error($error_message . ' (Parcel Number: ' . $parcel_number . ')', $post_fields);
- throw new Exception($error_message);
+ throw new Exception(esc_html($error_message));
}
return $body;
@@ -218,9 +218,10 @@
private function log_error($error_message, $params)
{
$sanitized_params = $this->sanitize_params_for_logging($params);
- error_log('** API request to: ' . $this->api_url . ' FAILED **
- Request Params: {' . wp_json_encode($sanitized_params) . '}
- Error: ' . $error_message . '
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional API error logging for debugging
+ error_log('** API request to: ' . $this->api_url . ' FAILED **
+ Request Params: {' . wp_json_encode($sanitized_params) . '}
+ Error: ' . $error_message . '
** END **');
}
@@ -235,10 +236,11 @@
if (isset($body['POD']) && $body['POD']) {
$body['POD'] = 'SANITIZED';
}
-
- error_log('** API request to: ' . $this->api_url . ' SUCCESS **
- Request Params: {' . wp_json_encode($sanitized_params) . '}
- Response Body: ' . wp_json_encode($body) . '
+
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional API response logging for debugging
+ error_log('** API request to: ' . $this->api_url . ' SUCCESS **
+ Request Params: {' . wp_json_encode($sanitized_params) . '}
+ Response Body: ' . wp_json_encode($body) . '
** END **');
}
}
--- a/gls-shipping-for-woocommerce/includes/api/class-gls-shipping-pickup-api-service.php
+++ b/gls-shipping-for-woocommerce/includes/api/class-gls-shipping-pickup-api-service.php
@@ -62,7 +62,7 @@
// Handle invalid date
if ($timestamp === false) {
- throw new Exception('Invalid date format: ' . $date_string);
+ throw new Exception(esc_html('Invalid date format: ' . $date_string));
}
return '/Date(' . ($timestamp * 1000) . ')/';
@@ -141,36 +141,36 @@
if (is_wp_error($response)) {
$error_message = $response->get_error_message();
- throw new Exception('Error communicating with GLS API: ' . $error_message);
+ throw new Exception(esc_html('Error communicating with GLS API: ' . $error_message));
}
$body = json_decode(wp_remote_retrieve_body($response), true);
$response_code = wp_remote_retrieve_response_code($response);
if ($response_code !== 200) {
- throw new Exception('GLS API returned error code: ' . $response_code);
+ throw new Exception(esc_html('GLS API returned error code: ' . $response_code));
}
// Check for API errors
if (isset($body['ErrorCode']) && $body['ErrorCode'] !== 0) {
$error_message = isset($body['ErrorDescription']) ? $body['ErrorDescription'] : 'Unknown API error';
- throw new Exception('GLS API Error: ' . $error_message);
+ throw new Exception(esc_html('GLS API Error: ' . $error_message));
}
// Check for pickup request specific errors
if (isset($body['PickupRequestErrors']) && !empty($body['PickupRequestErrors'])) {
$pickup_errors = $body['PickupRequestErrors'];
$error_messages = array();
-
+
foreach ($pickup_errors as $error) {
if (isset($error['ErrorCode']) && $error['ErrorCode'] !== 0) {
$error_msg = isset($error['ErrorDescription']) ? $error['ErrorDescription'] : 'Unknown pickup error';
$error_messages[] = $error_msg;
}
}
-
+
if (!empty($error_messages)) {
- throw new Exception('GLS Pickup Error: ' . implode('; ', $error_messages));
+ throw new Exception(esc_html('GLS Pickup Error: ' . implode('; ', $error_messages)));
}
}
@@ -212,6 +212,7 @@
'response' => $response
);
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional API logging for debugging
error_log('GLS Pickup API Response: ' . wp_json_encode($log_entry));
}
@@ -227,6 +228,7 @@
'request_data' => $pickup_data // pickup_data doesn't contain credentials, safe to log
);
+ // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional API error logging for debugging
error_log('GLS Pickup API Error: ' . wp_json_encode($log_entry));
}
}
--- a/gls-shipping-for-woocommerce/includes/methods/class-gls-shipping-method-parcel-locker-zones.php
+++ b/gls-shipping-for-woocommerce/includes/methods/class-gls-shipping-method-parcel-locker-zones.php
@@ -1,4 +1,7 @@
<?php
+if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+}
function gls_shipping_method_parcel_locker_zones_init()
{
--- a/gls-shipping-for-woocommerce/includes/methods/class-gls-shipping-method-parcel-locker.php
+++ b/gls-shipping-for-woocommerce/includes/methods/class-gls-shipping-method-parcel-locker.php
@@ -1,4 +1,7 @@
<?php
+if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+}
function gls_shipping_method_parcel_locker_init()
{
@@ -66,6 +69,7 @@
'weight_based_rates' => array(
'title' => __('Weight Based Rates: max_weight|cost', 'gls-shipping-for-woocommerce'),
'type' => 'textarea',
+ /* translators: %s: weight unit (e.g. kg, lbs) */
'description' => sprintf(__('Optional: Enter weight based rates (one per line). Format: max_weight|cost. Example: 1|100 means up to 1 %s costs 100. Leave empty to use default price.', 'gls-shipping-for-woocommerce'), $weight_unit),
'default' => '',
'placeholder' => 'max_weight|cost
--- a/gls-shipping-for-woocommerce/includes/methods/class-gls-shipping-method-parcel-shop-zones.php
+++ b/gls-shipping-for-woocommerce/includes/methods/class-gls-shipping-method-parcel-shop-zones.php
@@ -1,4 +1,7 @@
<?php
+if ( ! defined( 'ABSPATH' ) ) {
+ exit;
+}
function gls_shipping_method_parcel_shop_zones_init()
{
@@ -64,6 +67,7 @@
'weight_based_rates' => array(
'title' => __('Weight Based Rates: max_weight|cost', 'gls-shipping-for-woocommerce'),
'type' => 'textarea',
+ /* translators: %s: weight unit (e.g. kg, lbs) */
'description' => sprintf(__('Optional: Enter weight based rates (one per line). Format: max_weight|cost. Example: 1|100 means up to 1 %s costs 100. Leave empty to use default price.', 'gls-shipping-for-woocommerce'), $weight_unit),
'default' => '',
'placeholder' => 'max_weight|cost
--- a/gls-shipping-for-woocommerce/includes/methods/class-gls-shipping-method-parcel-shop.php
+++ b/gls-shipping-for-woocommerce/includes/methods/class-gls-shipping-method-parcel-shop.php
@@ -1,4 +1,7 @@
<?ph