=== TextMe SMS ===
Contributors: amitrotem, ramiy, sdp49
Tags: sms, text message, notifications, woocommerce, contact form 7
Requires at least: 6.1
Tested up to: 7.0
Requires PHP: 7.4
Stable tag: 2.1.5
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Send custom SMS messages from your WordPress site to your customers using the TextMe SMS gateway.

== Description ==

TextMe SMS Integration allows you to send SMS messages from your WordPress site using the TextMe SMS gateway service.

**Features:**

* Send SMS notifications for WooCommerce orders
* Contact Form 7 integration
* Elementor Forms integration
* User registration SMS notifications
* Admin OTP/2FA for secure logins
* Phone number login shortcodes
* Out of stock notifications
* Balance monitoring with email alerts

**WooCommerce Integration:**

* New order notifications (customer and admin)
* Order complete notifications
* Order cancelled notifications
* Pending payment reminders
* Custom order status notifications
* Customer notes via SMS

**Login Security:**

* Two-factor authentication via SMS OTP
* Phone number login support
* International phone number support

== Installation ==

1. Upload the plugin files to the `/wp-content/plugins/textme-sms-integration` directory, or install the plugin through the WordPress plugins screen directly.
2. Activate the plugin through the 'Plugins' screen in WordPress.
3. Go to Settings > TextMe SMS to configure the plugin.
4. Enter your TextMe SMS API credentials.

== Frequently Asked Questions ==

= What is TextMe SMS? =

TextMe SMS is an SMS gateway service that allows you to send text messages from your applications.

= Do I need a TextMe account? =

Yes, you need an active TextMe SMS account with API credentials to use this plugin.

= Does this work with WooCommerce? =

Yes, the plugin includes full WooCommerce integration for order notifications.

== Changelog ==

= 2.1.5 =
* Feat: Added a clean uninstall routine with an opt-in "Remove data on uninstall" setting (off by default). When enabled, deleting the plugin removes all of its options, log tables, stored device fingerprints, transients, and scheduled tasks (multisite-aware and namespaced, so nothing else is touched). Deactivating never removes data.
* UI: The settings screen is now fully responsive. On mobile the navigation collapses to an icon-only strip with the tab title shown on hover, and a convenient "Save Settings" button is available in the navigation column (hidden on tabs that have no form).
* UI: Theme-provided OTP fields (the textme_sms_form_fields hook, e.g. the Vibes theme) now render in their own "Theme OTP" tab that only appears when a theme registers the hook, instead of a loose form at the bottom of the page.
* UI: The shipping-rules matrix is now a responsive card-based repeater instead of a wide table, and long log messages/URLs wrap instead of overflowing.
* UI: Fixed right-to-left text being clipped and horizontal overflow across all settings tabs on narrow screens — form-tables and the dynamic order-status table stack to fit, fixed-width fields become fluid, and button-icon alignment is corrected. Verified zero horizontal overflow down to 375px.
* i18n: Completed Hebrew coverage for the new and updated screens. WordPress now auto-loads the bundled translations via the plugin headers (the redundant manual loader was removed), while the complete bundled catalog is still preferred over any stale wp.org copy.
* Hardening: Added wp_unslash()/sanitize_text_field() to client-IP and user-agent reads, routed the API request body through wp_json_encode(), set SSL verification explicitly on the legacy gateway call, and added direct-access protection to the bundled translation files (WordPress.org Plugin Check compliance; no behavioural change).
* Compatibility: Minimum WordPress raised to 6.1.

= 2.1.4 =
* Change: Removed the non-functional "Allow ManageWP login" toggle. ManageWP's one-click login authenticates through its own signed channel during must-use-plugin load — before this plugin runs — so it cannot be gated by SMS from a WordPress plugin; the toggle could never take effect. Secure that path on the ManageWP account itself (enable 2FA there). All other login methods (wp-login.php, XML-RPC, REST, Application Passwords) remain fully OTP-protected.
* Change: The OTP message fields now note that a default message is sent when left blank (and show exactly what that default is), and that the [code] placeholder is added automatically if missing.
* i18n: Completed Hebrew coverage — every user- and admin-facing string in the plugin is now translated (100%); regenerated the .pot template and refreshed the translation catalog.
* Chore: Removed leftover commented-out debug logging.

