Skip to content

feat: HWP Previews plugin initial commit #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
Open
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
2 changes: 2 additions & 0 deletions plugins/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ WordPress plugins for the Headless WordPress Toolkit. Each plugin is paired with

## Plugins

- `hwp-previews`: WordPress plugin for previewing posts in a headless environment

- `hwp-cli`: WordPress plugin for CLI operations and status endpoints
- NPM Package: `@placeholder/cli`
- Features: REST API endpoints, admin interface
Binary file added plugins/hwp-previews.zip
Binary file not shown.
18 changes: 18 additions & 0 deletions plugins/hwp-previews/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org

# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = tab


[*.md]
trim_trailing_whitespace = false
1 change: 1 addition & 0 deletions plugins/hwp-previews/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/vendor
139 changes: 139 additions & 0 deletions plugins/hwp-previews/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# HWP Previews

**Headless Previews** solution for WordPress: fully configurable preview URLs via the settings page.

[![Version](https://img.shields.io/badge/version-0.0.1-blue)]() [![License](https://img.shields.io/badge/license-GPLv2%2B-lightgrey)]()

---

## Table of Contents

* [Overview](#overview)
* [Features](#features)
* [Configuration](#configuration)
* [Hooks & Extensibility](#hooks--extensibility)
* [Integration](#integration)

## Overview

HWP Previews is a robust and extensible WordPress plugin that centralizes all preview configurations into a user-friendly settings interface.
It empowers site administrators and developers to tailor preview behaviors for each public post type independently, facilitating seamless headless or decoupled workflows.
With HWP Previews, you can define dynamic URL templates, enforce unique slugs for drafts, allow all post statuses be used as parent and extend functionality through flexible hooks and filters, ensuring a consistent and conflict-free preview experience across diverse environments.

---

## Features

* **Enable/Disable Previews**: Turn preview functionality on or off for each public post type (including custom types).
* **Custom URL Templates**: Define preview URLs using placeholder tokens for dynamic content. Default tokens include:

* `{ID}` – Post ID
* `{author_ID}` – Post author’s user ID
* `{status}` – Post status slug
* `{slug}` – Post slug
* `{parent_ID}` – Parent post ID (hierarchical types)
* `{type}` – Post type slug
* `{uri}` – Page URI/path
* `{template}` – Template filename

* **Unique Post Slugs**: Force unique slugs for all post statuses in the post status config.
* **Parent Status**: Allow posts of **all** statuses to be used as parent within hierarchical post types.
* **Default Post Statuses Config**: `publish`, `future`, `draft`, `pending`, `private`, `auto-draft` (modifiable via core hook).
* **Parameter Registry**: Register, unregister, or customize URL tokens through the `hwp_previews_core` action.
* **Iframe Template for Previews**: Allows enable previews in the iframe on the WP Admin side. User can override the iframe preview template via `hwp_previews_template_path` filter.

---

## Configuration

### Default Post Types Config:
All public post types are enabled by default on the settings page. It is filterable via `hwp_previews_filter_post_type_setting` filter hook.

### Default Post Statuses Config:
Post statuses are `publish`, `future`, `draft`, `pending`, `private`, `auto-draft` (modifiable via core hook).

### Configure HWP Previews Plugin:
Navigate in WP Admin to **Settings › HWP Previews**. For each public post type, configure:

* **Enable HWP Previews** – Master switch
* **Unique Post Slugs** – Force unique slugs for all post statuses in the post status config.
* **Allow All Statuses as Parent** – (Hierarchical types only)
* **Preview URL Template** – Custom URL with tokens like `{ID}`, `{slug}`
* **Load Previews in Iframe** – Toggle iframe-based preview rendering

_Note: Retrieving of settings is cached for performance._

---

## Hooks & Extensibility

### Filter: Post Types List

Modify which post types appear in the settings UI:

```php
// Removes attachment post type from the settings page configuration.

add_filter( 'hwp_previews_filter_post_type_setting', 'hwp_previews_filter_post_type_setting_callback' );
function hwp_previews_filter_post_type_setting_callback( $post_types ) {
if ( isset( $post_types['attachment'] ) ) {
unset( $post_types['attachment'] );
}
return $post_types;
}
```

### Action: Core Registry

Register or unregister URL parameters, and adjust types/statuses:

```php
add_action( 'hwp_previews_core', 'modify_preview_url_parameters' );
function modify_preview_url_parameters(
\HWP\Previews\Preview\Parameter\Preview_Parameter_Registry $registry
) {
// Remove default parameter
$registry->unregister( 'author_ID' );

// Add custom parameter
$registry->register( new \HWP\Previews\Preview\Parameter\Preview_Parameter(
'current_time',
static fn( \WP_Post $post ) => (string) time(),
__( 'Current Unix timestamp', 'your-domain' )
) );
}
```

Modify post types and statuses:

```php
add_action( 'hwp_previews_core', 'modify_post_types_and_statuses_configs', 10, 3 );
function modify_post_types_and_statuses_configs(
\HWP\Previews\Preview\Parameter\Preview_Parameter_Registry $registry,
\HWP\Previews\Post\Type\Post_Types_Config $types,
\HWP\Previews\Post\Status\Post_Statuses_Config $statuses
) {
// Limit to pages only
$types->set_post_types( [ 'page' ] );
// Only include drafts
$statuses->set_post_statuses( [ 'draft' ] );
}
```

### Filter: Iframe Template Path

Use your own template for iframe previews:

```php
add_filter( 'hwp_previews_template_path', function( $default_path ) {
return get_stylesheet_directory() . '/my-preview-template.php';
});
```

---

## Integration

<!-- TODO: Add integration instructions for headless frameworks, GraphQL, or external systems. -->

---
1 change: 1 addition & 0 deletions plugins/hwp-previews/assets/js/hwp-previews.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log('hwp-preview-test');
50 changes: 50 additions & 0 deletions plugins/hwp-previews/autoload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/**
* Autoloader for HWP Previews Plugin.
*
* Prioritizes Composer's autoloader if available,
* otherwise implements a PSR-4 compatible autoloader.
*
* @package HWP\Previews
*/

if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {
require __DIR__ . '/vendor/autoload.php';

return;
}

spl_autoload_register( function ( $class ) {
// Define namespace prefix for your plugin
$prefix = 'HWP\\Previews\\';
$base_dir = __DIR__ . '/src/';

$len = strlen( $prefix );
if ( strncmp( $prefix, $class, $len ) !== 0 ) {
return;
}

$file = $base_dir . str_replace( '\\', '/', substr( $class, $len ) ) . '.php';

if ( file_exists( $file ) ) {
require $file;

return;
}

if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
_doing_it_wrong(
__FUNCTION__,
sprintf(
/* translators: 1: Class name, 2: File path */
__( 'Class %1$s could not be loaded. File %2$s not found.', 'hwp-previews' ),
'<code>' . esc_html( $class ) . '</code>',
'<code>' . esc_html( $file ) . '</code>'
),
'1.0.0'
);

error_log( sprintf( 'HWP Previews: Failed to load class %s, file %s not found', $class, $file ) );
}
} );
87 changes: 87 additions & 0 deletions plugins/hwp-previews/composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"name": "hwp/previews",
"version": "1.0.0",
"type": "wordpress-plugin",
"description": "This is a WordPress plugin that provides a preview....",
"keywords": [
"package",
"dependency",
"autoload"
],
"homepage": "https://wpengine.com/",
"license": "GPL-2.0-or-later",
"authors": [
{
"name": "WP Engine Headless OSS Development Team",
"email": "[email protected]",
"homepage": "https://wpengine.com/"
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"require": {
"php": "^7.4 || ^8.0"
},
"require-dev": {
"automattic/vipwpcs": "^3.0",
"dealerdirect/phpcodesniffer-composer-installer": "^1.0",
"humanmade/psalm-plugin-wordpress": "^3.1",
"johnpbloch/wordpress-core": "^6.8",
"phpcompatibility/phpcompatibility-wp": "^2.0",
"phpstan/phpstan-strict-rules": "^2.0",
"slevomat/coding-standard": "^8.0",
"szepeviktor/phpstan-wordpress": "^2.0"
},
"config": {
"allow-plugins": {
"dealerdirect/phpcodesniffer-composer-installer": true,
"phpstan/extension-installer": true
},
"optimize-autoloader": true,
"platform": {
"php": "7.4"
},
"preferred-install": "dist",
"sort-packages": true
},
"extra": {
"phpstan": {
"includes": [
"phpstan/rules.neon"
]
}
},
"autoload": {
"psr-4": {
"HWP\\Previews\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"HWP\\Previews\\Unit\\": "tests/unit/",
"HWP\\Previews\\Integration\\": "tests/integration/",
"HWP\\Previews\\PHPStan\\": "phpstan/",
"HWPStandard\\": "phpcs/HWPStandard"
}
},
"scripts": {
"php:lint": "vendor/bin/phpcs",
"php:lint:i": [
"php ./vendor/bin/phpcs -i"
],
"php:lint:fix": "vendor/bin/phpcbf",
"php:stan": [
"phpstan analyze --ansi --memory-limit=2G -v"
],
"php:psalm": "psalm"
},
"scripts-descriptions": {
},
"support": {
"docs": "https://github.com/composer/composer/docs",
"email": "[email protected]",
"forum": "https://github.com/composer/composer/forum",
"issues": "https://github.com/composer/composer/issues",
"security": "https://github.com/composer/composer/security/policy"
}
}
Loading