Skip to content

Commit

Permalink
feat: Add Cloud loader support (#180)
Browse files Browse the repository at this point in the history
* Add Cloud loader support

* store manifest id's on preview actions and expose them to the schema

* the manifest id should come from the post being previewed, not the action monitor post

* rename to content sync

* pull manifest ID from preview action monitor post instead of reconstructing it.

* Only store unique manifest id's

* more null checks and access object not array!

* Update CHANGELOG.md

* reorganize and reword options page
  • Loading branch information
TylerBarnes authored Aug 25, 2021
1 parent 407f42c commit 15dc1a7
Show file tree
Hide file tree
Showing 6 changed files with 185 additions and 8 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Change Log

## Upcoming

- Added support for the new Gatsby Cloud Content Sync API. This new API moves the WPGatsby Preview loader logic to the Gatsby Cloud side as Cloud has more context on the Gatsby process making it more reliable than the existing WPGatsby preview loader with fewer restrictions and caveats.

## 1.0.12

Preview webhooks added the remote url as a property on the webhook body. When publishing updates we also send a preview webhook to update the preview Gatsby site. These two webhook bodies previously differed in that the latter didn't include a remoteUrl property. As of gatsby-source-wordpress@5.10.0 this causes problems because the source plugin assumes this property always exists. Related to https://github.com/gatsbyjs/gatsby/issues/32732. Fixed in https://github.com/gatsbyjs/wp-gatsby/pull/184
Expand Down
4 changes: 4 additions & 0 deletions src/ActionMonitor/ActionMonitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,10 @@ function register_post_graphql_fields() {
'type' => 'Int',
'description' => __( 'The WordPress database ID of the preview. If this is a draft it will potentially return 0, if it\'s a revision of a post, it will return the ID of the original post that this is a revision of.', 'WPGatsby' ),
],
'manifestIds' => [
'type' => [ 'list_of' => 'String' ],
'description' => __( 'A list of manifest ID\'s a preview action has seen during it\'s lifetime.', 'WPGatsby' ),
]
]
]
);
Expand Down
35 changes: 34 additions & 1 deletion src/ActionMonitor/Monitors/Monitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use GraphQLRelay\Relay;
use WPGatsby\ActionMonitor\ActionMonitor;
use WPGatsby\Admin\Preview;

abstract class Monitor {

Expand Down Expand Up @@ -294,10 +295,42 @@ public function log_action( array $args ) {
if ( $action_monitor_post_id !== 0 ) {

if ( isset( $args['preview_data'] ) ) {
$existing_preview_data = \get_post_meta(
$action_monitor_post_id,
'_gatsby_preview_data',
true
);

$manifest_id = Preview::get_preview_manifest_id_for_post(
get_post( $args['node_id'] )
);

$manifest_ids = [$manifest_id];

// if we have existing data, we want to merge our manifest id
// into any existing manifest ids
if ( $existing_preview_data && $existing_preview_data !== "" ) {
$existing_preview_data = json_decode( $existing_preview_data );

if ( $existing_preview_data->manifestIds ?? false ) {
$manifest_ids = array_unique(
array_merge(
$existing_preview_data->manifestIds,
$manifest_ids
)
);
}
}

// add manifest ids
$preview_data = json_decode( $args['preview_data'] );
$preview_data->manifestIds = $manifest_ids;
$preview_data = json_encode( $preview_data );

\update_post_meta(
$action_monitor_post_id,
'_gatsby_preview_data',
$args['preview_data']
$preview_data
);
}

Expand Down
106 changes: 106 additions & 0 deletions src/Admin/Preview.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,114 @@ function() {
$this->registerPreviewStatusFieldsAndMutations();
}
);

$use_cloud_loader = self::get_setting( 'use_gatsby_content_sync' );

if ( $use_cloud_loader === 'on' ) {
add_filter( 'preview_post_link', function( $link, $post ) {
return self::get_gatsby_content_sync_url_for_post( $post );
}, 10, 2 );
}
}
}