= 2.1.3 =
* Security: The generated one-time code returned by the gateway is now masked in the API log (it was stored in cleartext in the response, letting anyone with DB/backup/log access read live OTPs).
* Security: The emergency escape hatch (`TEXTME_DISABLE_LOGIN_GUARD`) now also disables OTP enforcement, not just rate limiting, so a lost/undelivered phone can no longer lock an administrator out with no recovery path but the database.
* Security: The security audit log's client-IP resolver now validates Cloudflare edge origins (it previously trusted `CF-Connecting-IP` unconditionally, allowing IP spoofing / audit-log poisoning on non-Cloudflare sites).
* Feat: The "Enforce OTP on all login forms" setting is now functional — when on (and customer OTP is enabled), it extends server-side OTP enforcement to customer logins, closing the direct-POST bypass for the customer login form.
* Fix: OTP send now falls back to the default message template when the field is blank (a blank template was rejected by the gateway), and shows the gateway's actual failure reason instead of a generic error.
* Fix: SMS order tags such as {order_total} are rendered as plain text — WooCommerce price markup and HTML entities no longer leak into messages.
* Fix: The security audit-log table is created on load (via a schema-version check), so it is present after zip-upload upgrades that skip the activation hook.
* Fix: New-device detection no longer keys on IP, so admins on dynamic/mobile IPs are not alerted on every login.
* i18n: All admin-OTP status messages, the login/OTP modal UI strings, and the 2.1.x admin settings + Login Security screen labels are now translatable and shipped with Hebrew translations.

= 2.1.2 =
* Feat: Admin login hardening package (all opt-in, default off): rate limiting with time-boxed lockout, manual lockout release from a new "Login Security" screen, a security audit log of admin login events, and an SMS alert when an admin logs in from a new device.
* Security: While Admin OTP is enabled, administrator logins are blocked on every route that does not pass SMS verification — including the WooCommerce account form, XML-RPC, and the REST API (Application Passwords).
* Security: The lockout counter also tracks attempts per-username, so brute-force from rotating IPs is throttled; the `CF-Connecting-IP` header is trusted only for requests originating from a Cloudflare edge, preventing IP spoofing and audit-log poisoning.
* Security: The enforcer verifies the plugin's own OTP-flow nonce rather than trusting the request's action name, and the REST guard tests for a genuine cookie session rather than a raw auth header.
* Security: Failed OTP verifications now count toward the lockout threshold.

= 2.1.1 =
* Security: Admin OTP is now enforced at the WordPress authentication layer. Previously the OTP prompt was only shown in the browser login form — a direct POST to wp-login.php, XML-RPC, or the REST API could authenticate an administrator without OTP. Privileged logins that do not pass through the SMS-verified flow are now rejected.
* Security: When Admin OTP is active, XML-RPC is disabled and Application-Password (HTTP Basic) authentication is blocked for administrators, closing two paths that bypass OTP. XML-RPC can be re-enabled with the `textme_allow_xmlrpc` filter.
* Feat: New "Allow ManageWP login" toggle lets the ManageWP one-click "WP Admin" login skip OTP when needed. ManageWP's routine background sync is unaffected regardless of this setting.

