Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .distignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ vendor/*

# AI guidance and dev docs
.claude/*
.vibe/*
AGENTS.md
CLAUDE.md
README.md
Expand Down
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
.gitignore export-ignore
.distignore export-ignore
.claude export-ignore
.vibe export-ignore
.DS_Store export-ignore
.vscode export-ignore
.idea export-ignore
Expand Down
186 changes: 186 additions & 0 deletions .vibe/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
active_model = "mistral-medium-3.5"
vim_keybindings = false
disable_welcome_banner_animation = false
displayed_workdir = ""
auto_compact_threshold = 200000
context_warnings = false
textual_theme = "catppuccin-mocha"
instructions = ""
system_prompt_id = "vibe"
include_commit_signature = true
include_model_info = true
include_project_context = true
include_prompt_detail = true
enable_update_checks = true
api_timeout = 720.0
tool_paths = []
mcp_servers = []
enabled_tools = []
disabled_tools = []

[[providers]]
name = "mistral"
api_base = "https://api.mistral.ai/v1"
api_key_env_var = "MISTRAL_API_KEY"
api_style = "openai"
backend = "mistral"

[[providers]]
name = "llamacpp"
api_base = "http://127.0.0.1:8080/v1"
api_key_env_var = ""
api_style = "openai"
backend = "generic"

[[models]]
name = "mistral-vibe-cli-latest"
provider = "mistral"
alias = "mistral-medium-3.5"
temperature = 1.0
input_price = 1.5
output_price = 7.5
thinking = "high"

[[models]]
name = "devstral-small-latest"
provider = "mistral"
alias = "devstral-small"
temperature = 0.2
input_price = 0.1
output_price = 0.3

[[models]]
name = "devstral"
provider = "llamacpp"
alias = "local"
temperature = 0.2
input_price = 0.0
output_price = 0.0

[project_context]
max_chars = 40000
default_commit_count = 5
max_doc_bytes = 32768
truncation_buffer = 1000
max_depth = 3
max_files = 1000
max_dirs_per_level = 20
timeout_seconds = 2.0

[session_logging]
save_dir = "/Users/jasperfrumau/.vibe/logs/session"
session_prefix = "session"
enabled = true

[tools.search_replace]
permission = "ask"
allowlist = []
denylist = []
max_content_size = 100000
create_backup = false
fuzzy_threshold = 0.9

[tools.bash]
permission = "ask"
allowlist = [
"cat",
"echo",
"file",
"find",
"git diff",
"git log",
"git status",
"head",
"ls",
"pwd",
"stat",
"tail",
"tree",
"uname",
"wc",
"which",
"whoami",
]
denylist = [
"gdb",
"pdb",
"passwd",
"nano",
"vim",
"vi",
"emacs",
"bash -i",
"sh -i",
"zsh -i",
"fish -i",
"dash -i",
"screen",
"tmux",
]
max_output_bytes = 16000
default_timeout = 30
denylist_standalone = [
"ipython",
"bash",
"sh",
"nohup",
"vi",
"vim",
"emacs",
"nano",
"su",
]

[tools.grep]
permission = "always"
allowlist = []
denylist = []
max_output_bytes = 64000
default_max_matches = 100
default_timeout = 60
exclude_patterns = [
".venv/",
"venv/",
".env/",
"env/",
"node_modules/",
".git/",
"__pycache__/",
".pytest_cache/",
".mypy_cache/",
".tox/",
".nox/",
".coverage/",
"htmlcov/",
"dist/",
"build/",
".idea/",
".vscode/",
"*.egg-info",
"*.pyc",
"*.pyo",
"*.pyd",
".DS_Store",
"Thumbs.db",
]
codeignore_file = ".vibeignore"

[tools.read_file]
permission = "always"
allowlist = []
denylist = []
max_read_bytes = 64000
max_state_history = 10

[tools.todo]
permission = "always"
allowlist = []
denylist = []
max_todos = 100

[tools.write_file]
permission = "ask"
allowlist = []
denylist = []
max_write_bytes = 64000
create_parent_dirs = true
63 changes: 63 additions & 0 deletions .vibe/prompts/vibe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# Custom Instructions for Vibe

## Primary Directive
Always follow the rules and conventions in the project's `CLAUDE.md` file. This is your authoritative source for all project-specific guidance.

## Project Structure

**warder-cookie-consent** is a WordPress plugin wrapping the [vanilla-cookieconsent](https://github.com/orestbida/cookieconsent) v3 library.

Key files:
- `warder-cookie-consent.php` — all PHP logic (~851 lines), single-file plugin
- `src/index.js` — JS entry point, maps settings to vanilla-cookieconsent config
- `dist/cookieconsent.bundle.js` — compiled output (do not edit directly)
- `assets/js/warder-admin.js` — admin page JS (AJAX save, UI interactions)

## Before Responding
1. **Review CLAUDE.md** for:
- Architecture and data flow
- PHP function naming conventions (`warder_` prefix)
- Versioning rules (four files must be updated together)
- Build commands

2. **Check Current Context**:
- Confirm the current branch and git status
- Review recent commits for relevant changes

3. **Adhere to Key Principles**:
- All PHP functions use the `warder_` prefix; options stored under `warder_options` in `wp_options`
- Settings are deep-merged with defaults via `warder_get_merged_options()` — never read raw from DB
- JS is bundled via webpack: run `npx webpack` after editing `src/index.js`
- `.vibe/` directories are untracked and should remain so
- PHP requires 8.0+; no test suite exists

## Build Commands

```bash
npm install # Install JS dependencies
npx webpack # Build dist/cookieconsent.bundle.js
npx webpack --watch # Rebuild on file change
```

## Versioning (bump all four together)

- `warder-cookie-consent.php` — `Version:` header + `WARDER_VERSION` constant
- `readme.txt` — `Stable tag:` + changelog entry
- `CHANGELOG.md` — new version heading
- `package.json` — `version` field

Do **not** add a `version` field to `composer.json`.

## Git Commits

- Do not mention "Claude", "Claude Code", or AI tools in commit messages
- Do not include "Co-Authored-By: Mistral Vibe" or any AI attribution
- Use atomic commits; stage files individually or in logical groups with specific messages
- Follow standard conventional commit format (`feat:`, `fix:`, `docs:`, `refactor:`, etc.)

## Response Guidelines
- Be concise and technical
- Reference specific files and line numbers
- Use markdown formatting for code and structure
- Prioritize verification over assumptions
- When unsure, ask for clarification before acting
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

All notable changes to Warder Cookie Consent are documented here.

## [1.5.2] - 2026-05-28

### Added
- AJAX save for the settings page via `wp_ajax_warder_save_settings` (`warder_ajax_save_settings()`). Submit is intercepted in `assets/js/admin.js`, the form serializes through `$.post( ajaxurl, ... )`, and the response is shown in a dismissible `.warder-ajax-notice` injected before the form — no `options.php` redirect, no scroll-to-top
- Admin JS extracted from the inline `wp_add_inline_script()` heredoc into `assets/js/admin.js`, enqueued via `wp_enqueue_script( 'warder-admin' )` with `wp_localize_script` providing `warderAdmin.ajaxurl`, `warderAdmin.save`, and `warderAdmin.saving`
- `?warder_notice=saved` redirect-after-POST in `warder_handle_admin_actions()` so add/delete-category and add/delete-cookie actions show a success notice on the resulting page

### Fixed
- Setup welcome notice in `warder_admin_notices()` now self-suppresses once `warder_options_last_updated` is set, so it stops appearing on every admin page after configuration (WordPress.org guideline 11)
- Add Cookie form was nested inside `#warder-main-settings-form` and used the HTML5 `form="..."` attribute to target a hidden form elsewhere in the DOM. Browsers handle `display:none` target forms inconsistently, which dropped the `is_regex` checkbox state and caused the AJAX save handler to intercept Add Cookie submissions. Each Add Cookie form is now rendered as a self-contained `<form>` after `</form>` of the main settings form
- AJAX save notice is now scrolled into view via `$( 'html, body' ).animate( { scrollTop: $notice.offset().top - 50 }, 300 )` so it is visible regardless of the scroll position at submit time
- Show-add-cookie button scrolls the now-revealed container into view on open

### Changed
- Dropped the `:not([form])` filters on the change-highlight selector and submit-button lookup in `assets/js/admin.js`, and removed the JS `.after()` reposition of add-cookie containers. These were workarounds for the old nested-form layout and are no longer needed now that PHP renders the containers outside the main form

## [1.5.1] - 2026-05-28

### Fixed
Expand Down
48 changes: 30 additions & 18 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,31 @@ There are no tests. PHP requires 8.0+.

To install as a Composer dependency:
```bash
composer require imagewize/simple-cookie-consent
composer require imagewize/warder-cookie-consent
```

## Architecture

### Data Flow

```
WordPress DB (scc_options key)
scc_enqueue_scripts() fetches and localizes
WordPress DB (warder_options key)
warder_enqueue_scripts() fetches and localizes
→ window.sccSettings in browser
→ createConfigFromSettings() in src/index.js
→ CookieConsent.run(config)
```

### PHP Layer (`simple-cookie-consent.php`)
### PHP Layer (`warder-cookie-consent.php`)

All plugin logic is in this single file (~552 lines):
All plugin logic is in this single file (~851 lines):

- **`scc_get_default_options()`** — defines the canonical default settings structure
- **`scc_get_merged_options()`** — retrieves DB options and deep-merges with defaults; always returns a complete settings object
- **`scc_validate_options()`** — sanitizes/validates before saving to `scc_options` in `wp_options`
- **`scc_enqueue_scripts()`** — enqueues `dist/cookieconsent.bundle.js` and localizes it as `window.sccSettings`
- **`scc_settings_page()`** — renders the admin UI at Settings > Cookie Consent
- Settings are versioned via `scc_options_last_updated` timestamp for cache busting
- **`warder_get_default_options()`** — defines the canonical default settings structure
- **`warder_get_merged_options()`** — retrieves DB options and deep-merges with defaults; always returns a complete settings object
- **`warder_validate_options()`** — sanitizes/validates before saving to `warder_options` in `wp_options`
- **`warder_enqueue_scripts()`** — enqueues `dist/cookieconsent.bundle.js` and localizes it as `window.sccSettings`
- **`warder_render_options_page()`** — renders the admin UI at Settings > Cookie Consent
- Settings are versioned via `warder_options_last_updated` timestamp for cache busting

### JS Layer (`src/index.js` → `dist/cookieconsent.bundle.js`)

Expand All @@ -59,12 +59,24 @@ Scripts are blocked until consent is given via `data-cookiecategory` HTML attrib
### Settings Structure

```php
scc_options = [
'general' => [ position, language, ... ],
'texts' => [ banner title/description, accept/reject button labels, ... ],
'categories' => [
'necessary' => [ enabled, readonly, cookies[] ],
'analytics' => [ enabled, cookies[] ],
warder_options = [
'enabled' => bool,
'current_lang' => string,
'autoclear_cookies' => bool,
'page_scripts' => bool,
'show_preferences_toggle' => bool,
'preferences_toggle_position'=> string,
'title' => string,
'description' => string,
'primary_btn_text' => string,
'primary_btn_role' => string,
'secondary_btn_text' => string,
'secondary_btn_role' => string,
'privacy_policy_url' => string,
'cookie_categories' => [
'necessary' => [ title, description, enabled, readonly, cookies[] ],
'analytics' => [ title, description, enabled, cookies[] ],
... // user-defined categories
],
]
```
Expand All @@ -75,7 +87,7 @@ Each `cookies` entry supports `name` (exact string or `/regex/` pattern) and `do

The `Version:` header in `warder-cookie-consent.php` is the canonical version (this is what WordPress.org reads). When bumping the version, update all of these together:

- `warder-cookie-consent.php` — `Version:` header
- `warder-cookie-consent.php` — `Version:` header and `WARDER_VERSION` constant
- `readme.txt` — `Stable tag:` plus new `== Changelog ==` and `== Upgrade Notice ==` entries
- `CHANGELOG.md` — new version heading
- `package.json` — `version` field (kept in sync even though this package is not published to npm)
Expand Down
Loading
Loading