public static function get_preview_manifest_id_for_post( $post ) {
$graphql_single_name =
get_post_type_object( $post->post_type )
->graphql_single_name;

if ( !$graphql_single_name || $graphql_single_name === "" ) {
// if we don't have a graphql single name
// Gatsby can't use this post anyway.
// No need to return a manifest
return null;
}

$action_monitor_posts = new \WP_Query( [
'post_type' => 'action_monitor',
'post_status' => 'any',
'posts_per_page' => 1,
'no_found_rows' => true,
'fields' => 'ids',
'tax_query' => [
'relation' => 'AND',
[
'taxonomy' => 'gatsby_action_ref_node_dbid',
'field' => 'name',
'terms' => sanitize_text_field( $post->ID ),
],
[
'taxonomy' => 'gatsby_action_ref_node_type',
'field' => 'name',
'terms' => sanitize_text_field( $graphql_single_name ),
],
[
'taxonomy' => 'gatsby_action_stream_type',
'field' => 'name',
'terms' => 'PREVIEW',
]
],
] );

if (
isset( $action_monitor_posts->posts )
&& ! empty( $action_monitor_posts->posts )
) {
$action_monitor_post_id = $action_monitor_posts->posts[0];
$referenced_node_preview_data = get_post_meta(
$action_monitor_post_id,
'_gatsby_preview_data',
true
);

$preview_data = false;

if (
$referenced_node_preview_data
&& $referenced_node_preview_data !== ""
) {
$preview_data = json_decode( $referenced_node_preview_data );
}

if (
$preview_data
&& property_exists( $preview_data, 'manifestIds' )
&& count( $preview_data->manifestIds ) > 0
) {
return $preview_data->manifestIds[0];
}
}

// if the above doesn't return a value we generate a new manifest ID from the post_modified date and post db id
$revision = self::getPreviewablePostObjectByPostId( $post->ID );
$revision_modified = $revision->post_modified ?? null;

if ( !$revision_modified || $revision_modified === "" ) {
return null;
}

$manifest_id = $post->ID . $revision_modified;

return $manifest_id;
}

public static function get_gatsby_content_sync_url_for_post( $post ) {
// get the Gatsby Cloud loader url w/ site id
$gatsby_content_sync_url = self::get_setting( 'gatsby_content_sync_url' );

// create the dynamic path the loader will need
$manifest_id = self::get_preview_manifest_id_for_post( $post );
$path = "/gatsby-source-wordpress/$manifest_id";

$url = preg_replace(
// remove any double forward slashes from the path
'/([^:])(\/{2,})/', '$1/',
"$gatsby_content_sync_url$path"
);

return $url;
}