= 2.1.0 =
* Feat: Shipping-method SMS rules — map a WooCommerce shipping method + order status to a custom SMS template; a matching rule replaces the default status SMS and can also notify the admin. Managed from a new "Shipping Rules" settings tab.
* Feat: Dynamic placeholders now support both {curly} and [bracket] formats, plus {order_id}, {pickup_address}, and a generic {meta:your_key} tag for any order meta.
* Feat: {pickup_address} resolves from (in order) a per-rule meta key, a global meta key, auto-detected pickup-point meta keys, a per-rule static address, then the store base address — compatible with delivery plugins that store the pickup point in order meta.
* Feat: Collapsible, icon-only settings navigation (WordPress-style) with hover labels, so the settings fit better on smaller screens.
* Fix: Bundled Hebrew translation now loads correctly on the admin (a stale wp.org language pack was overriding the plugin's own translations); full Hebrew coverage for the new screens.
* Fix: Out-of-stock notify toggle could not be saved when a theme provided its own stock-notify class; the toggle now saves correctly.
* Fix: Bulk SMS sends (restock / stock-notify) are now logged with the correct phone, message, and type in the API log.

= 2.0.8 =
* Fix: Out of stock notify form now appears correctly on variable products when selecting an out-of-stock variation — previously the form would flash briefly then disappear because WooCommerce updates `.woocommerce-variation-availability` after firing `found_variation`, overwriting a direct DOM injection
* Fix: Stock notify form is now correctly injected into `availability_html` via `woocommerce_available_variation` (primary path) so WooCommerce's own JS includes it when updating the DOM; a `setTimeout(0)` JS fallback covers themes such as WooCommerce Variation Swatches that handle the variation event differently
* Fix: Stock notify form now renders on the product page when all variations of a variable product are out of stock — previously the form was silently skipped for all variable product types
* Fix: Removed duplicate `id="textme-stock-phone"` on pages where both the static all-OOS form and a per-variation form are visible simultaneously; field now uses a class selector throughout

= 2.0.7 =
* Feat: Added `[shipping_method]` and `[payment_method]` dynamic tags for WooCommerce SMS templates — both available in the "Insert Dynamic Field" dropdown on all order SMS fields
* Feat: Blacklisted phone numbers can now complete the OTP login flow — send_otp is tried first; only on failure is the number temporarily removed from the blacklist and the send retried; no blacklist API calls are made for regular users
* Fix: Blacklisted numbers are restored in all exit paths — session timeout, max OTP attempts exceeded, last wrong-code attempt, and successful login all trigger an immediate restore; a WP-Cron safety net (15 min) covers the abandoned-session case where the user closes the browser mid-flow
* Fix: If OTP delivery still fails after temporarily removing a number from the blacklist, the number is restored to the blacklist immediately
* Fix: Clarified "Shipping Number" dropdown labels — `[shipping_number]` is the current tag and `[ship_num]` is labelled as migrated from v1

= 2.0.6 =
* Fix: Remove redundant woocommerce_order_status_{status} fallback hooks and handle_order_status_fallback() — WooCommerce fires both the individual-status hook and woocommerce_order_status_changed from the same status_transition() call, so the fallback provided no additional coverage and could still produce duplicates if the transient lock expired or the object cache was unavailable

= 2.0.5 =
* Fix: Duplicate SMS sent on WooCommerce order status change — replaced per-object order meta lock with a transient-based lock shared across all WC_Order instances in the same request

= 2.0.4 =
* Fix: Remove global session_start() on init — prevents "Active PHP Session Detected" Site Health warning, REST API timeout (cURL error 28), and block editor load failures caused by PHP session lock blocking concurrent requests
* Fix: session_write_close() now called after every AJAX handler that reads/writes $_SESSION, releasing the server-level lock immediately
* Feat: Replace sticky tag-chip block with per-textarea "Insert Field..." dropdown; tag is inserted at cursor position and works in dynamically added custom status rows
* Feat: Switch WooCommerce order SMS from individual woocommerce_order_status_{status} hooks to universal woocommerce_order_status_changed hook — SMS now fires reliably from PayPlus, shipping plugins, REST API, HPOS, and other third-party triggers
* Feat: Add "Status Change Debug Log" toggle in WooCommerce tab; logs every order status transition and SMS send/skip reason to WooCommerce → Status → Logs (source: textme-sms)
* Fix: Deduplication lock (_textme_sms_sent_{status} order meta) prevents duplicate SMS if both the universal and individual hooks fire for the same transition

= 2.0.3 =
* Fix: Fatal error "Cannot use object of type WC_Meta_Data as array" when changing order status — ShipOS tracking number now correctly reads the WC_Meta_Data object value
* Fix: Extension fields added via the textme_sms_form_fields action hook now have a dedicated Save button and AJAX handler; data is saved to textme_sms_option for full backward compatibility with theme extensions

= 2.0.2 =
* Fix: WooCommerce SMS templates with v1-style tags ([first name], [last name], [order number] with spaces) were sent with unreplaced literal tags after migration — backward-compatible aliases added
* Fix: [order_status], [ship_num], and [shipping_number] tags were shown in the admin tag picker but never replaced in outgoing SMS messages
* Fix: [ship_num] and [shipping_number] now correctly read from ShipOS (wc-shipos-delivery) order meta using the actual delivery_number field
* Fix: Carriage return characters (\r) from textarea form submissions were appearing as &#xD; in received SMS messages
* Fix: TEXTME_SMS_VERSION constant was out of sync with plugin header version

= 2.0.1 =
**Architecture**

* Complete plugin rewrite with a modular, class-based architecture
* Each feature now stores its own settings separately — no more shared flat options array
* New top-level admin menu replacing the nested Settings page
* Built-in migration tool to carry all v1.x settings forward to v2.0.0 automatically
* PHP 7.4+ and WordPress 5.2+ now required

**WooCommerce**

* Independent customer and admin SMS toggles per order event
* Added pending payment SMS notifications (customer and admin)
* Added support for custom order statuses with individual SMS messages
* Added customer note SMS (send from the WooCommerce order note field)
* Added option to save customer phone number to address book on order

**Out of Stock Notifications (new)**

* Customers can subscribe to restock alerts directly from the product page
* Optional name, email, and terms & conditions fields on the subscription form
* Admin reports page with Pending and Sent tabs showing all subscribers
* Bulk SMS — notify all waiting subscribers in one click when stock returns

**User Registration Coupon (new)**

* Generate a unique WooCommerce coupon automatically on new user registration
* Send the coupon code to the customer via SMS
* Configurable discount type, amount, and coupon code length

**Login Security (new)**

* Admin OTP / 2FA — intercepts wp-login.php and requires SMS verification before granting admin access
* `[textme_login_form]` shortcode — custom login form with username, password, and SMS OTP step
* `[textme_phone_login]` shortcode — passwordless login using phone number and SMS OTP
* Configurable max OTP attempts, resend cooldown, and fallback phone meta field
* International phone number support

**Balance Monitoring (new)**

* Daily cron job checks your TextMe account balance
* Sends an email alert to the site admin when balance drops below a configurable threshold

**Reports & Logging (new)**

* API call log viewer in the admin — shows phone, message preview, status, and HTTP code
* Enable/disable logging toggle — disabled by default
* Clear all logs button
* Logs auto-pruned after 90 days (configurable)

**Admin & UX**

* Test SMS sending directly from the settings page with live response display
* Connection status indicator in the settings header
* Copy-on-click shortcode helper
* Fully responsive admin design

**Internationalization**

* Full Hebrew translation included
* All JavaScript strings localized

**Security**

* Session cookies hardened with Secure, HttpOnly, and SameSite=Strict flags
* Session ID regenerated after every successful OTP login to prevent session fixation
* Brute-force protection on credential login (5 attempts per 15 minutes)
* XXE vulnerability patched in legacy XML API parser
* Open redirect blocked — shortcode redirect attribute restricted to same-site URLs
* SSL verification explicitly enforced on all outbound API calls
* Generic error messages on phone lookup to prevent user enumeration
* Plugin options set to autoload=false — settings not loaded on front-end pages that don't use them

= 1.0.0 =
* Initial release

== Upgrade Notice ==

= 2.0.8 =
Bug fix release. Out of stock notify form now works correctly on variable products — shows on page load when all variations are out of stock, and appears reliably when selecting an out-of-stock variation, including with WooCommerce Variation Swatches.

= 2.0.7 =
Feature and fix release. Adds [shipping_method] and [payment_method] SMS tags for WooCommerce orders. Blacklisted phone numbers can now complete OTP login and are automatically re-blacklisted after login in all exit scenarios, including abandoned sessions via WP-Cron safety net.

= 2.0.4 =
Bug fix and feature release. Fixes REST API timeouts, Site Health session warning, and block editor failures caused by PHP session locking. Adds per-textarea tag insertion dropdown and more reliable WooCommerce order SMS via the universal status-changed hook.

= 2.0.3 =
Bug fix release. Fixes fatal error on order status change when ShipOS is active, and restores save functionality for settings page extensions added via the textme_sms_form_fields hook.

= 2.0.2 =
Bug fix release. Fixes SMS template tags not being replaced after v1 migration, &#xD; characters appearing in messages, and ShipOS tracking number tags.

= 2.0.1 =
Major rewrite. All v1.x settings are migrated automatically on first activation. New features include OTP/2FA login, phone number login shortcodes, out of stock notifications, user registration coupons, balance monitoring, and API logs. Requires PHP 7.4+ and WordPress 5.2+.
