VOOZH about

URL: https://deepwiki.com/pcescato/ajc-bridge/8-development-guide

⇱ Development Guide | pcescato/ajc-bridge | DeepWiki


Loading...
Menu

Development Guide

This guide is for developers who want to contribute to the AJC Bridge plugin or extend its functionality. It covers development environment setup, coding standards, architecture patterns, testing procedures, and build processes.

For information about creating releases and deploying the plugin, see Release Workflow. For customizing front matter output, see Front Matter Templates.


Development Environment Setup

Prerequisites

The plugin requires a local development environment with the following components:

ComponentVersionPurpose
PHP8.1+Core language runtime
ComposerLatestDependency management
WordPress6.9+Plugin host platform
GitLatestVersion control
Imagick or GDLatestImage processing extension

Optional but recommended:

  • Local WordPress environment (Local by Flywheel, Laravel Valet, or Docker)
  • IDE with PHP support (VS Code with PHP Intelephense or PHPStorm)
  • GitHub account with test repository
  • Dev.to account with API key

Installation Steps

1. Clone the repository:


2. Install Composer dependencies:


This installs the required packages specified in composer.json:

  • intervention/image v3.11+ - Image processing with WebP/AVIF support
  • league/html-to-markdown v5.1+ - HTML to Markdown conversion
  • woocommerce/action-scheduler v3.9+ - Async background job processing

3. Link to WordPress plugins directory:


4. Activate the plugin:

  • Navigate to WordPress Admin → Plugins
  • Find "AJC Bridge" and click Activate

5. Enable Debug Mode:

  • Go to Settings → AJC Bridge → General
  • Check "Enable Debug Mode"
  • Logs will be written to /wp-content/uploads/ajc-bridge-logs/

Sources: README.md631-683 README_OLD.md631-683


Directory Structure and File Organization

