Skip to content

Commit 1dbc036

Browse files
authored
Merge pull request #406 from wpengine/chore-hwp-previews-updates-sept-2025
chore: Previews minor updates
2 parents 23da236 + 59882a7 commit 1dbc036

File tree

5 files changed

+73
-34
lines changed

5 files changed

+73
-34
lines changed

.changeset/rare-lemons-applaud.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@wpengine/hwp-previews-wordpress-plugin": patch
3+
---
4+
5+
chore: Fix for the admin settings page to check capabilities.

plugins/hwp-previews/README.md

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
-----
1010

1111
[![Version](https://img.shields.io/github/v/release/wpengine/hwptoolkit?include_prereleases&label=previews&filter=%40wpengine%2Fhwp-previews-wordpress-plugin-*)](https://github.com/wpengine/hwptoolkit/releases)
12-
[![License](https://img.shields.io/badge/license-GPLv2%2B-green)]()
12+
[![License](https://img.shields.io/badge/license-GPLv2%2B-green)](https://www.gnu.org/licenses/gpl-2.0.html)
1313
![GitHub forks](https://img.shields.io/github/forks/wpengine/hwptoolkit?style=social)
1414
![GitHub stars](https://img.shields.io/github/stars/wpengine/hwptoolkit?style=social)
1515
[![Testing Integration](https://img.shields.io/github/check-runs/wpengine/hwptoolkit/main?checkName=hwp-previews%20codeception%20tests&label=Automated%20Tests)](https://github.com/wpengine/hwptoolkit/actions)
@@ -21,7 +21,7 @@
2121

2222

2323
> [!CAUTION]
24-
> This plugin is currently in an beta state. It's still under active development, so you may encounter bugs or incomplete features. Updates will be rolled out regularly. Use with caution and provide feedback if possible. You can create an issue at [https://github.com/wpengine/hwptoolkit/issues](https://github.com/wpengine/hwptoolkit/issues)
24+
> This plugin is currently in a beta state. It's still under active development, so you may encounter bugs or incomplete features. Updates will be rolled out regularly. Use with caution and provide feedback if possible. You can create an issue at [https://github.com/wpengine/hwptoolkit/issues](https://github.com/wpengine/hwptoolkit/issues)
2525
2626
---
2727

@@ -40,7 +40,7 @@
4040

4141
HWP Previews is a robust and extensible WordPress plugin that centralizes all preview configurations into a user-friendly settings interface.
4242
It empowers site administrators and developers to tailor preview behaviors for each public post type independently, facilitating seamless headless or decoupled workflows.
43-
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.
43+
With HWP Previews, you can define dynamic URL templates, allow posts of all statuses to be used as parents, and extend functionality through flexible hooks and filters, ensuring a consistent and conflict-free preview experience across diverse environments.
4444

4545

4646

@@ -53,7 +53,7 @@ With HWP Previews, you can define dynamic URL templates, enforce unique slugs fo
5353

5454
- **Enable/Disable Previews**: Turn preview functionality on or off for each public post type (including custom types).
5555
- **Custom URL Templates**: Define preview URLs using placeholder tokens for dynamic content.
56-
- **Parent Status**: Allow posts of **all** statuses to be used as parent within hierarchical post types.
56+
- **Parent Status**: Allow posts of **all** statuses to be used as parents within hierarchical post types.
5757
- **Highly Customizable**: Extend core behavior with a comprehensive set of actions and filters.
5858
- **Faust Compatibility**: The plugin is compatible with [Faust.js](https://faustjs.org/) and the [FaustWP plugin](https://github.com/wpengine/faustjs/tree/canary/plugins/faustwp).
5959

@@ -64,9 +64,9 @@ This guide will help you set up your first headless preview link for the "Posts"
6464

6565
1. **Activate the Plugin:** Ensure "HWP Previews" is installed and activated.
6666
2. **Navigate to Settings:** Go to **Settings > HWP Previews** in your WordPress admin dashboard.
67-
3. **Enable for Posts:** On the "Posts" tab check the "Enable HWP Previews" box. If you have Faust installed this option will be enabled by default. Find more information about Faust integration below.
67+
3. **Enable for Posts:** On the "Posts" tab, check the "Enable HWP Previews" box. If you have Faust installed, this option will be enabled by default. Find more information about Faust integration below.
6868
4. **Set the Preview URL:** In the "Preview URL Template" field for Posts, enter the URL for your front-end application's preview endpoint. Use parameters to add dynamic information that you want to access.
69-
5. **Save and Test:** Save changes and go to any post, make a change, and click the "Preview" button. You should be redirected to the URL you just configured.
69+
5. **Save and Test:** Save changes, go to any post, make a change, and click the "Preview" button. You should be redirected to the URL you just configured.
7070

7171
---
7272

@@ -81,15 +81,16 @@ hwp-previews/
8181
│ ├── Preview/ # Preview URL logic, template resolver, helpers
8282
│ ├── Plugin.php # Main plugin class (entry point)
8383
│ └── Autoload.php # PSR-4 autoloader
84+
├── examples/ # Example front-end integrations for WP GraphQL and REST
8485
├── tests/ # All test suites
85-
│ ├── wpunit/ # WPBrowser/Codeception unit
86-
├── [hwp-previews.php]
87-
├── [activation.php]
88-
├── [composer.json]
89-
├── [deactivation.php]
90-
├── [ACTIONS_AND_FILTERS.md]
91-
├── [TESTING.md]
92-
├── [README.md]
86+
│ ├── wpunit/ # WPBrowser/Codeception unit
87+
├── hwp-previews.php
88+
├── activation.php
89+
├── composer.json
90+
├── deactivation.php
91+
├── ACTIONS_AND_FILTERS.md
92+
├── TESTING.md
93+
├── README.md
9394
```
9495

9596
## Configuration
@@ -101,12 +102,12 @@ HWP Previews configuration located at **Settings > HWP Previews** page in your W
101102
For each public post type, you can configure:
102103

103104
- **Enable HWP Previews:** This is the master switch for the post type. If disabled, WordPress will revert to its default preview behavior for these posts.
104-
- **Allow All Statuses as Parent:** This option is only available for Pages type. By default, WordPress only allows published posts to be parents. Enable this to build parent-child relationships using draft or pending posts.
105+
- **Allow All Statuses as Parent:** This option is only available for hierarchical post types like Pages. By default, WordPress only allows published posts to be parents. Enable this to build parent-child relationships using draft or pending posts.
105106
- **Load Previews in Iframe:** When enabled, the preview will be displayed directly within the WordPress editor in a sandboxed `<iframe>`. This provides a more integrated experience but requires your front-end to be configured to allow embedding. If disabled, clicking "Preview" will open a new browser tab.
106-
- **Preview URL:** You will be redirected to this link, whenever you click the preview button for the enabled post type.
107+
- **Preview URL:** You will be redirected to this link whenever you click the preview button for the enabled post type.
107108

108109
> [!NOTE]
109-
> Retrieving of settings is cached for performance.
110+
> Retrieval of settings is cached for performance.
110111
111112
### Parameters
112113

@@ -132,7 +133,9 @@ Default post statuses are `publish`, `future`, `draft`, `pending`, `private`, `a
132133

133134
HWP Previews is framework and API agnostic, meaning you can integrate it with any front-end application and with any data-fetching method (WPGraphQL, REST).
134135

135-
To get started quickly you can use our [example based on Next.js and WPGraphQL](https://github.com/wpengine/hwptoolkit/tree/main/examples/next/hwp-preview-wpgraphql). This example uses the Draft Mode feature of Next.js.
136+
To get started quickly you can use our [example based on Next.js and WPGraphQL](https://github.com/wpengine/hwptoolkit/tree/main/plugins/hwp-previews/examples/hwp-preview-wpgraphql). This example uses the Draft Mode feature of Next.js.
137+
138+
For REST users, you can follow our example [here](https://github.com/wpengine/hwptoolkit/tree/main/plugins/hwp-previews/examples/hwp-preview-rest) with Next.js App Router.
136139

137140
To implement your own approach from scratch you can refer to the appropriate documentation pages for each framework. HWP Previews relies on custom preview URLs, allowing you to integrate any method. Below you can find the guides to implement framework-specific preview mode.
138141

plugins/hwp-previews/bin/install-test-env.sh

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ install_db() {
4444
# create database
4545
echo -e "$(status_message "Creating the database (if it does not exist)...")"
4646

47-
RESULT=$(mysql -u $WORDPRESS_DB_USER --password="$WORDPRESS_DB_PASSWORD" --skip-column-names -e "SHOW DATABASES LIKE '$WORDPRESS_DB_NAME'"$EXTRA)
48-
if [ "$RESULT" != $WORDPRESS_DB_NAME ]; then
49-
mysqladmin create $WORDPRESS_DB_NAME --user="$WORDPRESS_DB_USER" --password="$WORDPRESS_DB_PASSWORD"$EXTRA
50-
fi
47+
RESULT=$(mysql --no-defaults --ssl=false -u $WORDPRESS_DB_USER --password="$WORDPRESS_DB_PASSWORD" --skip-column-names -e "SHOW DATABASES LIKE '$WORDPRESS_DB_NAME'"$EXTRA)
48+
if [ "$RESULT" != $WORDPRESS_DB_NAME ]; then
49+
mysqladmin --no-defaults --ssl=false create $WORDPRESS_DB_NAME --user="$WORDPRESS_DB_USER" --password="$WORDPRESS_DB_PASSWORD"$EXTRA
50+
fi
5151
}
5252

5353
download() {
@@ -196,15 +196,6 @@ post_setup() {
196196
wp config set WP_AUTO_UPDATE_CORE false --raw --type=constant --quiet --allow-root
197197
wp config set AUTOMATIC_UPDATER_DISABLED true --raw --type=constant --quiet --allow-root
198198

199-
# Export the db for codeception to use
200-
SQLDUMP="$WORDPRESS_ROOT_DIR/wp-content/plugins/$PLUGIN_SLUG/tests/_data/dump.sql"
201-
mkdir -p "$(dirname "$SQLDUMP")"
202-
if [ ! -f "$SQLDUMP" ]; then
203-
echo -e "$(status_message "Exporting test database dump...")"
204-
205-
wp db export "$SQLDUMP" --allow-root
206-
fi
207-
208199
echo -e "$(status_message "Installed plugins")"
209200
wp plugin list --allow-root
210201
}

plugins/hwp-previews/src/Admin/Settings_Page.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ protected function __construct() {
5858
* Initializes the settings page.
5959
*/
6060
public static function init(): ?Settings_Page {
61-
if ( ! is_admin() ) {
61+
if ( ! is_admin() || ! current_user_can( 'manage_options' ) ) {
6262
return null;
6363
}
6464
if ( ! isset( self::$instance ) || ! ( is_a( self::$instance, self::class ) ) ) {

plugins/hwp-previews/tests/wpunit/Admin/SettingsPageTest.php

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ public function in_admin( $context = null ) {
2121
return $context === 'user';
2222
}
2323
};
24+
25+
// Reset the instance before each test
26+
$reflection = new ReflectionClass( Settings_Page::class );
27+
$instanceProperty = $reflection->getProperty( 'instance' );
28+
$instanceProperty->setAccessible( true );
29+
$instanceProperty->setValue( null );
2430
}
2531

2632
public function tearDown() : void {
@@ -29,13 +35,40 @@ public function tearDown() : void {
2935
parent::tearDown();
3036
}
3137

38+
public function test_init_returns_null_if_not_admin() {
39+
// Unset the admin screen mock
40+
unset( $GLOBALS['current_screen'] );
41+
42+
$instance = Settings_Page::init();
43+
$this->assertNull( $instance, 'Settings_Page::init() should return null if not in admin.' );
44+
}
45+
46+
public function test_init_returns_null_for_user_without_manage_options_cap() {
47+
$user_id = self::factory()->user->create( [ 'role' => 'subscriber' ] );
48+
wp_set_current_user( $user_id );
49+
50+
$instance = Settings_Page::init();
51+
$this->assertNull( $instance, 'Settings_Page::init() should return null for users without manage_options capability.' );
52+
}
53+
54+
public function test_init_returns_instance_for_user_with_manage_options_cap() {
55+
$user_id = self::factory()->user->create( [ 'role' => 'administrator' ] );
56+
wp_set_current_user( $user_id );
57+
58+
$instance = Settings_Page::init();
59+
$this->assertInstanceOf( Settings_Page::class, $instance, 'Settings_Page::init() should return an instance for users with manage_options capability.' );
60+
}
61+
3262
public function test_settings_page_instance() {
3363
$reflection = new ReflectionClass( Settings_Page::class );
3464
$instanceProperty = $reflection->getProperty( 'instance' );
3565
$instanceProperty->setAccessible( true );
36-
$instanceProperty->setValue( null );
3766

3867
$this->assertNull( $instanceProperty->getValue() );
68+
69+
// To pass the capability check
70+
$user_id = self::factory()->user->create( [ 'role' => 'administrator' ] );
71+
wp_set_current_user( $user_id );
3972
$instance = Settings_Page::init();
4073

4174
$this->assertInstanceOf( Settings_Page::class, $instanceProperty->getValue() );
@@ -44,7 +77,11 @@ public function test_settings_page_instance() {
4477

4578
public function test_get_current_tab() {
4679
$_GET['attachment'] = 'attachment';
47-
$settings_page = Settings_Page::init();
80+
81+
// To pass the capability check
82+
$user_id = self::factory()->user->create( [ 'role' => 'administrator' ] );
83+
wp_set_current_user( $user_id );
84+
$settings_page = Settings_Page::init();
4885

4986
$post_preview_service = new Post_Preview_Service();
5087
$post_types = $post_preview_service->get_post_types();
@@ -61,6 +98,9 @@ public function test_get_current_tab() {
6198
}
6299

63100
public function test_register_hooks() {
101+
// To pass the capability check
102+
$user_id = self::factory()->user->create( [ 'role' => 'administrator' ] );
103+
wp_set_current_user( $user_id );
64104
$settings_page = Settings_Page::init();
65105
$this->assertNull( $settings_page->register_settings_page() );
66106
$this->assertNull( $settings_page->register_settings_fields() );

0 commit comments

Comments
 (0)