# WordPress Plugin Foundation Skill

> **Implicit Skill:** This skill is AUTOMATICALLY applied to EVERY task. You never need to explicitly reference it.

---

## Purpose

This skill defines the foundational security, compliance, and coding standards that apply to ALL development tasks in the Comments Press Zone plugin. It is the bedrock upon which all other skills build.

---

## WordPress.org Compliance (ZERO TOLERANCE)

### 1. Naming Conventions (4+ Character Minimum)

**MANDATORY:** All global identifiers (functions, classes, variables, CSS, JS) must have 4+ character prefixes.

```php
// ✅ CORRECT - 4+ characters
namespace CommentsPressZone;
function presszone_comments_init() {}
$presszone_comments_data = [];
define('PRESSZONE_COMMENTS_VERSION', '1.0.0');
```

```javascript
// ✅ CORRECT - 4+ characters
const CommentsPresszoneApp = {};
window.presszoneCommentsData = {};
```

```scss
// ✅ CORRECT - 4+ characters
$presszone-comments-primary: #1f71dd;
.presszone-comments-btn {}
@keyframes presszone-comments-fade-in {}
```

```php
// ❌ FORBIDDEN - TOO SHORT (will cause plugin rejection)
namespace PZ;
function pz_init() {}
$pz_data = [];
```

### 2. Text Domain (Consistent Everywhere)

**Text Domain:** `comments-press-zone`

```php
// ✅ CORRECT
__('Hello', 'comments-press-zone')
esc_html__('Hello', 'comments-press-zone')
_n('1 comment', '%s comments', $count, 'comments-press-zone')
```

```php
// ❌ WRONG
__('Hello', 'presszone-comments')  // Inconsistent
__('Hello')  // Missing text domain
```

**🚨 CRITICAL: NO VARIABLES IN GETTEXT FUNCTIONS**

**FORBIDDEN:** Using variables as the first argument to translation functions.

```php
// ❌ FORBIDDEN - WordPress.org will reject
__($variable, 'comments-press-zone')
__($email_template, 'comments-press-zone')
__($some_dynamic_text, 'comments-press-zone')

// ❌ FORBIDDEN - Even with phpcs:disable
// phpcs:disable WordPress.WP.I18n.NonSingularStringLiteralText
__($user_configurable_text, 'comments-press-zone');
// phpcs:enable
```

**WHY:** Translation parsers read code statically (without executing it). They cannot see variable values, so translators never receive these strings.

**CORRECT APPROACH - Dynamic Values via printf:**

```php
// ✅ CORRECT - Static string with placeholder
printf(
    /* translators: %s: User's first name */
    esc_html__('Hello %s, how are you?', 'comments-press-zone'),
    esc_html($user_firstname)
);

// ✅ CORRECT - Multiple placeholders
printf(
    /* translators: 1: Post title, 2: Author name */
    esc_html__('"%1$s" by %2$s', 'comments-press-zone'),
    esc_html($post_title),
    esc_html($author_name)
);
```

**USER-CONFIGURABLE CONTENT (NEVER TRANSLATE):**

Admin-defined email templates, tooltip text, or database-stored values should NOT be passed through gettext:

```php
// ❌ WRONG - These are dynamic user data, not translatable strings
$tooltip = __($admin_configured_tooltip, 'comments-press-zone');
$email_body = __($user_email_template, 'comments-press-zone');

// ✅ CORRECT - Return user data as-is
private static function get_tooltip_text(): string {
    $value = get_option('presszone_comments_tooltip_text', 'Default text');
    // User-configured values are returned directly
    // They are NOT translatable strings
    return $value;
}
```

---

## Security Standards (MANDATORY)

### 1. SQL Injection Prevention

**ALWAYS use `$wpdb->prepare()` for dynamic queries.**

```php
// ✅ CORRECT
global $wpdb;
$table = $wpdb->prefix . 'presszone_comments_likes';
$count = $wpdb->get_var($wpdb->prepare(
    "SELECT COUNT(*) FROM $table WHERE comment_id = %d AND type = %s",
    $comment_id,
    $type
));
```

```php
// ❌ FORBIDDEN - SQL Injection vulnerability
$results = $wpdb->get_results("SELECT * FROM $table WHERE id = $id");
```

### 2. XSS Prevention (Output Escaping)

**ALWAYS escape output. Late escaping is mandatory.**

```php
// ✅ CORRECT - Escape at output time
echo esc_html($user_input);
echo esc_attr($attribute_value);
echo esc_url($url);
echo wp_kses_post($html_content);
```

```php
// ❌ WRONG - No escaping
echo $user_input;
echo "<div data-value='$value'>";
```

```javascript
// ✅ CORRECT - Use textContent for user data
element.textContent = userData;

// ❌ FORBIDDEN - XSS vulnerability
element.innerHTML = userData;
```

### 3. CSRF Prevention (Nonce Verification)

**ALWAYS verify nonces for state-changing operations.**

```php
// AJAX Handler
$nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
if (!wp_verify_nonce($nonce, 'presszone_comments_nonce')) {
    wp_send_json_error(['message' => esc_html__('Security check failed.', 'comments-press-zone')]);
}

// Forms
wp_nonce_field('presszone_comments_action');

// REST API - X-WP-Nonce header is automatic
```

