=== Simply Buy ===
Contributors: nebim
Tags: form, shop, booking, calculator, clearance
Requires at least: 6.2
Tested up to: 7.0
Requires PHP: 8.0
Stable tag: 1.3.16
License: GPLv3.0
License URI: https://www.gnu.org/licenses/gpl-3.0.html

SimplyBuy is the easiest way to add a small "shop-like" request form or service calculator to WordPress.

== Description ==

**SimplyBuy** is a lightweight WordPress plugin that lets you create simple online shop-style requests or price calculations — completely without WooCommerce, without a shopping cart, and without payment processing.

Originally developed as a bulky-waste calculator for clearance companies, SimplyBuy works for any service provider who needs a simple eCommerce-like solution without the complexity of a traditional WordPress online shop plugin.

Because SimplyBuy avoids unnecessary features found in typical WordPress shop plugins, it is:

* Easy to set up
* Lean in code
* Ready to use immediately
* Does not store customer data
* Does not require shipping rules
* Free of inventory management

SimplyBuy can be used as a WordPress plugin shop-free alternative for services — perfect for anyone needing shop-style functionality without WooCommerce and without a shopping cart.

== Who is SimplyBuy made for? ==

SimplyBuy is for doers.

It is ideal for clearance companies, moving companies, agencies, and service providers who want fast customer inquiries — not a full WordPress shopping plugin.

Ideal for:

* Service providers needing simple online requests
* Local businesses looking for a WordPress shop plugin free alternative
* Companies needing a WordPress product plugin without a shopping cart
* Users who want a simple eCommerce plugin for WordPress
* Anyone wanting a mini “shop” experience without payment and without WooCommerce

Although designed for clearance services, SimplyBuy is flexible and can be used in many industries.

== What makes SimplyBuy special ==

* Works like a simple WordPress online shop plugin, without the complexity of a real shop
* No WooCommerce, no checkout flow, no payment forms
* Ideal if you want a WordPress shop without WooCommerce
* Display simple service “products” or price options
* Perfect for websites offering quotes, requests, or simple services
* 100% compatible with any theme
* Shortcode-based and fully responsive
* A great alternative to free WordPress shop plugins that are too complex

== What SimplyBuy is NOT ==

* Not a full eCommerce system
* Not a shopping cart plugin
* Not for selling products with stock
* Not for tickets, events, or limited inventory
* Not a traditional WordPress shop setup
* Not a WooCommerce replacement for online payments

SimplyBuy is a request-first tool, not a payment or checkout plugin.

== Multilingual support ==

SimplyBuy works on multilingual WordPress sites with the following caveats:

* **Polylang (recommended):** Fully supported. Product search and selection respect the current page language. The plugin's automatic page creation (Cart, Checkout, Thank You) creates one page per active Polylang language and links them as translations.
* **WPML:** Not officially supported yet. Single-language sites work fine. On multilingual WPML setups, the product search may return results from all languages.
* **Weglot:** Not applicable — Weglot translates the page output, not the database. SimplyBuy's product database remains in the source language; Weglot then translates the displayed text on the fly.
* **No multilingual plugin:** Works as a single-language site. All products in the database are shown, regardless of the WordPress site language. The "language" of the products is whatever the site owner typed when creating them.

The plugin's user interface ships with English (default) and German translations. Other site languages will fall back to English for the plugin's own labels (product titles and descriptions are not affected — they come from the database as-is).

== Installation ==

1. Upload the plugin files to the `/wp-content/plugins/simply-buy` directory or install the plugin through the WordPress plugins screen directly.
2. Activate the plugin through the 'Plugins' screen in WordPress.
3. Go to "SimplyBuy" to configure plugin settings.

== Screenshots ==

1. SimplyBuy settings panel – configure pricing, surcharges, currency, pages, and enable optional branding support.
2. Booking calendar – manage available dates and time slots for customer requests with a visual yearly overview.
3. Cart page setup – example of the Cart page using SimplyBuy shortcodes to display selected services.
4. Checkout page setup – example of the Checkout page where users submit their request without payment processing.


== Changelog ==

= 1.3.16 =
* Improved: Mobile touch targets — the cart's remove-item (X) button and the search dropdown's result entries now have a minimum 44x44px touch hit area on mobile, matching iOS Human Interface Guidelines. The visual size of the X icon and the dropdown text style are unchanged on desktop. Only mobile layouts (<=768px) are affected.

