This commit is contained in:
punitverma123 2024-09-06 18:34:40 +05:30
parent 50ccbcb373
commit d1697a6bc6
24 changed files with 19961 additions and 0 deletions

3
.gitignore vendored
View file

@ -128,3 +128,6 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*

/vendor/
/build

View file

@ -0,0 +1,106 @@
<?php

/**
* Plugin Name: Block editor for playground blueprint
* Description: Design playground blueprints with a specialized block editor interface in WordPress.
* Version: 1.0.0
* Requires PHP: 7.4
* Author: Lubus
* Author URI: https://lubus.in/
* Contributor: Lubus, https://lubus.in/
* Text Domain: block-editor-for-playground-blueprint
*
* @package block-editor-for-playground-blueprint
*/

namespace Lubus\BlockEditorForPlaygroundBlueprint;

use Lubus\Admin\BlockEditorForPlaygroundBlueprint\BlueprintPostType;
use Lubus\Admin\BlockEditorForPlaygroundBlueprint\BlueprintSteps;
use Lubus\Admin\BlockEditorForPlaygroundBlueprint\EnqueueScripts;

defined('ABSPATH') || exit;

require_once 'vendor/autoload.php';
require_once 'inc/functions.php';

if (!class_exists('BlockEditorForPlaygroundBlueprint')) {

/**
* Block editor for playground blueprint Main Class
*/
class BlockEditorForPlaygroundBlueprint
{
/**
* The single instance of the class.
*
* @var BlockEditorForPlaygroundBlueprint
*/
protected static $_instance = null;

/**
* Singleton instance method.
*
* @return self
*/
public static function instance()
{
if (is_null(self::$_instance)) {
self::$_instance = new self();
}
return self::$_instance;
}

/**
* Constructor to initialize the plugin.
*/
public function __construct()
{
$this->setup_constants();
$this->bootstrap();
}

/**
* Setup plugin constants.
*/
private function setup_constants()
{
// Plugin version.
if (!defined('BEPB_VERSION')) {
define('BEPB_VERSION', '0.1.0');
}

// Plugin Root File.
if (!defined('BEPB_PLUGIN_FILE')) {
define('BEPB_PLUGIN_FILE', __FILE__);
}

// Plugin Folder Path.
if (!defined('BEPB_PLUGIN_DIR')) {
define('BEPB_PLUGIN_DIR', plugin_dir_path(BEPB_PLUGIN_FILE));
}

// Plugin Folder URL.
if (!defined('BEPB_PLUGIN_URL')) {
define('BEPB_PLUGIN_URL', plugin_dir_url(BEPB_PLUGIN_FILE));
}

// Plugin Basename aka: "block-editor-for-playground-blueprint/block-editor-playground-blueprint.php".
if (!defined('BEPB_PLUGIN_BASENAME')) {
define('BEPB_PLUGIN_BASENAME', plugin_basename(BEPB_PLUGIN_FILE));
}
}

/**
* Bootstraps the plugin.
*/
private function bootstrap()
{
new BlueprintPostType();
new BlueprintSteps();
new EnqueueScripts();
}
}
}

return BlockEditorForPlaygroundBlueprint::instance();

15
composer.json Normal file
View file

@ -0,0 +1,15 @@
{
"name": "lubus/block-editor-for-playground-blueprint",
"description": "Design playground blueprints with a specialized block editor interface in WordPress.",
"autoload": {
"classmap": [
"inc/"
]
},
"authors": [
{
"name": "lubus"
}
],
"require": {}
}

18
composer.lock generated Normal file
View file

@ -0,0 +1,18 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "512d1fc7cf86404d62e199ad668cfb65",
"packages": [],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.6.0"
}

View file

@ -0,0 +1,67 @@
<?php

/**
* This class handles registering and enqueueing scripts and styles.
*
* @package wordpress-popup-builder
*/

namespace Lubus\Admin\BlockEditorForPlaygroundBlueprint;

