Orki Table Builder Pro - Full Changelog
========================================

This is the complete version history. The Changelog section in readme.txt
shows only the most recent releases (WordPress.org's readme parser truncates
the Changelog section at 5000 characters).


== Changelog ==

= 0.15.1 =
* Fixed the last remaining Plugin Check warning: uninstall.php declared $table_posts at the top level of the file without the plugin's prefix. Wrapped the cleanup logic in a prefixed function (orkitbp_uninstall_cleanup()) instead of just renaming the variable, so this file can't reintroduce the same issue if it grows later.

= 0.15.0 =
* BREAKING CHANGE, per a WordPress.org review finding: the "tbp" prefix used throughout this plugin (class names, constants, the post type, the taxonomy, meta keys, shortcode tags, hook names, nonce actions, enqueue handles, JS globals) was flagged as too short and too generic to safely avoid collisions with other plugins. Renamed everything to "orkitbp" (25+ identifiers, all cross-checked for consistency between PHP/JS/CSS).
* If you've created any test tables on your site under the previous version: the post type changed from tbp_table to orkitbp_table, so existing tables will no longer appear in the admin list (they still exist in the database, just under an unregistered post type) — you'll need to recreate them. Any shortcodes already pasted into content, [tbp_table id="X"] or [tbp_category id="X"], need updating to [orkitbp_table id="X"] / [orkitbp_category id="X"].
* The 11 include files were also renamed (class-tbp-*.php to class-orkitbp-*.php) for consistency with the classes they define — required for require_once statements to keep matching, since one of the mass find-and-replace passes changed the file-path strings in the code before the actual files were renamed to match.

= 0.14.4 =
* Addressed the WordPress.org human review findings: replaced the last hard-coded frontend <style> tag (conditional-formatting color overrides) with wp_add_inline_style() on a dedicated handle, with a wp_footer fallback print for normal page rendering and a restructured render-before-print order on the standalone Preview/PDF pages, which don't fire wp_footer().
* Added sanitize_text_field() to every wp_verify_nonce(wp_unslash(...)) call, per the reviewer's explicit guidance, replacing the ignore-comments I'd used to justify omitting it.
* Fixed a genuine path-traversal edge case in the "File on server" import option: the ABSPATH-prefix check used plain string matching, which a sibling directory (e.g. /var/www/html-backup when the install is /var/www/html) could pass despite being a different folder entirely. Now requires the path separator immediately after the prefix.
* Corrected the readme.txt Contributors field to the actual WordPress.org account username.