= 1.3.15 =
* Fixed: Polylang term-language slug prefix — Polylang stores term-language slugs with a 'pll_' prefix (e.g. 'pll_de', 'pll_en'), while post-language slugs are plain 'de'/'en'. The term post-filter was looking up the slug without the prefix and therefore failed to find the language term, causing the filter to early-return without filtering. The lookup now uses the correct 'pll_' + language code.

= 1.3.14 =
* Fixed: Polylang AJAX language filter (final) — pll_get_term_language() and pll_get_post_language() return unreliable results in the nopriv admin-ajax context (they can fall back to the request's referer language instead of the term/post's stored language). The post-filter now reads the language assignment directly from Polylang's term_language / language taxonomies via $wpdb. This is context-free and gives the correct stored language regardless of admin-ajax quirks. Confirmed root cause via runtime logging in admin-ajax.

= 1.3.13 =
* Fixed: Polylang AJAX language filter (continued) — the language validation against pll_languages_list() failed silently in the nopriv admin-ajax context because Polylang Free's API/model isn't reliably initialized there (pll_languages_list() can return an empty array). The validation now falls back to a locale-format check when Polylang's language list isn't available, so the language code from the request reaches the post-filter even in that context. An invalid code simply matches no terms downstream, so this is safe.

= 1.3.12 =
* Fixed: Polylang AJAX language filter — even with the active language passed to AJAX handlers, Polylang Free does not apply its language filter in admin-ajax context (is_admin() is true there). Search results and product loading now post-filter the returned terms and posts by their Polylang language assignment, so English mode no longer returns German products and vice versa. This works with Polylang Free 3.x and Polylang Pro.

= 1.3.11 =
* Fixed: Multilingual sites (Polylang) — the product search and selection now respect the current page language. The active language is passed from the page render context to the AJAX handlers, so AJAX-based search and product loading return results only for the current language (previously, searching in the English UI could return German products and vice versa).
* Improved: Cart and checkout list now show newest items first — the freshly added item lands at the top in view, making the row highlight much more visible.
* Improved: Cart row highlight after adding an item is now more noticeable — longer (1.8s, with a hold phase) and slightly more saturated.
* Improved: On mobile, the search field auto-scrolls to the top of the viewport on focus and the results list is height-capped to the space above the on-screen keyboard (uses visualViewport API).
* Fixed: Restored the correct Select2 dropdown positioning rule (search results could render off-screen). The compiled CSS is authoritative; the SCSS source was out of sync.
* Added: Mobile sticky checkout bar on the cart page — subtotal and the "Go to checkout" button stay pinned to the bottom of the screen while scrolling. Desktop layout is unchanged.
* Added: Visual confirmation when an item is added to the cart — a short toast (check mark + product name), a brief highlight of the affected cart row, and a light haptic vibration on supported mobile devices.
* Improved: The search field now clears automatically after an item is added, so the next item can be entered right away.
* Improved: On the checkout page, the optional "Company" and "Notes" fields are now collapsed by default and expand on click, keeping the form shorter and less cluttered.

= 1.3.3 =
* Added: Cache-plugin compatibility layer. SimplyBuy now automatically registers its cart cookie (`simply-buy-products`) on the bypass / vary list of WP Rocket, WP Super Cache, and LiteSpeed Cache. This prevents stale cart and checkout pages from being served to logged-out visitors with an active cart. Other cache layers (W3 Total Cache, WP Fastest Cache, Cloudflare page cache, Varnish, etc.) need to be configured manually — add the cookie name `simply-buy-products` to your cache plugin's bypass list.
* Added: Second "Back to cart" button on the checkout page, shown directly below the cart table. Reduces the need for visitors to use the browser back arrow.
* Fixed: Removed dead `wp-jquery-ui-dialog` CSS dependency from the checkout stylesheet. Themes that deregister `dashicons` for performance reasons (which broke the dependency chain and caused the checkout layout to collapse) are no longer affected. Saves one HTTP request on the checkout page.

= 1.3.2 =
* Automated WordPress.org deployment pipeline. No functional changes from 1.3.1.

= 1.3.1 =
* Fix: Admin booking notification email previously used the customer's email address in the From header, causing rejections at providers with strict DMARC/SPF policies (Gmail, Outlook, etc.). The From header now uses the site's own domain (no-reply@domain), and the customer's name and email are moved to the Reply-To header, preserving one-click reply to the customer while fixing deliverability.

