用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/wpgaurav/WordPress-skills --skill wp-block-quick命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Author Bricks Builder (WordPress) layouts, templates, and full designs as paste-ready JSON. Use for any Bricks task — sections, pages, headers/footers, query loops, ACF/dynamic data, faceted filters, conditions, interactions/animations, popups, WooCommerce templates, custom elements, or hooks. Verified against Bricks 2.3.6 source.
Use when pushing content, docs, posts, changelogs, or other updates to Fluent Community spaces through the Fluent Community REST API.
Generate or edit design for WordPress Gutenberg blocks using Greenshift/GreenLight plugin. Convert any data to wordpress blocks or convert greenshift blocks back to html + css + js. Use when user asks to create design with Greenshift or Greenlight blocks for wordpress site, convert anything to wordpress blocks or build charts in content. Triggers on keywords: wordpress, gutenberg, greenshift, greenlight, convert to wordpress, convert greenshift blocks to vanilla html, build chart.
基于 SOC 职业分类
正在显示 SKILL.md
| name | wp-block-quick |
| description | Build custom Gutenberg blocks using the WordPress Block API and @wordpress/scripts. |
Build custom Gutenberg blocks using the WordPress Block API and @wordpress/scripts.
/CLAUDE/context/wordpress-dev.md for standardsRenders same content in editor and frontend from saved markup.
Renders via PHP callback, content generated server-side.
Uses @wordpress/interactivity API for frontend interactivity without full React.
# Create new block plugin
npx @wordpress/create-block my-block --namespace gt
# Create dynamic block
npx @wordpress/create-block my-dynamic-block --namespace gt --variant dynamic
# Create interactive block
npx @wordpress/create-block my-interactive-block --namespace gt --template @wordpress/create-block-interactive-template
# Initialize npm
npm init -y
# Install dependencies
npm install @wordpress/scripts --save-dev
# Add to package.json scripts
{
"scripts": {
"build": "wp-scripts build",
"start": "wp-scripts start",
"format": "wp-scripts format",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"packages-update": "wp-scripts packages-update"
}
}
my-block/
├── my-block.php # Plugin file / block registration
├── package.json
├── src/
│ ├── block.json # Block metadata
│ ├── index.js # Block registration
│ ├── edit.js # Editor component
│ ├── save.js # Save component
│ ├── style.scss # Frontend + editor styles
│ ├── editor.scss # Editor-only styles
│ └── view.js # Frontend interactivity (optional)
└── build/ # Compiled output (gitignored)
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "gt/my-block",
"version": "1.0.0",
"title": "My Block",
"category": "widgets",
"icon": "smiley",
"description": "A custom block that does something useful.",
"keywords": ["custom", "example"],
"textdomain": "my-block",
"attributes": {
"content": {
"type": "string",
"source":
<?php
/**
* Plugin Name: My Block
* Description: A custom Gutenberg block.
* Version: 1.0.0
* Author: Gaurav Tiwari
* Text Domain: my-block
*
* @package MyBlock
*/
defined( 'ABSPATH' ) || exit;
/**
* Register block.
*/
function gt_my_block_init() {
register_block_type( __DIR__ . '/build' );
}
add_action( 'init', 'gt_my_block_init' );
<?php
/**
* Register dynamic block.
*/
function gt_my_block_init() {
register_block_type(
__DIR__ . '/build',
array(
'render_callback' => 'gt_my_block_render',
)
);
}
add_action( 'init', 'gt_my_block_init' );
/**
* Render callback.
*
* @param array $attributes Block attributes.
* @param string $content Block content.
* @param WP_Block $block Block instance.
* @return string
*/
function gt_my_block_render( $attributes, $content, $block ) {
// Get block wrapper attributes.
$wrapper_attributes = get_block_wrapper_attributes(
array(
'class' => 'gt-my-block',
)
);
// Build output.
$output = sprintf(
'<div %1$s><p>%2$s</p></div>',
$wrapper_attributes,
esc_html( $attributes['content'] ?? '' )
);
return $output;
}
<?php
/**
* Block render template.
*
* @var array $attributes Block attributes.
* @var string $content Block content.
* @var WP_Block $block Block instance.
*
* @package MyBlock
*/
defined( 'ABSPATH' ) || exit;
$content_text = $attributes['content'] ?? '';
$show_icon = $attributes['showIcon'] ?? true;
?>
<div <?php echo get_block_wrapper_attributes( array( 'class' => 'gt-my-block' ) ); ?>>
<?php if ( $show_icon ) : ?>
<span class="gt-my-block__icon" aria-hidden="true">★</span>
<?php endif; ?>
<p class="gt-my-block__content"><?php echo esc_html( $content_text ); ?></p>
</div>
/**
* Block registration.
*/
import { registerBlockType } from '@wordpress/blocks';
import './style.scss';
import Edit from './edit';
import save from './save';
import metadata from './block.json';
registerBlockType( metadata.name, {
edit: Edit,
save,
} );
/**
* Editor component.
*/
import { __ } from '@wordpress/i18n';
import {
useBlockProps,
RichText,
BlockControls,
AlignmentToolbar,
InspectorControls,
} from '@wordpress/block-editor';
import {
PanelBody,
ToggleControl,
RangeControl,
} from '@wordpress/components';
import './editor.scss';
export default function Edit( { attributes, setAttributes } ) {
const { content, alignment, showIcon, iconSize } = attributes;
const blockProps = useBlockProps( {
className: `has-text-align-${ alignment }`,
} );
return (
<>
<BlockControls>
<AlignmentToolbar
value={ alignment }
onChange={ ( newAlignment ) =>
setAttributes( { alignment: newAlignment } )
}
/>
</BlockControls>
<InspectorControls>
< = ( '', '' ) }>
setAttributes( { showIcon: value } )
}
/>
{ showIcon && (
setAttributes( { iconSize: value } )
}
min={ 16 }
max={ 64 }
/>
) }
{ showIcon && (
★
) }
setAttributes( { content: value } )
}
placeholder={ __( 'Enter text…', 'my-block' ) }
/>
);
}
/**
* Save component.
*/
import { useBlockProps, RichText } from '@wordpress/block-editor';
export default function save( { attributes } ) {
const { content, alignment, showIcon, iconSize } = attributes;
const blockProps = useBlockProps.save( {
className: `has-text-align-${ alignment }`,
} );
return (
<div { ...blockProps }>
{ showIcon && (
<span
className="gt-my-block__icon"
style={ { fontSize: iconSize } }
aria-hidden="true"
>
★
</span>
) }
<RichText.Content
tagName="p"
className="gt-my-block__content"
value={ content }
/>
</div>
);
}
import { useBlockProps, InnerBlocks } from '@wordpress/block-editor';
const ALLOWED_BLOCKS = [ 'core/paragraph', 'core/heading', 'core/image' ];
const TEMPLATE = [
[ 'core/heading', { placeholder: 'Enter heading...' } ],
[ 'core/paragraph', { placeholder: 'Enter content...' } ],
];
export default function Edit() {
const blockProps = useBlockProps();
return (
<div { ...blockProps }>
<InnerBlocks
allowedBlocks={ ALLOWED_BLOCKS }
template={ TEMPLATE }
templateLock={ false }
/>
</div>
);
}
export function save() {
const blockProps = useBlockProps.save();
return (
<div { ...blockProps }>
);
}
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
export default function Edit( { attributes } ) {
const { postId } = attributes;
const post = useSelect(
( select ) => {
if ( ! postId ) return null;
return select( coreStore ).getEntityRecord(
'postType',
'post',
postId
);
},
[ postId ]
);
const isLoading = useSelect(
( select ) => {
if ( ! postId ) return false;
return select( coreStore ).isResolving( 'getEntityRecord', [
'postType',
'post',
postId,
] );
},
[ postId ]
);
if ( isLoading ) {
return <p>Loading...</p>;
}
return (
< { () }>
{ post ? post.title.rendered : 'No post selected' }
);
}
import { useState } from '@wordpress/element';
import { ComboboxControl } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { store as coreStore } from '@wordpress/core-data';
function PostSelector( { value, onChange } ) {
const [ search, setSearch ] = useState( '' );
const posts = useSelect(
( select ) => {
return select( coreStore ).getEntityRecords( 'postType', 'post', {
per_page: 10,
search,
_fields: 'id,title',
} );
},
[ search ]
);
const options = ( posts || [] ).map( ( post ) => ( {
value: post.id,
label: post.title.rendered,
} ) );
return (
<ComboboxControl
label="Select Post"
value={ }
= }
= }
= }
/>
);
}
/**
* Frontend interactivity.
*/
import { store, getContext } from '@wordpress/interactivity';
store( 'gt/my-block', {
state: {
get isOpen() {
const context = getContext();
return context.isOpen;
},
},
actions: {
toggle() {
const context = getContext();
context.isOpen = ! context.isOpen;
},
open() {
const context = getContext();
context.isOpen = true;
},
close() {
const context = getContext();
context.isOpen = false;
},
},
callbacks: {
onToggle() {
const context = getContext();
console.log( 'Toggled:', context.isOpen );
},
},
} );
<?php
/**
* Interactive block render.
*/
$unique_id = wp_unique_id( 'gt-accordion-' );
?>
<div
<?php echo get_block_wrapper_attributes(); ?>
data-wp-interactive="gt/my-block"
<?php echo wp_interactivity_data_wp_context( array( 'isOpen' => false ) ); ?>
>
<button
data-wp-on--click="actions.toggle"
data-wp-bind--aria-expanded="state.isOpen"
aria-controls="<?php echo esc_attr( $unique_id ); ?>"
>
<?php esc_html_e( 'Toggle Content', 'my-block' ); ?>
</button>
<div
id="<?php echo esc_attr( $unique_id ); ?>"
data-wp-bind--hidden="!state.isOpen"
data-wp-watch="callbacks.onToggle"
>
<?php echo wp_kses_post( $content ); ?>
</div>
</div>
.wp-block-gt-my-block {
padding: 1.5rem;
border: 1px solid #ddd;
border-radius: 4px;
&__icon {
display: inline-block;
margin-right: 0.5rem;
color: var(--wp--preset--color--accent, #0073aa);
}
&__content {
margin: 0;
}
// Alignment variations
&.has-text-align-center {
text-align: center;
}
&.has-text-align-right {
text-align: right;
}
// Support for color settings
&.has-background {
padding: 2rem;
}
}
.wp-block-gt-my-block {
// Editor-specific styles
outline: 2px dashed transparent;
transition: outline-color 0.2s;
&:focus-within {
outline-color: var(--wp-admin-theme-color, #007cba);
}
// Placeholder styling
.components-placeholder {
margin: 0;
}
}
import { registerBlockVariation } from '@wordpress/blocks';
registerBlockVariation( 'core/group', {
name: 'gt-card',
title: 'Card',
description: 'A card container with shadow and padding.',
attributes: {
className: 'is-style-gt-card',
style: {
spacing: {
padding: {
top: 'var:preset|spacing|40',
right: 'var:preset|spacing|40',
bottom: 'var:preset|spacing|40',
left: 'var:preset|spacing|40',
},
},
border: {
radius: '8px',
},
},
backgroundColor: 'base',
},
isActive: ( blockAttributes ) =>
blockAttributes.className?.includes( 'is-style-gt-card' ),
scope: [ 'inserter', 'transform' ],
icon: 'id-alt',
} );
import { createBlock } from '@wordpress/blocks';
const transforms = {
from: [
{
type: 'block',
blocks: [ 'core/paragraph' ],
transform: ( { content } ) => {
return createBlock( 'gt/my-block', {
content,
} );
},
},
{
type: 'shortcode',
tag: 'my_shortcode',
transform: ( { named: { content } } ) => {
return createBlock( 'gt/my-block', {
content: content || '',
} );
},
},
],
to: [
{
type: 'block',
blocks: [ 'core/paragraph' ],
transform: ( { content } ) => {
return createBlock( 'core/paragraph', {
content,
} );
},
},
],
};
// Add to block registration
registerBlockType( metadata.name, {
edit: Edit,
save,
transforms,
} );
const deprecated = [
{
attributes: {
content: {
type: 'string',
source: 'html',
selector: '.my-block-content', // Old selector
},
},
save( { attributes } ) {
return (
<div className="my-old-block">
<p className="my-block-content">{ attributes.content }</p>
</div>
);
},
migrate( attributes ) {
return {
...attributes,
// Transform old attributes to new format
};
},
},
];
registerBlockType( metadata.name, {
edit: Edit,
save,
deprecated,
} );
/**
* @jest-environment jsdom
*/
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import Edit from '../edit';
// Mock WordPress packages
jest.mock( '@wordpress/block-editor', () => ( {
useBlockProps: () => ( { className: 'test-block' } ),
RichText: ( { value, onChange, placeholder } ) => (
<input
value={ value }
onChange={ ( e ) => onChange( e.target.value ) }
placeholder={ placeholder }
/>
),
InspectorControls: ( { children } ) => <div>{ children }</div>,
BlockControls: ( { children } ) => <div>{ children }</div>,
} ) );
describe( 'Edit component', () => {
const defaultAttributes = {
content: ,
: ,
: ,
: ,
};
( , {
setAttributes = jest.();
(
);
( screen.( ) ).();
} );
( , () => {
setAttributes = jest.();
user = userEvent.();
(
);
user.( screen.( ), );
( setAttributes ).();
} );
} );
# Development (watch mode)
npm start
# Production build
npm run build
# Lint JavaScript
npm run lint:js
# Lint CSS
npm run lint:css
# Format code
npm run format
# Update WordPress packages
npm run packages-update
# Create production zip
npm run plugin-zip