{"id":167587,"date":"2022-12-21T14:21:05","date_gmt":"2022-12-21T14:21:05","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/insim\/"},"modified":"2026-08-16T18:41:21","modified_gmt":"2026-08-16T18:41:21","slug":"insim","status":"publish","type":"plugin","link":"https:\/\/mri.wordpress.org\/plugins\/insim\/","author":20811354,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"5.2.0","stable_tag":"5.2.0","tested":"7.0.4","requires":"6.4","requires_php":"7.4","requires_plugins":null,"header_name":"inSIM","header_author":"2WS Technologies","header_description":"This plugin allows to create an automation or a campaign in order to send sms to a list of recipients as you can do with emails and newsletters.","assets_banners_color":"d0dee2","last_updated":"2026-08-16 18:41:21","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/ardary-insim.com\/","header_author_uri":"https:\/\/ardary-insim.com\/about","rating":0,"author_block_rating":0,"active_installs":0,"downloads":1358,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"3.0.0":{"tag":"3.0.0","author":"2wstechnologies","date":"2026-05-17 23:18:51"},"4.0":{"tag":"4.0","author":"2wstechnologies","date":"2026-05-17 23:18:51"},"5.0":{"tag":"5.0","author":"2wstechnologies","date":"2026-05-17 23:24:25"},"5.2.0":{"tag":"5.2.0","author":"2wstechnologies","date":"2026-08-16 18:41:21"}},"upgrade_notice":{"5.2.0":"<p>Rebuilt on the inSIM platform with a new design. Connect by API key or by scanning a QR code with the inSIM mobile app. Reconnect your store after updating.<\/p>","1.2.0":"<p>Housekeeping for WordPress.org: removed unused bundled libraries (Bootstrap CSS\/JS, FontAwesome) and dead legacy code. No functional change.<\/p>","1.1.9":"<p>All features are now fully functional with no restrictions; only the actual SMS sending uses your inSIM account. Security and coding-standards improvements throughout.<\/p>","1.1.8":"<p>Code-quality and coding-standards pass (Plugin Check clean). No functional change.<\/p>","1.1.7":"<p>Housekeeping only: removed unused legacy files from the package (no functional change).<\/p>","1.1.6":"<p>Final polish before release: removed the empty Customer ID field, hardened input handling, and code-quality cleanup. No functional changes.<\/p>","1.1.5":"<p>Adds one-click sign-in to the inSIM web app from the Helpdesk and Balance buttons (activates automatically once the service enables it; until then the buttons keep working as before).<\/p>","1.1.4":"<p>Important fix: plugin CSS\/JS were cached under a stale version and never refreshed on update. Assets now cache-bust correctly, so interface fixes actually take effect. Clear your page cache once after updating.<\/p>","1.1.3":"<p>Makes the campaign detail toolbar layout fix apply reliably on all setups. Reinstall and clear any page cache to see it.<\/p>","1.1.2":"<p>Adds WooCommerce HPOS (High-Performance Order Storage) and block cart\/checkout compatibility, so the &quot;incompatible plugin&quot; notice is gone and order-based campaign targeting works on HPOS stores. Recommended for everyone.<\/p>","1.1.1":"<p>Fixes the account appearing disconnected shortly after connecting, and a button layout issue on the campaign detail screen.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":2837425,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128}},"assets_banners":{"banner-1544x500.jpg":{"filename":"banner-1544x500.jpg","revision":2937563,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.jpg":{"filename":"banner-772x250.jpg","revision":2937563,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["3.0.0","4.0","5.0","5.2.0"],"block_files":[],"assets_screenshots":[],"screenshots":{"1":"Connect \u2014 pair your store with your API key or by scanning a QR code with the inSIM mobile app.","2":"SMS Campaigns \u2014 your campaigns at a glance, with status, recipients and delivery counts.","3":"Campaign wizard \u2014 choose recipients from your WooCommerce customers with smart filters.","4":"Campaign wizard \u2014 write your message with merge tags and a live phone preview.","5":"Per-campaign analytics \u2014 sent, delivered, failed, clicks and click-through rate.","6":"Automations \u2014 one-click SMS for order confirmations, status changes, welcomes and low-stock alerts.","7":"Abandoned cart \u2014 a reminder sequence with one-tap recovery links and optional coupons.","8":"Helpdesk \u2014 open the inSIM web app to manage conversations and your account.","9":"Reports \u2014 delivery rate, clicks and totals over the period you choose.","10":"Account \u2014 your subscription and connection status, right inside WordPress.","11":"History \u2014 your recent campaigns and a log of every SMS sent, with delivery status."}},"plugin_section":[],"plugin_tags":[15962,711,76174,1201,286],"plugin_category":[41],"plugin_contributors":[244628],"plugin_business_model":[],"class_list":["post-167587","plugin","type-plugin","status-publish","hentry","plugin_tags-abandoned-cart","plugin_tags-sms","plugin_tags-sms-campaign","plugin_tags-sms-notifications","plugin_tags-woocommerce","plugin_category-communication","plugin_contributors-2wstechnologies","plugin_committers-2wstechnologies"],"banners":{"banner":"https:\/\/ps.w.org\/insim\/assets\/banner-772x250.jpg?rev=2937563","banner_2x":"https:\/\/ps.w.org\/insim\/assets\/banner-1544x500.jpg?rev=2937563","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/insim\/assets\/icon-128x128.png?rev=2837425","icon_2x":false,"generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p><strong>inSIM turns WooCommerce into an SMS marketing and notifications powerhouse.<\/strong> Recover abandoned carts, keep customers updated at every stage of their order, and run bulk promotional campaigns \u2014 all sent straight from your store through the inSIM service. Connect once and you're live: either paste your API key or scan a QR code with the inSIM mobile app to pair your store automatically.<\/p>\n\n<p>Text messages are opened within minutes and read far more than email. inSIM helps you put that channel to work for your shop, without ever leaving your WordPress dashboard.<\/p>\n\n<h4>Why inSIM?<\/h4>\n\n<ul>\n<li><strong>Recover lost sales automatically.<\/strong> Capture a shopper's number at checkout and follow up with a timely reminder \u2014 including a one-tap link that rebuilds their cart on any device \u2014 when they don't complete the order.<\/li>\n<li><strong>Keep customers informed.<\/strong> Automatic SMS for order confirmations, status changes, new-customer welcomes and low-stock alerts \u2014 each with its own on\/off switch and message.<\/li>\n<li><strong>Run real campaigns.<\/strong> A guided wizard lets you target the right customers, write your message, review your audience, and send now or schedule for later.<\/li>\n<li><strong>Personalise every message.<\/strong> Merge tags such as {firstname} and {order_number} drop customer and order details into your text automatically.<\/li>\n<li><strong>Reward and track.<\/strong> Attach a discount coupon to any campaign or reminder and see the redemptions and revenue it brought in.<\/li>\n<li><strong>Stay compliant.<\/strong> Built-in STOP \/ unsubscribe handling and an optional opt-out notice keep your sending clean.<\/li>\n<\/ul>\n\n<h4>Recover abandoned carts<\/h4>\n\n<p>inSIM saves a shopper's phone number the moment they start checkout, then follows up after a delay you choose. Your reminder carries a personal recovery link that restores their exact cart and sends them back to checkout \u2014 even on a different device. If they place the order in the meantime, the reminder is automatically skipped.<\/p>\n\n<h4>Automated order &amp; customer SMS<\/h4>\n\n<p>Switch on the notifications you want and customise the wording of each:<\/p>\n\n<ul>\n<li>Order confirmation<\/li>\n<li>Order status updates \u2014 with a separate message for each status, so \"Processing\", \"Completed\" and \"Shipped\" can each read differently<\/li>\n<li>New-customer welcome<\/li>\n<li>Low-stock alerts for you or your team<\/li>\n<\/ul>\n\n<h4>SMS marketing campaigns<\/h4>\n\n<p>A simple four-step wizard \u2014 <strong>Recipients \u2192 Message \u2192 Schedule \u2192 Review<\/strong>:<\/p>\n\n<ul>\n<li>Target customers by criteria such as number of orders, total spent or country.<\/li>\n<li>Pick individual customers, or add everyone who matches in a single click.<\/li>\n<li>Review your recipient count before you send.<\/li>\n<li>Send immediately, or schedule for a future date and time.<\/li>\n<li>Save a campaign as a draft and finish it later.<\/li>\n<\/ul>\n\n<h4>Track your results<\/h4>\n\n<ul>\n<li>A clear dashboard per campaign: sent, delivered, failed, clicks and click-through rate.<\/li>\n<li>Live delivery updates while a campaign is going out.<\/li>\n<li>One-click retry for any messages that didn't get through.<\/li>\n<li>Export your recipient list to CSV.<\/li>\n<li>Overview reports with delivery rate, clicks and totals over the period you choose.<\/li>\n<\/ul>\n\n<h4>Coupons that drive action<\/h4>\n\n<p>Link a discount code to a campaign or an abandoned-cart reminder, and inSIM attributes every redemption \u2014 and the revenue behind it \u2014 back to the message that earned it. See exactly which sends pay for themselves.<\/p>\n\n<h4>Built for WooCommerce<\/h4>\n\n<ul>\n<li>Works alongside your existing setup with no theme changes.<\/li>\n<li>A modern, clean interface designed to stay out of your way.<\/li>\n<li>Fully translatable \u2014 ships complete in English and French.<\/li>\n<li>Reliable background sending that respects your account's rate limits, with automatic retry when needed.<\/li>\n<li>Built to WordPress security and coding standards.<\/li>\n<\/ul>\n\n<p>inSIM requires an inSIM account at insim.app (create one in minutes). See the \"External services\" section below for exactly what data is sent and when.<\/p>\n\n<h3>External services<\/h3>\n\n<p>This plugin connects to the inSIM API (insim.app) to send SMS messages and manage your inSIM account. This connection is required for the plugin to function.<\/p>\n\n<p>When you use the plugin, the following data is sent to the inSIM service (https:\/\/insim.app), operated by 2WS Technologies:<\/p>\n\n<ul>\n<li>Your account login (email) and access key, to authenticate every request.<\/li>\n<li>When sending an SMS (campaigns, abandoned-cart reminders, order notifications): the recipient's mobile phone number (in E.164 format) and the message text, which may include customer data you insert via merge tags (e.g. first name, last name, order number).<\/li>\n<li>When creating an account from the plugin: the email and password you enter, plus your store URL.<\/li>\n<li>When pairing by QR code: a one-time pairing token and your store URL, so the inSIM mobile app can link your store to your account.<\/li>\n<li>Your shop name and store URL, and date ranges when requesting statistics.<\/li>\n<\/ul>\n\n<p>Data is sent only when you (or an automation you configure) trigger a send, a connection test, a stats refresh, QR-code pairing, or account creation. No data is sent to any other third party.<\/p>\n\n<p>This service is provided by 2WS Technologies. By using it you agree to their Terms of Service and Privacy Policy:<\/p>\n\n<ul>\n<li>Terms of Service: https:\/\/ardary-insim.com\/terms<\/li>\n<li>Privacy Policy: https:\/\/ardary-insim.com\/privacy<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>insim<\/code> folder to <code>\/wp-content\/plugins\/<\/code>, or install through the WordPress Plugin Directory.<\/li>\n<li>Activate the plugin through the Plugins menu.<\/li>\n<li>Go to WooCommerce &gt; inSIM.<\/li>\n<li>Connect your store one of two ways: paste your insim.app login email and access key and click Save &amp; Test Connection, or scan the on-screen QR code with the inSIM mobile app to pair automatically.<\/li>\n<li>A success indicator confirms the connection.<\/li>\n<li>Open the SMS Automations tab, toggle the events you want, and customise the copy.<\/li>\n<li>Optionally open the SMS Campaigns tab to build and send your first bulk campaign.<\/li>\n<\/ol>\n\n<h4>Requirements<\/h4>\n\n<ul>\n<li>WordPress 6.4 or later.<\/li>\n<li>WooCommerce 8.0 or later.<\/li>\n<li>PHP 7.4, 8.0, 8.1, or 8.2.<\/li>\n<li>An active inSIM account at insim.app with a valid access key.<\/li>\n<\/ul>\n\n<!--section=faq-->\n<dl>\n<dt id=\"do%20i%20need%20an%20insim%20account%3F\"><h3>Do I need an inSIM account?<\/h3><\/dt>\n<dd><p>Yes. inSIM sends through the inSIM service, so you need an inSIM account at insim.app. Creating one takes a minute \u2014 then connect either by copying your access key into the plugin, or by scanning the pairing QR code with the inSIM mobile app.<\/p><\/dd>\n<dt id=\"how%20much%20does%20it%20cost%3F\"><h3>How much does it cost?<\/h3><\/dt>\n<dd><p>The plugin is free, and messages go out through your own paired mobile SIM \u2014 there is no per-SMS cloud credit or balance to buy. A PREMIUM inSIM subscription unlocks the advanced features (automations, tracking URLs and abandoned-cart recovery); see insim.app for current plans.<\/p><\/dd>\n<dt id=\"which%20countries%20can%20i%20send%20to%3F\"><h3>Which countries can I send to?<\/h3><\/dt>\n<dd><p>inSIM supports international sending. Because messages are sent through your paired mobile SIM, the available destinations follow your own mobile plan. You choose a default country code in Settings and can message any destination your SIM supports.<\/p><\/dd>\n<dt id=\"do%20i%20need%20a%20phone%20or%20a%20sim%20card%3F\"><h3>Do I need a phone or a SIM card?<\/h3><\/dt>\n<dd><p>inSIM sends through your own paired mobile SIM via the inSIM service, so you connect a mobile number once \u2014 either with just your API key, or by scanning a QR code with the inSIM mobile app to pair in seconds. Sending itself runs server-side in the background; you do not keep a phone tethered to your store.<\/p><\/dd>\n<dt id=\"will%20messages%20still%20send%20if%20i%20am%20not%20logged%20into%20wordpress%3F\"><h3>Will messages still send if I am not logged into WordPress?<\/h3><\/dt>\n<dd><p>Yes. Automated messages fire on your store's events (new order, status change, and so on), and campaign and abandoned-cart sends run in the background through WordPress's scheduler. No one needs to be logged in.<\/p><\/dd>\n<dt id=\"does%20it%20work%20with%20guest%20checkout%3F\"><h3>Does it work with guest checkout?<\/h3><\/dt>\n<dd><p>Yes. Abandoned-cart capture works for both logged-in customers and guests, as long as a phone number is entered at checkout.<\/p><\/dd>\n<dt id=\"is%20it%20compatible%20with%20woocommerce%20hpos%20%28high-performance%20order%20storage%29%3F\"><h3>Is it compatible with WooCommerce HPOS (High-Performance Order Storage)?<\/h3><\/dt>\n<dd><p>Yes. inSIM declares full compatibility with High-Performance Order Storage and with the block-based cart and checkout.<\/p><\/dd>\n<dt id=\"how%20do%20i%20stay%20compliant%20with%20sms%20marketing%20rules%3F\"><h3>How do I stay compliant with SMS marketing rules?<\/h3><\/dt>\n<dd><p>inSIM honours STOP \/ unsubscribe replies \u2014 opted-out numbers are skipped automatically \u2014 and can append an opt-out notice to first-contact messages. You remain responsible for having the consent required to message your customers under your local regulations (for example GDPR \/ PECR in Europe or TCPA in the US).<\/p><\/dd>\n<dt id=\"can%20i%20test%20a%20message%20before%20sending%20to%20everyone%3F\"><h3>Can I test a message before sending to everyone?<\/h3><\/dt>\n<dd><p>Yes. Settings includes a \"Send test SMS\" tool, and the campaign wizard shows the recipient count before you launch.<\/p><\/dd>\n<dt id=\"will%20it%20slow%20down%20my%20store%3F\"><h3>Will it slow down my store?<\/h3><\/dt>\n<dd><p>No. Sending happens in the background in rate-limited batches, so checkout and the admin stay fast. If the SMS service is momentarily unreachable, your store keeps working normally and the plugin retries automatically.<\/p><\/dd>\n<dt id=\"is%20it%20available%20in%20other%20languages%3F\"><h3>Is it available in other languages?<\/h3><\/dt>\n<dd><p>Yes. The interface is in English by default and ships with a complete French translation. It is fully translatable into any language using standard WordPress tools.<\/p><\/dd>\n<dt id=\"what%20happens%20to%20my%20data%20if%20i%20uninstall%3F\"><h3>What happens to my data if I uninstall?<\/h3><\/dt>\n<dd><p>Deleting the plugin removes its data (tables, options and scheduled tasks). Deactivating without deleting keeps everything, so you can reactivate later with your settings intact.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>5.2.0<\/h4>\n\n<ul>\n<li>Rebuilt on the inSIM platform with the new design.<\/li>\n<li>Connect your store by API key or by QR-code pairing with the inSIM mobile app.<\/li>\n<li>Sends through your own paired mobile SIM \u2014 no cloud SMS credits or balance to buy; PREMIUM subscription unlocks automations, tracking URLs and abandoned-cart recovery.<\/li>\n<li>Campaigns, automations, abandoned-cart recovery, helpdesk and reports.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Removed unused bundled third-party libraries (Bootstrap CSS &amp; JS, FontAwesome) and dead legacy admin code, so the package ships only first-party, human-readable source with no minified vendor bundles and no remote asset calls.<\/li>\n<\/ul>\n\n<h4>1.1.9<\/h4>\n\n<ul>\n<li>All plugin features (automations, abandoned-cart sequences, campaign setup) are fully functional and configurable with no account restriction; only the actual sending of an SMS uses your connected inSIM account.<\/li>\n<li>Security &amp; standards: all admin scripts\/styles are enqueued (no inline tags), request inputs are unslashed\/sanitized, outputs escaped, and no remote assets are loaded (the interface uses inline SVG icons).<\/li>\n<li>Housekeeping: dropped an unused bundled library, removed dead legacy code, and translations now load automatically.<\/li>\n<\/ul>\n\n<h4>1.1.8<\/h4>\n\n<ul>\n<li>Coding standards: full WordPress Plugin Check pass \u2014 <code>date()<\/code>\u2192<code>gmdate()<\/code>, i18n placeholder ordering and translators comments, output escaping on a few admin views, unslash\/sanitize on form inputs, and documented (phpcs-annotated) direct queries on the plugin's own custom tables. No functional change.<\/li>\n<\/ul>\n\n<h4>1.1.7<\/h4>\n\n<ul>\n<li>Housekeeping: removed unused legacy assets from the distributed package (leftover images, dead stylesheets, and internal API docs) \u2014 smaller download, no functional change.<\/li>\n<\/ul>\n\n<h4>1.1.6<\/h4>\n\n<ul>\n<li>Removed the Customer ID field from the account view (the API does not provide it).<\/li>\n<li>Hardening: unslash\/sanitize on server\/request inputs, saved SMS message sanitized.<\/li>\n<li>Code quality: removed debug console logging; documented safe SQL\/output for a clean Plugin Check run.<\/li>\n<\/ul>\n\n<h4>1.1.5<\/h4>\n\n<ul>\n<li>New: one-click single sign-on to the inSIM web app \u2014 the Helpdesk \"Open web app\" button and the Balance \"Buy SMS \/ See plans\" buttons can drop you straight into your account, already signed in. Uses a secure, client-scoped one-time login link (your own credentials only; no shared secret shipped in the plugin). Activates automatically when the service enables the endpoint; until then the buttons open the web app as before.<\/li>\n<\/ul>\n\n<h4>1.1.4<\/h4>\n\n<ul>\n<li>Fix (important): admin CSS and JavaScript were enqueued with a stale, hardcoded version, so browsers and caching plugins kept serving old files after every update \u2014 interface fixes never appeared. Plugin assets now use file-modification-time cache-busting and the correct plugin version, so updates take effect immediately. This is what was preventing the campaign-detail toolbar fix from showing.<\/li>\n<\/ul>\n\n<h4>1.1.3<\/h4>\n\n<ul>\n<li>Fix: the campaign detail toolbar buttons (Refresh now \/ Export CSV \/ Retry failed) now render correctly on every setup \u2014 the layout rule moved into the always-loaded stylesheet so it no longer depends on a conditional file or page cache.<\/li>\n<\/ul>\n\n<h4>1.1.2<\/h4>\n\n<ul>\n<li>Compatibility: declares support for WooCommerce High-Performance Order Storage (HPOS) and the block-based cart &amp; checkout \u2014 removes the WooCommerce \"incompatible\" notice.<\/li>\n<li>Fix: campaign recipient targeting by order count and total spend now reads the correct order data on HPOS stores (previously it could return no matches when HPOS was enabled).<\/li>\n<li>Docs: rewritten plugin description, expanded FAQ, and added screenshots.<\/li>\n<\/ul>\n\n<h4>1.1.1<\/h4>\n\n<ul>\n<li>Fix: account no longer appears disconnected a few minutes after connecting \u2014 the account state now re-hydrates when the short display cache expires and keeps you connected through brief API hiccups (only missing or revoked credentials show as disconnected).<\/li>\n<li>Fix: campaign detail toolbar buttons (Refresh now \/ Export CSV \/ Retry failed) no longer overlap \u2014 labelled action buttons now size correctly.<\/li>\n<li>UI: wider plugin canvas and a clearer distinction between the \"Next\" and \"Launch campaign\" buttons in the campaign wizard.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Reach design refonte across all screens; multi-relance abandoned-cart engine; coupon tracking; full English\/French i18n; accessibility &amp; responsive improvements.<\/li>\n<\/ul>\n\n<h4>1.0.16<\/h4>\n\n<ul>\n<li>Expiry normalizer (Fix 1): PHP <code>insim_format_expiry()<\/code> and JS <code>normalizeExpiry()<\/code> now recurse through the double-nested Mongo extended-JSON shape <code>{\"$date\": {\"$numberLong\": \"&lt;ms&gt;\"}}<\/code> observed in real API responses. The old implementation only unwrapped one level, so the date rendered as \"[object Object]\" or \"Array\". Both normalizers accept: null\/empty \u2192 <code>-<\/code>, ISO string \u2192 first 10 chars, numeric ms \u2192 UTC date, <code>{$date: \u2026}<\/code> \/ <code>{date: \u2026}<\/code> \u2192 recurse, <code>{$numberLong\/Int\/Double: \u2026}<\/code> \u2192 resolve to number then date.<\/li>\n<li>Balance refresh button (Fix 2): the click handler in <code>admin.js<\/code> now uses a delegated <code>$(document).on(\u2026)<\/code> binding for both <code>#insim-balance-refresh<\/code> and <code>.insim-balance-refresh<\/code> so it fires regardless of DOM timing (e.g. when the Settings tab is revealed after initial page load). The handler restores the original button label after success\/failure and updates both <code>#insim-balance-value<\/code> and <code>.insim-current-balance<\/code> elements simultaneously.<\/li>\n<li>History delivery column (Fix 3): every SMS log row now shows one of four states \u2014 <strong>Refresh<\/strong> button (Mongo ID present), <strong>Sent<\/strong> pill (HTTP 2xx, no error code), <strong>Failed<\/strong> pill (error_code set), or <code>\u2014<\/code> (truly unknown). Previously rows without a Mongo ID always showed <code>\u2014<\/code>. New <code>.insim-status-pill<\/code>, <code>.insim-status-sent<\/code>, <code>.insim-status-failed<\/code> CSS classes added to <code>admin.css<\/code>. Column header simplified to \"Delivery\" with tooltip (the <code>?<\/code> character was removed from visible text).<\/li>\n<\/ul>\n\n<h4>1.0.15<\/h4>\n\n<ul>\n<li>Campaign Wizard Step 4 \"Current balance\" (Fix 1): balance is now always populated from the freshly-localized <code>ardarySms.balance<\/code> value (set via <code>InSIM_License_Gate::credits()<\/code> in <code>enqueue_scripts()<\/code>). Previously, if the 5-minute account transient had expired before the page loaded, <code>data-balance<\/code> on the wizard container was empty and the balance cell showed \"\u2014\" even when the account was connected.<\/li>\n<li>Refresh delivery button defensive guard (Fix 2): a JS-side check now validates the <code>data-sms-id<\/code> attribute against the Mongo ObjectId regex before firing AJAX. Buttons that slip through with a non-hex ID are replaced inline with a \"\u2014\" span. Server-side, <code>ajax_refresh_delivery()<\/code> now returns <code>error_code: NOT_TRACKED<\/code> with HTTP 200 (not an unstructured error) so the UI can handle it gracefully.<\/li>\n<li>Refresh balance button (Fix 3): a \"\u21bb Refresh\" button now appears next to the balance value in both the Settings account card and the Help tab account snapshot. Clicking it calls a new <code>insim_refresh_balance<\/code> AJAX endpoint that hits the API, refreshes the transient, and updates the displayed balance without a page reload.<\/li>\n<\/ul>\n\n<h4>1.0.14<\/h4>\n\n<ul>\n<li>Credits real-time update (Fix 1): after a successful <code>send_sms()<\/code> call the cached <code>sms_credits<\/code> transient is decremented immediately (optimistic local decrement), so the balance card in Settings \/ Help reflects the spend on the very next page load without waiting 5 minutes for the TTL to expire.<\/li>\n<li>Credits background refresh (Fix 1): after every send pipeline run, an Action Scheduler action (<code>insim_refresh_account_cache<\/code>) is enqueued to pull the authoritative balance from the inSIM API and overwrite the transient within ~10 seconds.<\/li>\n<li>History delivery Refresh button (Fix 2): the Refresh button in the Recent SMS log is now only rendered for rows whose <code>id_sms_api<\/code> value is a valid 24-hex Mongo ObjectId. Rows with internally-generated IDs (e.g. <code>wp:automation:\u2026<\/code>) show a <code>\u2014<\/code> with a tooltip instead, explaining that delivery tracking is not available and directing the user to ardary-insim.com. The Refresh button handler now always updates the row UI \u2014 it shows green\/amber\/red status on success and an inline error message on failure, and never silently ignores the response.<\/li>\n<li>Delivery column header: a small <code>?<\/code> tooltip explains that live delivery status is only available for API-registered SMS.<\/li>\n<li>AJAX validation: <code>ajax_refresh_delivery()<\/code> now validates every submitted SMS ID against the Mongo ObjectId pattern server-side and returns a clear error if the ID is invalid, preventing wasteful API round-trips.<\/li>\n<\/ul>\n\n<h4>1.0.13<\/h4>\n\n<ul>\n<li>Settings: the \"Technical details\" collapsible panel under failed test-connection cards was removed. Failure cards now show only the human-readable error message (\"Check your email and access key on ardary-insim.com -&gt; Settings -&gt; API.\"). The server still emits the <code>debug<\/code> block (URL, HTTP status, body snippet) for support log purposes; the merchant UI no longer surfaces it.<\/li>\n<li>Settings: the \"API base URL (advanced)\" input row in Step 4 was deleted. The API endpoint is controlled exclusively by the <code>INSIM_API_BASE_URL<\/code> constant in <code>insim.php<\/code>. The activator deletes any pre-existing <code>insim_api_base_url<\/code> option on upgrade so every install resolves to the constant. The <code>api_base_url<\/code> POST handler in <code>ajax_save_and_test()<\/code> and <code>_post_process()<\/code> was removed.<\/li>\n<li>Settings: the Test connection button spinner now has a visible gap before the \"Testing connection...\" label. The button uses <code>display: inline-flex !important; gap: 10px !important;<\/code> so the WP <code>.button-primary<\/code> rule cannot override it back to <code>inline-block<\/code> (which silently dropped the gap in v1.0.12). The spinner itself is now <code>flex: 0 0 16px<\/code> so themes that set <code>flex: 1<\/code> on button children cannot squash it to zero width.<\/li>\n<li>Settings: success card no longer renders \"Connected as Foo Bar ()\" when the API account payload omits the login echo. The parenthesised login is only included when non-empty.<\/li>\n<li>Settings + Help: expiry_date is now normalised before display. The API returns it as a MongoDB extended-JSON object (<code>{\"$date\": \"2027-01-01T00:00:00.000Z\"}<\/code>) in some environments, which previously rendered as \"[object Object]\" (Settings) and \"Array\" (Help). A new shared helper file <code>includes\/class-insim-helpers.php<\/code> adds <code>insim_format_expiry()<\/code> (PHP) and the matching <code>normalizeExpiry()<\/code> (JS) accept plain ISO strings, <code>{$date}<\/code>, <code>{date}<\/code> and <code>{$numberLong}<\/code> shapes and reduce each to <code>YYYY-MM-DD<\/code>. <code>sms_credits<\/code> is normalised via <code>insim_format_credits()<\/code> \/ <code>parseFloat<\/code> with a <code>-<\/code> fallback so a numeric-shaped object cannot leak through.<\/li>\n<\/ul>\n\n<h4>1.0.12<\/h4>\n\n<ul>\n<li>API base URL updated to production endpoint <code>https:\/\/ardary-insim.com\/api\/v2\/<\/code>. Existing installs that had the old URL saved as an option override are automatically cleared on next plugin load.<\/li>\n<li>Debug log feature removed. The \"Technical Details\" collapsible panel on test-connection failures is retained.<\/li>\n<li>Test-connection spinner: added <code>margin-right<\/code> and <code>inline-flex<\/code> alignment to the button so the spinner and label are properly spaced.<\/li>\n<\/ul>\n\n<h4>1.0.11<\/h4>\n\n<ul>\n<li>Settings \u2014 Diagnostics: new \"API base URL (advanced)\" field in Step 4. Leave empty to use the built-in default (<code>INSIM_API_BASE_URL<\/code>); enter a full URL to override it per-site without a code change. The active URL (option or constant) is displayed below the debug-log toggle with an \"Override active\" badge when an override is in effect. The override is persisted as the <code>insim_api_base_url<\/code> option and honoured by every API call. Cleared field deletes the option so the default reapplies. The Test Connection button and AJAX save path both respect the new value immediately.<\/li>\n<\/ul>\n\n<h4>1.0.10<\/h4>\n\n<ul>\n<li>Settings: the \"your inSIM account\" anchor on Step 1 now points to https:\/\/ardary-insim.com\/ (the actual web app) with a visible external-link SVG icon. Every WP-admin URL that takes the merchant to the account dashboard, billing or API page now uses ardary-insim.com \u2014 see html-help.php, class-insim-help-tab.php, class-insim-send-tab.php (<code>upgrade_hint<\/code>), class-insim-settings.php (humanize_error + WC_Admin_Settings notice), class-insim-news.php and admin\/assets\/js\/campaign-wizard.js. Marketing-domain mentions (ardary-insim.com pricing, support email, status, the company brand reference) are intentionally kept.<\/li>\n<li>Postman collection: a Postman v2.1 collection covering the 8 endpoints the plugin uses (account, sendsms, sms, sms\/detail, sms\/conversation, sms\/delivery_status, stats\/overview, stats\/clicks) ships at docs\/insim-api.postman_collection.json (and inside the dist ZIP at docs\/insim-api.postman_collection.json). Each request has Content-Type\/Accept headers, a raw JSON body referencing <code>{{login}}<\/code> \/ <code>{{accessKey}}<\/code> collection variables and a link back to the matching api\/endpoints\/*.md spec.<\/li>\n<li>Test connection loader: the spinner is now 18px \/ 3px stroke \/ WP-admin blue on a #dcdcde track so it is visible on the green-ish button. The button is disabled while pending, its label is replaced with <code>&lt;spinner&gt; Testing connection\u2026<\/code>, and the original label is restored on completion (stored in <code>data-original-label<\/code>). A <code>min-width: 200px<\/code> rule prevents layout jump.<\/li>\n<li>Diagnostics: every API response now carries a <code>debug<\/code> block (<code>url<\/code>, <code>http_status<\/code>, <code>transport_message<\/code>, <code>body_snippet<\/code>). <code>ajax_save_and_test<\/code> returns it on both success and failure, and settings.js renders a collapsible \"Technical details\" section under the error card so the merchant sees the exact URL hit, HTTP status and the first 200 chars of the error body without enabling any log.<\/li>\n<li>Diagnostics \u2014 debug log: a new opt-in setting (<code>insim_debug_log<\/code>, off by default) writes one JSON line per API call to <code>wp-content\/uploads\/insim-debug.log<\/code>. The file is truncated to ~1 MB on every write. A \"Diagnostics\" row was added to Step 4 of the Settings accordion with the checkbox and a panel showing the live <code>INSIM_API_BASE_URL<\/code> value so the merchant can verify which environment is being hit.<\/li>\n<\/ul>\n\n<h4>1.0.9<\/h4>\n\n<ul>\n<li>Save as draft: the success redirect now lands the merchant on the Campaigns list as intended. The wizard previously resolved a relative <code>admin.php?...<\/code> URL onto whichever route the wizard was rendered through, occasionally landing on Settings. <code>ajax_send_campaign<\/code> now returns a canonical <code>redirect_url<\/code> and the JS uses it (with <code>ardarySms.adminUrl<\/code> as a fallback). A 1.5s success toast precedes the redirect.<\/li>\n<li>Auth lockdown (server + client). Tracking URL field and every Automations checkbox + textarea now ship with the <code>disabled<\/code> attribute when <code>connection_state()<\/code> is not <code>connected<\/code>, plus a lock hint pointing at Settings. <code>_post_process<\/code> short-circuits unconfigured POSTs so DevTools tampering still cannot persist activation. <code>ajax_save_abandoned_settings<\/code> now returns HTTP 412 NOT_CONFIGURED with an Open Settings link before falling back to feature-flag gating. <code>connectionState<\/code> and <code>settingsUrl<\/code> are localized into <code>window.ardarySms<\/code> on every plugin admin page.<\/li>\n<li>Helpdesk tab: stripped down to a single CTA opening https:\/\/ardary-insim.com\/ (the actual web app) in a new tab with a visible external-link SVG icon. The legacy in-WP test-SMS form was removed (Settings already exposes the same form). <code>ajax_send_test<\/code>, <code>helpdesk.js<\/code> and the <code>wp_ajax_insim_helpdesk_send_test<\/code> registration were deleted.<\/li>\n<li>Action button polish: the Campaign list row actions are now an inline row of 30x30 icon-only buttons (View \/ Edit \/ Delete) with Feather-style SVG icons, hover + focus states, and a red-tinged hover variant for Delete. The \"Create new campaign\" button uses an inline SVG <code>+<\/code> so the icon sits cleanly on the button baseline regardless of theme overrides.<\/li>\n<li>Tab order: the \"Settings first until configured\" logic now reads from <code>InSIM_License_Gate::connection_state()<\/code> directly so all surfaces (tab order, wizard banner, lock hints) agree on a single source of truth.<\/li>\n<\/ul>\n\n<h4>1.0.8<\/h4>\n\n<ul>\n<li>Campaign wizard: fixed a state-sync bug where the first click of \"Next\" on Step 2 silently re-rendered the same step. The wizard now exposes <code>window.insimWizard.showStep(n)<\/code> and the filter manager uses it, so one click always advances. Per-field inline error messages were added.<\/li>\n<li>Authentication vs license messaging: new <code>InSIM_License_Gate::connection_state()<\/code> helper returns one of <code>unconfigured<\/code> \/ <code>unverified<\/code> \/ <code>inactive<\/code> \/ <code>connected<\/code>. The wizard, <code>ajax_send_campaign<\/code> and <code>ajax_save_message<\/code> now distinguish \"credentials not entered yet\" (412 NOT_CONFIGURED with an \"Open Settings\" link) from \"feature not on plan\" (403 LICENSE_REQUIRED, neutral copy). Step 4 of the wizard surfaces the right banner and disables Launch while keeping Save as Draft available.<\/li>\n<li>Campaign name persistence: <code>ajax_send_campaign<\/code> now accepts an existing draft <code>campaign_id<\/code> and updates that row instead of inserting a fresh one. The temporary <code>CAMPAIGN-&lt;timestamp&gt;<\/code> placeholder no longer leaks into the campaign list when the merchant typed a real name.<\/li>\n<li>Save as Draft: new third action on Step 4 of the wizard between Back and Launch. Saves the campaign with <code>status='draft'<\/code> and redirects to the campaign list. The list shows a Draft badge, an Edit button that re-opens the wizard at Step 2 pre-filled, and a Delete button. A daily Action Scheduler job <code>insim_drafts_cleanup<\/code> removes drafts untouched for more than 30 days.<\/li>\n<li>UX polish pass: campaign detail page now groups \"Refresh now\" and \"Export CSV\" in a single right-aligned toolbar with Dashicons icons. \"Back to campaigns\", filter chips, wizard nav buttons and \"Create new campaign\" use a consistent icon+label spec. Wizard fields show a red border and inline error message on invalid input. Campaign list rows have a hover state and a standardised status-badge spec.<\/li>\n<\/ul>\n\n<h4>1.0.7<\/h4>\n\n<ul>\n<li>Helpdesk tab: simplified to a portal page. SMS conversations are managed in the inSIM web app; the in-WP inbox \/ conversation viewer \/ reply form was removed. Helpdesk now shows a description, an \"Open inSIM web app\" button, and a \"Send test SMS\" form (phone + message) that reuses the existing Sender pipeline. The <code>ajax_load_inbox<\/code>, <code>ajax_load_conversation<\/code>, <code>ajax_send_reply<\/code>, <code>ajax_add_optout<\/code> endpoints were removed.<\/li>\n<li>Reports tab: module-not-enabled gate dropped. Reports always attempt <code>stats\/overview<\/code> and degrade gracefully: stat cards on success, \"Statistics are not available for your account.\" on <code>LICENSE_REQUIRED<\/code>, \"Could not load statistics. Try again later.\" on any other error.<\/li>\n<li>Help tab: \"Modules enabled\" row removed from the account snapshot. The <code>LICENSE_REQUIRED<\/code> error card was rephrased to a neutral \"Some features require a higher plan.\" text with no mention of specific module names.<\/li>\n<li>Settings tab order: Settings is now the first tab until the account is configured, then moves to last. When the merchant lands on the admin page without a <code>?tab=<\/code> query argument and the account is not yet configured, the default tab is Settings.<\/li>\n<li>Tab styling: every tab shares the same green top border so the visual treatment is consistent.<\/li>\n<li>\"Create new campaign\" button: the <code>+<\/code> icon is a centred round badge to the left of the label.<\/li>\n<li>License-gate UI surface neutralised: no more \"Some automations require the X module\" banners or per-row \"Upgrade required\" badges; the Tracking URL field is no longer gated in the UI. Server-side license checks still run but their error messages are a neutral \"Not available on your current account.\"<\/li>\n<\/ul>\n\n<h4>1.0.6<\/h4>\n\n<ul>\n<li>Send Campaign tab: removed four unregistered (dead) AJAX handlers including one that echoed <code>$_REQUEST['callback']<\/code> (potential reflected XSS if ever wired). <code>ajax_send_campaign<\/code> now pre-checks SMS credits before inserting any DB row, returning HTTP 402 <code>INSUFFICIENT_CREDITS<\/code> if short.<\/li>\n<li>Automations: <code>on_status_changed()<\/code> now honors both the global \"Order status update\" toggle and the per-status checkbox (<code>ardary_sms_isactive_action_order_status_update_wc-&lt;status&gt;<\/code>), and uses the per-status message body when one was customised.<\/li>\n<li>Settings and Automations forms: added <code>wp_nonce_field<\/code> and <code>wp_verify_nonce<\/code> to the two POST handlers. Posts without a valid nonce are silently dropped.<\/li>\n<li>Campaign detail: <code>ajax_retry_failed<\/code> cancels any in-flight <code>insim_campaign_batch<\/code> actions for the campaign before re-queuing, to prevent duplicate sends. <code>admin_post_export_csv<\/code> streams in 500-row pages with <code>fflush<\/code> between pages.<\/li>\n<li>Uninstall: sweep now removes legacy <code>ardary_sms_*<\/code> option keys and their transient timeouts in addition to the <code>insim_*<\/code> prefix.<\/li>\n<li><code>_ajax_process_countRecipientsFromQuery<\/code> now requires <code>manage_woocommerce<\/code>.<\/li>\n<\/ul>\n\n<h4>1.0.5<\/h4>\n\n<ul>\n<li>Send Campaign tab: \"Add to Campaign\" button now adapts to selection. When no rows are ticked it reads \"Add all (N) to campaign\" and submits the whole filtered result via <code>insim_add_recipients_from_query<\/code>. When rows are ticked it reads \"Add N selected to campaign\" and uses the per-ID <code>insim_add_recipients_by_ids<\/code> path.<\/li>\n<\/ul>\n\n<h4>1.0.4<\/h4>\n\n<ul>\n<li>Send Campaign tab: recipient cards now expose a tickable checkbox plus a \"Select all on this page\" header row. A new <code>insim_add_recipients_by_ids<\/code> AJAX endpoint persists only the chosen rows into the draft campaign.<\/li>\n<li>SMS Campaigns tab: default view is now a paginated list of existing campaigns (newest first) with status badges, recipient\/progress columns and a \"Create new campaign\" CTA. Each row links to a new analytics detail page (<code>?action=view&amp;id=N<\/code>) with counters (Sent \/ Delivered \/ Failed \/ Clicks \/ CTR \/ Credits used), per-recipient table, 10-second auto-refresh polling while sending (paused via Page Visibility API), CSV export, and a \"Retry failed (N)\" button that re-queues failed rows through Action Scheduler. History tab campaign names also link to the detail page.<\/li>\n<\/ul>\n\n<h4>1.0.3<\/h4>\n\n<ul>\n<li>Automations tab: server-side license gating. AJAX endpoints reject attempts to activate any automation whose required feature flag is missing on the account. Disabling an automation is always allowed.<\/li>\n<li>Campaign wizard: Step 2 gains a Tracking URL field and a Priority radio (Normal \/ High). Both values are forwarded into the per-message <code>url<\/code> and <code>priority<\/code> fields on <code>POST \/sendsms<\/code>. New columns <code>tracking_url<\/code> and <code>priority<\/code> added to <code>wp_insim_campaigns<\/code> via an idempotent schema upgrade (no manual re-activation needed).<\/li>\n<li>Help tab: the <code>LICENSE_REQUIRED<\/code> entry now lists the feature flags the plugin gates against and the recovery path.<\/li>\n<\/ul>\n\n<h4>1.0.2<\/h4>\n\n<ul>\n<li>Send Campaign tab redesigned as a 4-step wizard (Recipients &gt; Message &gt; Schedule &gt; Review) with progress stepper, live SMS preview, GSM-7 segment counter, and cost vs balance check before launch.<\/li>\n<li>Settings: Step 3 (\"Test SMS\") input and button share a single inline row with status icons and spinner outside the button label.<\/li>\n<li>Settings Step 4: Default country code is now a searchable dropdown of 73 countries (was a 2-letter text input). Defaults to FR.<\/li>\n<li>New \"Help\" tab: full reference of every API <code>error_code<\/code> returned by the inSIM v2 API, with HTTP status, trigger, recovery action and example response. Includes a live account-snapshot panel.<\/li>\n<li>API audit: confirmed all endpoints used by the plugin match the documented payload and response shapes.<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Maintenance release.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release.<\/li>\n<li>Five automation hooks: order confirmation, status update, new account, low stock, abandoned cart.<\/li>\n<li>Visual campaign filter engine with guest-cart inclusion.<\/li>\n<li>Scheduled campaigns and rate-limit-aware batch sending via Action Scheduler.<\/li>\n<li>Abandoned-cart recovery with configurable delay, expiry, and recent-order exclusion.<\/li>\n<li>Delivery status polling from the History tab.<\/li>\n<li>STOP keyword opt-out list.<\/li>\n<li>8 dedicated database tables; full uninstall sweep.<\/li>\n<li>i18n ready, .pot file included.<\/li>\n<\/ul>","raw_excerpt":"Abandoned-cart recovery, order notifications and SMS marketing campaigns for WooCommerce \u2014 sent server-side, no phone or SIM required.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/167587","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=167587"}],"author":[{"embeddable":true,"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/2wstechnologies"}],"wp:attachment":[{"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=167587"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=167587"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=167587"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=167587"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=167587"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/mri.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=167587"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}