Directory Structure
```mermaid
graph TB
 subgraph "Plugin Root"
 Bootstrap["ajc-bridge.php<br/>Plugin Header & Bootstrap"]
 Composer["composer.json<br/>Dependencies"]
 Uninstall["uninstall.php<br/>Cleanup Handler"]
 end
 
 subgraph "core/ - Business Logic"
 Plugin["class-plugin.php<br/>Singleton Bootstrap"]
 SyncRunner["class-sync-runner.php<br/>Orchestrator"]
 QueueMgr["class-queue-manager.php<br/>Async Tasks"]
 Logger["class-logger.php<br/>Logging System"]
 GitAPI["class-git-api.php<br/>GitHub Client"]
 DevToAPI["class-devto-api.php<br/>Dev.to Client"]
 MediaProc["class-media-processor.php<br/>Image Processing"]
 Redirect["class-headless-redirect.php<br/>Frontend Redirects"]
 end
 
 subgraph "adapters/ - Content Conversion"
 Interface["interface-adapter.php<br/>Adapter Contract"]
 Hugo["class-hugo-adapter.php<br/>Hugo/Jekyll"]
 Astro["class-astro-adapter.php<br/>Astro/MDX"]
 DevTo["class-devto-adapter.php<br/>Dev.to Platform"]
 end
 
 subgraph "admin/ - User Interface"
 Admin["class-admin.php<br/>Menu Coordination"]
 Settings["class-settings.php<br/>Settings Pages"]
 Columns["class-columns.php<br/>Post List UI"]
 MetaBox["class-post-meta-box.php<br/>Editor Sidebar"]
 end
 
 subgraph "Build & Deploy"
 DistIgnore[".distignore<br/>Exclude Rules"]
 Workflow[".github/workflows/release.yml<br/>CI/CD Pipeline"]
 GitTag["git-tag.sh<br/>Tag Script"]
 end
 
 Bootstrap --> Plugin
 Plugin --> SyncRunner
 Plugin --> QueueMgr
 Plugin --> Admin
 
 SyncRunner --> Hugo
 SyncRunner --> Astro
 SyncRunner --> DevTo
 
 Hugo --> MediaProc
 Astro --> MediaProc
 
 Hugo --> GitAPI
 Astro --> GitAPI
 DevTo --> DevToAPI
 
 Admin --> Settings
 Admin --> Columns
 Admin --> MetaBox

Sources: README_OLD.md451-502


Coding Standards

The plugin adheres strictly to WordPress Coding Standards with modern PHP 8.1+ type safety enhancements.

PHP Standards

All PHP files must include:

1. Strict Type Declaration:


2. Namespace Declaration:


3. Security Check:


Sources: core/class-headless-redirect.php1-14 admin/class-post-meta-box.php1-14

Naming Conventions

ElementConventionExample
ClassesPascalCase with underscoresSync_Runner, Queue_Manager
Methodssnake_caseenqueue_post(), get_redirect_base()
Functionssnake_caseajc_bridge_init()
ConstantsSCREAMING_SNAKE_CASEAJC_BRIDGE_VERSION
Variablessnake_case$post_id, $sync_status

Type Hints

All method parameters and return types must have type hints:


Sources: core/class-headless-redirect.php96-116

Documentation

All classes and methods require PHPDoc blocks:


Sources: core/class-headless-redirect.php16-22 core/class-headless-redirect.php95-102

Code Formatting

  • Indentation: Tabs (not spaces)
  • Line Length: 100 characters soft limit
  • Braces: Opening brace on same line for control structures
  • Array Syntax: Short array syntax [] preferred over array()

Example:



Architecture Patterns

Class Initialization Pattern

All major classes use a static init() method for WordPress hook registration:


This pattern allows the Plugin singleton to initialize components without instantiating them:


Sources: core/class-headless-redirect.php24-31 admin/class-post-meta-box.php21-29

Adapter Pattern Implementation

Adapter Pattern Flow
```mermaid
graph LR
 SyncRunner["Sync_Runner::run()"]
 
 subgraph "Strategy Selection"
 CheckStrategy{"settings<br/>publishing_strategy"}
 end
 
 subgraph "Adapter Interface"
 HugoAdapter["Hugo_Adapter<br/>implements Adapter_Interface"]
 AstroAdapter["Astro_Adapter<br/>implements Adapter_Interface"]
 DevToAdapter["DevTo_Adapter<br/>implements Adapter_Interface"]
 end
 
 subgraph "Common Methods"
 Sync["sync(post_id, api)"]
 Delete["delete(post_id, api)"]
 end
 
 SyncRunner --> CheckStrategy
 CheckStrategy -->|"github_only"| HugoAdapter
 CheckStrategy -->|"github_only (astro)"| AstroAdapter
 CheckStrategy -->|"devto_only"| DevToAdapter
 CheckStrategy -->|"dual_github_devto"| HugoAdapter
 CheckStrategy -->|"dual_github_devto"| DevToAdapter
 
 HugoAdapter --> Sync
 AstroAdapter --> Sync
 DevToAdapter --> Sync
 
 HugoAdapter --> Delete
 AstroAdapter --> Delete
 DevToAdapter --> Delete

The Adapter_Interface defines the contract that all content converters must implement. This allows Sync_Runner to work with any adapter without knowing implementation details.

Adding a new adapter:

  1. Create class in adapters/ directory
  2. Implement Adapter_Interface methods
  3. Add adapter instantiation logic to Sync_Runner::run()
  4. Add corresponding strategy option to settings

Sources: Architecture diagrams (Diagram 1)

Singleton Pattern

The Plugin class uses a singleton pattern to ensure single initialization:


This pattern prevents multiple registrations of WordPress hooks and ensures centralized plugin state.

Sources: Architecture diagrams (Diagram 1)

Queue Management Pattern