= 1.3.0 =
* Added: Full Polylang support. Plugin now detects Polylang and creates Cart, Checkout and Thank-you pages for every active language on install. German and English pages include translated titles and slugs. Other languages use English fallback text (users can rename and translate these pages manually in WP Admin).
* Added: Runtime language-aware routing — Cart, "Continue to checkout" buttons, and post-submit redirects now link to the page matching the visitor's current language.
* Added: New helper function sbuy_get_localized_page_id() for theme/plugin developers who need language-aware page ID lookups.
* Added: Admin notice shown on Polylang sites with 3+ languages, linking users to the Pages screen so they can review auto-created language variants.
* Note: Sites without Polylang are unaffected — plugin behaves identically to previous versions.

= 1.2.9 =
* Fix: Time slot no longer disappears from the Zeit dropdown when the checkout form is submitted with other required fields missing. The "morning" / "afternoon" option cleanup now runs only when the form is valid and about to re-fetch the shift, not before the missing-fields return path (regression from 1.2.6 where the placeholder cleanup was too aggressive).

= 1.2.8 =
* Fix: "Test connection" button on the Calendar settings tab now auto-saves the form before running the API test. Previously, changing the service-account JSON or calendar ID and clicking the button tested the old saved values instead of what was on screen (same fix pattern as the "Test email" button on the Review Requests tab).

= 1.2.7 =
* Fix: "Mindestabnehmerwert" renamed to "Mindestabholpreis" in German translations (both du-form and Sie-form)
* Fix: Minimum-pickup help line is now hidden on the checkout when the minimum value is empty or 0 (no more "... is 0€" message)
* Improved: Earliest Booking Offset dropdown no longer shows a disabled "Select days" placeholder — first option is now directly "1 day"

= 1.2.6 =
* Fix: Time slot picker — after selecting a date, the proposed slot is now actually `selected` in the DOM. Previously the UI displayed the slot but the submit handler still saw the placeholder and rejected the booking with "please choose a time slot"

= 1.2.5 =
* Fix: Booking emails and Google Calendar events now correctly show the full product list + difficulty surcharges + final total (regression introduced by 1.2.3 server-side price recalculation)
* Fix (frontend): Checkout JS now sends product IDs, walkway numeric value and floor numeric value to the server alongside the display labels, so server-side price calculation has the data it needs

= 1.2.4 =
* Added: Google Calendar "Test connection" button in the Calendar settings tab — read-only diagnostic (calendars.get API call), never creates events. Shows specific errors for empty JSON, invalid JSON, 401 (unauthorized), 403 (forbidden), 404 (calendar not found)

= 1.2.3 =
* Security fix: Checkout total is now recomputed server-side from real product meta prices + finance settings. Previously the POSTed total was trusted verbatim, allowing a hostile client to submit a manipulated price
* Fix: `sbuy_install_starter_products()` is now idempotent — skips when starter products already exist (previously yielded 434, 651, … duplicates on repeated calls)
* Added: Self-healing DB tables — if `sbuy_booking` / `sbuy_logs` tables are missing (e.g. after an uninstall + manual reinstall), they are recreated on `plugins_loaded` via dbDelta

= 1.2.2 =
* Fix: Removed the theme's default 1px box-shadow under the cart search pill (the faint grey line under the orange border)

= 1.2.1 =
* Fix: Checkout button label now consistently reads "Weiter zur Kasse" / "Go to checkout" (was flipping to "Kasse" after JS cart updates because the localize string used the old msgid)

= 1.2.0 =
* Improved: Cart search field made wider on desktop (min-width 720px) — previously squeezed to ~270px on themes with an empty sidebar
* Improved: Removed stray separator lines around the cart search field and the selected-items heading
* Improved: Font Awesome dependency removed — the three icons in use (info, arrows-left, paper-plane) now render as inline SVG. Saves ~1 MB webfonts + 74 KB CSS on every checkout page
* Renamed: "Objekt" → "Gegenstand" throughout the German UI; "Kasse" button label → "Weiter zur Kasse"; cart heading "Gegenstände" → "Ausgewählte Gegenstände"

= 1.1.3 =
* Fix: Cart search field redesign — orange border + magnifier button (previously landed in 1.1.2 dev).
* Added: Self-healing plugin pages. If Cart / Checkout / Thank-you pages are deleted in WP admin, the plugin recreates them on the next request (also triggers on plugin re-activation).

