# Recast Paywall

A WordPress plugin that integrates **RecastPay** to monetize your content. Features automatic content synchronization, dual editor support, and comprehensive theme customization options.

## Description

Recast Paywall transforms your WordPress site into a premium content platform with:

- **🎨 Themeable Design**: Modern Medium-style paywalls with faded overlays and gradient backgrounds
- **📱 Responsive Layout**: Mobile-first design with dark mode support
- **🔒 Content Gating**: Gate entire posts or individual blocks behind paywalls
- **⚡ Automatic Sync**: Posts automatically synchronize with Recast Inventory items
- **🎯 Dual Editor Support**: Works seamlessly with both Classic and Block Editor (Gutenberg)
- **💾 Smart Caching**: Entitlement decisions cached for optimal performance
- **🔔 Webhook Support**: Real-time updates from Recast for instant content delivery
- **🌐 Multisite Ready**: Fully compatible with WordPress multisite installations
- **🛠️ Developer Friendly**: Extensive hooks, filters, and customization options

## Features

### Content Management
- **Post-Level Gating**: Gate entire posts with beautiful Medium.com-style paywalls
- **Block-Level Gating**: Gate individual blocks with streamlined inline paywalls
- **Automatic Sync**: Posts automatically sync with Recast Inventory items
- **Excerpt-Based Previews**: Paywalls display post excerpts as preview text

### User Experience
- **Login-First Flow**: Users must log in before purchasing (WordPress authentication)
- **Real-Time Pricing**: Display current pricing from Recast inventory
- **Status Indicators**: Show availability status (Pre-sale, Available, Coming Soon)
- **Seamless Purchase**: One-click purchase flow with immediate content access

### Theme Integration
- **Complete Customization**: Override HTML, CSS, and JavaScript via WordPress hooks
- **Responsive Design**: Mobile-first approach with dark mode support
- **Animation Support**: Smooth transitions and hover effects
- **Accessibility**: WCAG compliant with keyboard navigation

### Developer Features
- **Extensive Hooks**: Customize every aspect of the paywall system
- **REST API**: Full REST API for custom integrations
- **WP-CLI Support**: Command-line tools for management
- **Debug Logging**: Comprehensive logging for troubleshooting

## Requirements

- WordPress 6.2 or higher
- PHP 8.0 or higher
- Recast account with API credentials
- Modern web browser with JavaScript enabled

## Installation

1. Upload the `recast-paywall` folder to your `/wp-content/plugins/` directory
2. Activate the plugin through the 'Plugins' menu in WordPress
3. Go to **Settings > Recast Paywall** to configure your API credentials

## Configuration

### 1. API Setup

