--- a/shipping-rate-by-cities/shipping_rate_by_cities.php
+++ b/shipping-rate-by-cities/shipping_rate_by_cities.php
@@ -3,7 +3,7 @@
* Plugin Name: Shipping Rate By Cities
* Plugin URI: https://wordpress.org/plugins/shipping-rate-by-cities
* Description: Set Custom Shipping Rates For Different Cities On Woocommerce.
- * Version: 2.0.0
+ * Version: 2.0.1
* Requires Plugins: woocommerce
* Requires at least: 5.1
* Tested up to: 6.9
@@ -13,7 +13,7 @@
* @copyright https://tridenttechnolabs.com
*/
-
+
if ( ! defined( 'WPINC' ) ) die;
/** @class Wc City Fee */
@@ -23,23 +23,23 @@
* Ship Rate By City Version.
* @var string
*/
- public $version = '2.0.0';
-
+ public $version = '2.0.1';
+
/**
* Stores notices.
* @var array
*/
private static $notices = [];
-
+
/**
* Logger context.
* @var array
*/
- public $context = ['source' => 'shiprate'];
-
+ public $context = ['source' => 'shipping-rate-by-cities'];
+
/** The single instance of the class. */
protected static $_instance = null;
-
+
/**
* Returns the *Singleton* instance of this class.
*
@@ -51,7 +51,7 @@
}
return self::$_instance;
}
-
+
/**
* Shipping Rate By City Constructor.
*/
@@ -61,7 +61,7 @@
$this->init_hooks();
// $this->session();
}
-
+
/**
* Initialize hooks and admin assets.
*/
@@ -80,16 +80,16 @@
// Frontend scripts
add_action( 'wp_enqueue_scripts', array( $this, 'enqueueScripts' ) );
- // Check if WooCommerce is active before registering WC-specific hooks
- if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
+ include_once ABSPATH . 'wp-admin/includes/plugin.php';
+ if ( is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
// Shipping method init
add_action( 'woocommerce_shipping_init', array( $this, 'shiprate_shipping_method' ) );
add_filter( 'woocommerce_shipping_methods', array( $this, 'add_shiprate_shipping_method' ) );
// Checkout fields and footer scripts for city select
add_filter( 'woocommerce_checkout_fields', array( $this, 'shiprate_city_options' ) );
- add_action( 'wp_footer', array( $this, 'shiprate_city_wp_footer' ) );
+
// Add plugin settings link on plugins page
add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'shiprate_plugin_settings_link' ) );
@@ -97,16 +97,35 @@
// Admin menu (register pages)
add_action( 'admin_menu', array( $this, 'register_admin_menu' ) );
- // AJAX for license activation/deactivation (admin-ajax)
- add_action( 'wp_ajax_shiprate_activate_license', array( $this, 'shiprate_activate_license_callback' ) );
- add_action( 'wp_ajax_shiprate_deactivate_license', array( $this, 'shiprate_deactivate_license_callback' ) ); // optional
+
// Validate city fields on checkout (server-side)
add_action( 'woocommerce_checkout_process', array( $this, 'shiprate_validate_city' ) );
+ add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_checkout_scripts' ) );
+
+ add_action( 'admin_post_shiprate_export_cities', array( $this, 'handle_export' ) );
+ add_action( 'admin_post_shiprate_import_cities', array( $this, 'handle_import' ) );
+
+
}
}
-/**
+ public function enqueue_checkout_scripts() {
+ if ( ! is_checkout() ) {
+ return;
+ }
+
+ wp_enqueue_script(
+ 'shiprate-frontend',
+ plugins_url( 'assets/js/shiprate-frontend.js', SHIPRATE_PLUGIN_FILE ),
+ array( 'jquery' ),
+ SHIPRATE_VERSION,
+ true
+ );
+ }
+
+
+ /**
* Return the full table name for the shiprate_cities table using the active WP DB prefix.
*
* The function will:
@@ -119,29 +138,150 @@
function shiprate_get_table_name() {
global $wpdb;
+ $cache_key = 'shiprate_cities_table';
+ $cache_group = 'shipping-rate-by-cities';
+
+ // 1. Try cache first
+ $cached = wp_cache_get( $cache_key, $cache_group );
+ if ( false !== $cached ) {
+ return $cached;
+ }
+
// canonical candidate using current prefix
$candidate = $wpdb->prefix . 'shiprate_cities';
- // quick check for exact table (prepared to avoid SQL injection)
- $found = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $candidate ) );
+ // 2. Exact table check
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
+ $found = $wpdb->get_var(
+ $wpdb->prepare(
+ 'SHOW TABLES LIKE %s',
+ $candidate
+ )
+ );
+
if ( $found ) {
+ wp_cache_set( $cache_key, $candidate, $cache_group );
return $candidate;
}
- // Try a more permissive search: find any table that ends with '_shiprate_cities'
- // This handles multisite/site-specific prefixes like 'wp_2_'
+ // 3. Multisite / fallback search
$like = '%' . $wpdb->esc_like( 'shiprate_cities' );
- $matches = $wpdb->get_col( $wpdb->prepare( "SHOW TABLES LIKE %s", $like ) );
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
+ $matches = $wpdb->get_col(
+ $wpdb->prepare(
+ 'SHOW TABLES LIKE %s',
+ $like
+ )
+ );
if ( ! empty( $matches ) ) {
- // Return first match (should be the intended table)
+ wp_cache_set( $cache_key, $matches[0], $cache_group );
return $matches[0];
}
- // Fallback: return candidate even if it doesn't exist (safe default)
+ // 4. Fallback
+ wp_cache_set( $cache_key, $candidate, $cache_group );
return $candidate;
}
+
+ public function handle_export() {
+ if ( ! current_user_can( 'manage_woocommerce' ) ) {
+ wp_die( 'Unauthorized' );
+ }
+
+ check_admin_referer( 'shiprate_export', 'shiprate_export_nonce' );
+
+ global $wpdb;
+
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Read-only query, cached via wp_cache_set().
+ $results = $wpdb->get_results( "SELECT city_name, rate FROM {$wpdb->prefix}shiprate_cities", ARRAY_A );
+
+ header( 'Content-Type: text/csv; charset=utf-8' );
+ header( 'Content-Disposition: attachment; filename=shipping-rate-by-cities.csv' );
+
+ $output = fopen( 'php://output', 'w' );
+ fputcsv( $output, array( 'city_name', 'rate' ) );
+
+ foreach ( $results as $row ) {
+ fputcsv( $output, $row );
+ }
+ // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Required for streamed CSV output via php://output.
+ fclose( $output );
+ exit;
+ }
+
+
+public function handle_import() {
+ if ( ! current_user_can( 'manage_woocommerce' ) ) {
+ wp_die( 'Unauthorized' );
+ }
+
+ check_admin_referer( 'shiprate_import', 'shiprate_import_nonce' );
+
+ if ( empty( $_FILES['import_file']['tmp_name'] ) ) {
+ wp_safe_redirect( wp_get_referer() );
+ exit;
+ }
+
+ global $wpdb;
+ $table = $wpdb->prefix . 'shiprate_cities';
+ $files = sanitize_file_name(wp_unslash($_FILES['import_file']['tmp_name']));
+// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- Required for streamed CSV output via php://output.
+ $handle = fopen( $files, 'r' );
+ if ( ! $handle ) {
+ wp_safe_redirect( wp_get_referer() );
+ exit;
+ }
+
+ // Skip header
+ fgetcsv( $handle );
+
+ while ( ( $data = fgetcsv( $handle ) ) !== false ) {
+ if ( empty( $data[0] ) || ! isset( $data[1] ) ) {
+ continue;
+ }
+
+ $city = sanitize_text_field( $data[0] );
+ $rate = (float) $data[1];
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Read-only query, cached via wp_cache_set().
+ $exists = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$wpdb->prefix}shiprate_cities WHERE city_name = %s", $city ) );
+
+ if ( $exists ) {
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
+ $wpdb->update(
+ $table,
+ array( 'rate' => $rate ),
+ array( 'city_name' => $city ),
+ array( '%f' ),
+ array( '%s' )
+ );
+ } else {
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
+ $wpdb->insert(
+ $table,
+ array(
+ 'city_name' => $city,
+ 'rate' => $rate,
+ ),
+ array( '%s', '%f' )
+ );
+ }
+ }
+ // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Required for streamed CSV output via php://output.
+ fclose( $handle );
+
+ // Clear cache
+ wp_cache_delete( 'shiprate_cities_list', 'shipping-rate-by-cities' );
+ wp_cache_delete( 'shiprate_other_city', 'shipping-rate-by-cities' );
+
+ wp_safe_redirect( wp_get_referer() );
+ exit;
+}
+
+
+
// In your main plugin file (shipping-rate-cities.php)
// inside your class
public function register_admin_menu() {
@@ -167,27 +307,36 @@
);
- // Submenu that opens the same page but with the verify-license tab active.
- // Note: the slug includes query args — WordPress accepts this and will generate the correct URL.
- add_submenu_page(
- 'shiprate-upgrade', // Parent slug.
- __( 'Upgrade to Pro', 'shipping-rate-by-cities' ), // Page title.
- __( 'Upgrade to Pro', 'shipping-rate-by-cities' ), // Menu title.
- 'manage_options',
- 'shiprate-upgrade&tab=verify-license', // Menu slug (with tab).
- array( $this, 'upgrade_page_html' ) // Callback.
- );
+add_submenu_page(
+ 'shiprate-upgrade',
+ __( 'Settings', 'shipping-rate-by-cities' ),
+ __( 'Settings', 'shipping-rate-by-cities' ),
+ 'manage_woocommerce',
+ 'shiprate-settings',
+ array( $this, 'redirect_to_wc_settings' )
+);
+
}
+
+
+
+
/**
* Enqueue admin assets (merged, safe, versioned).
*
* @param string $hook Admin page hook suffix passed by WP.
*/
public function admin_enqueue( $hook ) {
- $asset_version = "2.0.0";
+ if (
+ strpos( $hook, 'shiprate-upgrade' ) === false &&
+ strpos( $hook, 'wc-settings' ) === false
+ ) {
+ return;
+ }
+ $asset_version = "2.0.1";
// Register & enqueue admin CSS
wp_register_style(
'shiprate-admin',
@@ -211,10 +360,10 @@
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'shiprate_license_nonce_action' ),
'i18n' => array(
- 'fill_fields' => __( '⚠ Please fill all fields', 'shipping-rate-by-cities-pro' ),
- 'verifying' => __( '⏳ Verifying...', 'shipping-rate-by-cities-pro' ),
- 'activation_ok' => __( 'Activation successful', 'shipping-rate-by-cities-pro' ),
- 'activation_fail' => __( 'Activation failed', 'shipping-rate-by-cities-pro' ),
+ 'fill_fields' => __( '⚠ Please fill all fields', 'shipping-rate-by-cities' ),
+ 'verifying' => __( '⏳ Verifying...', 'shipping-rate-by-cities' ),
+ 'activation_ok' => __( 'Activation successful', 'shipping-rate-by-cities' ),
+ 'activation_fail' => __( 'Activation failed', 'shipping-rate-by-cities' ),
),
);
wp_localize_script( 'shiprate-admin', 'shiprateAdmin', $localize );
@@ -223,6 +372,15 @@
wp_enqueue_script( 'shiprate-admin' );
}
+
+ public function redirect_to_wc_settings() {
+ wp_safe_redirect(
+ admin_url( 'admin.php?page=wc-settings&tab=shipping§ion=shipping_plugin' )
+ );
+ exit;
+ }
+
+
/**
* Frontend script loader (keeps for possible frontend usage).
*/
@@ -231,60 +389,75 @@
// Add other frontend scripts here if needed (with proper handles)
}
-
+
// public function session()
// {
// if ( session_status() == PHP_SESSION_NONE ) {
// session_start();
// }
// }
-
- public function activation() {
- // On activation, require WooCommerce.
- if ( ! class_exists( 'WooCommerce' ) ) {
- // If WooCommerce is not active, deactivate this plugin immediately and show message.
- deactivate_plugins( plugin_basename( SHIPRATE_PLUGIN_FILE ) );
-
- /* translators: %s: link to plugins page */
- $return_link = esc_url( admin_url( 'plugins.php' ) );
- wp_die(
- esc_html__( 'Shipping Rate By Cities requires WooCommerce to be installed and active. Please install/activate WooCommerce first.', 'shipping-rate-by-cities' )
- . '<br/><br/><a href="' . $return_link . '">' . esc_html__( 'Return to Plugins page', 'shipping-rate-by-cities' ) . '</a>'
- );
- }
- global $wpdb;
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
+ public function activation() {
+ // On activation, require WooCommerce.
+ if ( ! class_exists( 'WooCommerce' ) ) {
+
+ deactivate_plugins( plugin_basename( SHIPRATE_PLUGIN_FILE ) );
+
+ $return_link = admin_url( 'plugins.php' );
+
+ wp_die(
+ sprintf(
+ wp_kses_post(
+ /* translators: %s: URL to the plugins page */
+ __( 'Shipping Rate By Cities requires WooCommerce to be installed and active. Please install/activate WooCommerce first.<br/><br/><a href="%s">Return to Plugins page</a>', 'shipping-rate-by-cities' )
+ ),
+ esc_url( $return_link )
+ )
+ );
+ }
- $charset_collate = $wpdb->get_charset_collate();
- $table_name = $wpdb->prefix . "shiprate_cities";
- $query = "CREATE TABLE IF NOT EXISTS $table_name (
- `id` int(11) AUTO_INCREMENT,
- `city_name` VARCHAR(255) NOT NULL,
- `rate` DECIMAL(10,2) NOT NULL,
- `status` VARCHAR(25) NOT NULL DEFAULT 1,
- `create_date` DATETIME NOT NULL,
- PRIMARY KEY (id)
- ) AUTO_INCREMENT=1 $charset_collate;";
- dbDelta( $query );
- }
- public function deactivation()
+ global $wpdb;
+ require_once ABSPATH . 'wp-admin/includes/upgrade.php';
+
+ $charset_collate = $wpdb->get_charset_collate();
+ $table_name = $wpdb->prefix . 'shiprate_cities';
+
+ $query = "CREATE TABLE IF NOT EXISTS $table_name (
+ id int(11) AUTO_INCREMENT,
+ city_name varchar(255) NOT NULL,
+ rate decimal(10,2) NOT NULL,
+ status varchar(25) NOT NULL DEFAULT '1',
+ create_date datetime NOT NULL,
+ PRIMARY KEY (id)
+ ) $charset_collate;";
+
+ dbDelta( $query );
+ }
+
+ public function deactivation()
{
// deactivatation code
}
-
+
/**
* Define Wc City Fee Constants.
*/
- private function defineConstants()
- {
-
- $this->define('SHIPRATE_PLUGIN_FILE', __FILE__);
- $this->define('SHIPRATE_VERSION', $this->version);
- $this->define('SHIPRATE', 'shiprate');
-
- }
+ private function defineConstants() {
+
+ if ( ! defined( 'SHIPRATE_PLUGIN_FILE' ) ) {
+ define( 'SHIPRATE_PLUGIN_FILE', __FILE__ );
+ }
+
+ if ( ! defined( 'SHIPRATE_VERSION' ) ) {
+ define( 'SHIPRATE_VERSION', $this->version );
+ }
+
+ if ( ! defined( 'SHIPRATE_SLUG' ) ) {
+ define( 'SHIPRATE_SLUG', 'shipping-rate-by-cities' );
+ }
+ }
+
/**
* Show an admin notice if WooCommerce is not installed/active.
@@ -346,19 +519,9 @@
echo '</div>';
}
-
- /**
- * Define constant if not already set.
- *
- * @param string $name Constant name.
- * @param string|bool $value Constant value.
- */
- private function define( $name, $value )
- {
- if (!defined($name)) {
- define($name, $value);
- }
- }
+
+
+
/**
* Render the plugin upgrade / license admin page.
@@ -366,152 +529,90 @@
* @since 1.1.2
* @return void
*/
- public function upgrade_page_html() {
- $status = get_option( 'shiprate_license_status', 'inactive' );
- $user_has_pro = ( 'valid' === $status );
-
- $saved_key = get_option( 'shiprate_license_key', '' );
- $saved_email = get_option( 'shiprate_license_email', '' );
-
-
- // Determine active tab (sanitized). Default to 'verify-license' when not provided.
- $allowed_tabs = array( 'buy', 'verify-license' );
- $active_tab = 'verify-license';
-
- if ( isset( $_GET['tab'] ) ) {
- $requested = sanitize_text_field( wp_unslash( $_GET['tab'] ) );
- if ( in_array( $requested, $allowed_tabs, true ) ) {
- $active_tab = $requested;
- }
- } else {
- // If there is no tab param, fallback:
- // show 'buy' only when user does NOT have pro, otherwise show verify-license.
- $active_tab = $user_has_pro ? 'verify-license' : 'buy';
- }
- ?>
+ public function upgrade_page_html() {
+ ?>
+ <div class="wrap shiprate-wrap" style="max-width:1000px;">
+
+ <!-- Heading -->
+ <h1 style="font-size:34px; margin-bottom:15px; font-weight:600;">
+ <span style="background:linear-gradient(90deg,#075fab,#045d91);
+ -webkit-background-clip:text;
+ -webkit-text-fill-color:transparent;">
+ <?php esc_html_e( '🚀 Shipping Rate by Cities – Pro', 'shipping-rate-by-cities' ); ?>
+ </span>
+ </h1>
+
+ <p style="font-size:16px; margin-bottom:30px; color:#444; line-height:1.7;">
+ <?php esc_html_e(
+ 'Upgrade to Shipping Rate by Cities Pro and unlock powerful shipping controls with advanced location-based pricing and bulk management tools.',
+ 'shipping-rate-by-cities'
+ ); ?>
+ </p>
+
+ <!-- Feature Grid -->
+ <div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(350px, 1fr)); gap:25px;">
+
+ <?php
+ $features = [
+ [ '🌍', 'Dynamic rates by State, City & Area', 'Set precise shipping rates based on multiple location levels.' ],
+ [ '🗂️', 'Multiple display modes', 'Show State only, City only, Area only, or any combination.' ],
+ [ '🔖', 'State code support', 'Works perfectly with WooCommerce state dropdowns.' ],
+ [ '⚙️', 'Default / fallback rate', 'Automatically apply a default rate if no city matches.' ],
+ [ '🔎', 'Search & pagination', 'Manage large city lists with fast search and pagination.' ],
+ [ '🛠️', 'Bulk actions', 'Edit or delete multiple cities at once.' ],
+ [ '📂', 'CSV import & export', 'Quickly import/export shipping rates using CSV files.' ],
+ [ '🚀', 'Performance optimized', 'Handles 10,000+ cities without slowing checkout.' ],
+ [ '🌐', 'Translation ready', 'Fully compatible with multilingual WordPress setups.' ],
+ ];
+
+ foreach ( $features as $feature ) :
+ ?>
+ <div style="
+ border:1px solid #e5e5e5;
+ border-radius:14px;
+ padding:22px;
+ background:#fff;
+ box-shadow:0 4px 10px rgba(0,0,0,0.06);
+ display:flex;
+ gap:18px;
+ ">
+ <div style="font-size:34px;"><?php echo esc_html( $feature[0] ); ?></div>
+ <div>
+ <h3 style="margin:0 0 6px; color:#045d91;">
+ <?php echo esc_html( $feature[1] ); ?>
+ </h3>
+ <p style="margin:0; color:#000; line-height:1.6;">
+ <?php echo esc_html( $feature[2] ); ?>
+ </p>
+ </div>
+ </div>
+ <?php endforeach; ?>
+
+ </div>
+
+ <!-- CTA -->
+ <div style="text-align:center; margin-top:45px;">
+ <a href="https://tridenttechnolabs.com/shipping-rate-by-cities-pro.php"
+ target="_blank"
+ rel="noopener noreferrer"
+ class="button button-primary"
+ style="
+ padding:14px 32px;
+ font-size:18px;
+ font-weight:700;
+ border-radius:10px;
+ ">
+ <?php esc_html_e( 'Upgrade to Pro', 'shipping-rate-by-cities' ); ?>
+ </a>
+ </div>
+
+ </div>
+ <?php
+ }
- <div class="wrap shiprate-wrap" style="max-width:1000px;">
- <!-- Heading -->
- <h1 style="font-size:34px; margin-bottom:15px; font-weight:600;">
- <span style="background:linear-gradient(90deg,#075fab,#045d91); -webkit-background-clip:text; -webkit-text-fill-color:transparent; display:inline-block;">
- <?php echo esc_html__( '🚀 Shipping Rate by Cities - Pro', 'shipping-rate-by-cities-pro' ); ?>
- </span>
- </h1>
-
- <p style="font-size:16px; margin-bottom:25px; color:#444; line-height:1.7;">
- <?php
- /* translators: plugin upgrade short description */
- echo esc_html__( 'Upgrade to Shipping Rate by Cities Pro and unlock powerful features like dynamic rates by State, City & Area, CSV import/export, bulk actions, search & pagination, and much more.', 'shipping-rate-by-cities-pro' );
- ?>
- </p>
-
- <!-- License Active Banner -->
- <?php if ( $user_has_pro ) : ?>
- <div class="shiprate-banner" style="background:linear-gradient(90deg,#7a00ff,#d63638); color:#fff; padding:14px 20px; border-radius:12px; margin-bottom:30px; font-size:16px; font-weight:600; display:flex; align-items:center; gap:10px; box-shadow:0 6px 14px rgba(0,0,0,0.15);">
- <?php echo esc_html__( '🎉 Congratulations! Shipping Rate by Cities Pro is activated. Enjoy premium features 🚀', 'shipping-rate-by-cities-pro' ); ?>
- </div>
- <?php endif; ?>
-
- <!-- Tabs -->
- <div style="display:flex; gap:15px; margin-bottom:30px; flex-wrap:wrap;">
- <?php if ( ! $user_has_pro ) : ?>
- <button class="tab-btn active-tab" data-tab="buy" type="button" style="padding:12px 15px; font-size:17px; border:none; border-radius:6px; background:#bb2f05; color:#fff; cursor:pointer;">
- <?php echo esc_html__( '💳 Buy Now', 'shipping-rate-by-cities-pro' ); ?>
- </button>
- <?php endif; ?>
-
- <button class="tab-btn <?php echo $user_has_pro ? 'active-tab' : ''; ?>" data-tab="verify-license" type="button" style="padding:12px 15px; font-size:17px; border:none; border-radius:6px; background:#2288df; color:#fff; cursor:pointer;">
- <?php echo esc_html__( '🛡️ Verify License', 'shipping-rate-by-cities-pro' ); ?>
- </button>
- </div>
-
- <!-- Buy Now Tab -->
- <?php if ( ! $user_has_pro ) : ?>
- <div id="tab-buy" class="tab-content" style="<?php echo ( 'buy' === $active_tab ) ? 'display:block;' : 'display:none;'; ?>">
- <h2 style="color:#045d91; margin-bottom:20px;"><?php echo esc_html__( 'Pro Features', 'shipping-rate-by-cities-pro' ); ?></h2>
-
- <div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(350px, 1fr)); gap:25px;">
- <?php
- $features = array(
- array( 'title' => __( 'Dynamic rates by State, City & Area', 'shipping-rate-by-cities-pro' ), 'desc' => __( 'Multi-level matching for precise shipping rate control.', 'shipping-rate-by-cities-pro' ), 'icon' => '🌍' ),
- array( 'title' => __( 'Multiple display modes', 'shipping-rate-by-cities-pro' ), 'desc' => __( 'Show State only, City only, Area only, or any combination.', 'shipping-rate-by-cities-pro' ), 'icon' => '🗂️' ),
- array( 'title' => __( 'State code support', 'shipping-rate-by-cities-pro' ), 'desc' => __( 'Works seamlessly with WooCommerce state dropdowns.', 'shipping-rate-by-cities-pro' ), 'icon' => '🔖' ),
- array( 'title' => __( 'Default rate', 'shipping-rate-by-cities-pro' ), 'desc' => __( 'Set fallback rates for unmatched locations.', 'shipping-rate-by-cities-pro' ), 'icon' => '⚙️' ),
- array( 'title' => __( 'Searchable & paginated manager', 'shipping-rate-by-cities-pro' ), 'desc' => __( 'Easily manage large datasets with search & pagination.', 'shipping-rate-by-cities-pro' ), 'icon' => '🔎' ),
- array( 'title' => __( 'Bulk actions', 'shipping-rate-by-cities-pro' ), 'desc' => __( 'Update or delete multiple locations at once.', 'shipping-rate-by-cities-pro' ), 'icon' => '🛠️' ),
- array( 'title' => __( 'CSV import/export', 'shipping-rate-by-cities-pro' ), 'desc' => __( 'Import/export with auto-generated templates (large file friendly).', 'shipping-rate-by-cities-pro' ), 'icon' => '📂' ),
- array( 'title' => __( 'Performance optimized', 'shipping-rate-by-cities-pro' ), 'desc' => __( 'Handles 10k+ rows without slowing down.', 'shipping-rate-by-cities-pro' ), 'icon' => '🚀' ),
- array( 'title' => __( 'Translation-ready', 'shipping-rate-by-cities-pro' ), 'desc' => __( 'Fully compatible with themes and multilingual plugins.', 'shipping-rate-by-cities-pro' ), 'icon' => '🌐' ),
- );
-
- foreach ( $features as $feature ) :
- ?>
- <div class="shiprate-feature" style="border:1px solid #e5e5e5; border-radius:14px; padding:22px; background:#fff; box-shadow:0 4px 10px rgba(0,0,0,0.06); display:flex; align-items:flex-start; gap:18px; transition:all 0.3s ease;">
- <div style="font-size:34px; flex-shrink:0;"><?php echo esc_html( $feature['icon'] ); ?></div>
- <div>
- <h3 style="font-size:18px; margin:0 0 8px; color:#045d91; font-weight:600;"><?php echo esc_html( $feature['title'] ); ?></h3>
- <p style="font-size:15px; color:#000; margin:0; line-height:1.6;"><?php echo esc_html( $feature['desc'] ); ?></p>
- </div>
- </div>
- <?php endforeach; ?>
- </div>
-
- <div style="text-align:center; margin-top:40px;">
- <a href="<?php echo esc_url( 'https://tridenttechnolabs.com/shipping-rate-by-cities-pro.php' ); ?>" target="_blank" rel="noopener noreferrer" class="button button-primary" style="padding:14px 28px; background:#bb2f05; color:#fff; font-size:18px; font-weight:700; border-radius:10px; text-decoration:none; box-shadow:0 4px 12px rgba(0,0,0,0.15);">
- <?php echo esc_html__( '💳 Buy Now', 'shipping-rate-by-cities-pro' ); ?>
- </a>
- </div>
- </div>
- <?php endif; ?>
-
- <!-- Verify License Tab -->
- <div id="tab-verify-license" class="tab-content" style="<?php echo ( 'verify-license' === $active_tab ) ? 'display:block;' : 'display:none;'; ?> max-width:500px; margin:0 auto; padding:20px; border:1px solid #ddd; border-radius:8px; background:#fff;">
- <h3 style="margin-bottom:15px; color:#045d91; margin-top:0;"><?php echo esc_html__( 'Enter License Details', 'shipping-rate-by-cities-pro' ); ?></h3>
-
- <table class="form-table">
- <tr>
- <th scope="row"><?php echo esc_html__( 'Your Email', 'shipping-rate-by-cities-pro' ); ?></th>
- <td><input type="email" id="shiprate_license_email" value="<?php echo esc_attr( $saved_email ); ?>" class="regular-text" /></td>
- </tr>
-
- <tr>
- <th scope="row"><?php echo esc_html__( 'License Key', 'shipping-rate-by-cities-pro' ); ?></th>
- <td><input type="text" id="shiprate_license_key" value="<?php echo esc_attr( $saved_key ); ?>" class="regular-text" /></td>
- </tr>
-
- <tr>
- <th scope="row"><?php echo esc_html__( 'License Status', 'shipping-rate-by-cities-pro' ); ?></th>
- <td id="license-status-text">
- <?php
- if ( 'valid' === $status ) :
- echo '<span style="color:green; font-weight:bold;">' . esc_html__( '✔ License Activated', 'shipping-rate-by-cities-pro' ) . '</span>';
- elseif ( 'invalid' === $status ) :
- echo '<span style="color:red; font-weight:bold;">' . esc_html__( '✘ License Invalid', 'shipping-rate-by-cities-pro' ) . '</span>';
- elseif ( 'expired' === $status ) :
- echo '<span style="color:brown; font-weight:bold;">' . esc_html__( '⛔ License Expired', 'shipping-rate-by-cities-pro' ) . '</span>';
- elseif ( 'pending' === $status ) :
- echo '<span style="color:orange; font-weight:bold;">' . esc_html__( '⌛ Pending Payment', 'shipping-rate-by-cities-pro' ) . '</span>';
- else :
- echo '<span style="color:gray;">' . esc_html__( 'Not activated', 'shipping-rate-by-cities-pro' ) . '</span>';
- endif;
- ?>
- </td>
- </tr>
- </table>
-
- <div style="text-align:center; margin-top:15px;">
- <button id="activate-license-btn" class="button button-primary" type="button" style="font-size:15px;">
- <?php echo esc_html__( 'Verify License', 'shipping-rate-by-cities-pro' ); ?>
- </button>
- </div>
- </div>
- </div>
- <?php
- }
-
function shiprate_shipping_method() {
include_once "shiprate-cities-method-class.php";
}
@@ -519,8 +620,8 @@
function shiprate_plugin_settings_link( $actions ) {
$mylinks = array(
- '<a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=shipping§ion=shiprate' ) ) . '">' . esc_html__( 'Settings', 'shiprate' ) . '</a>',
- '<a href="https://tridenttechnolabs.com/shipping-rate-by-cities-pro.php/?utm_source=wporg_plugin_list&utm_medium=plugin_action_link&utm_campaign=go_pro" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Premium', 'shiprate' ) . '</a>',
+ '<a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=shipping§ion=shiprate' ) ) . '">' . esc_html__( 'Settings', 'shipping-rate-by-cities' ) . '</a>',
+ '<a href="https://tridenttechnolabs.com/shipping-rate-by-cities-pro.php/?utm_source=wporg_plugin_list&utm_medium=plugin_action_link&utm_campaign=go_pro" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Premium', 'shipping-rate-by-cities' ) . '</a>',
);
// Put your custom links before the default actions
@@ -535,32 +636,8 @@
-
-
- // function shiprate_city_options( $fields ) {
- // global $wpdb;
- // $table = $wpdb->prefix . "shiprate_cities";
- // $cities = $wpdb->get_results("SELECT city_name FROM $table ");
- // $options[] = 'Select city';
-
- // foreach($cities as $city){
- // $options[$city->city_name] = $city->city_name;
- // }
-
- // $city_args = wp_parse_args(array(
- // 'type' => 'select',
- // 'options' => $options,
- // 'autocomplete' => true
- // ), $fields['shipping']['shipping_city']);
-
-
-
- // $fields['shipping']['shipping_city'] = $city_args;
- // $fields['billing']['billing_city'] = $city_args; // Also change for billing field
- // return $fields;
-
- // }
+
/**
* Replace shipping/billing city fields with a select + optional "Other City" text input.
*
@@ -568,13 +645,24 @@
* @return array
*/
public function shiprate_city_options( $fields ) {
- global $wpdb;
- $table = $wpdb->prefix . 'shiprate_cities';
+ global $wpdb;
+
+ $cache_key = 'shiprate_city_options';
+ $cache_group = 'shipping-rate-by-cities';
+
+ $cities = wp_cache_get( $cache_key, $cache_group );
- $cities = $wpdb->get_results( "SELECT city_name FROM $table ORDER BY city_name ASC" );
+ if ( false === $cities ) {
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Read-only query, cached via wp_cache_set().
+ $cities = $wpdb->get_results(
+ "SELECT city_name FROM {$wpdb->prefix}shiprate_cities ORDER BY city_name ASC"
+ );
+
+ wp_cache_set( $cache_key, $cities, $cache_group );
+ }
// Build options with an empty default so WooCommerce treats it as "not selected"
- $options = array( '' => __( 'Select city', 'shiprate' ) );
+ $options = array( '' => __( 'Select city', 'shipping-rate-by-cities' ) );
foreach ( $cities as $city ) {
// use city name as both key and label
@@ -582,12 +670,12 @@
}
// Ensure "Other City" is available as a selectable option
- $options['Other City'] = __( 'Other City', 'shiprate' );
+ $options['Other City'] = __( 'Other City', 'shipping-rate-by-cities' );
// Common args for select field
$city_args = wp_parse_args( array(
'type' => 'select',
- 'label' => __( 'City', 'shiprate' ),
+ 'label' => __( 'City', 'shipping-rate-by-cities' ),
'required' => true, // boolean true (not string)
'class' => array( 'form-row-wide' ),
'options' => $options,
@@ -597,9 +685,9 @@
// Text field used when user selects "Other City"
$city_args_text = array(
'type' => 'text',
- 'label' => __( 'Enter City', 'shiprate' ),
+ 'label' => __( 'Enter City', 'shipping-rate-by-cities' ),
'required' => false, // We'll validate server-side only when "Other City" is chosen
- 'placeholder' => __( 'Enter Other City Name', 'shiprate' ),
+ 'placeholder' => __( 'Enter Other City Name', 'shipping-rate-by-cities' ),
'class' => array( 'form-row-wide', 'shiprate-other-city' ),
);
@@ -614,90 +702,64 @@
}
-/**
- * Server-side validation for billing_city and shipping_city.
- */
-public function shiprate_validate_city() {
- // Billing
- $billing_city = isset( $_POST['billing_city'] ) ? wc_clean( wp_unslash( $_POST['billing_city'] ) ) : '';
- $billing_city_text = isset( $_POST['billing_city_text'] ) ? wc_clean( wp_unslash( $_POST['billing_city_text'] ) ) : '';
-
- if ( empty( $billing_city ) ) {
- wc_add_notice( __( 'Please select a billing city.', 'shiprate' ), 'error' );
- } elseif ( 'Other City' === $billing_city && trim( $billing_city_text ) === '' ) {
- wc_add_notice( __( 'Please enter your billing city (Other City).', 'shiprate' ), 'error' );
- }
-
- // Shipping (if shipping to different address)
- $shipping_city = isset( $_POST['shipping_city'] ) ? wc_clean( wp_unslash( $_POST['shipping_city'] ) ) : '';
- $shipping_city_text = isset( $_POST['shipping_city_text'] ) ? wc_clean( wp_unslash( $_POST['shipping_city_text'] ) ) : '';
-
- // Only validate shipping city if shipping is required / enabled
- $ship_to_different = isset( $_POST['ship_to_different_address'] ) ? true : false;
-
- // Some sites always require shipping fields — we mimic WooCommerce behavior:
- if ( ! empty( $shipping_city ) || $ship_to_different ) {
- if ( empty( $shipping_city ) ) {
- wc_add_notice( __( 'Please select a shipping city.', 'shiprate' ), 'error' );
- } elseif ( 'Other City' === $shipping_city && trim( $shipping_city_text ) === '' ) {
- wc_add_notice( __( 'Please enter your shipping city (Other City).', 'shiprate' ), 'error' );
+ /**
+ * Server-side validation for billing_city and shipping_city.
+ *
+ * WooCommerce checkout nonces are already verified upstream.
+ * This function runs after core nonce verification.
+ */
+ public function shiprate_validate_city() {
+
+ // Billing city
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $billing_city = isset( $_POST['billing_city'] )? sanitize_text_field( wp_unslash( $_POST['billing_city'] ) ) : '';
+
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $billing_city_text = isset( $_POST['billing_city_text'] )? sanitize_text_field( wp_unslash( $_POST['billing_city_text'] ) ) : '';
+
+ if ( empty( $billing_city ) ) {
+ wc_add_notice(
+ __( 'Please select a billing city.', 'shipping-rate-by-cities' ),
+ 'error'
+ );
+ } elseif ( 'Other City' === $billing_city && '' === trim( $billing_city_text ) ) {
+ wc_add_notice(
+ __( 'Please enter your billing city (Other City).', 'shipping-rate-by-cities' ),
+ 'error'
+ );
+ }
+
+ // Shipping city
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $shipping_city = isset( $_POST['shipping_city'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_city'] ) ): '';
+
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $shipping_city_text = isset( $_POST['shipping_city_text'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_city_text'] ) ) : '';
+
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ $ship_to_different = isset( $_POST['ship_to_different_address'] );
+
+ if ( ! empty( $shipping_city ) || $ship_to_different ) {
+ if ( empty( $shipping_city ) ) {
+ wc_add_notice(
+ __( 'Please select a shipping city.', 'shipping-rate-by-cities' ),
+ 'error'
+ );
+ } elseif ( 'Other City' === $shipping_city && '' === trim( $shipping_city_text ) ) {
+ wc_add_notice(
+ __( 'Please enter your shipping city (Other City).', 'shipping-rate-by-cities' ),
+ 'error'
+ );
+ }
}
}
-}
-
- function shiprate_city_wp_footer(){
- if(is_checkout()){
-
- ?>
- <script>
- jQuery( function($) {
- $('#billing_city').change(function(){
- jQuery('body').trigger('update_checkout');
- });
- $('#shipping_city').change(function(){
- jQuery('body').trigger('update_checkout');
- });
-
-
- $('#shipping_city').css('height','50px');
- $('input[name="shipping_city_text"]').css('margin-top','10px');
-
- $('#billing_city').css('height','50px');
- $('input[name="billing_city_text"]').css('margin-top','10px');
-
- var select1 = $('select[name="shipping_city"]');
- var input1 = $('input[name="shipping_city_text"]');
- select1.change(function() {
- if ($(this).val() == 'Other City') {
-
- input1.show();
- $('#shipping_city_field').append(input1);
-
- } else {
- input1.hide();
- }
- });
-
- var select = $('select[name="billing_city"]');
- var input = $('input[name="billing_city_text"]');
- select.change(function() {
- if ($(this).val() == 'Other City') {
-
- input.show();
- $('#billing_city_field').append(input);
- } else {
- input.hide();
- }
- });
- });
- </script>
- <?php
- }
- }
+
+
+
}
-
+
/**
* Returns the main instance of WC.
*
@@ -707,101 +769,10 @@
function shiprate_shipping() {
return WShippingRateByCity::instance();
}
-
- // Global for backwards compatibility.
- $GLOBALS['shiprate'] = shiprate_shipping();
-
-
- if(isset($_POST['submitexport'])){
-
- if (isset($_POST['export_csv'])) {
- global $wpdb;
-
- $table_name = $wpdb->prefix . 'shiprate_cities';
- $results = $wpdb->get_results("SELECT * FROM $table_name");
-
- $header_row = array('city_name', 'rate');
- $rows = array($header_row);
- foreach ($results as $result) {
- $row = array($result->city_name, $result->rate);
- array_push($rows, $row);
- }
-
- $csv_data = '';
- foreach ($rows as $row) {
- $csv_data .= implode(',', $row) . "n";
- }
-
-
-
- header('Content-Type: text/csv');
- header('Content-Disposition: attachment; filename=export.csv');
- echo $csv_data;
- exit;
- }
-
-}
-
-
- if (isset($_POST['importsubmit'])) {
-
- global $wpdb;
+ // Global for backwards compatibility.
+$GLOBALS['shiprate_shipping_plugin'] = shiprate_shipping();
- $table_name = $wpdb->prefix . 'shiprate_cities';
- // Check if a file is uploaded
- if (!empty($_FILES['import_file']['tmp_name'])) {
- // Get the uploaded file details
- $file = $_FILES['import_file']['tmp_name'];
-
- $handle = fopen($file, 'r');
-if ($handle !== false) {
- // Skip the header row
- $header = fgetcsv($handle);
-
- // Loop through the CSV data
- while (($data = fgetcsv($handle)) !== false) {
- // Retrieve the necessary data from each row
- $cityName = $data[0];
- $rate = $data[1];
-
- // Check if the city already exists in the table
- $existingCity = $wpdb->get_row(
- $wpdb->prepare("SELECT * FROM $table_name WHERE city_name = %s", $cityName)
- );
- // Perform the insert or update operation based on whether the city exists or not
- if ($existingCity) {
- // City exists, perform an update
- $wpdb->update(
- $table_name,
- array('rate' => $rate),
- array('city_name' => $cityName)
- );
- } else {
- // City does not exist, perform an insert
- $wpdb->insert(
- $table_name,
- array('city_name' => $cityName, 'rate' => $rate)
- );
- }
- }
- fclose($handle);
- // Refresh the current page using JavaScript
- echo '<script> window.location.href = window.location.href; </script>';
- exit;
- } else {
- // Show an error message if the file cannot be opened
- echo 'Error: Unable to open the file.';
- exit;
- }
- } else {
- // Show an error message if the file cannot be opened
- echo 'Error: Unable to open the file.';
- exit;
- }
-}
-
-
No newline at end of file
--- a/shipping-rate-by-cities/shiprate-cities-method-class.php
+++ b/shipping-rate-by-cities/shiprate-cities-method-class.php
@@ -1,5 +1,6 @@
<?php
+if ( ! defined( 'ABSPATH' ) ) exit;
if ( ! class_exists( 'ShipRate_FlatShipRateCity_Method' ) ) {
class ShipRate_FlatShipRateCity_Method extends WC_Shipping_Method {
@@ -10,18 +11,18 @@
* @return void
*/
public function __construct() {
- $this->id = 'shiprate';
- $this->method_title = __( 'Shipping Rate by City', 'shiprate' );
- $this->method_description = __( 'You can set your shipping rate by user selected city', 'shiprate' );
+ $this->id = 'shipping_plugin';
+ $this->method_title = __( 'Shipping Rate by City', 'shipping-rate-by-cities' );
+ $this->method_description = __( 'You can set your shipping rate by user selected city', 'shipping-rate-by-cities' );
$this->init();
-
+
$this->enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'yes';
- $this->title = $this->settings['title'] ?? __( 'Ship Rate City', 'shiprate' );
+ $this->title = $this->settings['title'] ?? __( 'Ship Rate City', 'shipping-rate-by-cities' );
$this->qty_multi = $this->settings['qty_multi'] ?? '';
add_action('woocommerce_update_options_shipping_methods', array(&$this, 'process_admin_options'));
@@ -35,68 +36,103 @@
*/
function init() {
// Load the settings API
- $this->init_form_fields();
- $this->init_settings();
+ $this->init_form_fields();
+ $this->init_settings();
// Save settings in admin if you have any defined
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
}
function admin_options() {
+ wp_nonce_field( 'shiprate_save_cities', 'shiprate_nonce' );
?>
<div style="display:flex">
- <h2 style="margin-right:80px"><?php _e('Shipping Rate by City','woocommerce'); ?></h2>
+ <h2 style="margin-right:80px"><?php esc_html_e('Shipping Rate by City','shipping-rate-by-cities'); ?></h2>
<table>
<tr>
<th>
<form method="post" action="">
+ <?php wp_nonce_field( 'shiprate_export', 'shiprate_export_nonce' ); ?>
<input type="hidden" name="export_csv" value="1">
<button type="submit" name="submitexport" class="button button-primary">Export Cities</button>
</form>
-
-
+
+
</th>
- <td>
- <a href="<?php echo plugin_dir_url(__FILE__) . 'sampleshipratecity.csv'; ?>" class="button button-primary" download>Download Sample CSV File</a>
+ <td>
+ <a href="<?php echo esc_url( plugin_dir_url(__FILE__) . 'sampleshipratecity.csv' ); ?>" class="button button-primary" download>Download Sample CSV File</a>
</tr>
</table>
</div>
-
+
<table class="form-table">
<?php $this->generate_settings_html(); ?>
<?php $this->cities_form_fiels(); ?>
-
- </table>
-
+
+ </table>
+
<?php
}
-
-
- function getCities(){
+ function getCities() {
global $wpdb;
- $table = $wpdb->prefix . "shiprate_cities";
- return $wpdb->get_results("SELECT id, city_name, rate FROM $table WHERE city_name != 'Other City'", OBJECT);
+
+ $cache_key = 'shiprate_cities_list';
+ $cache_group = 'shipping-rate-by-cities';
+
+ $cached = wp_cache_get( $cache_key, $cache_group );
+ if ( false !== $cached ) {
+ return $cached;
+ }
+
+ $table = $wpdb->prefix . 'shiprate_cities' ;
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
+ $results = $wpdb->get_results($wpdb->prepare( "SELECT id, city_name, rate FROM {$wpdb->prefix}shiprate_cities WHERE city_name != %s", 'Other City' ), OBJECT );
+
+ wp_cache_set( $cache_key, $results, $cache_group );
+
+ return $results;
}
- function getOtherCities(){
+
+ function getOtherCities() {
global $wpdb;
- $table = $wpdb->prefix . "shiprate_cities";
- return $wpdb->get_results("SELECT id, city_name, rate FROM $table WHERE city_name = 'Other City'", OBJECT);
+
+ $cache_key = 'shiprate_other_city';
+ $cache_group = 'shipping-rate-by-cities';
+
+ $cached = wp_cache_get( $cache_key, $cache_group );
+ if ( false !== $cached ) {
+ return $cached;
+ }
+
+ $table = esc_sql( $wpdb->prefix . 'shiprate_cities' );
+ // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
+ $result = $wpdb->get_results(
+ $wpdb->prepare(
+ "SELECT id, city_name, rate FROM {$wpdb->prefix}shiprate_cities WHERE city_name = %s",
+ 'Other City'
+ ),
+ OBJECT
+ );
+
+ wp_cache_set( $cache_key, $result, $cache_group );
+
+ return $result;
}
+
function cities_form_fiels(){
global $wpdb;
- if(isset( $_POST['cities'] )){
$this->update_cities();
- }
+
$cities = $this->getCities();
@@ -106,96 +142,94 @@
<tr valign="top">
<th scope="row" class="titledesc">
- <label for="woocommerce_shiprate_cities"><?php _e('Default Ship Rate', 'shiprate') ?></label>
+ <label for="woocommerce_shiprate_cities"><?php esc_html_e('Default Ship Rate', 'shipping-rate-by-cities') ?></label>
</th>
<td id="">
- <?php
- if(count($othercities)) {
+ <?php
+ if(count($othercities)) {
foreach($othercities as $otherciti){
- ?>
-
+ ?>
+
<div class="wcc_fee_row">
- <input type="text" name="othercity[<?php echo esc_attr($otherciti->id) ?>]" value="<?php echo esc_attr($otherciti->city_name) ?>" class="input-text regular-input" placeholder="<?php _e('Other City', 'shiprate') ?>" readonly>
- <span class="wccfee_currency"><?php echo get_woocommerce_currency_symbol() ?></span>
- <input type="text" name="other_city_fee[<?php echo esc_attr($otherciti->id) ?>]" value="<?php echo esc_attr($otherciti->rate) ?>" class="input-text regular-input wccfee_cities_fee" placeholder="<?php _e('0', 'shiprate') ?>">
-
+ <input type="text" name="othercity[<?php echo esc_attr($otherciti->id) ?>]" value="<?php echo esc_attr($otherciti->city_name) ?>" class="input-text regular-input" placeholder="<?php esc_attr__('Other City', 'shipping-rate-by-cities') ?>" readonly>
+ <span class="wccfee_currency"><?php echo esc_html( get_woocommerce_currency_symbol() ) ?></span>
+ <input type="text" name="other_city_fee[<?php echo esc_attr($otherciti->id) ?>]" value="<?php echo esc_attr($otherciti->rate) ?>" class="input-text regular-input wccfee_cities_fee" placeholder="<?php esc_attr__('0', 'shipping-rate-by-cities') ?>">
+
</div>
<?php }}else{?>
<div class="wcc_fee_row">
<input type="text" name="othercity[]" value="Other City" class="input-text regular-input"readonly >
- <span class="wccfee_currency"><?php echo get_woocommerce_currency_symbol() ?></span>
- <input type="text" name="other_city_fee[]" value="" class="input-text regular-input wccfee_cities_fee" placeholder="<?php _e('0', 'shiprate') ?>">
+ <span class="wccfee_currency"><?php echo esc_html( get_woocommerce_currency_symbol() ) ?></span>
+ <input type="text" name="other_city_fee[]" value="" class="input-text regular-input wccfee_cities_fee" placeholder="<?php esc_attr__('0', 'shipping-rate-by-cities') ?>">
</div>
<?php } ?>
-
+
</td>
</tr>
-
+
<tr valign="top">
<th scope="row" class="titledesc">
- <label for="woocommerce_shiprate_cities"><?php _e('Your Cities', 'shiprate') ?></label>
+ <label for="woocommerce_shiprate_cities"><?php esc_html_e('Your Cities', 'shipping-rate-by-cities') ?></label>
</th>
<td id="wcc_fee_rows">
- <!-- <div class="row" style="display:flex;justify-content: space-around;border:1px solid #000;width:80%">
- <div class="col-md-4" style="width:40%">City Name</div>
- <div class="col-md-4" style="width:40%">Ship Rate</div>
- <div class="col-md-4" style="width:20%">Action</div>
- </div> -->
- <?php
- if(count($cities)) {
+
+ <?php
+ if(count($cities)) {
foreach($cities as $citi){
- ?>
- <!-- <div class="row wcc_fee_row" style="display:flex;justify-content: space-around;border:1px solid #000;width:80%">
- <div class="col-md-4" style="width:40%"> <input type="text" style="" name="cities[<?php echo esc_attr($citi->id) ?>]" value="<?php echo esc_attr($citi->city_name) ?>" class="input-text regular-input" placeholder="<?php _e('City Name', 'shiprate') ?>"></div>
- <div class="col-md-4" style="width:40%"> <span class="wccfee_currency"><?php echo get_woocommerce_currency_symbol() ?></span>
- <input type="text" name="cities_fee[<?php echo esc_attr($citi->id) ?>]" value="<?php echo esc_attr($citi->rate) ?>" class="input-text regular-input wccfee_cities_fee" placeholder="<?php _e('0', 'shiprate') ?>"></div>
- <div class="col-md-4" style="width:20%"> <span class="dashicons dashicons-trash wccfee_delcity" data-id="<?php echo esc_attr($citi->id) ?>"></span></div>
- </div> -->
+ ?>
+
<div class="wcc_fee_row" >
- <input type="text" name="cities[<?php echo esc_attr($citi->id) ?>]" value="<?php echo esc_attr($citi->city_name) ?>" class="input-text regular-input" placeholder="<?php _e('City Name', 'shiprate') ?>">
- <span class="wccfee_currency"><?php echo get_woocommerce_currency_symbol() ?></span>
- <input type="text" name="cities_fee[<?php echo esc_attr($citi->id) ?>]" value="<?php echo esc_attr($citi->rate) ?>" class="input-text regular-input wccfee_cities_fee" placeholder="<?php _e('0', 'shiprate') ?>">
+ <input type="text" name="cities[<?php echo esc_attr($citi->id) ?>]" value="<?php echo esc_attr($citi->city_name) ?>" class="input-text regular-input" placeholder="<?php esc_attr__('City Name', 'shipping-rate-by-cities') ?>">
+ <span class="wccfee_currency"><?php echo esc_html( get_woocommerce_currency_symbol() ) ?></span>
+ <input type="text" name="cities_fee[<?php echo esc_attr($citi->id) ?>]" value="<?php echo esc_attr($citi->rate) ?>" class="input-text regular-input wccfee_cities_fee" placeholder="<?php esc_attr__('0', 'shipping-rate-by-cities') ?>">
<span class="dashicons dashicons-trash wccfee_delcity" data-id="<?php echo esc_attr($citi->id) ?>"></span>
</div>
-
+
<?php }} else { ?>
<div class="wcc_fee_row">
- <input type="text" name="cities[]" value="" class="input-text regular-input" placeholder="<?php _e('City Name', 'shiprate') ?>">
- <span class="wccfee_currency"><?php echo get_woocommerce_currency_symbol() ?></span>
- <input type="text" name="cities_fee[]" value="" class="input-text regular-input wccfee_cities_fee" placeholder="<?php _e('0', 'shiprate') ?>">
+ <input type="text" name="cities[]" value="" class="input-text regular-input" placeholder="<?php esc_attr__('City Name', 'shipping-rate-by-cities') ?>">
+ <span class="wccfee_currency"><?php echo esc_html( get_woocommerce_currency_symbol() ) ?></span>
+ <input type="text" name="cities_fee[]" value="" class="input-text regular-input wccfee_cities_fee" placeholder="<?php esc_attr__('0', 'shipping-rate-by-cities') ?>">
<span class="dashicons dashicons-trash wccfee_delcity"></span>
</div>
<?php } ?>
-
+
</td>
</tr>
-
+
<tr valign="top">
<th style="padding-top:0"></th>
<td style="padding-top:0" id="del_citites">
-
- <button class="button-primary wccfee_addcity" type="button"><span class="dashicons dashicons-plus-alt"></span> <?php _e('Add City', 'shiprate') ?></button>
+
+ <button class="button-primary wccfee_addcity" type="button"><span class="dashicons dashicons-plus-alt"></span> <?php esc_html_e('Add City', 'shipping-rate-by-cities') ?></button>
</td>
</tr>
<tr>
<th scope="row" class="titledesc">
- <label for="woocommerce_import_cities"><?php _e('Import Cities', 'shiprate') ?></label>
+ <label for="woocommerce_import_cities"><?php esc_html_e('Import Cities', 'shipping-rate-by-cities') ?></label>
</th>
<td>
- <form method="post" enctype="multipart/form-data">
- <input type="file" name="import_file" id="ImportFile" accept=".csv">
- <button class="button-primary" type="submit" name="importsubmit" id="ImportBtn"> Import</button>
+ <form method="post" enctype="multipart/form-data"
+ action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
+ <?php wp_nonce_field( 'shiprate_import', 'shiprate_import_nonce' ); ?>
+ <input type="hidden" name="action" value="shiprate_import_cities">
+
+ <input type="file" name="import_file" accept=".csv" required>
+ <button class="button-primary" type="submit">
+ Import
+ </button>
</form>
+
</td>
<tr>
<style>
.wcc_fee_row { display: flex; margin-bottom: 5px; }
- .wccfee_cities_fee {
- width:80px !important;
- margin: 0 6px !important;
- padding-left: 20px !important;
+ .wccfee_cities_fee {
+ width:80px !important;
+ margin: 0 6px !important;
+ padding-left: 20px !important;
}
.wccfee_addcity .dashicons { margin: 4px 4px 0 0; }
/*.wccfee_delcity:hover { color: red; }*/
@@ -215,84 +249,170 @@
<?php
}
- function update_cities(){
+ function update_cities() {
global $wpdb;
- $othercities = array_map( 'sanitize_text_field',$_POST['othercity']);
- $othercityfees = array_map( 'sanitize_text_field', $_POST['other_city_fee']);
-
- $table = $wpdb->prefix . "shiprate_cities";
- foreach($othercities as $id1 => $otherciti){
-
- $othercity = [
- 'city_name' => $otherciti,
- 'rate' => $othercityfees[$id1]
- ];
-
- $check1 = $wpdb->get_results("SELECT id FROM $table where id = '$id1' ORDER BY id ASC", OBJECT);
-
- if($check1)
- $result1 = $wpdb->update($table, $othercity, ['id' => $id1]);
- else
- $result1 = $wpdb->insert($table, $othercity);
- }
+ // Capability check (admin only)
+ if ( ! current_user_can( 'manage_woocommerce' ) ) {
+ return;
+ }
+
+ // Nonce verification (required by WP.org)
+ if (
+ ! isset( $_POST['shiprate_nonce'] ) ||
+ ! wp_verify_nonce(
+ sanitize_text_field( wp_unslash( $_POST['shiprate_nonce'] ) ),
+ 'shiprate_save_cities'
+ )
+ ) {
+ return;
+ }
+
+
+
+ $table = esc_sql( $wpdb->prefix . 'shiprate_cities' );
+
+ /* =========================
+ * OTHER CITY
+ * ========================= */
+ if ( isset( $_POST['othercity'], $_POST['other_city_fee'] ) && is_array( $_POST['o