= 0.14.3 =
* Fixed the last 6 Plugin Check warnings: two more nonce/sanitization false positives (a function only ever called after its caller's nonce check; two custom sanitizing helper methods the scanner doesn't recognize by name — both already documented and now correctly covered by the existing ignore comments' scope), and the "Changelog section too long" warning.
* readme.txt's Changelog section was 31,000+ characters — WordPress.org's readme parser truncates that section at 5000, which would have cut a version's changelog entry off mid-sentence on the plugin's actual directory page. Moved the full version history to a new changelog.txt file (standard practice for plugins with a long history) and trimmed readme.txt's own Changelog section to recent releases, with a pointer to changelog.txt for the rest.
* The About page's changelog now reads from changelog.txt instead of readme.txt, so it keeps showing the complete history in the admin UI even though the readme.txt copy is intentionally shortened.

= 0.14.2 =
* Fixed the root cause behind ~400 Plugin Check errors: the "Text Domain" header and every translation function call still used "table-builder-pro", but WordPress.org assigned the slug "orki-table-builder-pro" — text domain must match that exactly. Replaced throughout every PHP and JS file (verified against the block's own registered name, which is a different string and was correctly left untouched).
* Fixed 5 real output-escaping gaps in the frontend table renderer (explicit int-casts on width/height values, and documented why two calls intentionally output raw HTML rather than double-escaping it and breaking image/link/Advanced Cell rendering).
* Added missing translator comments on every translatable string with a placeholder.
* Corrected several of my own phpcs:ignore comments that referenced the wrong sniff code name (file_system_read_* instead of the actual file_system_operations_*), meaning they weren't suppressing anything before.
* Rewrote the Preview and PDF-export standalone pages to enqueue their stylesheet/script through wp_enqueue_style()/wp_enqueue_script() instead of hard-coded tags.
* The ZIP download in bulk export now reads the finished file via WP_Filesystem where possible, with a direct fallback if that can't initialize (relevant since this runs inside a file-download response, where a credentials prompt has no way to surface).
* Reviewed every remaining nonce/sanitization warning individually rather than blanket-suppressing: most were genuine false positives (a nonce verified earlier in the same function, custom sanitizing helpers or realpath()-based path validation the scanner doesn't recognize by name, or WordPress-core hooks like edited_{taxonomy} that only fire after core's own nonce check) — each now has a comment explaining specifically why, scoped as narrowly as possible.
* Tested up to: 7.1, reflecting WordPress's actual current release. As before: this states what the code should be compatible with based on using only standard, non-deprecated APIs — I still can't run this plugin on a live install myself, so treat this as a starting point for your own testing, not a substitute for it.

= 0.14.1 =
* Fixed a WordPress.org plugin-check rejection: Plugin URI and Author URI were both set to https://orki.in, and those two headers are required to be different (they describe two different things — a page about the plugin itself vs. a page about its author). Removed the Author URI line per instruction to drop it; Plugin URI stays as-is, and "Author: Orki" now shows as plain text rather than a link. Nothing else in the plugin reads that header field, so this is a self-contained fix.

= 0.14.0 =
* Renamed the plugin to Orki Table Builder Pro throughout — plugin header, admin menu, block title/label, block-inserter hint, and every user-facing string that named the plugin. Internal identifiers (function/class names, the text domain, the block's own registered name) were deliberately left unchanged, since renaming those is a much bigger, riskier undertaking than a display-name change and nothing asked for it.
* Author, Author URI, and Plugin URI now point to Orki / https://orki.in — these control the "By Orki" and "Visit plugin site" links WordPress shows on the Plugins page.
* Added a credit line to the admin footer, after WordPress's own "Thank you for creating with WordPress." text, on every screen that belongs to this plugin (table list/edit, Add New/Import/Export/About, Table Category) — not shown on unrelated wp-admin screens.
* Built out the About page with the plugin's real information — version/requirements table, description, installation, FAQ, and full changelog — pulled directly from this readme.txt rather than duplicated by hand, so the two can't drift out of sync.
* Corrected two outdated claims while updating this file, per instruction to fix wording as needed: the feature list previously mentioned formulas (removed in 0.3.1) and said CSV import wasn't available (it's been fully built since 0.11.0) — both now reflect what's actually in this version.

= 0.13.0 =
* Implemented the Export page, matching the reference UI: multi-select table list (with Select all / Reverse list), Export Format, CSV Delimiter, and a ZIP option — selecting more than one table automatically bundles the exports into one ZIP.
* Text adjusted from the reference to describe what this plugin actually exports: CSV and XLSX carry the table's text content only (no formatting/images/links/settings), and PDF is called out as a one-table-at-a-time, print-view-based export rather than claiming it fits into a bulk/ZIP export the way it doesn't.
* Built by extracting the existing, working single-table CSV/XLSX export logic into shared functions that return raw bytes, then having both the original single-table export and the new bulk/ZIP export call them — verified the single-table export path produces identical output to before, byte for byte.

= 0.12.0 =
* New: PDF export — a print-optimized view of the table; use your browser's Print dialog and choose "Save as PDF" as the destination. Implemented this way deliberately: a from-scratch binary PDF generator would be substantial, hard-to-verify code, where a bug could mean broken exports with no easy way for me to catch it in advance. This approach relies entirely on well-established, universal browser functionality instead. Added alongside CSV/XLSX as a table row action and in the new sidebar Export box.
* New: two sidebar boxes on each table's edit screen, positioned right after Table Category — Import (append or replace this table's data from a CSV file) and Export (CSV/XLSX/PDF buttons for this specific table).
* The sidebar Import box reuses the same import logic as the centralized Import page (0.11.0) rather than a separate code path — Append and Replace both go through the same tested handler.

= 0.11.0 =
* Implemented the Import page, matching the reference UI: Import Source (File Upload / URL / File on server / Manual Input) and Add/Replace/Append with a table picker, all working — not a placeholder anymore.
* CSV is fully supported across all four sources. XLSX, ODS, HTML, and JSON are not — the page says so plainly rather than claiming support that isn't built and tested. Building a correct XLSX/ODS parser is substantial, separate work.
* Built by extracting the CSV-parsing logic from the existing, working per-table CSV import into a shared function — the per-table import's own behavior (nonce, validation, response) is completely unchanged, it just now calls the shared parser instead of an inline copy of the same code.
* "File on server" is restricted to paths inside the WordPress installation, to prevent reading arbitrary files via the path field.
* "Add as new table" creates the table and takes you straight to its editor; "Replace" and "Append" do the same for the target table you picked.

= 0.10.2 =
* Removed an entire layer of custom serialization from the database side, rather than proposing another theory about the same layer: table data and settings are now stored as native PHP arrays via update_post_meta() — WordPress's own standard mechanism for structured postmeta, used throughout WordPress core — instead of being pre-encoded to a JSON string by this plugin first. There is no wp_json_encode() call left anywhere in the save path for table data. This is on top of, not instead of, the base64 transport fix from 0.10.1 — that fix hardens how data gets from the browser to the server; this one hardens how it's stored once it arrives. Applied consistently everywhere table data is written: normal saves, CSV import, and new-table creation. Reading is backward-compatible — tables saved before this version (stored as a JSON string) are still detected and decoded correctly.
* If you're still seeing this after updating: please do a hard refresh of the table's edit screen (not just re-clicking Update in an already-open tab) and check the Save Diagnostics box's "Base64-safe transport used" line specifically — if it shows the older-browser-tab warning, the fix hasn't been exercised yet and reloading the page is the next step before anything else.

= 0.10.1 =
* Found the mechanism behind the "<br>n" corruption, and it explains the whole-table data loss too: the table's data was submitted to the server as raw JSON in a form field. WordPress automatically runs addslashes()-style processing on all submitted form data, and our own save code correctly reverses that once with wp_unslash() — but if that slash-processing ends up applied twice anywhere in the request lifecycle (I can't point to the exact second call with full certainty), a JSON-escaped newline (the two characters backslash+n, used to represent a line break inside stored text) loses its backslash on the second pass, leaving a stray literal "n" behind — reproduced exactly in a direct simulation: "Line 1<br>\nLine 2" becomes "Line 1<br>nLine 2", character for character matching what was reported. HTML/multi-line content hits this because it's specifically the kind of content likely to contain backslash-requiring sequences; plain single-line text mostly doesn't, which is why it was saving correctly.
* Fix: the table's data is now transmitted as base64 when saving (previously only done for loading, in 0.9.4) — the same fix applied to the other half of the round trip. Base64 text is built only from letters, numbers, +, /, and = — it structurally cannot contain a backslash, quote, or null byte, so addslashes()/stripslashes() cannot alter it no matter how many times that processing runs. This isn't a workaround for one call site; it removes the entire mechanism the corruption depends on.
* The Save Diagnostics box now shows whether the base64-safe path was used for each save attempt, so this stays verifiable rather than another unconfirmed claim. Falls back gracefully to the previous raw-JSON handling for any browser tab still running the old JS from before this update (reload the page to pick up the fix).