class EnqueueScripts
{
/**
* Constructor to initialize WordPress hooks.
*/
public function __construct()
{
add_action('enqueue_block_editor_assets', [$this, 'enqueue_editor_scripts']);
}

/**
* Enqueues scripts and styles for the block editor based on a specific post type.
*/
public function enqueue_editor_scripts()
{
$screen = get_current_screen();

// Only enqueue scripts/styles for the 'blueprint' post type in the editor
if ('blueprint' !== $screen->post_type) {
return;
}

$this->enqueue_editor_js_scripts();
}

/**
* Enqueues the editor-specific js scripts.
*/
private function enqueue_editor_js_scripts()
{
$assetFile = $this->get_asset_file();

wp_enqueue_script(
'blueprint-editor',
BEPB_PLUGIN_URL . 'build/settings.js',
$assetFile['dependencies'],
$assetFile['version'],
true
);
}

/**
* Retrieves the asset file containing dependencies and version information.
*
* @return array|false The asset file array or false on failure.
*/
private function get_asset_file()
{
$assetFilePath = BEPB_PLUGIN_DIR . 'build/settings.asset.php';

if (file_exists($assetFilePath)) {
return require $assetFilePath;
}

return false;
}
}

View file

@ -0,0 +1,60 @@
<?php

/**
* This class defines a custom post type for creating and managing blueprint.
*
* @package block-editor-for-playground-blueprint
*/

namespace Lubus\Admin\BlockEditorForPlaygroundBlueprint;

class BlueprintPostType
{
/**
* Construct that hooks into WordPress to initialize the post type and add custom columns.
*/
public function __construct()
{
add_action('init', [$this, 'register_blueprint_post_type']);
}

/**
* Registers the 'blueprint' post type with necessary arguments and labels.
*/
public function register_blueprint_post_type()
{
$labels = [
'name' => __('Blueprints'),
'singular_name' => __('Blueprint'),
'menu_name' => __('Blueprints'),
'name_admin_bar' => __('Blueprint'),
'add_new' => __('Add New Blueprint', 'blueprint'),
'add_new_item' => __('Add New Blueprint'),
'new_item' => __('New Blueprint'),
'edit_item' => __('Edit Blueprint'),
'view_item' => __('View Blueprint'),
'all_items' => __('All Blueprints'),
'search_items' => __('Search Blueprints'),
'parent_item_colon' => __('Parent Blueprints:'),
'not_found' => __('No blueprints found.'),
'not_found_in_trash' => __('No blueprints found in Trash.')
];

$args = [
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'show_in_rest' => true,
'query_var' => true,
'rewrite' => ['slug' => 'blueprint'],
'has_archive' => false,
'hierarchical' => false,
'menu_icon' => 'dashicons-format-aside',
'supports' => ['title', 'author', 'editor'],
];

register_post_type('blueprint', $args);
}
}

View file

@ -0,0 +1,29 @@
<?php

/**
* This class defines a custom blueprint steps.
*
* @package block-editor-for-playground-blueprint
*/

namespace Lubus\Admin\BlockEditorForPlaygroundBlueprint;

class BlueprintSteps
{
/**
* Construct that hooks into WordPress to initialize a blueprint steps.
*/
public function __construct()
{
add_action('init', [$this, 'register_blueprint_steps']);
}

/**
* Registers the 'blueprint steps' with necessary arguments and labels.
*/
public function register_blueprint_steps()
{
register_block_type(BEPB_PLUGIN_DIR . 'build/steps/login');
register_block_type(BEPB_PLUGIN_DIR . 'build/steps/install-plugin');
}
}

43
inc/functions.php Normal file
View file

@ -0,0 +1,43 @@
<?php

/**
* Filters the list of allowed block types in the block editor.
*
* This function restricts the available block types to Heading, List, Image, and Paragraph only.
*
* @param array|bool $allowed_block_types Array of block type slugs, or boolean to enable/disable all.
* @param object $block_editor_context The current block editor context.
*
* @return array The array of allowed block types.
*/
function example_allowed_block_types($allowed_block_types, $block_editor_context)
{

if (get_current_screen()->post_type == 'blueprint') {
$allowed_block_types = [
'lubus/login',
'lubus/install-plugin',
];

return $allowed_block_types;
};

return true;
}
add_filter('allowed_block_types_all', 'example_allowed_block_types', 10000, 2);

function add_new_block_category($block_categories, $block_editor_context)
{
// Unshift the new category to the beginning of the array
array_unshift(
$block_categories,
[
'slug' => 'steps',
'title' => esc_html__('Steps', 'text-domain'),
]
);

return $block_categories;
}

