#bash #woocommerce #devops #opensource
WooCommerce Aras Cargo Integration — Pluginless, Server-Side, Automated

Every Turkish e-commerce owner running WooCommerce on Linux faces the same tedious loop: order placed, cargo shipped, tracking number generated on ARAS end — and then someone has to manually copy that number into WooCommerce and update the order status. Every. Single. Order.

🛒 Order placed → 📦 Cargo shipped → 🔢 Tracking number on ARAS → ✅ done?
No. Someone still has to update WooCommerce manually.

That manual step is where fulfillment falls apart for small and mid-size shops. You're either paying for an expensive deep integration, or you're doing it by hand. I built woo-aras — a pluginless, server-side bash automation that bridges WooCommerce and ARAS Cargo without a WordPress plugin, without a monthly SaaS fee, and without touching your core WordPress files.

The Problem With Existing Solutions

ARAS Cargo is the most widely used and affordable cargo company in Turkey. WooCommerce is the dominant e-commerce platform. The integration between them should be trivial — but it isn't.

Deep integration solutions exist, but they are complex and costly, and built for high-volume enterprise shops. For small to mid-size stores, the realistic options were: pay for a plugin, hire a developer, or do it manually. None of these scale well and none of them are free.

The real problem: ARAS provides SOAP XML/JSON API access only to corporate customers. WooCommerce exposes order management via REST API. These two APIs speak completely different protocols — and bridging them typically requires a full application layer. We did it in bash instead.

The approach: instead of a deep bi-directional sync, the script listens to ARAS for newly generated tracking numbers, matches them against WooCommerce orders using fuzzy string matching, and then drives the entire order status transition and customer notification pipeline automatically.

How the Automation Works End-to-End

The core loop is straightforward. Every 30 minutes (configurable), the script wakes up, queries ARAS via SOAP for cargo entries from the last 10 days, cross-references them against WooCommerce's processing orders via REST API v3, and when a match is found — updates the order, attaches the tracking number via the AST plugin's REST endpoint, and fires the customer notification email.

WooCommerce aras kargo integration workflow diagram
ARAS SOAP → tracking number → Levenshtein match → WooCommerce REST → order status update → AST REST → customer email.

Three APIs are involved in every successful order transition:

  • ARAS SOAP API — queried via PHP SOAP client embedded in bash (php-soap), returns cargo entries in JSON or XML
  • WooCommerce REST API v3 — used for reading processing orders and writing status updates (processing → completed/shipped)
  • AST Plugin REST API — used to attach tracking number, carrier name, and tracking link to the completed order email

The String Matching Problem

The hardest part of this integration is not the API plumbing — it's matching the right cargo entry to the right WooCommerce order reliably.

ARAS stores the recipient's name as entered at the cargo drop-off point. WooCommerce stores the customer's billing name as entered at checkout. These two strings frequently differ: typos, abbreviated names, missing diacritics, character encoding mismatches. A naive exact-match approach fails constantly.

Example: WooCommerce has Mehmet Yılmaz, ARAS has Mehmet Yilmaz — the diacritic difference alone breaks an exact match. Or Ali Kaya vs A. Kaya. These are real-world mismatches that happen daily.

The solution is Levenshtein distance matching via Perl's Text::Fuzzy module. The script computes the edit distance between the ARAS recipient name and the WooCommerce billing name, and accepts the match if the distance is within the configured threshold (default: 3 characters). This handles typos, encoding differences, and minor abbreviations without false positives.

# String matching via perl Text::Fuzzy (Levenshtein distance)
# max_distance=3 means up to 3 character edits are tolerated
perl -MText::Fuzzy -e '
  my $tf = Text::Fuzzy->new($aras_name);
  $tf->set_max_distance($max_distance);
  my $dist = $tf->distance($woo_name);
  exit ($dist <= $max_distance ? 0 : 1);
'
Why Perl, not pure bash? GNU awk and sed don't have a native Levenshtein implementation suitable for production use. Python would work but adds a heavier dependency. Text::Fuzzy is a mature, fast C-backed Perl module — and PHP, Perl, and GNU tools are already required by the automation anyway.

Two Fulfillment Workflows

The automation supports two order state machines depending on your business process.

Default Workflow — Two States

When a tracking number is generated on the ARAS end, the order transitions from processing to completed. The tracking number and link are attached to the completion email via AST plugin. This is the zero-configuration path — no custom order statuses required.

Two-Way Workflow — Three States

For shops that need to distinguish between "shipped" and "delivered", the two-way workflow adds a custom delivered order status and a second notification email. The script monitors ARAS delivery confirmation and drives the second transition automatically.

Implementing this requires a custom order status registered via WordPress child theme — the automation handles this automatically during setup, or provides a step-by-step manual guide. Core WordPress and WooCommerce files are never touched — all modifications go into the child theme only.

Fulfillment Workflows
Default: when tracking number appears on ARAS, order moves directly from processing → completed and customer is notified. Two-way: processing → shipped (when tracking number generated) → delivered (when ARAS marks as delivered). Two separate customer emails.

