=== BlockGlow — Per-block Custom CSS ===
Contributors: eltresse93
Tags: blocks, custom-css, css, gutenberg, editor
Requires at least: 5.8
Tested up to: 6.8
Stable tag: 1.2.0
Requires PHP: 8.2
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Adds a "Custom CSS" inspector panel to every Gutenberg block and saves per-block CSS files to uploads for front-end enqueuing.

== Description ==
BlockGlow adds a "BlockGlow — Custom CSS" panel to the inspector of every block. Use it to scope custom CSS to a single block instance. The plugin stores CSS in the uploads folder (under uploads/blockglow/) and enqueues the generated CSS file when rendering on the front end. If the uploads directory isn't writable or file write fails, BlockGlow will fall back to outputting inline styles.

Key features:

* Adds two block attributes to every block: `blockglowCustomCSS` and `blockglowId`.
* Inspector panel with a CodeMirror-backed code editor (if WordPress provides it) or a fallback textarea supporting Tab and Shift+Tab outdent.
* Live preview inside the block editor: custom CSS is scoped to the block in the editor so you can see the effect while editing.
* CSS files are saved to `wp-content/uploads/blockglow/blockglow-<id>.css` and enqueued on the front end as a linked stylesheet; files are removed automatically when you clear the Custom CSS field.
* Graceful fallback to inline styles when file writing isn't possible.

How scoping works:

BlockGlow creates a unique `blockglowId` for each block instance and scopes your CSS with a wrapper selector like:

    [data-blockglow-id="bg-xxxxxxx"] { /* your declarations */ }

For convenience you can use `&` as the wrapper shorthand in the editor. Example:

    & .my-class { color: red; }

The plugin will replace `&` with the wrapper selector for both editor preview and front-end output.

== Installation ==

1. Upload the `blockglow` folder to the `/wp-content/plugins/` directory.
2. Activate the plugin through the 'Plugins' menu in WordPress.
3. Ensure the uploads folder is writable by WordPress so BlockGlow can create `wp-content/uploads/blockglow/` and write CSS files. If uploads aren't writable, the plugin will still work but will output inline styles instead of linked CSS files.

== Frequently Asked Questions ==

= Where are the CSS files stored? =
Files are stored in `wp-content/uploads/blockglow/` and are named like `blockglow-<id>.css`.

= Will the CSS affect other blocks or pages? =
No — BlockGlow scopes the CSS to the block instance using a data attribute. If you write global selectors inside the editor (for example `body { ... }`), those will still be global — be careful.

= How do I delete generated CSS files? =
If you clear the Custom CSS field in the block inspector and update the post/page, the plugin will attempt to delete the corresponding CSS file automatically.

= What if the Code Editor (CodeMirror) doesn't appear? =
Some WordPress setups don't expose the `wp.components.CodeEditor` component. In that case BlockGlow falls back to a textarea with Tab/Shift+Tab support.

= Is there any capability check? =
At present BlockGlow does not add extra capability checks beyond the normal block editing capabilities. If you need a role-based restriction, consider adding custom checks or ask for an enhancement.

= Is this safe for production? =
BlockGlow only writes CSS files and outputs styles. It's recommended to review custom CSS and limit who can edit posts/pages. This plugin does not sanitize arbitrary CSS; it persists whatever CSS you enter. Restrict editor access as needed.

== Screenshots ==

1. Inspector panel showing the CodeEditor or fallback textarea.
2. Live editor preview demonstrating scoped styles.
3. Example front-end output with linked per-block stylesheet.

== Changelog ==
= 1.2.0 =
* Performance: Added a new Performance Optimization tab in the admin dashboard.
* Performance: Added support for preloading the LCP image and applying `fetchpriority="high"` to improve Largest Contentful Paint (LCP) performance and page loading speed.

= 1.1.6 =
* Update: Create new blockglowId when a block is duplicated or copied.
* Update: Added pagination and multiple select to delete CSS files in Block Glow page in backend.  

= 1.1.5 =
* Admin: Fixed the nonce issue.

= 1.1.4 =
* Admin: Removed the CSS filename when creating the delete nonce.

= 1.1.3 =
* Fixed: Reordered logic in `BlockGlow_Admin::handle_delete_file()` so nonce validation runs before processing user input.
* Fixed: Addressed security scanner warning for missing nonce checks on `$_POST['file']` and `$_GET['file']`.
* Improved: Raw file input is now only read after successful nonce verification and capability checks.

= 1.1.2 =
* Security: Added stricter nonce validation and capability checks for file deletion handlers; accept both generic and per-file nonces for compatibility.
* Security: Improved inline CSS handling for untrusted users — HTML tags are stripped before inlining to reduce the risk of injecting HTML into a style context.
* Admin: Removed PHPCS suppression and standardized sanitization of request inputs; cleaned up admin enqueue logic to prefer built assets when available.

= 1.1.1 =
* Security: Tightened admin navigation and delete handlers — added nonce verification and input validation for admin page/tab navigation and file deletion.
* Admin: Removed Import/Export submenu and tab from the admin UI in this build to simplify the UI surface.
* Code Quality: Fixed PHPCS i18n warnings and added translator context where needed.