Async Processing Architecture
```mermaid
stateDiagram-v2
 [*] --> WordPress_Hook: "save_post action"
 
 WordPress_Hook --> Queue_Manager_enqueue: "Queue_Manager::enqueue(post_id)"
 
 state Queue_Manager_enqueue {
 [*] --> Validate_Post
 Validate_Post --> Check_Duplicate: "Post exists?"
 Check_Duplicate --> Set_Pending: "Not queued?"
 Set_Pending --> Schedule_Action: "update_post_meta<br/>_ajc_sync_status=pending"
 Schedule_Action --> AS_or_Cron: "as_schedule_single_action()"
 }
 
 AS_or_Cron --> ActionScheduler: "Preferred"
 AS_or_Cron --> WPCron: "Fallback"
 
 ActionScheduler --> Queue_Manager_process: "Queue_Manager::process_single()"
 WPCron --> Queue_Manager_process
 
 state Queue_Manager_process {
 [*] --> Acquire_Lock: "set_transient<br/>wpjamstack_lock_{post_id}"
 Acquire_Lock --> Lock_Success: "Lock acquired?"
 Acquire_Lock --> Skip: "Lock failed"
 Lock_Success --> Sync_Runner_run: "Sync_Runner::run(post_id)"
 Sync_Runner_run --> Release_Lock: "delete_transient"
 Release_Lock --> [*]
 Skip --> [*]
 }
 
 Queue_Manager_process --> Update_Meta: "update_post_meta<br/>_ajc_sync_status=success/error"
 Update_Meta --> [*]

The Queue_Manager class abstracts async processing, providing:

  • Duplicate prevention via _ajc_sync_status meta checks
  • Lock-based concurrency control using transients
  • Automatic retry with exponential backoff
  • Fallback from Action Scheduler to WP Cron

Sources: Architecture diagrams (Diagram 3)


Testing Procedures

Manual Testing Workflow

Before submitting pull requests or releases, verify functionality using this checklist:

GitHub-based strategies (github_only, dual_github_devto):

  • Publish new post → Verify commit appears on GitHub
  • Update existing post → Verify update commit
  • Delete post → Verify deletion commit
  • Add featured image → Verify WebP/AVIF files in repository
  • Add inline images → Verify all images extracted and uploaded
  • Test bulk sync → Verify all published posts sync
  • Test frontend redirect → Verify 301 redirect to GitHub Pages
  • Check commit messages → Verify descriptive messages

Dev.to-based strategies (devto_only, wordpress_devto, dual_github_devto):

  • Publish with "Publish to dev.to" checked → Verify article on dev.to
  • Publish without checkbox → Verify dev.to skipped
  • Update article → Verify update on dev.to
  • Check canonical URL → Verify correct canonical_url field
  • Test frontend redirect (devto_only) → Verify 301 redirect

Error handling:

  • Disconnect network → Verify retry mechanism activates
  • Invalid credentials → Verify error message displayed
  • Check logs → Verify detailed error information captured

Sources: README_OLD.md712-741

Debug Mode

Enable debug logging for development:

Via Settings UI:

  1. Navigate to Settings → AJC Bridge → General
  2. Check "Enable Debug Mode"
  3. Save changes

Debug output locations:

  • File logs: /wp-content/uploads/ajc-bridge-logs/ajc-bridge-YYYY-MM-DD.log
  • Admin UI: Settings → AJC Bridge → Logs tab (if implemented)

What gets logged:

  • All API requests and responses (tokens masked)
  • Image processing steps
  • Markdown conversion process
  • Error stack traces
  • Hook execution flow

Sources: README_OLD.md911-921

Connection Testing

Test external API connections before full sync:

Connection Testing Flow
```mermaid
sequenceDiagram
 participant Admin as "Admin User"
 participant Settings as "Settings::test_connection_ajax()"
 participant GitAPI as "Git_API::test_connection()"
 participant DevToAPI as "DevTo_API::test_connection()"
 participant GitHub as "api.github.com"
 participant DevTo as "dev.to/api"
 
 Admin->>Settings: "Click Test GitHub Connection"
 Settings->>Settings: "verify_nonce()"
 Settings->>Settings: "decrypt_github_token()"
 Settings->>GitAPI: "new Git_API(token, repo)"
 GitAPI->>GitHub: "GET /repos/owner/repo"
 GitHub-->>GitAPI: "200 OK + repo data"
 GitAPI-->>Settings: "true"
 Settings-->>Admin: "success: Connection successful"
 
 Admin->>Settings: "Click Test Dev.to Connection"
 Settings->>Settings: "verify_nonce()"
 Settings->>DevToAPI: "new DevTo_API(api_key)"
 DevToAPI->>DevTo: "GET /api/articles/me"
 DevTo-->>DevToAPI: "200 OK + articles"
 DevToAPI-->>Settings: "true"
 Settings-->>Admin: "success: Connection successful"