= 1.1.2 =
* Fix: Checkout now requires a time slot (client + server + calendar hook skip on empty shift)
* Version bump acts as cache-buster — clients and CDNs reload all plugin assets.

= 1.1.1 =
* Release bundles accumulated post-1.1.0 fixes (search field CSS, checkout scroll-to-error, submit-button href, plain-text review email, multisite uninstall, Google Calendar failure alert, etc.)
* Version bump acts as cache-buster — clients and CDNs reload all plugin assets.

= 1.1.0 =
* Fix: load_plugin_textdomain added — plugin now loads translations correctly
* Fix: Uninstall cleanup — removes database tables, options and plugin pages on uninstall
* Fix: Email validation added to checkout submission
* Fix: Rate limiting added to checkout (max 1 request per minute per IP)
* Fix: Removed non-functional unset($_COOKIE) call on deactivation
* Fix: Search now hides unused/deleted tags (hide_empty)
* Added: Info notice in Pages tab about auto-created pages
* Added: Starter Products page with 217 ready-to-use products (install/remove)
* Added: Documentation link in Calendar tab
* Added: Custom notification email and reply-to email in Email settings
* Added: Google Calendar location field (address/zip)
* Added: Extended debug logging (browser, calendar errors, price calculation)
* Improved: Branding tab redesign with feature preview and clearer value proposition
* Added: Bulk block days in bookings calendar (all Sundays, Mondays etc.)
* Added: Bulk price adjustment for all products with preview
* Added: Review request emails — event-based with configurable delay
* Improvement: Bulk calendar blocking, bulk price adjustment and review requests are now Pro-only features
* Fix: Minimum pickup price shown as disabled field instead of hidden when no Pro access
* Fix: Branding disable button now visible (greyed out) during cooldown period
* Improved: Bulk calendar day blocking redesigned as dropdown + button
* Added: Bulk vs manual booking distinction (is_bulk flag) — bulk remove only removes bulk blocks
* Added: Price Adjustment as separate menu item
* Added: Sidebar tip in Pages tab
* Improved: Search field wider border and better placeholder visibility
* Fix: Starter products — literal "\n" sequences are now converted to real line breaks on import; a one-time "Repair" button fixes posts imported with earlier versions
* Changed: Plugin author updated to ProfitClicker (https://profitclicker.com/)
* Added: Bulk price adjustment supports a fixed amount (€) in addition to percentage
* Fix: Uninstall now removes branding cooldown/dismiss flags, review request settings, legacy bulk-blocked-dates option, rate-limit transients and the review-email cron schedule
* Improved: Branding tab feature box renamed to "All Pro features — unlock for free" and lists all 5 unlocked features
* Improved: Starter product newline repair now runs silently on plugin update (no longer a manual button)
* Fix: Multisite — uninstall now iterates every site and removes its options, pages, tables, transients and cron events (role is removed once, globally); activation saves the branding backlink token per site instead of overwriting the main blog

= 1.0.8 =
* Add new features

= 1.0.7 =
* Add new features

= 1.0.6 =
* Add new features

= 1.0.5 =
* Add new features

= 1.0.4 =
* Add new features

= 1.0.3 =
* Add new features

= 1.0.2 =
* Add new features

= 1.0.1 =
* Add new features

= 1.0.0 =
* Add new features

== Upgrade Notice ==

= 1.3.2 =
Automated WordPress.org deployment pipeline. No functional changes from 1.3.1 — upgrade optional.

= 1.3.1 =
Critical fix for admin booking notifications — fixes email rejections at Gmail/Outlook caused by From-header spoofing. Recommended update for all users.

= 1.3.0 =
Adds multilingual support via Polylang. No action required for existing sites. Polylang users will get language-aware page routing after update.

= 1.2.9 =
Fixes time slot dropdown disappearing when checkout is submitted with missing required fields. Regression from 1.2.6.

= 1.0.8 =
* Add new features

= 1.0.7 =
* Add new features

= 1.0.6 =
* Add new features

= 1.0.5 =
* Add new features

= 1.0.4 =
* Add new features

= 1.0.3 =
* Add new features

= 1.0.2 =
* Add new features

= 1.0.1 =
* Add new features

= 1.0.0 =
* Add new features