add_filter('block_categories_all', 'add_new_block_category', 10, 2);

19038
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

20
package.json Normal file
View file

@ -0,0 +1,20 @@
{
"name": "block-editor-for-playground-blueprint",
"version": "1.0.0",
"description": "Design playground blueprints with a specialized block editor interface in WordPress.",
"main": "build/index.js",
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "lubus",
"license": "ISC",
"devDependencies": {
"@wordpress/scripts": "^28.6.0"
},
"dependencies": {
"@wordpress/blocks": "^13.7.0",
"@wordpress/icons": "^10.6.0"
}
}

134
src/settings/index.js Normal file
View file

@ -0,0 +1,134 @@
/**
* WordPress dependencies.
*/
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';
import { PluginDocumentSettingPanel } from '@wordpress/editor';
import { __experimentalInspectorPopoverHeader as InspectorPopoverHeader } from '@wordpress/block-editor';
import {
Dropdown,
Button,
SelectControl,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
__experimentalText as Text
} from '@wordpress/components';
import { copy, download, globe } from '@wordpress/icons';
import { useSelect } from '@wordpress/data';

/**
* PHP and WordPress version options for dropdowns.
*/
const PHP_VERSIONS = [
{ label: 'Latest', value: 'latest' },
{ label: '8.2', value: '8.2' },
{ label: '8.1', value: '8.1' },
{ label: '8.0', value: '8.0' },
{ label: '7.4', value: '7.4' },
];

const WP_VERSIONS = [
{ label: 'Latest', value: 'latest' },
{ label: '6.2', value: '6.2' },
{ label: '6.1', value: '6.1' },
{ label: '6.0', value: '6.0' },
{ label: '5.6', value: '5.6' },
];

/**
* Reusable Dropdown component for version control.
* @param {string} label - The label for the dropdown.
* @param {Array} versions - List of versions for the dropdown.
* @param {string} defaultValue - The default selected version.
*/
const DropdownVersionControl = ({ label, versions, defaultValue }) => (
<HStack justify='left'>
<Text style={{ width: '30%' }}>{label}</Text>
<Dropdown
popoverProps={{
placement: 'left-start',
offset: 118,
shift: true,
}}
renderToggle={({ isOpen, onToggle }) => (
<Button
variant="tertiary"
onClick={onToggle}
aria-expanded={isOpen}
>
{defaultValue}
</Button>
)}
renderContent={({ onClose }) => (
<VStack style={{ minWidth: '240px', margin: '8px' }} spacing={0}>
<InspectorPopoverHeader
title={__(label)}
onClose={onClose}
/>
<SelectControl
label={label}
hideLabelFromVision
value={defaultValue}
options={versions}
onChange={() => { }} // Placeholder for actual change handling
/>
</VStack>
)}
/>
</HStack>
);

/**
* Main component for displaying version control in post status info.
*/
function BlueprintVersionControl() {
// const playgroundBase = "https://playground.wordpress.net/#";

// const blocks = useSelect((select) => select('core/block-editor').getBlocks(), []);

// const handleDownloadClick = () => {
// const blockAttributes = blocks.map(block => ({
// name: block.name,
// attributes: block.attributes,
// }));
// console.log(blockAttributes);
// };

return (
<PluginDocumentSettingPanel name='playground-settings' title='Playground Settings'>
<HStack justify='left'>
<Button variant="secondary" icon={globe} href={''} target='_new'>
</Button>
<Button
variant="secondary"
icon={copy}
onClick={() => { }}>
</Button>
<Button
variant="secondary"
icon={download}
href={''}
onClick={handleDownloadClick}
>
</Button>
</HStack>
<VStack spacing={1} style={{ width: '100%' }}>
<DropdownVersionControl
label="PHP version"
versions={PHP_VERSIONS}
defaultValue="8.0"
/>
<DropdownVersionControl
label="WP version"
versions={WP_VERSIONS}
defaultValue="Latest"
/>
</VStack>
</PluginDocumentSettingPanel>
);
};

/**
* Registers the 'blueprint-version-control' plugin.
*/
registerPlugin('blueprint-version-control', { render: BlueprintVersionControl });

View file

