Skip to content

Commit

Permalink
Add a beta-test of using Playground for theme previews (#118)
Browse files Browse the repository at this point in the history
  • Loading branch information
dd32 committed Jun 28, 2024
1 parent d65d0f2 commit cc6fa38
Show file tree
Hide file tree
Showing 13 changed files with 391 additions and 78 deletions.
1 change: 1 addition & 0 deletions source/wp-content/themes/wporg-themes-2024/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
require_once( __DIR__ . '/src/theme-downloads/index.php' );
require_once( __DIR__ . '/src/theme-patterns/index.php' );
require_once( __DIR__ . '/src/theme-previewer/index.php' );
require_once( __DIR__ . '/src/theme-previewer-settings/index.php' );
require_once( __DIR__ . '/src/theme-settings/index.php' );
require_once( __DIR__ . '/src/theme-status-notice/index.php' );
require_once( __DIR__ . '/src/theme-style-variations/index.php' );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ function get_meta_block_value( $args, $block ) {
'<strong>' . $active_installs . '</strong>'
);
case 'preview-url':
return esc_url( untrailingslashit( get_permalink( $p ) ) . '/preview/' );
$playground = isset( $_REQUEST['playground-preview'] ) ? '?playground-preview=1' : '';

return esc_url( untrailingslashit( get_permalink( $p ) ) . '/preview/' . $playground );
case 'download-url':
return esc_url( $theme->download_link );
case 'download-text':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<!-- /wp:group -->

<!-- wp:wporg/theme-settings /-->
<!-- wp:wporg/theme-previewer-settings /-->
</div>
<!-- /wp:column -->

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "wporg/theme-previewer-settings",
"version": "0.1.0",
"title": "Theme Settings",
"category": "design",
"icon": "",
"description": "Settings for the theme owner.",
"textdomain": "wporg",
"supports": {
"html": false
},
"usesContext": [ "postId", "postType" ],
"editorScript": "file:./index.js",
"style": "file:./style-index.css",
"viewScriptModule": "file:./view.js",
"render": "file:./render.php"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* WordPress dependencies
*/
import { registerBlockType } from '@wordpress/blocks';

/**
* Internal dependencies
*/
import Edit from '../utils/dynamic-edit';
import metadata from './block.json';
import './style.scss';

registerBlockType( metadata.name, {
edit: Edit,
save: () => null,
} );
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
/**
* Block Name: Theme Settings
* Description: Settings for the theme owner.
*
* @package wporg
*/

namespace WordPressdotorg\Theme\Theme_Directory_2024\Theme_Previewer_Settings_Block;

defined( 'WPINC' ) || die();

add_action( 'init', __NAMESPACE__ . '\init' );

/**
* Register the block.
*/
function init() {
register_block_type( __DIR__ . '/../../build/theme-previewer-settings' );
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php

if ( ! $block->context['postId'] ) {
return '';
}

$theme_post = get_post( $block->context['postId'] );

// Not blueprint enabled, or the user is not an owner/admin.
if (
(
! $theme_post->preview_blueprint &&
empty( $_GET['playground-preview'] )
) || (
! current_user_can( 'edit_post', $theme_post->ID ) &&
get_current_user_id() !== $theme_post->post_author
)
) {
return;
}

// Enqueue this script, so that it's available for the interactivity view script.
wp_enqueue_script( 'wp-api-fetch' );

// Default blueprint is just install the theme & login.
$blueprint = [
'steps' => [
[
'step' => 'installTheme',
'themeZipFile' => [
'resource' => 'wordpress.org/themes',
'slug' => $theme_post->post_name,
],
],
[
'step' => 'login',
'username' => 'admin',
'password' => 'password',
],
]
];

if ( $theme_post->preview_blueprint ) {
$blueprint = $theme_post->preview_blueprint;
}

$blueprint = wp_json_encode( $blueprint, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );

// Initial state to pass to Interactivity API.
$init_state = [
'slug' => $theme_post->post_name,
'blueprint' => $blueprint,
'labels' => [
'invalid' => __( 'Invalid Blueprint provided, verify the JSON validates.', 'wporg-themes' ),
'success' => __( 'Blueprint saved correctly!', 'wporg-themes' ),
'error' => __( 'Error updating the Blueprint. Please try again.', 'wporg-themes' ),
],
];
$encoded_state = wp_json_encode( $init_state );

?>
<div
<?php echo get_block_wrapper_attributes(); // phpcs:ignore ?>
data-wp-interactive="wporg/themes/theme-previewer-settings"
data-wp-context="<?php echo esc_attr( $encoded_state ); ?>"
>
<h2><?php _e( 'Theme Preview options', 'wporg-themes' ) ?></h2>
<p class="wporg-theme-settings__description">
This is a work in progress, and not currently fully supported.<br>
Provide a Playground Blueprint to of your theme to be used for previews.<br>
The <a href="https://playground.wordpress.net/builder/builder.html#<?php echo urlencode( $blueprint ) ?>">Blueprint Builder</a> can be used to validate your JSON.
</p>
<form data-wp-on--submit="actions.onSubmit" method="POST">
<div class="wporg-theme-settings__blueprint-field">
<textarea
id="wporg-theme-settings-blueprint"
aria-describedby="wporg-theme-settings__blueprint-help"
name="blueprint"
rows="10"
data-wp-text="context.blueprint"
data-wp-on--keydown="actions.onChange"
><?php esc_textarea( $blueprint ); ?></textarea>
</div>
<div class="wporg-theme-settings__button wp-block-button is-small">
<button
class="wp-block-button__link wp-element-button"
data-wp-bind--aria-disabled="state.isSubmitting"
>
<?php esc_html_e( 'Save', 'wporg-themes' ); ?>
</button>
<div aria-live="polite" aria-atomic="true">
<span data-wp-text="state.resultMessage"></span>
</div>
</div>
</form>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.wp-block-wporg-theme-previewer-settings {
--wp--custom--form--border--width: 1px;
--wp--custom--form--border--color: var(--wp--preset--color--charcoal-5);

margin-top: var(--wp--preset--spacing--40);

h2 {
margin: 0;
}

> *,
form > * {
margin: 0;
}

> * + * {
margin-top: var(--wp--preset--spacing--20);
}

.wporg-theme-settings__button {
display: flex;
margin-top: var(--wp--preset--spacing--20);
gap: var(--wp--preset--spacing--20);
align-items: center;

[aria-disabled="true"] {
pointer-events: none;
--wp--custom--button--color--background: var(--wp--preset--color--charcoal-4);
}
}
}

.wporg-theme-settings_blueprint-field {
display: flex;
flex-direction: column;
gap: calc(var(--wp--preset--spacing--10) * 0.6);
font-family: monospace;

input {
width: 100%;

&:focus {
outline: 1.5px solid var(--wp--preset--color--blueberry-1);
outline-offset: -1.5px;
border-color: transparent;
}
}

.wporg-theme-settings__form-help {
margin: 0;
font-size: var(--wp--preset--font-size--small);
line-height: var(--wp--custom--body--small--typography--line-height);
color: var(--wp--preset--color--charcoal-4);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* WordPress dependencies
*/
import { getContext, store } from '@wordpress/interactivity';

const { state } = store( 'wporg/themes/theme-previewer-settings', {
state: {
isError: false,
isSuccess: false,
isInvalid: false,
isSubmitting: false,
get resultMessage() {
const { labels } = getContext();
if ( state.isInvalid ) {
return labels.invalid;
}
if ( state.isSuccess ) {
return labels.success;
}
if ( state.isError ) {
return labels.error;
}
return '';
},
},
actions: {
onChange() {
state.isSuccess = false;
state.isError = false;
state.isInvalid = false;
},
*onSubmit( event ) {
event.preventDefault();
const context = getContext();
const { slug } = context;
const newBlueprint = event.target.elements.blueprint?.value || '';

try {
const decoded = JSON.parse( newBlueprint );
if ( typeof decoded !== 'object' || ! decoded.steps ) {
throw new Exception( 'Invalid blueprint.' );
}
} catch( error ) {
state.isInvalid = true;
return;
}

state.isSubmitting = true;
try {
const response = yield wp.apiFetch( {
path: '/themes/v1/preview-blueprint/' + slug,
method: 'POST',
data: { blueprint: newBlueprint },
} );
if ( typeof response.steps === 'undefined' ) {
throw new Error( 'Invalid response from API.' );
}
state.isSuccess = true;
state.blueprint = newBlueprint
} catch ( error ) {
state.isError = true;
}
state.isSubmitting = false;
},
},
} );
Loading

0 comments on commit cc6fa38

Please sign in to comment.