1. Log in to your [RecastPay Dashboard](https://business.recast.tv)
2. Navigate to **API Settings**
3. Copy your **API Key**, **API Secret** and **Brand ID**
4. In WordPress, go to **Settings > Recast Paywall**
5. Enter your credentials and save

### 2. Content Settings

- **Show Teaser to Search Engines**: Allow search engines to see full content (use carefully)
- **Archive on Delete**: Archive Recast inventory items when posts are deleted

**Note**: Paywalls always display the WordPress post excerpt as the preview text. Set the excerpt in the post editor to control what visitors see before purchasing.

### 3. Webhook Setup

1. In your Recast Dashboard, go to **Webhooks**
2. Add a new webhook with the URL: `https://yoursite.com/?recast_webhook=1`
3. Select the events you want to receive (entitlement and inventory events)
4. Save the webhook

## Usage

### Content Gating Modes

The plugin supports two gating modes that can be toggled per post:

#### **Post-Level Gating (Default)**
- Gates the entire post content behind a paywall
- Shows a beautiful Medium.com-style paywall with post excerpt
- Best for premium articles and exclusive content
- **Preview Text**: Uses the post excerpt (set in post editor sidebar)

#### **Block-Level Gating**
- Allows selective gating of individual blocks within a post
- Provides more granular control over what content is premium
- Perfect for mixed free/premium content strategies

### Setting Up Content Gating

#### 1. Choose Your Gating Mode

1. Create or edit a post
2. In the **Document Settings** panel (Block Editor) or **"Recast Paywall"** meta box (Classic Editor)
3. Select your gating mode:
   - **"Post"** - Gate the entire post (default)
   - **"Block"** - Enable block-level gating
4. Save and Publish the post - it will automatically sync with Recast

#### 2. Post-Level Gating

When using **Post** mode:
- The entire post content is gated behind a paywall
- Users see the post excerpt and purchase options
- On archive/list pages, only the excerpt is shown (no content leak)
- **Tip**: Set a compelling excerpt to encourage purchases!

#### 3. Block-Level Gating

When using **Block** mode:
- Individual blocks can be marked for gating using the block's toolbar
- Users see full content except for gated blocks
- Gated blocks show streamlined paywall sections

### Block-Level Gating with Toolbar Integration

#### Using the Block Toolbar

1. **Enable Block Mode**: Set the post gating mode to **"Block"** in Document Settings
2. **Select a Block**: Click on any block in the editor
3. **Access the Toolbar**: Look for the **"Recast Paywall"** toggle in the block toolbar
4. **Toggle Gating**: Click the toggle to mark/unmark the block for gating
5. **Visual Indicator**: Gated blocks show a paywall icon in the editor

#### Supported Block Types

Block-level gating works with most Gutenberg blocks:
- Paragraphs
- Headings
- Images
- Videos
- Lists
- Custom blocks
- And more!

#### Using Shortcode (Alternative Method)

```php
[recast_paywall]
This content will be gated behind the paywall.
[/recast_paywall]
```

#### Using Legacy Paywall Block

1. Add the **"Recast Paywall Section"** block to your post
2. Add content inside the block
3. The content will be gated behind the paywall

### Theme Customization

The paywall system is completely themeable. Here are some examples:

#### Customize Post-Level Paywall HTML

```php
add_filter('recast_paywall_post_html', function($html, $postId, $inventoryData, $userState, $summary) {
    // Your custom HTML here
    $price = $inventoryData['price'];
    $priceDisplay = $price ? sprintf('%s', number_format($price)) : 'Free';
    
    return '<div class="my-theme-paywall">' .
           '<h2>Premium Content</h2>' .
           '<div class="price">' . esc_html($priceDisplay) . '</div>' .
           '<div class="summary">' . wp_kses_post($summary) . '</div>' .
           '</div>';
}, 10, 5);
```

#### Customize Block-Level Paywall HTML

```php
add_filter('recast_paywall_block_html', function($html, $postId, $inventoryData, $userState, $summary) {
    // Your custom HTML here
    return '<div class="my-theme-block-paywall">' .
           '<div class="summary">' . wp_kses_post($summary) . '</div>' .
           '<button onclick="recastPurchaseContent(' . esc_js($postId) . ')">Purchase</button>' .
           '</div>';
}, 10, 5);
```

#### Add Custom CSS

```php
add_action('wp_head', function() {
    ?>
    <style>
    .my-theme-paywall {
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 12px;
        padding: 2rem;
        color: white;
        text-align: center;
    }
    
    .my-theme-block-paywall {
        background: #f8f9fa;
        border: 2px dashed #dee2e6;
        border-radius: 8px;
        padding: 1.5rem;
        text-align: center;
    }
    </style>
    <?php
});
```

### JavaScript Integration

```javascript
// Custom purchase function
function recastPurchaseContent(postId) {
    const button = event.target;
    button.textContent = 'Processing...';
    button.disabled = true;
    
    fetch('/wp-json/recast-paywall/v1/purchase', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'X-WP-Nonce': recastPaywall.nonce
        },
        body: JSON.stringify({ post_id: postId })
    })
    .then(response => response.json())
    .then(data => {
        if (data.success) {
            window.location.reload();
        } else {
            alert(data.message || 'Purchase failed. Please try again.');
        }
    })
    .catch(error => {
        console.error('Purchase error:', error);
        alert('Purchase failed. Please try again.');
    })
    .finally(() => {
        button.textContent = originalText;
        button.disabled = false;
    });
}
```

## Hooks and Filters

### Paywall Customization

- `recast_paywall_post_html` - Customize post-level paywall HTML
- `recast_paywall_block_html` - Customize block-level paywall HTML
- `recast_paywall_template_locations` - Add custom template directories
- `recast_paywall_template_path` - Modify resolved template path
- `recast_paywall_user_state` - Extend user state data
- `recast_paywall_inventory_data` - Extend inventory data

### Content Management

- `recast_paywall_external_user_id` - Customize how user IDs are mapped to Recast
- `recast_paywall_is_bot_request` - Customize bot detection
- `recast_paywall_entitlement_ttl` - Set cache TTL for entitlement decisions
- `recast_paywall_inventory_payload` - Modify the payload sent to Recast

### Actions

- `recast_paywall_before_content` - Add content before paywall
- `recast_paywall_after_content` - Add content after paywall
- `recast_paywall_content_revealed` - Fired when content is revealed to entitled users
- `recast_paywall_sync_completed` - Fired when a post is synced with Recast
- `recast_paywall_webhook_received` - Fired when a webhook is received

## WP-CLI Commands

```bash
# Sync a specific post
wp recast sync --post_id=123

# Sync all posts
wp recast sync-all

# Clear entitlement cache
wp recast clear-cache

# Clear cache for specific post/user
wp recast clear-cache --post_id=123 --user_id=456
```

## Troubleshooting

### Common Issues

1. **Posts not syncing**: Check your API credentials and ensure the post is published
2. **Paywall not showing**: Verify your Brand ID is correct and the post has paywall enabled
3. **Entitlement not working**: Check that users have valid entitlements in your Recast dashboard
4. **Webhooks not working**: Verify the webhook URL and signature verification
5. **Styling conflicts**: Use more specific CSS selectors or customize via hooks

### Debug Mode

Enable WordPress debug mode to see detailed error logs:

```php
// In wp-config.php
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
```

### Testing

1. Use sandbox mode for testing
2. Create test posts and verify they sync to Recast
3. Test entitlement checks with different user accounts
4. Verify webhook delivery in your Recast dashboard
5. Test paywall appearance on different devices and themes

## Security

- API secrets are never exposed to the frontend
- All forms use WordPress nonces
- Webhook signatures are verified
- User capabilities are checked for admin actions
- Input is sanitized and validated
- XSS protection through proper escaping

## Performance

- Entitlement decisions are cached for 5 minutes (configurable)
- Smart content loading with size limits
- Progressive enhancement for better user experience
- Memory-optimized processing
- Efficient database queries

## Development

### Local Development Setup

#### Prerequisites
- PHP 8.0+ with Composer
- Docker and Docker Compose (for wp-env)
- Git for version control
- Node.js and npm (for asset compilation if needed)

#### Initial Setup

1. **Clone the repository**
   ```bash
   git clone https://github.com/your-username/recast-paywall.git
   cd recast-paywall
   ```

2. **Install PHP dependencies**
   ```bash
   composer install
   ```

3. **Install development dependencies**
   ```bash
   composer install --dev
   ```

4. **Set up WordPress environment with wp-env**

   wp-env runs in Docker. Be sure to have that installed.

   ```bash
   # Install wp-env
   npm i @wordpress/env --save-dev

   # Start the WordPress environment
   wp-env start
   
   # Install WordPress and activate the plugin
   wp-env run cli "wp core install --url=localhost:8888 --title='Recast Paywall Demo' --admin_user=admin --admin_password=password --admin_email=admin@example.com"
   wp-env run cli "wp plugin activate recast-paywall"
   
   # Ensure the environment can access external APIs (for Recast integration)
   ```

5. **Install Node.js dependencies and build editor assets**

   The plugin uses modern WordPress block editor components that need to be compiled. The editor panel (`src/editor/index.js`) must be built before it will appear in the WordPress block editor.

   ```bash
   # Install npm dependencies
   npm install
   
   # Build editor assets (required for the Recast Paywall panel to appear)
   npm run build
   ```

   **Important**: The `build/` directory must exist with compiled assets for the Recast Paywall settings panel to show up in the post editor. If you don't see the panel after activating the plugin, run `npm run build`.

#### Development Workflow

1. **Create a feature branch**
   ```bash
   git checkout -b feature/your-feature-name
   ```

2. **Make your changes**
   - Edit PHP files in the `src/` directory
   - Modify templates in the `templates/` directory
   - Update CSS/JS in the `assets/` directory
   - Edit block editor components in `src/editor/` (requires rebuild)

3. **Rebuild editor assets (if you modified editor files)**
   
   If you made changes to files in `src/editor/` or `src/editor/index.scss`, you need to rebuild:
   
   ```bash
   # Production build
   npm run build
   
   # Or use watch mode for automatic rebuilding during development
   npm start
   ```
   
   The watch mode (`npm start`) will automatically rebuild when you save changes to editor files, making development faster.

4. **Run tests**
   ```bash
   # Run all tests
   ./vendor/bin/phpunit
   
   # Run specific test file
   ./vendor/bin/phpunit tests/PluginTest.php
   
   # Run with coverage report
   ./vendor/bin/phpunit --coverage-html coverage/
   ```

5. **Code quality checks**
   ```bash
   # PHP CodeSniffer (WordPress standards)
   ./vendor/bin/phpcs --standard=WordPress src/
   
   # Auto-fix coding standards
   ./vendor/bin/phpcbf --standard=WordPress src/
   ```

6. **Commit your changes**
   ```bash
   git add .
   git commit -m "feat: add your feature description"
   ```

#### Testing Environment

1. **Enable debug mode**
   ```php
   // In wp-config.php
   define('WP_DEBUG', true);
   define('WP_DEBUG_LOG', true);
   define('WP_DEBUG_DISPLAY', false);
   ```

2. **Set up test data**
   - Create test posts with paywall content
   - Set up test user accounts
   - Configure Recast sandbox API credentials

3. **Test paywall functionality**
   - Verify content gating works correctly
   - Test different user scenarios (logged in, logged out, entitled, not entitled)
   - Check responsive design on various screen sizes

#### Debugging

1. **Check WordPress debug log**
   ```bash
   tail -f wp-content/debug.log
   ```

2. **Use WordPress debug bar**
   - Install Query Monitor plugin for detailed debugging
   - Monitor database queries and performance

3. **Test Recast API calls**
   - Use browser dev tools to monitor network requests
   - Check Recast dashboard for webhook delivery
   - Verify API responses in browser console

#### Building for Production

1. **Build editor assets**
   ```bash
   # Build and optimize editor assets (required before deployment)
   npm run build
   ```
   
   This creates the `build/` directory with:
   - `build/index.js` - Compiled JavaScript for the block editor panel
   - `build/index.css` - Compiled styles for the editor panel
   - `build/index.asset.php` - Dependency information for WordPress
   
   **Note**: The `build/` directory is required for the plugin to work. It should be committed to the repository and included in releases.

2. **Verify build files exist**
   ```bash
   # Check that build directory exists with required files
   ls -la build/
   # Should show: index.js, index.css, index.asset.php
   ```

3. **Run final tests**
   ```bash
   ./vendor/bin/phpunit
   ./vendor/bin/phpcs --standard=WordPress src/
   ```

4. **Create release package**
   ```bash
   # Remove development files
   rm -rf tests/ vendor/ .git/ .gitignore composer.lock
   
   # Create zip archive
   zip -r recast-paywall.zip . -x "*.git*" "tests/*" "vendor/*"
   ```

#### NPM Scripts Reference

The plugin includes several npm scripts for development:

```bash
# Build editor assets for production (required before deployment)
npm run build

# Start development watch mode (auto-rebuilds on file changes)
npm start

# Download external JavaScript dependencies (runs automatically on npm install)
npm run download-deps

# Sync version numbers across plugin files
npm run sync-version
```

**When to use each command:**
- `npm run build` - Before committing changes, before deployment, or when the editor panel isn't showing
- `npm start` - During active development of editor components (keeps running and watches for changes)
- `npm run download-deps` - Automatically runs on `npm install`, but can be run manually if dependencies are missing
- `npm run sync-version` - When updating the plugin version (usually handled by release workflow)

#### Useful Development Commands

```bash
# WordPress environment management
wp-env start          # Start the development environment
wp-env stop           # Stop the development environment
wp-env destroy        # Destroy and recreate the environment
wp-env run cli "wp --info"  # Run WP-CLI commands

# Node.js and asset management
npm install           # Install npm dependencies
npm run build         # Build editor assets (required for editor panel)
npm start             # Start watch mode for editor development

# WordPress and plugin commands
wp-env run cli "wp cache flush"           # Clear WordPress cache
wp-env run cli "wp recast clear-cache"    # Clear plugin cache
wp-env run cli "wp recast sync-all"       # Sync test content to Recast
wp-env run cli "wp plugin list | grep recast"  # Check plugin status
wp-env run cli "wp eval \"error_log('Test message');\""  # View plugin logs

# Access the environment
# WordPress: http://localhost:8888
# Admin: http://localhost:8888/wp-admin (admin/password)
# Database: localhost:8889 (root/root)
```

#### CI/CD Pipeline

The project uses GitHub Actions for continuous integration and deployment:

**Workflow Sequence:**
1. **`release-create.yml`** ("Release - Create") → Manual trigger with version input
   - Creates `release/v1.2.3` branch with proper version
   - Updates plugin files to release version
   - Creates PR with release checklist and notes
2. **`release-publish.yml`** ("Release - Publish") → Triggers when release PR is merged to `main`
   - Creates GitHub release and tag
   - Builds plugin package
   - Uploads plugin zip to release
   - Creates PR to sync main → develop
3. **`wordpress-deploy.yml`** ("Deploy - WordPress.org") → Manual deployment to WordPress.org
   - Only runs when explicitly triggered
   - Includes dry-run mode for testing

**CI Workflow** (`.github/workflows/ci.yml`):
- **PHP Tests**: Runs PHPUnit tests with MySQL service
- **Coding Standards**: WordPress coding standards and PHP Mess Detector
- **Plugin Validation**: Validates plugin structure and headers
- **Security Scan**: Dependency security checks and static analysis
- **Build**: Creates production-ready plugin package

**Release Management** (`.github/workflows/release-publish.yml`):
- **Release Validation**: Checks plugin version consistency
- **GitHub Releases**: Creates tagged releases with changelog
- **Plugin Building**: Generates production plugin package
- **WordPress.org Integration**: Prepares for WordPress.org deployment

**WordPress.org Deployment** (`.github/workflows/wordpress-org-deploy.yml`):
- **SVN Integration**: Automatically deploys to WordPress.org plugin repository
- **Version Tagging**: Creates proper SVN tags for each release
- **Production Ready**: Only deploys stable releases (no pre-releases)

**Version Management**:
- **Centralized sync script**: Keeps version numbers consistent across all files
- **Manual control**: Versions set explicitly via release workflow
- **No automatic bumping**: You control when versions change
- **Conventional Commits**: Follows conventional commit message standards
- **Release Integration**: Works with your release branch → PR → main workflow

#### Commit Message Standards

Follow conventional commit format for automatic versioning:

```bash
feat: add new paywall feature          # Minor version bump
fix: resolve entitlement bug           # Patch version bump
docs: update installation guide        # Patch version bump
BREAKING CHANGE: refactor API          # Major version bump
```

#### Required Secrets

Set these secrets in your GitHub repository:

- `WP_ORG_USERNAME`: WordPress.org SVN username
- `WP_ORG_PASSWORD`: WordPress.org SVN password
- `GITHUB_TOKEN`: Automatically provided by GitHub

#### How to Create a Release

1. **Go to Actions** → **Release - Create** → **Run workflow**
2. **Fill in the form:**
   - **Version**: Enter the release version (e.g., `1.2.3`)
   - **Release Type**: Choose `patch`, `minor`, or `major`
   - **Release Notes**: Optional description of changes
3. **Click "Run workflow"**
4. **Review the created PR** with release checklist
5. **Merge the PR** when ready for production
6. **The workflow automatically:**
   - Creates GitHub release
   - Builds plugin package
   - Deploys to WordPress.org
   - Prepares next development version

## Support

For support and questions:

1. Check the troubleshooting section above
2. Review the WordPress error logs
3. Contact Recast support for API-related issues
4. Open an issue on the plugin repository

## Changelog

### 0.0.1
- Initial release
- Completely themeable paywall system
- Recast API integration
- Medium.com-style post paywalls
- Gutenberg block-level paywalls
- Login-first user flow
- Real-time pricing display from inventory
- Responsive design with dark mode support
- Comprehensive theme customization hooks
- Toolbar integration for block-level gating
- Webhook handling

## License

GPL v2 or later

## Credits

Developed for Recast Paywall integration with WordPress. Built with modern web standards and accessibility in mind.
