---
name: plugin-development
description: WordPress plugin anatomy, lifecycle, and repository rules for code Lola generates through Plugin Builder.
domain: plugin_builder
type: system
version: 1.0.1
min_lolacore_version: 1.9.0
ability_prefixes:
  - create_plugin
  - update_plugin_code
  - list_built_plugins
  - get_built_plugin
  - get_installed_plugin
  - test_plugin
  - install_plugin
  - delete_built_plugin
triggers:
  keywords:
    - plugin builder
    - built plugin
    - create plugin
    - mini plugin
    - wordpress plugin
---

## Purpose

This playbook maps what a WordPress plugin is and which domain rules apply when Lola generates or iterates mini-plugins through Plugin Builder. It covers file anatomy, lifecycle hooks, data storage, and WordPress.org expectations. Behavioral procedures (security checklist, packaging, review steps) live in skills — this manual is the field guide.

## Key concepts

- **Main plugin file**: A single bootstrap PHP file with a standard header (`Plugin Name`, `Description`, `Version`, `Author`, `License: GPL-2.0-or-later`). WordPress discovers the plugin from this file.
- **Hooks**: Plugins extend WordPress through `add_action` and `add_filter`. Runnable logic belongs on hooks, not at file load (except hook registration and constants).
- **Lifecycle hooks**: `register_activation_hook`, `register_deactivation_hook`, and optionally `register_uninstall_hook` run at defined events. Activation hooks must be registered at root scope, never inside another callback.
- **Options API**: Small configuration uses `get_option` / `update_option` with a unique prefixed option name. Custom tables are a last resort.
- **Asset loading**: Scripts and styles load with `wp_enqueue_script` and `wp_enqueue_style`. Never print raw `<script>` or `<style>` blocks from PHP output.
- **Plugin Builder library**: Generated plugins are stored as built-plugin entries in LolaCore (not as files on disk until install or export). `create_plugin` and `update_plugin_code` mutate that library; `install_plugin_local` copies a reviewed build into `wp-content/plugins/`.
- **Three-file pattern**: Plugin Builder stores and installs exactly three files per plugin: `{slug}.php`, `{slug}.js`, and `{slug}.css` at the plugin root. There is no slot for `composer.json`, a `vendor/` tree, or additional PHP files — even if the user asks. All PHP logic must live in the single main file; do not `require` other project PHP files. For external capabilities, declare installable WordPress.org plugin slugs in metadata `dependencies` (e.g. `woocommerce`), not Composer packages.
- **GPL and WordPress.org**: Public plugins must be GPL-compatible. Repository guidelines forbid trialware, locked features, trademark misuse (`WordPress` / `WP` in the plugin name), dashboard nag screens, and phoning home without clear consent.
- **Unique prefix**: Every function, class, option key, meta key, and text domain must use a plugin-specific prefix to avoid collisions.

## Rules

1. Block direct file access in every PHP file with `if (!defined('ABSPATH')) { exit; }`.
2. Use a consistent unique prefix for all identifiers (functions, options, hooks, text domain).
3. Include a GPL-2.0-or-later license line in the plugin header. Never ship proprietary or obfuscated license gates in generated code.
4. Never generate trialware: no disabled UI with upsell locks, no artificial usage quotas, no features that require payment to unlock inside the free output.
5. Register activation and deactivation hooks at file root. Flush rewrite rules only after registering CPTs or rewrite changes, and only when needed.
6. Wrap admin-only code in `is_admin()`. Front-end hooks must not assume wp-admin context.
7. Prefer WordPress APIs (`WP_Query`, post meta, options) over raw SQL. When SQL is unavoidable, use `$wpdb->prepare`.
8. Distinguish library state from installed state: a built plugin in the library is not active on the site until installed and activated through WordPress.
9. Offer Playground testing before installing generated code on the live site when the user has not already validated it.
10. Do not invent plugin slugs or paths that are not returned by list/get built-plugin abilities.
11. Never promise or generate Composer-based packaging (`composer.json`, `vendor/autoload.php`, multi-file PHP layouts) through Plugin Builder — the library, Playground sandbox, and local installer only support the three root files above.

## Examples

- A hello-style mini-plugin: `my-cool-tool.php` (header + hooks), `my-cool-tool.js`, `my-cool-tool.css` enqueued with `plugins_url('my-cool-tool.js', __FILE__)`, text domain `my-cool-tool`, option `my_cool_tool_settings`.
- Activation that registers a CPT: register the post type on `init`, call `flush_rewrite_rules` only inside the activation hook after registration logic is available.