= 1.1.0 =
* Minor: Improved editor reliability and added an option to toggle in-editor rendering of custom CSS. This release is backwards-compatible; no data migration is required.

= 1.0.5 =
* Editor: improved attribute attachment in the block editor so `data-blockglow-id` is applied to the actual editor block element when possible (closest-node, clientId selector and MutationObserver fallback).
* Editor: added a clientId-based selector fallback so editor-scoped CSS applies even when a DOM attribute cannot be attached.
* Editor: added a ToggleControl to optionally enable/disable rendering custom CSS inside the editor preview (default: off).
* Editor: displays the "Generated CSS file" path under the CodeEditor/textarea in the inspector so you can quickly open or verify the created CSS file.

= 1.0.4 =
* Security: Sanitized input handling for $_POST['file'] and $_GET['file'] using sanitize_file_name() and wp_unslash().
* Security: Added nonce sanitization and validation for $_POST['_wpnonce'] and $_GET['_wpnonce'] using sanitize_text_field() and wp_verify_nonce().
* Code Quality: Resolved PHPCS warnings related to WordPress.Security.ValidatedSanitizedInput.InputNotSanitized.

= 1.0.3 =
* Security: replace use of `$_REQUEST` with explicit `$_POST`/`$_GET` handling and `wp_unslash()` for admin delete actions; improve input normalization and handling.

= 1.0.2 =
* Security: perform nonce verification (`check_admin_referer()`) and capability checks early for admin delete actions; normalize and sanitize request inputs.
* Output safety: apply "escape late" handling for inline CSS — raw CSS is allowed only for users with `unfiltered_html`; other users will have CSS escaped at output time to avoid XSS.
* Editor: improved dark fallback textarea styling (border-radius:0; background:#000; color:#fff; font-size:13px; padding:10px) and token color rules for editor where available.
* Misc: several bugfixes and code hygiene improvements addressing WordPress.org review feedback.

= 1.0.1 =
* Improved front-end output: removed automatic wrapper DIVs and now inject a `data-blockglow-id` attribute into the block's root element so global and theme styles are easier to author.
* Switched all inline stylesheet output to use `wp_register_style()` + `wp_add_inline_style()` and `wp_enqueue_style()` instead of echoing `<style>` tags directly.
* Added stronger admin-side security: nonce verification for delete actions via `check_admin_referer()` and capability checks for file management.
* Misc: improved input sanitization and removed unsafe direct superglobal usage in admin handlers.

== Upgrade Notice ==

= 1.0.0 =
First release.

== Arbitrary section ==

Development notes:

* Editor script: `assets/js/blockglow-editor.js` — registers attributes, provides the inspector panel and injects editor-scoped styles.
* Main plugin file: `blockglow.php` — enqueues editor assets and filters `render_block` to attach per-block CSS files or inline styles.
* Upload path: `wp_upload_dir()` + `/blockglow/`.
* File writes/deletes: BlockGlow uses the WordPress Filesystem API (WP_Filesystem) when available for compatibility with hosts using FTP/SFTP; when unavailable it will attempt direct writes. Editing capability is required (edit_posts) or operations performed via REST save.
* Per-post bundling: BlockGlow now generates a single stylesheet per post (`blockglow-post-<ID>.css`) on post save which contains the combined CSS from all blocks in that post. This reduces HTTP requests and improves performance.
* Admin UI: A new submenu under Tools → "BlockGlow CSS" lists generated files and allows administrators (capability is filterable) to delete them.
* Capability: File generation/deletion is restricted by a filterable capability `blockglow_manage_files_cap` (default `manage_options`). You can change this capability via the filter if you want other roles to manage files.
* If you'd like help preparing the plugin for WordPress.org (example `readme.txt` adjustments, SVN packaging, or adding screenshots), ping me and I can prepare the required assets and instructions.

== Source Code ==

The plugin includes built/minified assets under `assets/dist/` for distribution. The human-readable source for JavaScript is included in the plugin under `assets/js/` (e.g. `assets/js/blockglow-editor.js` and `assets/js/blockglow-admin.js`). The plugin also contains a `package.json` and `vite.config.js` in the plugin root describing how to rebuild these assets locally using `npm install` and `npm run build` or `npm run watch`.

If you need the sources to be hosted externally, provide a URL and I will add it here (for example an upstream GitHub repository).

== Installation Notes for WordPress.org ==

To publish on WordPress.org you will need:

* A fully-formed `readme.txt` (this file) using the plugin directory readme format.
* Screenshots (1.png, 2.png, etc.) placed in the assets/ directory when committing to SVN, or uploaded via the plugin admin UI after publishing.
* A stable tag or commit to `trunk/` in SVN. Typical workflow:
  1. Create a new plugin slug on https://wordpress.org/plugins/ and follow the email to get SVN access.
  2. Check out the plugin SVN repository, add your plugin files into `trunk/`, put screenshots into `assets/`, and tag a version.
  3. Commit and wait for the plugin page to become live.

== Support ==

If you find issues or want improvements (for example: limiting who can edit per-block CSS, collecting styles into a single head include, or adding an admin UI to manage generated CSS files), open an issue in the repository or reply here and I will assist.