@ -0,0 +1,52 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "lubus/install-plugin",
"version": "0.1.0",
"title": "Install Plugin",
"category": "steps",
"icon": "admin-plugins",
"description": "Installs a WordPress plugin in the Playground",
"example": {},
"supports": {
"html": false
},
"attributes": {
"step": {
"type": "string",
"default": "install-plugin"
},
"pluginZipFile": {
"type": "object",
"default": {
"resource": "url",
"url": ""
},
"properties": {
"resource": {
"type": "string",
"enum": [
"url",
"wordpress.org/plugins",
"vfs"
]
}
}
},
"options": {
"type": "object",
"default": {
"activate": true
},
"properties": {
"activate": {
"type": "boolean"
}
}
}
},
"textdomain": "install-plugin",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css"
}

View file

@ -0,0 +1,113 @@
/**
* WordPress dependencies.
*/
import { __ } from '@wordpress/i18n';
import {
InspectorControls,
useBlockProps
} from '@wordpress/block-editor';
import {
PanelBody,
TextControl,
ToggleControl,
__experimentalToggleGroupControl as ToggleGroupControl,
__experimentalToggleGroupControlOption as ToggleGroupControlOption,
} from '@wordpress/components';

/**
* Internal dependencies.
*/
import './editor.scss';

/**
* Edit function for the plugin installation block.
*
* @param {Object} props Component properties.
* @return {Element} Element to render.
*/
export default function Edit({ attributes, setAttributes }) {
const { pluginZipFile, options } = attributes;
const { resource, path, url, slug } = pluginZipFile;
const { activate } = options;

const handleResourceChange = (newResource) => {
let newAttributes = {
resource: newResource
};

// Conditionally add attributes based on the selected resource
if (newResource === 'vfs') {
newAttributes.path = pluginZipFile.path || '';
} else if (newResource === 'url') {
newAttributes.url = pluginZipFile.url || '';
} else if (newResource === 'wordpress.org/plugins') {
newAttributes.slug = pluginZipFile.slug || '';
}

setAttributes({
pluginZipFile: newAttributes
});
};

const handleInputChange = (field, value) => {
setAttributes({
pluginZipFile: {
...pluginZipFile,
[field]: value
}
});
};

return (
<>
<InspectorControls>
<PanelBody title={__('Install Plugin Step', 'install-plugin')}>
<ToggleGroupControl
label="Resource"
value={resource}
isBlock
onChange={handleResourceChange}
>
<ToggleGroupControlOption value="url" label="URL" />
<ToggleGroupControlOption value="wordpress.org/plugins" label="Plugin" />
<ToggleGroupControlOption value="vfs" label="VFS" />
</ToggleGroupControl>

{resource === 'vfs' && (
<TextControl
label={__('Path', 'install-plugin')}
value={path}
onChange={(newPath) => handleInputChange('path', newPath)}
/>
)}
{resource === 'url' && (
<TextControl
label={__('Url', 'install-plugin')}
value={url}
onChange={(newPath) => handleInputChange('url', newPath)}
/>
)}
{resource === 'wordpress.org/plugins' && (
<TextControl
label={__('Slug', 'install-plugin')}
value={slug}
onChange={(newPath) => handleInputChange('slug', newPath)}
/>
)}

<ToggleControl
label="Activate"
checked={activate}
onChange={() => setAttributes({
options: { activate: !activate }
})}
/>
</PanelBody>
</InspectorControls>

<div {...useBlockProps()}>
{__('Install Plugin Step', 'install-plugin')}
</div>
</>
);
}

View file

@ -0,0 +1,9 @@
/**
* The following styles get applied inside the editor only.
*
* Replace them with your own styles or remove the file completely.
*/

.wp-block-create-block-install-plugin {
border: 1px dotted #f00;
}

View file

@ -0,0 +1,40 @@
/**
* Registers a new block provided a unique name and an object defining its behavior.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
import { registerBlockType } from '@wordpress/blocks';

/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* All files containing `style` keyword are bundled together. The code used
* gets applied both to the front of your site and to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './style.scss';

/**
* Internal dependencies
*/
import Edit from './edit';
import save from './save';
import metadata from './block.json';