= 0.10.0 =
* Implemented the Advanced Cell (Special Cell) architecture: cells are now clearly one of two kinds.
   * Standard Cell: plain text only, exactly as before — HTML tags typed or pasted into it are always shown and stored as literal text, never rendered. No auto-detection anymore; a cell only ever becomes an Advanced Cell through an explicit action.
   * Advanced Cell: created by Insert Image, Insert Link, or saving from the Advanced Editor. Shown in the grid as an "HTML" badge with a short plain-text preview — never rendered, never directly text-editable. Clicking or double-clicking it reopens the Advanced Editor loaded with its exact saved content; Save updates that same cell, Cancel discards changes. Pasting into the grid never overwrites an Advanced Cell's content.
* This removes the inline contenteditable-HTML-source editing path entirely, along with the blur/paste HTML auto-detection that came with it — that combination was the most likely source of the update issues reported over the last several rounds, since it added extra render cycles specifically tied to HTML content. This is a genuine architecture change, not confirmed to be the root cause of the save bug — the Save Diagnostics box (0.9.6/0.9.7) and its "Error caught during save" reporting are still in place as a safety net and diagnostic tool regardless.

= 0.9.7 =
* Narrowed down further based on your report that plain text saves work but Insert Image/Insert Link/Advanced Editor don't: the save routine's data-processing step is now wrapped so that any fatal-class PHP error during it (e.g. an unexpected failure inside wp_kses() while processing HTML cell content) is caught, logged with its exact message and location, and — critically — can no longer corrupt the save or silently wipe existing data. The Save Diagnostics box will now show that exact error message if this is what's happening.
* Ruled out (confirmed safe, not the cause): the UTF-8 stripping and button-name sanitization added in 0.9.5/0.9.6 run unconditionally on every cell regardless of content type, so they cannot explain a difference between plain-text and HTML-cell saves specifically — re-reviewed sanitize_data()'s row/cell loop structure directly and found no logic that skips or drops rows based on cell type.