### 4. Input Sanitization

**ALWAYS sanitize input before processing.**

```php
// ✅ CORRECT
$comment_id = isset($_POST['comment_id']) ? absint($_POST['comment_id']) : 0;
$type = isset($_POST['type']) ? sanitize_key($_POST['type']) : '';
$text = isset($_POST['text']) ? sanitize_text_field(wp_unslash($_POST['text'])) : '';
$content = isset($_POST['content']) ? sanitize_textarea_field(wp_unslash($_POST['content'])) : '';
```

### 5. Authentication & Authorization

**ALWAYS check permissions before sensitive operations.**

```php
// Check if user is logged in
if (!is_user_logged_in()) {
    wp_send_json_error(['message' => esc_html__('You must be logged in.', 'comments-press-zone')]);
}

// Check capabilities
if (!current_user_can('moderate_comments')) {
    wp_send_json_error(['message' => esc_html__('Unauthorized.', 'comments-press-zone')]);
}

// REST API permission callback
public function check_permission() {
    return current_user_can('manage_options') || current_user_can('moderate_comments');
}
```

---

## Prefixing Standards

### PHP
- **Namespace:** `CommentsPressZone`
- **Functions:** `presszone_comments_*`
- **Constants:** `PRESSZONE_COMMENTS_*`
- **Options:** `presszone_comments_*`
- **User Meta:** `_presszone_comments_*`
- **Transients:** `presszone_comments_*`

### Database
- **Tables:** `{$wpdb->prefix}presszone_comments_*`
- Examples: `wp_presszone_comments_likes`, `wp_presszone_comments_reports`

### CSS/SCSS
- **Classes:** `.presszone-comments-*`
- **Variables:** `$presszone-comments-*`
- **Keyframes:** `@keyframes presszone-comments-*`
- **BEM:** `.presszone-comments-block__element--modifier`

### JavaScript
- **Globals:** `CommentsPresszoneApp`, `presszoneCommentsData`, `presszoneCommentsAdmin`
- **Actions:** `presszone_comments_*`
- **Events:** `presszone:comments:*`

### WordPress
- **Handles:** `presszone-comments-*`
- **Actions/Filters:** `presszone_comments_*`
- **AJAX Actions:** `presszone_comments_*`
- **REST Namespace:** `presszone-comments/v1`

---

## File Structure Standards

### PHP File Header (MANDATORY)

**For all PHP files except the main plugin file:**

```php
<?php
/**
 * [Description]
 *
 * @package CommentsPressZone\[Subpackage]
 */

declare(strict_types=1);

namespace CommentsPressZone\[Subpackage];

if (!defined('ABSPATH')) {
    exit;
}
```

**Note:** For main plugin file header requirements (Plugin Name, Description, Version, License, etc.), see `plugin-release-skill.md` - those are only checked during release preparation.

### Directory Structure

```
comments-press-zone/
├── includes/
│   ├── Core/
│   ├── Comments/
│   ├── Database/
│   └── Api/
├── admin/
│   ├── src-vanilla/
│   └── build/
├── assets/
│   ├── js/
│   └── css/
├── templates/
│   └── partials/
└── languages/
```

---

## Common Security Mistakes (ZERO TOLERANCE)

| Mistake | Consequence | Fix |
|---------|-------------|-----|
| No `$wpdb->prepare()` | SQL Injection → Plugin Rejection | Always use `$wpdb->prepare()` |
| No output escaping | XSS → Plugin Rejection | Use `esc_html()`, `esc_attr()`, etc. |
| No nonce verification | CSRF → Plugin Rejection | Verify nonces in all POST handlers |
| Missing `defined('ABSPATH')` | Direct file access → Plugin Rejection | Add to every PHP file |
| Short prefixes (<4 chars) | Namespace collision → Plugin Rejection | Use 4+ character prefixes |
| Missing text domain | Translation broken → Plugin Warning | Always include text domain |
| `innerHTML` with user data | XSS → Security vulnerability | Use `textContent` instead |

---

## WordPress APIs (Preferred Methods)

### Database
- `$wpdb->prepare()` - Parameterized queries
- `$wpdb->insert()` - Insert rows
- `$wpdb->update()` - Update rows
- `$wpdb->delete()` - Delete rows
- `$wpdb->get_results()` - Fetch multiple rows
- `$wpdb->get_row()` - Fetch single row
- `$wpdb->get_var()` - Fetch single value

### Options
- `get_option()` - Retrieve option
- `update_option()` - Save option
- `delete_option()` - Remove option

### User Meta
- `get_user_meta()` - Retrieve user meta
- `update_user_meta()` - Save user meta
- `delete_user_meta()` - Remove user meta

### Transients (Caching)
- `get_transient()` - Retrieve cached data
- `set_transient()` - Cache data with expiration
- `delete_transient()` - Remove cached data

### Hooks
- `add_action()` - Register action callback
- `add_filter()` - Register filter callback
- `do_action()` - Trigger custom action
- `apply_filters()` - Apply custom filter