Sources: Architecture diagrams (Diagram 6)


Build and Distribution

Local Development Build

For local testing, use development dependencies:


This installs all packages including development tools.

Production Build

For distribution, exclude development dependencies:


This creates an optimized autoloader and excludes packages listed in require-dev.

Distribution Exclusions

The .distignore file defines files excluded from the release ZIP:

.git
.github
node_modules
vendor/bin/
vendor/**/test/
vendor/**/tests/
docs/
*.sh
README.md

Key exclusions:

  • Development files (.github/, docs/)
  • Test files (vendor/**/tests/)
  • Build scripts (*.sh)
  • Documentation (README.md - uses readme.txt instead)

Sources: .distignore1-43

Release Process Overview

The release process is automated via GitHub Actions. For detailed information, see Release Workflow.

Quick overview:

  1. Update version in ajc-bridge.php header
  2. Run ./git-tag.sh 1.3.0 to create and push tag
  3. GitHub Actions builds and publishes release
  4. Download ajc-bridge.zip from GitHub Releases

Sources: git-tag.sh1-36 .github/workflows/release.yml1-65


Extending the Plugin

Adding Custom Hooks

The plugin provides several hooks for customization:

Filter hooks (planned):

  • ajc_bridge_markdown_content - Modify converted Markdown before save
  • ajc_bridge_front_matter - Modify front matter data
  • ajc_bridge_supported_post_types - Add custom post types

Action hooks (existing via WordPress):

  • save_post - Triggers sync queue
  • trash_post - Triggers deletion sync
  • untrashed_post - Triggers re-sync

Creating a New Adapter

To add support for a new static site generator:

1. Create adapter class:


2. Register in Sync_Runner: Modify Sync_Runner::run() to instantiate your adapter based on settings.

3. Add settings option: Add "Eleventy" to SSG type dropdown in Settings class.

4. Test thoroughly using manual testing checklist.

Customizing Front Matter

For information about customizing front matter templates, see Front Matter Templates.

Sources: Architecture diagrams (Diagram 4)


Common Development Tasks

Running PHPCS

Check code against WordPress Coding Standards:


Sources: README_OLD.md684-708

Viewing Action Scheduler Status

Monitor background jobs:

  1. Navigate to Tools → Scheduled Actions
  2. Filter by "ajc_bridge" group
  3. Check for pending, complete, or failed actions
  4. Click action to see details and errors

Clearing Post Meta

During development, you may need to reset sync status:


Sources: README_OLD.md603-619


Security Considerations

Token Encryption

GitHub Personal Access Tokens are encrypted before database storage:


Key points:

  • Uses WordPress salts for encryption keys
  • AES-256-CBC cipher
  • Tokens masked in UI as ghp_***...***
  • Never logged to files

Nonce Verification

All AJAX handlers verify nonces:


Sources: Architecture diagrams (Diagram 5)

Capability Checks

All administrative functions require capabilities:


Sources: admin/class-post-meta-box.php229-231


Performance Considerations

Image Processing Optimization

  • Images processed in temporary directory: /tmp/ajc-bridge-images/
  • Cleanup guaranteed via finally blocks
  • Imagick preferred over GD for better performance
  • AVIF generation conditional on Imagick availability

API Call Reduction

GitHub Trees API reduces API calls by approximately 70%:

Traditional approach:

  • 1 API call per file (Markdown + each image)
  • Example: 1 post + 5 images = 6 API calls

Trees API approach:

  • 1 blob creation per file
  • 1 tree creation (all files)
  • 1 commit creation
  • 1 ref update
  • Example: 1 post + 5 images = 4 API calls total

Sources: Architecture diagrams (Diagram 6)

Async Processing Benefits

All sync operations use Action Scheduler:

  • Non-blocking: Users don't wait for GitHub/dev.to API responses
  • Retry capability: Failed syncs automatically retry (max 3 attempts)
  • Scalable: Handles large sites with thousands of posts
  • Visible: Administrators can monitor queue status

Sources: Architecture diagrams (Diagram 3)

Refresh this wiki

On this page