WordPress Security

WordPress Security for Restaurant Sites: Protecting Orders and Customer Data

Secure your WordPress restaurant website with strategies to protect online orders, payment data, and customer information.

S
Sarah Chen
8 min read
1,681 views
Security guide for WordPress restaurant ordering websites

Restaurant websites handle sensitive customer data including payment information, delivery addresses, and dietary preferences. Protecting this data is essential for maintaining customer trust and regulatory compliance.

Restaurant Site Security Challenges

Restaurant websites face unique threats:

  • Order manipulation and fraud
  • Payment card data theft
  • Customer account hijacking
  • Menu price manipulation
  • Reservation system abuse

Sensitive Data Categories

Restaurant sites typically collect:

  • Customer names and contact information
  • Delivery addresses (home and work)
  • Payment card details
  • Order history and preferences
  • Dietary restrictions and allergies
  • Loyalty points and rewards

Secure Order Processing

Protect order submissions from manipulation:

function process_restaurant_order($order_data) {
    // Verify nonce
    if (!wp_verify_nonce($order_data['nonce'], 'restaurant_order')) {
        return new WP_Error('invalid_nonce', 'Security verification failed');
    }

    // Validate and recalculate prices server-side
    $order_items = array();
    $total = 0;

    foreach ($order_data['items'] as $item) {
        $menu_item = get_menu_item($item['id']);

        if (!$menu_item) {
            continue;
        }

        // Use database price, not client-submitted price
        $item_price = $menu_item['price'];
        $quantity = max(1, intval($item['quantity']));

        $order_items[] = array(
            'id' => $menu_item['id'],
            'name' => $menu_item['name'],
            'price' => $item_price,
            'quantity' => $quantity,
        );

        $total += $item_price * $quantity;
    }

    // Apply coupons server-side
    if (!empty($order_data['coupon'])) {
        $coupon = validate_coupon($order_data['coupon']);
        if ($coupon) {
            $total = apply_coupon_discount($total, $coupon);
        }
    }

    return array(
        'items' => $order_items,
        'total' => $total,
    );
}

Delivery Address Validation

Validate delivery addresses to prevent fraud:

function validate_delivery_address($address) {
    // Sanitize address fields
    $sanitized = array(
        'street' => sanitize_text_field($address['street']),
        'city' => sanitize_text_field($address['city']),
        'postal_code' => preg_replace('/[^A-Z0-9 -]/i', '', $address['postal_code']),
        'phone' => preg_replace('/[^0-9+() -]/', '', $address['phone']),
    );

    // Check delivery radius
    $restaurant_location = get_restaurant_coordinates();
    $delivery_coords = geocode_address($sanitized);

    if ($delivery_coords) {
        $distance = calculate_distance(
            $restaurant_location['lat'],
            $restaurant_location['lng'],
            $delivery_coords['lat'],
            $delivery_coords['lng']
        );

        if ($distance > get_option('max_delivery_radius', 10)) {
            return new WP_Error('out_of_range', 'Address is outside delivery area');
        }
    }

    // Verify phone number format
    if (strlen(preg_replace('/[^0-9]/', '', $sanitized['phone'])) < 10) {
        return new WP_Error('invalid_phone', 'Please enter a valid phone number');
    }

    return $sanitized;
}

Protecting Customer Accounts

Secure customer order history and saved data:

// Require re-authentication for sensitive actions
function require_customer_reauth() {
    $last_auth = get_user_meta(get_current_user_id(), 'last_password_entry', true);

    // Require password every 15 minutes for sensitive operations
    if (!$last_auth || (time() - $last_auth) > 900) {
        return false;
    }

    return true;
}

// Protect payment method changes
add_action('wp_ajax_update_payment_method', function() {
    if (!require_customer_reauth()) {
        wp_send_json_error(array('message' => 'Please confirm your password'));
    }

    // Process payment method update
});

// Protect address changes
add_action('wp_ajax_update_saved_address', function() {
    // Log address changes
    $old_address = get_user_meta(get_current_user_id(), 'delivery_address', true);

    log_security_event(array(
        'type' => 'address_change',
        'user_id' => get_current_user_id(),
        'old_value' => $old_address,
        'ip' => $_SERVER['REMOTE_ADDR'],
    ));
});

Reservation System Security

Protect the reservation system from abuse:

function validate_reservation($reservation) {
    // Rate limit reservations per IP
    $ip = $_SERVER['REMOTE_ADDR'];
    $key = 'reservations_' . md5($ip);
    $recent = get_transient($key) ?: 0;

    if ($recent > 3) { // Max 3 reservations per hour
        return new WP_Error('rate_limit', 'Too many reservation attempts');
    }

    set_transient($key, $recent + 1, HOUR_IN_SECONDS);

    // Validate party size
    $party_size = intval($reservation['party_size']);
    $max_party = get_option('max_party_size', 20);

    if ($party_size < 1 || $party_size > $max_party) {
        return new WP_Error('invalid_party', 'Invalid party size');
    }

    // Validate date/time
    $reservation_time = strtotime($reservation['datetime']);

    if ($reservation_time < time()) {
        return new WP_Error('past_date', 'Cannot book in the past');
    }

    // Check if time slot is available
    if (!is_slot_available($reservation_time, $party_size)) {
        return new WP_Error('unavailable', 'This time slot is not available');
    }

    // Verify confirmation code for modifications
    if (!empty($reservation['modification_code'])) {
        if (!verify_reservation_code($reservation['modification_code'])) {
            return new WP_Error('invalid_code', 'Invalid confirmation code');
        }
    }

    return true;
}

Menu Price Protection

Prevent unauthorized menu modifications:

// Log all menu price changes
add_action('save_post_menu_item', function($post_id, $post, $update) {
    if (!$update) {
        return;
    }

    $old_price = get_post_meta($post_id, '_price', true);
    $new_price = $_POST['menu_price'] ?? null;

    if ($new_price && $old_price !== $new_price) {
        log_menu_change(array(
            'item_id' => $post_id,
            'old_price' => $old_price,
            'new_price' => $new_price,
            'user' => get_current_user_id(),
            'time' => current_time('mysql'),
        ));

        // Alert for significant price changes
        $change_percent = abs(($new_price - $old_price) / $old_price * 100);

        if ($change_percent > 20) {
            wp_mail(
                get_option('admin_email'),
                'Large menu price change',
                sprintf(
                    'Item %s price changed by %.1f%% from %.2f to %.2f',
                    get_the_title($post_id), $change_percent, $old_price, $new_price
                )
            );
        }
    }
}, 10, 3);

Allergy Information Protection

Ensure dietary and allergy information is accurate:

// Track allergy information changes
add_action('update_post_meta', function($meta_id, $post_id, $meta_key, $meta_value) {
    if ($meta_key !== '_allergens') {
        return;
    }

    $old_allergens = get_post_meta($post_id, '_allergens', true);

    // Log the change with full audit trail
    global $wpdb;
    $wpdb->insert('allergen_audit_log', array(
        'menu_item_id' => $post_id,
        'old_allergens' => maybe_serialize($old_allergens),
        'new_allergens' => maybe_serialize($meta_value),
        'changed_by' => get_current_user_id(),
        'changed_at' => current_time('mysql'),
        'ip_address' => $_SERVER['REMOTE_ADDR'],
    ));
}, 10, 4);

Order History Privacy

Protect customer order history:

function get_customer_orders($customer_id, $requesting_user) {
    // Only allow customers to see their own orders
    if ($customer_id !== $requesting_user && !current_user_can('manage_orders')) {
        return new WP_Error('unauthorized', 'Cannot access other customer orders');
    }

    $orders = get_orders_by_customer($customer_id);

    // Mask sensitive data for display
    foreach ($orders as &$order) {
        if (isset($order['card_last_four'])) {
            $order['payment_display'] = '**** ' . $order['card_last_four'];
            unset($order['card_last_four']);
        }
    }

    return $orders;
}

Conclusion

Restaurant website security requires protecting order data, validating prices server-side, securing reservation systems, and maintaining accurate allergen information. Regular security audits help ensure ongoing customer protection.

Share:
S
Written by Sarah Chen

WP Folder Shield Team

Related Articles

SEO Spam Injection: How to Detect Hidden Links and Malicious Redirects
SEO Spam Injection: How to Detect Hidden Links and Malicious Redirects

Learn how hackers inject hidden links and malicious redirects into WordPress sites to steal your...

January 18, 2026
Understanding WordPress Malware Signatures and Detection Patterns
Understanding WordPress Malware Signatures and Detection Patterns

Learn how malware scanners detect threats using signatures and patterns. Understand the technology...

January 15, 2026
Country Blocking for WooCommerce: Protect Your Online Store
Country Blocking for WooCommerce: Protect Your Online Store

Learn how to implement country blocking for WooCommerce stores. Prevent fraud, reduce chargebacks...

January 10, 2026

Ready to Secure Your WordPress Site?

Get complete protection with WP Folder Shield.

Get Started