public static function print_initial_preview_template_state_js() {
global $post;
$post_id = $post->ID;
Expand Down Expand Up @@ -551,6 +656,7 @@ public function setup_preview_template( $template ) {

// Ensure the post_type is set to show_in_graphql
$post_type_object = $post_type ? get_post_type_object( $post->post_type ) : null;

if ( $post_type && ! $post_type_object->show_in_graphql ?? true ) {
return plugin_dir_path( __FILE__ ) . 'includes/post-type-not-shown-in-graphql.php';
}
Expand Down
29 changes: 22 additions & 7 deletions src/Admin/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@ function get_settings_fields() {
'wpgatsby_settings' => [
[
'name' => 'builds_api_webhook',
'label' => __( 'Builds Webhook', 'wpgatsby_settings' ),
'desc' => __( 'Enter your Gatsby Builds Webhook URL. Must begin with http:// or https://. Use a comma-separated list to configure multiple webhooks.', 'wpgatsby_settings' ),
'label' => __( 'Builds Webhook URL', 'wpgatsby_settings' ),
'desc' => __( 'Use a comma-separated list to configure multiple webhooks.', 'wpgatsby_settings' ),
'placeholder' => __( 'https://', 'wpgatsby_settings' ),
'type' => 'text',
'sanitize_callback' => function ( $input ) {
Expand All @@ -224,13 +224,12 @@ function get_settings_fields() {
[
'name' => 'enable_gatsby_preview',
'label' => __( 'Enable Gatsby Preview?', 'wpgatsby_settings' ),
'desc' => __( 'Yes', 'wpgatsby_settings' ),
'desc' => __( 'Yes, allow Gatsby to take over WordPress previews.', 'wpgatsby_settings' ),
'type' => 'checkbox',
],
[
'name' => 'preview_instance_url',
'label' => __( 'Preview Instance', 'wpgatsby_settings' ),
'desc' => __( 'Enter your Gatsby Preview instance URL. Must begin with http:// or https://.', 'wpgatsby_settings' ),
'label' => __( 'Preview Frontend URL', 'wpgatsby_settings' ),
'placeholder' => __( 'https://', 'wpgatsby_settings' ),
'type' => 'text',
'sanitize_callback' => function ( $input ) {
Expand All @@ -239,8 +238,24 @@ function get_settings_fields() {
],
[
'name' => 'preview_api_webhook',
'label' => __( 'Preview Webhook', 'wpgatsby_settings' ),
'desc' => __( 'Enter your Gatsby Preview Webhook URL. Must begin with http:// or https://. Use a comma-separated list to configure multiple webhooks.', 'wpgatsby_settings' ),
'label' => __( 'Preview Webhook URL', 'wpgatsby_settings' ),
'desc' => __( 'Use a comma-separated list to configure multiple webhooks.', 'wpgatsby_settings' ),
'placeholder' => __( 'https://', 'wpgatsby_settings' ),
'type' => 'text',
'sanitize_callback' => function ( $input ) {
return $this->sanitize_url_field( $input );
},
],
[
'name' => 'use_gatsby_content_sync',
'label' => __( 'Use Gatsby Content Sync? (BETA feature)', 'wpgatsby_settings' ),
'desc' => __( 'Yes, I want to use Gatsby Cloud to redirect admins to the right preview page. (BETA but recommended)', 'wpgatsby_settings' ),
'type' => 'checkbox',
],
[
'name' => 'gatsby_content_sync_url',
'label' => __( 'Gatsby Content Sync URL', 'wpgatsby_settings' ),
'desc' => __( 'Find this URL in your Gatsbyjs.com dashboard settings.', 'wpgatsby_settings' ),
'placeholder' => __( 'https://', 'wpgatsby_settings' ),
'type' => 'text',
'sanitize_callback' => function ( $input ) {
Expand Down
15 changes: 15 additions & 0 deletions src/Admin/includes/preview-template.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use WPGatsby\Admin\Preview;

$preview_url = Preview::get_gatsby_preview_instance_url();
$use_gatsby_content_sync = Preview::get_setting( 'use_gatsby_content_sync' );
?>

<html lang="en">
Expand All @@ -18,6 +19,20 @@
</style>

<script>
<?php
if ( $use_gatsby_content_sync === 'on' ) {
// Gutenberg seems to be using the preview_post_link filter so we may never reach this code path now. In the past Gutenberg did not respect this filter so there was no way to change the preview link.
// Leaving this here incase a user somehow makes it to the preview template when they should be at the loader.
// Redirecting via JS because the page headers have already been set by the time we get into this template so PHP wont redirect.
global $post;

$gatsby_content_sync_url = Preview::get_gatsby_content_sync_url_for_post(
$post
);

echo 'window.location.replace("'. $gatsby_content_sync_url .'")';
}
?>
<?php Preview::print_initial_preview_template_state_js(); ?>
<?php Preview::printFileContents( 'assets/dist/preview-client.js' ); ?>
</script>
Expand Down

0 comments on commit 15dc1a7

Please sign in to comment.