---

## Accessibility Requirements

- **Keyboard Navigation:** All interactive elements must be keyboard accessible
- **ARIA Labels:** Icon-only buttons need `aria-label`
- **Focus Management:** Trap focus in modals, restore on close
- **Reduced Motion:** Respect `prefers-reduced-motion` media query

```scss
@media (prefers-reduced-motion: reduce) {
    * {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}
```

---

## Performance Best Practices

1. **Minimize Database Queries:** Cache results with transients
2. **Conditional Loading:** Only enqueue scripts/styles when needed
3. **Lazy Loading:** Use dynamic imports for large JS modules
4. **Debounce/Throttle:** Limit API calls from user interactions

---

## Build Documentation Requirements (WordPress.org Compliance)

**MANDATORY:** If your plugin contains compiled/minified files, you MUST provide comprehensive build documentation.

### When Documentation is Required

Build documentation is REQUIRED if ANY of these exist:
- `package.json` with build scripts
- `webpack.config.js` or similar bundler config
- SCSS/SASS source files
- `.min.js` or `.min.css` files
- Any compiled/transpiled code (e.g., `admin/build/admin.js` from `admin/src-vanilla/`)

### Required Documentation (CONTRIBUTING.md or BUILD.md)

Create a `CONTRIBUTING.md` or `BUILD.md` file in the plugin root with:

1. **Prerequisites:**
   - List required tools (Node.js version, npm version, etc.)
   - System requirements if applicable

2. **Build Commands:**
   ```bash
   # Example required documentation:
   npm install              # Install dependencies
   npm run build           # Production build (admin JS)
   npm run build:css       # Production build (frontend CSS)
   npm run watch          # Development mode with auto-rebuild
   ```

3. **Source File Locations:**
   - Map compiled files to their sources
   - Example: "`admin/build/admin.js` is compiled from `admin/src-vanilla/`"

4. **Directory Structure:**
   - Explain the project layout
   - Indicate which directories contain source vs. compiled files

5. **Development Workflow:**
   - How to make changes and rebuild
   - How to test changes locally

### Example Documentation Structure

```markdown
# Development and Build Instructions

## Prerequisites
- Node.js 14.x or higher
- npm 6.x or higher

## Build Process

### First-Time Setup
1. Clone the repository
2. Run `npm install` in plugin root
3. Run `cd admin && npm install`

### Production Builds
- **Frontend CSS:** `npm run build:css` (from plugin root)
- **Admin Panel:** `cd admin && npm run build`

### Development Mode
- **Frontend CSS:** `npm run watch:css`
- **Admin Panel:** `cd admin && npm run watch`

## Source Files
- `assets/scss/` → `assets/css/frontend.css` (SCSS compilation)
- `admin/src-vanilla/` → `admin/build/admin.js` (Webpack + Babel)
```

### Common Mistakes to Avoid

```php
// ❌ Submitting without documentation
// Plugin has: admin/build/admin.js, webpack.config.js, package.json
// But no CONTRIBUTING.md or BUILD.md
// Result: WordPress.org REJECTION

// ✅ Proper submission
// Plugin has: CONTRIBUTING.md with complete build instructions
// Developers can build from source without guessing
// Result: WordPress.org APPROVAL
```

---

## Build Requirements

| Change Type | Command | Directory |
|-------------|---------|-----------|
| Admin JS/SCSS | `npm run build` | `admin/` |
| Frontend SCSS | `npm run build:css` | Plugin root |

**CRITICAL:** Always rebuild after changes. Forgetting = changes won't appear.

---

## Translation Maintenance

| Action | Requirement |
|--------|-------------|
| Add new UI string | Add to all `.po` files, translate to all languages |
| Remove UI string | Remove from all `.po` files to avoid bloat |
| Edit UI string | Update in all `.po` files, retranslate |

**File Locations:**
- `languages/comments-press-zone-{locale}.po` - PHP strings
- `languages/comments-press-zone-{locale}-presszone-comments-admin-app.json` - Admin JS strings

---

## Testing Checklist (Every Task)

Before completing any task, verify:

- [ ] All dynamic SQL uses `$wpdb->prepare()`
- [ ] All output is escaped (`esc_html`, `esc_attr`, `esc_url`, `wp_kses_post`)
- [ ] All POST/AJAX handlers verify nonces
- [ ] All input is sanitized (`sanitize_text_field`, `absint`, etc.)
- [ ] All strings have text domain `comments-press-zone`
- [ ] **NO variables in gettext functions** (`__($var, ...)` is forbidden)
- [ ] All prefixes are 4+ characters
- [ ] All files have `defined('ABSPATH')` check
- [ ] All permissions checked before sensitive operations
- [ ] Code rebuilt if JS/CSS changed
- [ ] No `innerHTML` with user data
- [ ] **Build documentation exists if plugin has compiled files**

**Note:** For release preparation checklist (plugin headers, version numbers, readme.txt, etc.), see `plugin-release-skill.md`.

---

## This Skill Applies To

**EVERYTHING.** Every single task, every file, every line of code. No exceptions.