= 0.9.6 =
* Since the previous two fix attempts (0.9.4, 0.9.5) did not resolve the reported data-loss-on-Update issue, this release adds real diagnostics instead of another unverified guess:
   * New "Save Diagnostics" box on each table's edit screen, showing exactly what happened on each of your last 10 save attempts — whether data was submitted, how many bytes, whether it decoded, how many rows were received vs. after sanitizing, whether re-encoding succeeded, and whether anything was actually written to the database.
   * New "Restore Previous Version" button (appears whenever a backup exists) — swaps your current and backup data, so a bad save can be undone immediately without waiting on a further fix.
* No new theory about the root cause is being claimed here. The goal of this release is to get hard evidence of what's actually happening on your site, since static code review alone has not been sufficient to find it.

= 0.9.5 =
* ACTUAL ROOT CAUSE FOUND AND FIXED — data reverting to demo content on Update: the previous fix (0.9.4) addressed a real risk in how data was transported to the browser, but wasn't the trigger you were hitting. The real cause: when saving, the table's data is re-encoded to JSON with wp_json_encode() before being stored. PHP's JSON encoder silently returns `false` — not an error, not a warning — when the data contains invalid UTF-8 byte sequences. That's exactly what shows up in HTML pasted from Word, Outlook, and some websites (curly quotes, em-dashes, and accented characters are often encoded as Windows-1252, not UTF-8) — precisely the workflow Insert Image, Insert Link, and Advanced Editor encourage. That `false` was being saved directly as the table's data; reloading it came back empty, which correctly (if unhelpfully) fell back to the blank demo table. Three fixes, together:
   1. Invalid UTF-8 byte sequences are now stripped from cell content before any further processing — this prevents the encoding failure from happening at all.
   2. The save routine now explicitly checks that the re-encode succeeded before writing anything — if it were ever to fail again for some other reason, your existing table data is left completely untouched instead of being overwritten.
   3. Added an automatic one-generation backup of your table's data on every successful save, and the table loader now recovers from that backup as a last resort if the main data is ever found empty — so even an unknown future issue would surface as "your last save's content, minus one edit" rather than losing everything.
* If you already lost data to this bug before updating: unfortunately, the backup safety net was only just added — it can't recover something lost before this version. Going forward, this class of failure should no longer occur, and if it somehow does, the backup will limit the damage.

= 0.9.4 =
* CRITICAL FIX — data loss on update: the table's data was being embedded on the page as JSON inside an HTML attribute. Rich HTML content (from Insert Image/Insert Link/Advanced Editor — full of quotes and special characters) could break that encoding, causing the editor to silently fall back to a blank table; clicking Update would then save that blank state over the real data. Fixed by switching to base64 encoding for this transport (eliminates the entire class of attribute-escaping bugs) and, as a second layer of protection, the editor now halts completely with a clear on-screen warning if its data ever fails to load — it will never silently proceed with an empty table that could then be saved over real content. Verified with a round-trip test using HTML, quotes, curly quotes, and accented characters.
* Also removed a raw form.submit() fallback in the "Update Table" button that bypassed WordPress's own save handling; it was a real risk factor even if not the primary cause. If the native Update button can't be found, you now get a clear message instead.
* Fixed: cells with HTML content (from Insert Image, Insert Link, or the Advanced Editor) were being rendered live in the backend editor — an actual image, an actual clickable link — instead of showing the raw HTML, making them impossible to edit directly. The editor now always shows the raw HTML source as plain, directly-editable text (double-click, Enter/F2, or just start typing, same as any other cell). The Advanced Editor modal still works the same way as before for a richer editing experience; both now read and write the exact same stored content, so there's one source of truth.