/**
* Every block starts by registering a new block type definition.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/
*/
registerBlockType(metadata.name, {

/**
* @see ./edit.js
*/
edit: Edit,

/**
* @see ./save.js
*/
save,
});

View file

@ -0,0 +1,24 @@
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
*/
import { useBlockProps } from '@wordpress/block-editor';

/**
* The save function defines the way in which the different attributes should
* be combined into the final markup, which is then serialized by the block
* editor into `post_content`.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save
*
* @return {Element} Element to render.
*/
export default function save() {
return (
<p { ...useBlockProps.save() }>
{ 'Install Plugin Block hello from the saved content!' }
</p>
);
}

View file

@ -0,0 +1,12 @@
/**
* The following styles get applied both on the front of your site
* and in the editor.
*
* Replace them with your own styles or remove the file completely.
*/

.wp-block-create-block-install-plugin {
background-color: #21759b;
color: #fff;
padding: 2px;
}

View file

@ -0,0 +1,31 @@
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "lubus/login",
"version": "0.1.0",
"title": "Login",
"category": "steps",
"description": "Logs in to Playground",
"example": {},
"supports": {
"html": false
},
"attributes": {
"step": {
"type": "string",
"default": "login"
},
"username": {
"type": "string",
"default": ""
},
"password": {
"type": "string",
"default": ""
}
},
"textdomain": "login",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css"
}

54
src/steps/login/edit.js Normal file
View file

@ -0,0 +1,54 @@
/**
* Wordpress dependencies.
*/
import { __ } from '@wordpress/i18n';
import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
import { PanelBody, TextControl} from '@wordpress/components';

/**
* Internal dependencies.
*/
import './editor.scss';

/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @return {Element} Element to render.
*/
export default function Edit({ attributes, setAttributes }) {
const { username, password } = attributes;

return (
<>
<InspectorControls>
<PanelBody title={__('Login Step', 'login')}>
<TextControl
label={__(
'Username',
'login'
)}
value={username || ''}
onChange={(value) =>
setAttributes({ username: value })
}
/>
<TextControl
label={__(
'Password',
'login'
)}
value={password || ''}
onChange={(value) =>
setAttributes({ password: value })
}
/>
</PanelBody>
</InspectorControls>

<p {...useBlockProps()}>
{__('Login Step', 'login')}
</p>
</>
);
}

View file

@ -0,0 +1,9 @@
/**
* The following styles get applied inside the editor only.
*
* Replace them with your own styles or remove the file completely.
*/

.wp-block-create-block-login {
border: 1px dotted #f00;
}

31
src/steps/login/index.js Normal file
View file

@ -0,0 +1,31 @@
/**
* Wordpress dependencies.
*/
import { registerBlockType } from '@wordpress/blocks';
import { login } from '@wordpress/icons';

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

/**
* Every block starts by registering a new block type definition.
*/
registerBlockType(metadata.name, {

icon: login,

/**
* @see ./edit.js
*/
edit: Edit,

/**
* @see ./save.js
*/
save,
});

24
src/steps/login/save.js Normal file
View file

@ -0,0 +1,24 @@
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
*/
import { useBlockProps } from '@wordpress/block-editor';

/**
* The save function defines the way in which the different attributes should
* be combined into the final markup, which is then serialized by the block
* editor into `post_content`.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save
*
* @return {Element} Element to render.
*/
export default function save() {
return (
<p { ...useBlockProps.save() }>
{ 'Login Block hello from the saved content!' }
</p>
);
}

View file

@ -0,0 +1,12 @@
/**
* The following styles get applied both on the front of your site
* and in the editor.
*
* Replace them with your own styles or remove the file completely.
*/

.wp-block-create-block-login {
background-color: #21759b;
color: #fff;
padding: 2px;
}

17
webpack.config.js Normal file
View file

@ -0,0 +1,17 @@
const defaultConfig = require('@wordpress/scripts/config/webpack.config');
const { getWebpackEntryPoints } = require('@wordpress/scripts/utils/config');
const path = require('path');

module.exports = {
...defaultConfig,
entry: {
...getWebpackEntryPoints(),
'settings': './src/settings/index.js',
'steps/install-plugin/index': './src/steps/install-plugin/index.js',
'steps/login/index': './src/steps/login/index.js'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js'
}
};