Credential Encryption — The Bash Security Problem

Storing API credentials in bash scripts is a well-known security hazard. Plain-text credentials in a shell script are readable by anyone with filesystem access, show up in process lists, and leak into logs. The automation addresses this with encrypted credential storage.

During setup, credentials (WooCommerce REST key/secret, ARAS SOAP username/password, merchant code, endpoint URL) are encrypted and stored in the .lck directory. The main script decrypts them at runtime only when needed and never writes them to logs or stdout.

Credentials are always a headache in bash scripting. The encryption here is not military-grade, but it prevents casual filesystem snooping and keeps secrets out of log files — which covers the realistic threat model for a shop server.

Interactive Setup — What woo-aras-setup.sh Does

The one-liner setup script handles the full environment preparation automatically:

# One-liner setup
sudo bash < <(curl -Ss https://psaux-it.github.io/woo-aras-setup.sh)

Under the hood, woo-aras-setup.sh performs the following in sequence:

  1. Detects the Linux distribution (Debian, Ubuntu, CentOS, Fedora, RHEL, Arch, Gentoo, SUSE, and more) and installs required runtime packages
  2. Creates a dedicated system user with limited sudo privileges — the automation never runs as root in production
  3. Downloads the latest source tree to the user's home directory
  4. Installs the en_US locale for iconv character encoding (critical for Turkish diacritic normalization)
  5. Prompts for all credentials interactively via whiptail — a TUI library that keeps credentials off the terminal history
  6. Validates the setup by running live test queries against both ARAS SOAP and WooCommerce REST before committing the configuration
  7. Prints a clear pass/fail status for QA purposes
Validation before commitment: The setup requires you to have live data on both sides — at least one WooCommerce order in processing state, and at least one ARAS cargo entry — so the matching algorithm can be validated against real data before the automation goes live.

Job Scheduling — Cron and Systemd

The automation supports both cron and systemd timer as scheduling backends. The default schedule runs every 30 minutes during business hours, Monday through Saturday:

# Cron schedule (default)
*/30 9-19 * * 1-6

# Systemd timer equivalent
on_calendar="Mon..Sat 9..19:00/30:00 Europe/Istanbul"

# Separate updater job — Sundays at 09:19
19 9 * * 0

The timezone is hardcoded to Europe/Istanbul — appropriate for the Turkish market this integration targets. The updater cron job runs weekly on Sunday mornings and auto-upgrades the script to the latest version from GitHub.

Hard Dependencies

Dependency Purpose Notes
curl REST API calls to WooCommerce and AST Standard on most distros
perl-Text::Fuzzy >= 0.29 Levenshtein distance string matching C-backed Perl module — fast
jq >= 1.6 JSON parsing for WooCommerce REST responses Version-sensitive — 1.5 has breaking differences
php, php-soap SOAP client for ARAS API queries Already present on WooCommerce servers
GNU awk >= 5 Text processing and data extraction gawk on Ubuntu
GNU sed >= 4.8 Stream editing for data normalization BSD sed on macOS won't work
whiptail TUI dialogs for interactive setup Also known as newt/libnewt

Debugging and Statistics

When something goes wrong — a missed order, a wrong tracking number assignment, a stalled two-way workflow — the script provides targeted debugging parameters rather than forcing you to dig through raw logs.

# Debug shipped orders — filter by date range and order/tracking ID
./woocommerce-aras-cargo.sh -g '1[1-9]-09-2024' '13241\|108324345362'

# Debug delivered orders — filter by specific date and tracking number
./woocommerce-aras-cargo.sh -z 15-09-2024 108324345362

# Check automation statistics and health
./woocommerce-aras-cargo.sh --status

# Force-ship orders stuck in processing when ARAS already shows delivered
./woocommerce-aras-cargo.sh --force-shipped

The --force-shipped flag deserves special mention. In the two-way workflow, if an order is already marked as delivered on the ARAS side before the automation had a chance to mark it as shipped, the script gets stuck — it's looking for a processing order to transition, but the order is still in processing while ARAS shows delivered. --force-shipped resolves this edge case by forcibly applying the shipped transition so the two-way pipeline can continue.

Known Limitations

Partial shipments: If a single customer has multiple orders and you ship them with separate tracking numbers, the Levenshtein matching algorithm may fail to correctly associate each tracking number to its order. Ship multiple orders from the same customer together when possible.

The second limitation is the name match itself. The script tolerates up to 3 character edits by default (max_distance=3). If the name on the ARAS cargo entry is significantly different from the WooCommerce billing name — more than 3 characters off — the match will fail silently and the order won't be updated. You can raise max_distance to 4 or 5, but higher values increase the risk of false positive matches.

This solution is explicitly designed for small to mid-size shops. For high-volume operations where partial shipments are common or where per-order accuracy is critical, a deep integration solution is the right tool.

Set it up once, forget it. The automation runs on schedule, emails you on errors, rotates its own logs, and upgrades itself on Sundays. Your only job is to ship the packages.

Leave a Reply

Your email address will not be published. Required fields are marked *

Post comment