= 0.9.3 =
* Replaced the old inline "Edit HTML" panel with a proper Advanced Editor modal: select a cell, click Advanced Editor, and get a popup with Add Media, quicktag buttons (b/i/link/del/ins/img/code/close tags), a large textarea loaded with the cell's current content, and Cancel/Save — Save updates only that cell, Cancel discards changes.
* New: Insert Image toolbar button — select a cell, pick an image from the Media Library, and it's inserted as a real `<img>` tag with width/height filled in, fully editable afterward (via the cell directly or the Advanced Editor).
* New: Insert Link toolbar button — opens a modal to enter a URL and link text, or upload/select a file from the Media Library, with an "open in new tab" option; inserts a real `<a>` tag, fully editable afterward.
* New: a "Settings" link now appears on the Plugins page for this plugin, before Deactivate, pointing to All Tables.
* Cleaned up now-dead code and styles left over from the old Edit HTML panel.
* Still not done: the full Import tab overhaul (multiple file formats, Add/Replace/Append with a table picker, matching the reference UI) — this is a substantial piece on its own and needs its own focused round. The existing per-table CSV import (from each table's edit screen) is unaffected and still works.

= 0.9.2 =
* Fixed: Table Name Bold had no visible effect. Cause: h3 elements are bold by default in virtually every theme, so checking the box only re-applied the same default weight — it needed to explicitly set "normal" when unchecked to actually toggle anything.
* Fixed: right-click context menu wasn't appearing. Cause: the cell's mousedown handler ran for every mouse button, including right-click, and its preventDefault() was interfering with the browser's own right-click sequence before "contextmenu" could fire cleanly.
* New: typing or pasting HTML directly into a standard cell now works without opening the separate Edit HTML panel first — if what you type or paste looks like real markup (starts with a tag), it's rendered as HTML automatically. Plain text (including things like "5 < 10") is never affected. Multi-line HTML pasted into one cell (e.g. a `<strong>` line followed by a `<span>` line) is now kept as one HTML cell instead of being split into separate rows.
* Added width/height as allowed attributes on `<img>` tags in cell HTML (style="width:...;height:...;" already worked; now the plain HTML attributes do too).

= 0.9.1 =
* New: right-click context menus on cells, row headers, and column headers (insert, duplicate, merge/split, delete, move).
* New: column resize by dragging the right edge of a column header; row resize by dragging the bottom edge of a row header. Applies on both the editor and the live site.
* New: true drag-and-drop row and column reordering — drag a row/column header and drop it where you want it (Move Up/Down/Left/Right buttons still work too).
* Changed: Link Column's "Display as OPEN button" checkbox replaced with a Button Name field — leave it empty for a plain file-name link, or type a label (e.g. "Download PDF") to show a button with that exact text instead. Tables saved before this change keep showing their OPEN button automatically.
* Fixed: Width/Height inputs on Image Column cells were too small to use comfortably; widened along with the new Button Name field.

= 0.9.0 =
* New: Bold/Italic/Underline for the Table Name, independently combinable with the existing font/size/color/alignment options.
* New: Image Column — a toolbar button inserts a column where every cell gets an "Upload Image" button (WordPress Media Library), plus W/H (px) fields. On the frontend, images render at exactly the size you set, or scale responsively if left blank so they never break the layout. Multiple Image Columns are supported.
* New: Link Column — same pattern for any file type, with a checkbox to display either the file name as a link or an "OPEN" button. Multiple Link Columns are supported.
* Both new column types insert to the right of the selected column (or the last column if none is selected), and behave like ordinary columns for move/delete/duplicate/save/load — nothing about existing row/column management needed to change for them to work.
* Clarifying, not new: HTML content inside a standard cell is already supported via the existing "Edit HTML" toolbar button — paste or type your HTML there (img, a, strong/b, em/i, u, br, span with style, ul/ol/li are all already allowed, everything else is stripped) and it renders on the frontend exactly as entered.
* Still deferred: row/column resize by mouse drag, true drag-and-drop row/column reordering, right-click context menus.

= 0.8.0 =
* New: real Conditional Formatting — rules (column + greater than/less than/equals/contains + fill/font color) editable from the toolbar panel, applied live in the editor and on the frontend. Replaces the earlier "coming soon" placeholder.
* New: real backend Filter — pick a column and a value to show only matching rows while editing a large table; a workspace aid only, nothing about it is saved with the table.
* New: Preview Table button inside the Publish box — opens the table's live rendered output in a new tab before you paste its shortcode anywhere.
* Still deferred: row/column resize by mouse drag, true drag-and-drop row/column reordering (Move Up/Down/Left/Right already cover reordering), right-click context menus, live/recalculating formulas, Google Sheets sync, multi-table export, and Import/Export/About tab functionality (pending your spec).

= 0.7.0 =
* Fixed the persistent cell-editing focus bug: clicking a different cell now properly ends editing on the previous one before the new cell becomes active. Root cause: preventDefault() on a cell's mousedown (added to stop native text-drag from fighting cell range-selection) was also silently blocking the browser's normal blur of the previously-focused cell, so it stayed editable and kept receiving keystrokes.
* New: the category list screen now has a Shortcode column with a Copy button for every category.
* New: Table Priority — on a category's edit screen, drag to reorder the tables assigned to it; that order is what the category shortcode uses on the frontend. Tables added later appear at the end until arranged; removed tables just drop out of the list.

= 0.6.1 =
* Fix: updating a table could fail with a "Value must be greater than or equal to 6" browser error on the Table Name font size field, even with "Table name on frontend" unchecked. Cause: an unset font size rendered as 0, which is below the field's own minimum of 6, so the browser blocked the whole form from submitting. The field now renders empty (with an "auto" placeholder) until a size is actually chosen.
* The Table Name formatting fields now visually dim when "Table name on frontend" is unchecked, without disabling them — so nothing is silently lost from a saved font/size/color choice if the box gets unchecked temporarily.
* Fix: the Table Category Shortcode now has its own always-visible section in Table Info, showing the real shortcode(s) for whatever category is assigned, or a short note on how to get one if none is assigned yet — previously this only appeared once a category had already been assigned, so it was easy to miss entirely.

= 0.6.0 =
* New: Table Category taxonomy (Categories → checkbox-style assignment on each table's edit screen, standard WordPress term management screen).
* New: category shortcode `[tbp_category id="X"]` — shows every published table in that category on one page, no need to paste each table's shortcode individually.
* New: tab navigation across All Tables / Add New / Table Category / Import / Export / About.
* New: custom "Add New Table" screen — set Table Name, Table Category, Description, Number of Rows, and Number of Columns up front; rows/columns can still be freely added or removed afterward in the editor.
* New: Import and Export and About tabs are in place as placeholders (their actual functionality is still to be defined).
* New: shortcode fields (table and category) now show with a Copy button instead of plain text.
* Not done yet, deferred: drag-and-drop row/column reordering (the existing Move Up/Down/Left/Right buttons already cover reordering; true drag gestures are a separate, riskier piece of work), row/column resize by mouse drag, a live Preview button, and a real (stored/re-evaluated) Conditional Formatting engine. Font family/size and text alignment controls already exist in the toolbar from earlier updates.

= 0.5.1 =
* Import CSV temporarily disabled (the underlying code is untouched, just not registered — trivial to bring back).
* Reverted the full-width edit-screen layout change from 0.5.0: the Publish box stays on the right in its normal position again.

= 0.5.0 =
* Real Merge: now works on a selected cell range (spans both rows and columns), a whole selected row (or several), or a whole selected column (or several) — not just "merge with the cell to the right." Split undoes both directions.
* New: Table Title formatting — font family, color, size, and alignment (only applies when "Table name on frontend" is on).
* Fixed: Clear All now clears every cell's content across the whole table immediately, with no selection required first; row/column structure and formatting are left alone, and nothing gets auto-selected afterward.
* Removed the Border toggle from the toolbar.
* "Table Data" and the other edit-screen sections now use the full page width; "How to Add This Table" moved from the sidebar to above "Table Data".
* Known limitation: merging is most reliable on a table that doesn't already have other merges in the same rows/columns — stacking a new merge directly on top of a complex existing one is an edge case that may not align perfectly.

= 0.4.2 =
* Spreadsheet-style typing: select a cell and just start typing — no double-click needed. Double-click, Enter, or F2 still edit in place (cursor at the end, content kept) when you want to edit rather than replace.
* Fixed: cell editing now updates the clicked cell directly instead of rebuilding the whole toolbar/grid and refocusing afterward — this was the likely cause of paste not working reliably while editing.
* Insert menu now inserts as many rows/columns as you have selected, not always just one.
* Fill Colour and Font Colour buttons now say "Fill Colour" / "Font Colour" instead of both showing "Select Color".
* Alternate-row background and font color now take priority over default and per-cell Fill/Font colors, as intended — implemented as a CSS override, so nothing about your actual cell colors is changed or lost if you turn alternate rows off again.
* Removed icons from Undo/Redo (text only) and removed the Wrap Text button.

= 0.4.1 =
* Fix: pasting into a selected (but not actively-edited) cell showed "Click a cell, row, or column heading first." instead of pasting. Cause: 0.4.0 split "selected" from "editing," but the real paste handler was only attached to cells in edit mode. Selecting a cell no longer enters edit mode by itself, so Ctrl+V had nothing to attach to. Fixed with a hidden focus target that catches real paste (and copy/cut) events whenever something is selected, so paste works immediately after a single click — no need to double-click into edit mode first. A single copied value now also fills every cell in a multi-cell selection, matching typical spreadsheet behavior.

= 0.4.0 =
* Real multi-select: drag across cells, Shift/Ctrl+click for cells, rows, and columns, plus arrow-key navigation (Shift+Arrow extends). Single click now selects a cell; double-click or Enter starts typing in it.
* Cut/Copy/Paste and Undo/Redo now work via keyboard shortcuts (Ctrl/Cmd+C/X/V/Z/Y).
* Fill and font color now use the smooth WordPress color picker (drag to pick) instead of the plain browser color dialog.
* Font family selector restored (defaults to your theme's font unless you pick one).
* Find & Replace is a menu now: a live "Find" that highlights matches as you type, a separate "Replace All", and Close.
* New: alternate-row font color, and optional row hover background/font color (off by default — no hover effect unless you set one).
* Fixed: the frozen first column could be visually overlapped while scrolling; it now has a proper z-index and an opaque background.
* Added an Update button at the bottom of the editor, next to the row/column panel.
* Multiple rows or columns can now be deleted at once when several are selected.

= 0.3.1 =
* Fix: CSV import no longer breaks the main Update button. It was rendering a second <form> inside WordPress's post-edit form (invalid HTML — nested forms get merged by the browser), which was hijacking the Update button's submission. Import now runs over AJAX instead.
* Toolbar: replaced Cut/Copy/Paste with Undo/Redo (with real history, plus Ctrl/Cmd+Z and Ctrl/Cmd+Y).
* Toolbar: Border, Fill, and Font buttons now show their labels, not just icons; alignment buttons now read Left/Center/Right; Wrap Text/Merge/Split show text only (icons removed).
* Toolbar: Insert is now a dropdown menu (add row above/below, add column left/right).
* Removed the Formulas toolbar section (may return in a later phase).
* Font size is now a free-entry field instead of a fixed list; removed the font-family override so cells follow your site's theme font.

= 0.3.0 =
* Major editor rewrite: Excel-style column/row headers, whole-row/column selection, redesigned toolbar (top + bottom) with cell-level formatting, separate row/column action panel, paste-as-plain-text from external sources, basic one-time formulas, sort by column, find & replace, table meta bar (ID/description/shortcode/last modified), show/hide table name, contained table scrolling with sticky header.
* Formatting is now applied at the cell level (via the toolbar) rather than as rich text typed inline, which is what makes style-free pasting from other sources possible.
* Removed the table width % setting.
* Not yet included: true multi-cell drag/keyboard selection, right-click context menus, live/recalculating formulas, real conditional formatting, rectangular (multi-row) merge, admin area tabs, categories, multi-table export.

= 0.2.0 =
* Add: CSV import (own form, separate from the main editor screen).
* Add: real .xlsx export alongside CSV export.
* Fix: adding/deleting/duplicating a column now accounts for merged cells correctly, instead of shifting by raw array position.

= 0.1.1 =
* Fix: color settings no longer store an invalid/null value (avoids a PHP 8.1+ notice under WP_DEBUG).

= 0.1.0 =
* Initial development version.

