我正在尝试将为 WordPress 创建的静态古腾堡块转换为动态块。我已经寻找其他解决方案,但没有成功。这个问题(将使用@wordpress/create-block创建的静态gutenberg块转换为使用PHP注册的动态块的正确方法是什么?)与我正在寻找的非常相似,但我的静态块不是使用 @wordpress/create-block 制作,在完成所有建议的步骤后,我看到了似乎是弃用问题。
class-hello-tools-custom-blocks.php(注册块)
静态版本如下所示:
register_block_type( 'hello-tools/custom-cta', array(
'style' => $this->plugin_slug . '-public',
'editor_style' => 'hello-gutenberg-admin',
'editor_script' => $this->plugin_slug . '-custom-blocks',
) );
动态变化如下:
register_block_type( __DIR__ . '/src/js/blocks/custom-cta/custom-cta-block.json', array(
'style' => $this->plugin_slug . '-public',
'editor_style' => 'hello-gutenberg-admin',
'editor_script' => $this->plugin_slug . '-custom-blocks',
'render_callback' => array( $this, 'hello_tools_custom_cta_callback' )
) );
同一插件文件中的回调函数如下所示:
public function hello_tools_custom_cta_callback( $attributes, $content ) {
ob_start();
require plugin_dir_path( __DIR__ ) . 'includes/partials/block-callbacks/hello-custom-cta-callback.php';
$output = ob_get_contents();
ob_end_clean();
return $output;
}
custom-cta-block.json(定义块属性)
如上面
register_block_type()
中所引用,这是 block.json 文件。
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "hello-tools/custom-cta",
"title": "Custom CTA",
"category": "hello-blocks",
"icon": "align-center",
"description": "Create call to action element with photo image, text, and button link",
"keywords": [ "call", "action" ],
"version": "1.0.1",
"textdomain": "hello-tools",
"editorScript": "hello-tools-custom-blocks",
"editorStyle": "hello-gutenberg-admin",
"style": "hello-tools-public",
"attributes": {
"switchOrientation": {
"type": "boolean",
"default": false
},
"imageID": {
"type": "integer"
},
"imageURL": {
"type": "string"
},
"imageALT": {
"type": "string",
"default": ""
},
"imageBgColor": {
"type": "string",
"default": "orange"
},
"hideCTAImageOnMobile": {
"type": "boolean",
"default": false
},
"renderWithoutImageBg": {
"type": "boolean",
"default": false
},
"imageRatio": {
"type": "string",
"default": "golden"
},
"textBgColor": {
"type": "string",
"default": "faint-gray"
},
"hasIcon": {
"type": "boolean",
"default": false
},
"iconID": {
"type": "integer"
},
"iconURL": {
"type": "string"
},
"iconALT": {
"type": "string",
"default": ""
},
"hasSuperHeading": {
"type": "boolean",
"default": false
},
"superHeading": {
"type": "string"
},
"headline": {
"type": "string"
},
"blurb": {
"type": "string"
},
"ctaButtonText": {
"type": "string"
},
"ctaLinkURL": {
"type": "string"
},
"textClasses": {
"type": "string",
"default": "hello-custom-cta__description flex-fill hello-flex hello-flex--fixed-size align-self-stretch align-items-center p-3 p-sm-4 p-lg-5"
},
"blockClasses": {
"type": "string",
"default": "hello-block--fullwidth px-sm-3 mb-5 mb-md-6 mb-lg-7 mb-7"
}
},
"supports": {
"multiple": true
},
"example": {
"attributes": {
"headline": "This is a custom CTA!",
"blurb": "<p>Add a catchy headline and body text to capture people's attention</p>",
"ctaButtonText": "Click here"
}
}
}
自定义-cta.js
原来的
save()
函数已被删除,以告诉 Wordpres 它应该动态渲染,但之前的弃用版本已保持不变。
import { registerBlockType } from '@wordpress/blocks';
import { __ } from '@wordpress/i18n';
import { InspectorControls, MediaUpload, MediaUploadCheck, RichText, URLInput } from '@wordpress/blockEditor';
import { Button, PanelBody, TextControl, TextareaControl, ToggleControl, SelectControl, IconButton } from '@wordpress/components';
import { omit } from 'lodash';
import settings from './custom-cta-block.json';
const blockAttributes = settings.attributes;
registerBlockType( settings, {
edit: ( props ) => {
const { attributes: { switchOrientation, imageID, imageURL, imageALT, imageBgColor, imageRatio, hideCTAImageOnMobile, textBgColor, hasIcon, iconID, iconURL, iconALT, hasSuperHeading, superHeading, headline, blurb, ctaButtonText, ctaLinkURL, blockClasses, textClasses, renderWithoutImageBg }, setAttributes, className, isSelected } = props;
const ctaButtonPlaceholderText = __( "Button text", "hello-tools" );
const flexClasses = `hello-flex hello-wrap--content align-items-center ${switchOrientation && 'switch-orientation'}`;
const onImageSelect = ( imageObj ) => {
// use the medium_large image size of it exists, otherwise use the full-size image
const imageObjURL = ( imageObj.sizes.medium_large ) ? imageObj.sizes.medium_large.url : imageObj.sizes.full.url;
// set the image attributes
setAttributes( { imageID: imageObj.id } );
setAttributes( { imageURL: imageObjURL } );
setAttributes( { imageALT: imageObj.alt } );
}
const onImageBgChange = ( value ) => {
setAttributes( { imageBgColor: value } );
setAttributes( { renderWithoutImageBg: ( value == 'none') ? true : false } );
}
const onIconSelectorChange = ( value ) => {
setAttributes( { hasIcon: value } );
// clear icon image attributes if show icon toggle is changed to false
if ( !value ) {
setAttributes( { iconID: '' } );
setAttributes( { iconURL: '' } );
setAttributes( { iconALT: '' } );
}
}
const onIconSelect = ( imageObj ) => {
setAttributes( { iconID: imageObj.id } );
if ( imageObj.sizes.thumbnail ) {
setAttributes( { iconURL: imageObj.sizes.thumbnail.url } );
} else {
setAttributes( { iconURL: imageObj.sizes.full.url } );
}
setAttributes( { iconALT: imageObj.alt } );
}
return (
<div className="hello-custom-cta-editor p-0 mb-0">
<InspectorControls>
<PanelBody
title={ __( 'Image settings', 'hello-tools' ) }
initialOpen={ true }
>
{ imageID && __( 'You can change the CTA image here', 'hello-tools' ) }
{ imageID && (
<div style={{ margin: '0 0 15px 0', }}>
<MediaUploadCheck>
<MediaUpload
onSelect={ onImageSelect }
allowedTypes="image"
value={ imageID }
render={ ( { open } ) => (
<Button className="hello-components-button" onClick={ open }>
{ __( 'Choose new image', 'hello-tools' ) }
</Button>
) }
/>
</MediaUploadCheck>
</div>
) }
<SelectControl
label={ __( 'Image background color', 'hello-tools' ) }
value={ imageBgColor }
onChange={ onImageBgChange }
options={ [
{ value: 'orange', label: __( 'Orange', 'hello-tools' ) },
{ value: 'blue', label: __( 'Blue', 'hello-tools' ) },
{ value: 'powder-blue', label: __( 'Light blue', 'hello-tools' ) },
{ value: 'faint-gray', label: __( 'Gray', 'hello-tools' ) },
{ value: 'green', label: __( 'Green', 'hello-tools' ) },
{ value: 'none', label: __( 'No background color', 'hello-tools' ) },
] }
/>
<SelectControl
label={ __( 'Image ratio', 'hello-tools' ) }
value={ imageRatio }
onChange={ value => setAttributes( { imageRatio: value } ) }
options={ [
{ value: 'golden', label: '16:9' },
{ value: 'half', label: '1:1' },
] }
/>
<ToggleControl
label={ __( 'Hide image on mobile phones?', 'hello-tools' ) }
checked={ hideCTAImageOnMobile }
onChange={ value => setAttributes( { hideCTAImageOnMobile: value } ) }
/>
<ToggleControl
label={ __( 'Move photo to the right of the text?', 'hello-tools' ) }
help='The default is to have the photo to the left of the text, but you can switch it here.'
checked={ switchOrientation }
onChange={ value => setAttributes( { switchOrientation: value } ) }
/>
</PanelBody>
<PanelBody
title={ __( 'Text settings', 'hello-tools' ) }
initialOpen={ true }
>
<SelectControl
label={ __( 'Background color', 'hello-tools' ) }
value={ textBgColor }
onChange={ value => setAttributes( { textBgColor: value } ) }
options={ [
{ value: 'faint-gray', label: __( 'Gray', 'hello-tools' ) },
{ value: 'white', label: __( 'White', 'hello-tools' ) },
] }
/>
<ToggleControl
label={ __( 'Show icon above the text?', 'hello-tools' ) }
checked={ hasIcon }
onChange={ onIconSelectorChange }
/>
{ hasIcon && (
<div style={{ margin: '-15px 0 15px 0', }}>
<MediaUploadCheck>
<MediaUpload
onSelect={ onIconSelect }
allowedTypes="image"
value={ iconID }
render={ ( { open } ) => (
<Button className="hello-components-button" onClick={ open }>
{ !iconID && __( 'Choose icon image', 'hello-tools' ) }
{ iconID && __( 'Replace icon image', 'hello-tools' ) }
</Button>
) }
/>
</MediaUploadCheck>
</div>
) }
<ToggleControl
label={ __( 'Show super heading?', 'hello-tools' ) }
checked={ hasSuperHeading }
onChange={ value => setAttributes( { hasSuperHeading: value } ) }
/>
</PanelBody>
</InspectorControls>
<div className={ flexClasses }>
{ renderWithoutImageBg && imageURL && (
<div className={ `hello-custom-cta__image-wrap ${imageRatio} no-padding hello-flex align-self-stretch align-items-center` }>
<div className="objectfit__container w-100 h-100">
<img className="hello-custom-cta__image objectfit__image w-100 h-100" src={ imageURL } alt={ imageALT } />
</div>
</div>
) }
{ !renderWithoutImageBg && imageURL && (
<div className={ `hello-custom-cta__image-wrap ${imageRatio} hello-bg--${imageBgColor} hello-flex align-self-stretch align-items-center p-sm-4 p-lg-5` }>
<img className="hello-custom-cta__image" src={ imageURL } alt={ imageALT } />
</div>
) }
{ !renderWithoutImageBg && !imageID && (
<MediaUploadCheck>
<MediaUpload
onSelect={ onImageSelect }
allowedTypes="image"
value={ imageID }
render={ ( { open } ) => (
<Button onClick={ open }>
{ __( 'Choose Image', 'hello-tools' ) }
</Button>
) }
/>
</MediaUploadCheck>
) }
<div className={ `${textClasses} hello-bg--${textBgColor}` }>
<div>
{ hasIcon && iconID && (
<div className="flex-item--fullwidth">
<img className="hello-custom-cta__icon circle d-block mx-auto" src={ iconURL } alt={ iconALT } />
</div>
) }
{ hasSuperHeading && (
<TextControl
className="hello-custom-cta__superheading hello-interactive-input"
value={ superHeading }
onChange={ value => setAttributes( { superHeading: value } ) }
placeholder={ __( 'Add super heading here (optional)', 'hello-tools' ) }
allowedFormats={ [] }
/>
) }
<TextareaControl
className="hello-custom-cta__headline w-100 hello-interactive-input font-weight-bold"
value={ headline }
onChange={ value => setAttributes( { headline: value } ) }
placeholder={ __( 'Add CTA headline here', 'hello-tools' ) }
allowedFormats={ [] }
rows="2"
/>
{ ( isSelected || ( blurb && blurb != '<p></p>' ) ) && (
<div className="w-100">
<RichText
tagName="div"
multiline="p"
className="hello-custom-cta__blurb font-weight-light mt-0 w-100"
translate-name="blurb"
onChange={ value => setAttributes( { blurb: value } ) }
placeholder={ __( 'Subtext goes here (optional)', 'hello-tools' ) }
value={ blurb }
allowedFormats={ [ 'core/bold', 'core/italic' ] }
focusOnInsert={ false }
/>
</div>
) }
<div className="hello-tools-editable-btn-text-wrapper">
<div className="hello-inline-flex">
<RichText
tagName="div"
placeholder={ ctaButtonPlaceholderText }
onFocus={ (e) => e.target.placeholder = "" }
value={ ctaButtonText }
onChange={ value => setAttributes( { ctaButtonText: value } ) }
className="hello-tools-editable-btn-text mt-4 hello-btn hello-btn--blue"
withoutInteractiveFormatting
allowedFormats={ [] }
/>
</div>
</div>
</div>
</div>
</div>
{ isSelected && (
<div className="hello-block-post-selector">
<form
key={ "form-link" }
onSubmit={ ( event ) => event.preventDefault() }
className="hello-flex hello-bg--white">
<URLInput
value={ ctaLinkURL }
onChange={ value => setAttributes( { ctaLinkURL: value } ) }
autoFocus={ false }
/>
<IconButton
className="hello-bg--white"
icon={ "editor-break" }
label={ __( "Apply", "hello-tools" ) }
type={ "submit" }
/>
</form>
</div>
) }
</div>
);
},
save() {
return null; // Data is rendered via PHP callback
},
deprecated: [
{
attributes: { ...blockAttributes },
save( { attributes } ) {
const { switchOrientation, imageID, imageURL, imageALT, imageBgColor, imageRatio, hideCTAImageOnMobile, textBgColor, hasIcon, iconID, iconURL, iconALT, hasSuperHeading, superHeading, headline, blurb, ctaButtonText, ctaLinkURL, blockClasses, textClasses, renderWithoutImageBg } = attributes;
const flexClasses = `hello-flex hello-wrap--content align-items-center ${switchOrientation && 'switch-orientation'}`;
const superHeadingExtraClasses = ( hasIcon && iconID ) ? 'mt-2 ' : '';
const hideImageOnPhones = ( hideCTAImageOnMobile ) ? ' d-upto-md-none' : '';
return (
<div className={ blockClasses }>
<div className="hello-wrap--narrow">
<div className={ flexClasses }
>
{ renderWithoutImageBg && imageURL && (
<div className={ `hello-custom-cta__image-wrap ${imageRatio} hello-flex align-self-stretch align-items-center${hideImageOnPhones}` }>
<div className="objectfit__container w-100 h-100">
<img className="hello-custom-cta__image objectfit__image w-100 h-100" src={ imageURL } alt={ imageALT } />
</div>
</div>
) }
{ !renderWithoutImageBg && imageURL && (
<div className={ `hello-custom-cta__image-wrap ${imageRatio} hello-bg--${imageBgColor} hello-flex align-self-stretch align-items-center p-sm-4 p-lg-5${hideImageOnPhones}` }>
<img className="hello-custom-cta__image" src={ imageURL } alt={ imageALT } />
</div>
) }
<div className={ `${textClasses} hello-bg--${textBgColor}` }>
<div>
{ iconID && (
<div className="flex-item--fullwidth">
<img className="hello-custom-cta__icon circle d-block mx-auto" src={ iconURL } alt={ iconALT } />
</div>
) }
{ hasSuperHeading && superHeading && (
<div translate-name="custom-cta__superheading" className={`${superHeadingExtraClasses}hello-custom-cta__superheading hello-1rem-text font-weight-bold text-uppercase hello-text--orange`}>
<span>{ superHeading }</span>
</div>
) }
<div translate-name="custom-cta__headline" className="hello-custom-cta__headline h2 font-weight-bold my-2 my-md-3">
{ headline }
</div>
{ ( blurb && blurb != '<p></p>' ) && (
<RichText.Content
className="hello-custom-cta__blurb"
tagName="div"
value={ blurb }
/>
) }
{ ctaButtonText && ctaLinkURL && (
<a href={ ctaLinkURL } translate-name="custom-cta__btn-link" className="hello-custom-cta__btn-link mb-3 mb-md-0 btn hello-btn hello-btn--blue">
{ ctaButtonText }
</a>
) }
</div>
</div>
</div>
</div>
</div>
)
}
},
{
attributes: {
...blockAttributes,
blockClasses: {
type: 'string',
default: 'hello-block--fullwidth px-sm-3 mb-7',
},
},
save( { attributes } ) {
const { switchOrientation, imageID, imageURL, imageALT, imageBgColor, imageRatio, hideCTAImageOnMobile, textBgColor, hasIcon, iconID, iconURL, iconALT, hasSuperHeading, superHeading, headline, blurb, ctaButtonText, ctaLinkURL, blockClasses, textClasses, renderWithoutImageBg } = attributes;
const flexClasses = `hello-flex hello-wrap--content align-items-center ${switchOrientation && 'switch-orientation'}`;
const superHeadingExtraClasses = ( hasIcon && iconID ) ? 'mt-2 ' : '';
const hideImageOnPhones = ( hideCTAImageOnMobile ) ? ' d-upto-md-none' : '';
return (
<div className={ blockClasses }>
<div className="hello-wrap--narrow">
<div className={ flexClasses }
>
{ renderWithoutImageBg && imageURL && (
<div className={ `hello-custom-cta__image-wrap ${imageRatio} hello-flex align-self-stretch align-items-center${hideImageOnPhones}` }>
<div className="objectfit__container w-100 h-100">
<img className="hello-custom-cta__image objectfit__image w-100 h-100" src={ imageURL } alt={ imageALT } />
</div>
</div>
) }
{ !renderWithoutImageBg && imageURL && (
<div className={ `hello-custom-cta__image-wrap ${imageRatio} hello-bg--${imageBgColor} hello-flex align-self-stretch align-items-center p-sm-4 p-lg-5${hideImageOnPhones}` }>
<img className="hello-custom-cta__image" src={ imageURL } alt={ imageALT } />
</div>
) }
<div className={ `${textClasses} hello-bg--${textBgColor}` }>
<div>
{ iconID && (
<div className="flex-item--fullwidth">
<img className="hello-custom-cta__icon circle d-block mx-auto" src={ iconURL } alt={ iconALT } />
</div>
) }
{ hasSuperHeading && superHeading && (
<div translate-name="custom-cta__superheading" className={`${superHeadingExtraClasses}hello-custom-cta__superheading hello-1rem-text font-weight-bold text-uppercase hello-text--orange`}>
<span>{ superHeading }</span>
</div>
) }
<div translate-name="custom-cta__headline" className="hello-custom-cta__headline h2 font-weight-bold my-2 my-md-3">
{ headline }
</div>
{ ( blurb && blurb != '<p></p>' ) && (
<RichText.Content
className="hello-custom-cta__blurb"
tagName="div"
value={ blurb }
/>
) }
{ ctaButtonText && ctaLinkURL && (
<a href={ ctaLinkURL } translate-name="custom-cta__btn-link" className="hello-custom-cta__btn-link mb-3 mb-md-0 btn hello-btn hello-btn--blue no-external-icon same-window">
{ ctaButtonText }
</a>
) }
</div>
</div>
</div>
</div>
</div>
)
}
}
],
} );
hello-custom-cta-callback.php(处理实际的PHP渲染,在回调函数中引用)
<?php
global $post;
$plugin_slug = hello_get_plugin_slug();
$is_admin = ( is_admin() ) ? true : false;
$switchOrientation = ( array_key_exists( 'switchOrientation', $attributes ) ) ? $attributes['switchOrientation'] : false;
$imageID = ( array_key_exists( 'imageID', $attributes ) ) ? $attributes['imageID'] : '';
$imageURL = ( array_key_exists( 'imageURL', $attributes ) ) ? $attributes['imageURL'] : '';
$imageALT = ( array_key_exists( 'imageALT', $attributes ) ) ? $attributes['imageALT'] : '';
$imageBgColor = ( array_key_exists( 'imageBgColor', $attributes ) ) ? $attributes['imageBgColor'] : 'orange';
$hideCTAImageOnMobile = ( array_key_exists( 'hideCTAImageOnMobile', $attributes ) ) ? $attributes['hideCTAImageOnMobile'] : false;
$renderWithoutImageBg = ( array_key_exists( 'renderWithoutImageBg', $attributes ) ) ? $attributes['renderWithoutImageBg'] : false;
$imageRatio = ( array_key_exists( 'imageRatio', $attributes ) ) ? $attributes['imageRatio'] : 'golden';
$textBgColor = ( array_key_exists( 'textBgColor', $attributes ) ) ? $attributes['textBgColor'] : 'faint-gray';
$hasIcon = ( array_key_exists( 'hasIcon', $attributes ) ) ? $attributes['hasIcon'] : false;
$iconID = ( array_key_exists( 'iconID', $attributes ) ) ? $attributes['iconID'] : '';
$iconURL = ( array_key_exists( 'iconURL', $attributes ) ) ? $attributes['iconURL'] : '';
$iconALT = ( array_key_exists( 'iconALT', $attributes ) ) ? $attributes['iconALT'] : '';
$hasSuperHeading = ( array_key_exists( 'hasSuperHeading', $attributes ) ) ? $attributes['hasSuperHeading'] : false;
$superHeading = ( array_key_exists( 'superHeading', $attributes ) ) ? $attributes['superHeading'] : '';
$headline = ( array_key_exists( 'headline', $attributes ) ) ? $attributes['headline'] : '';
$blurb = ( array_key_exists( 'blurb', $attributes ) ) ? $attributes['blurb'] : '';
$ctaButtonText = ( array_key_exists( 'ctaButtonText', $attributes ) ) ? $attributes['ctaButtonText'] : '';
$ctaLinkURL = ( array_key_exists( 'ctaLinkURL', $attributes ) ) ? $attributes['ctaLinkURL'] : '';
$textClasses = ( array_key_exists( 'textClasses', $attributes ) ) ? $attributes['textClasses'] : 'hello-custom-cta__description flex-fill hello-flex hello-flex--fixed-size align-self-stretch align-items-center p-3 p-sm-4 p-lg-5';
$blockClasses = ( array_key_exists( 'blockClasses', $attributes ) ) ? $attributes['blockClasses'] : 'hello-block--fullwidth px-sm-3 mb-5 mb-md-6 mb-lg-7 mb-7';
$flexClasses = 'hello-flex hello-wrap--content align-items-center';
$flexClasses = ($switchOrientation) ? $flexClasses . ' switch-orientation' : $flexClasses;
$superHeadingExtraClasses = ( $hasIcon && $iconID ) ? 'mt-2 ' : '';
$hideImageOnPhones = ( $hideCTAImageOnMobile ) ? ' d-upto-md-none' : '';
$is_rtl = ( apply_filters( 'wpml_is_rtl', NULL) ) ? true : false;
if ( is_object( $post ) && get_post_meta( $post->ID, '_icl_lang_duplicate_of', true ) ) {
$is_rtl = false; // if this is on a duplicate page, keep the content LTR
}
echo '<pre>'.print_r($attributes,true).'</pre>';
?>
<div class="<?= $blockClasses; ?>">
<div class="hello-wrap--narrow">
<div class="<?= $flexClasses; ?>">
<?php if ($renderWithoutImageBg && $imageURL) : ?>
<div class="hello-custom-cta__image-wrap <?= $imageRatio; ?> hello-flex align-self-stretch align-items-center<?= $hideImageOnPhones; ?>">
<div class="objectfit__container w-100 h-100">
<img class="hello-custom-cta__image objectfit__image w-100 h-100" src="<?= $imageURL; ?>" alt="<?= $imageALT; ?>" />
</div>
</div>
<?php elseif ( !$renderWithoutImageBg && $imageURL ) : ?>
<div class="hello-custom-cta__image-wrap <?= $imageRatio; ?> hello-bg--<?= $imageBgColor; ?> hello-flex align-self-stretch align-items-center p-sm-4 p-lg-5<?= $hideImageOnPhones; ?>">
<img class="hello-custom-cta__image" src="<?= $imageURL; ?>" alt="<?= $imageALT; ?>" />
</div>
<?php endif; ?>
<div class="<?= $textClasses; ?> hello-bg--<?= $textBgColor; ?>">
<div>
<?php if ($iconID) : ?>
<div class="flex-item--fullwidth">
<img class="hello-custom-cta__icon circle d-block mx-auto" src="<?= $iconURL; ?>" alt="<?= $iconALT; ?>" />
</div>
<?php endif; ?>
<?php if ($hasSuperHeading && $superHeading) : ?>
<div translate-name="custom-cta__superheading" class="<?= $superHeadingExtraClasses; ?>hello-custom-cta__superheading hello-1rem-text font-weight-bold text-uppercase hello-text--orange">
<span><?= $superHeading; ?></span>
</div>
<?php endif; ?>
<div translate-name="custom-cta__headline" class="hello-custom-cta__headline h2 font-weight-bold my-2 my-md-3">
<?= $headline; ?>
</div>
<?php if ($blurb && $blurb !== '<p></p>') : ?>
<div class="hello-custom-cta__blurb"><?= $blurb; ?></div>
<?php endif; ?>
<?php if ($ctaButtonText && $ctaLinkURL) : ?>
<a href="<?= $ctaLinkURL; ?>" translate-name="custom-cta__btn-link" class="hello-custom-cta__btn-link mb-3 mb-md-0 btn hello-btn hello-btn--blue"><?= $ctaButtonText; ?></a>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
我注意到渲染回调中无法在 JavaScript 中完成的主要功能是检查
wpml_is_rtl
和 _icl_lang_duplicate_of
。为此,使用 PHP/动态渲染来获取该值是有意义的。尽管将原来的 save()
函数重写到 PHP 中,弃用前一个块然后从 PHP 中的属性重置所有变量似乎并不理想。最终目标是相同的输出:渲染的 HTML。我在将现有插件迁移到 Gutenberg 块时遇到了类似的问题,您实际上只需要一点点 PHP 功能即可在最终标记中获得正确的逻辑。
替代方法:
注册块后,可以使用 wp_localize_script 本地化块 JavaScript。这种方法的优点是您可以将值从 PHP 传递到 JavaScript
save()
,而不必仅仅为了访问 PHP 函数而重写所有标记。
class-hello-tools-custom-blocks.php
// Revert to original static block
register_block_type( 'hello-tools/custom-cta', array(
'style' => $this->plugin_slug . '-public',
'editor_style' => 'hello-gutenberg-admin',
'editor_script' => $this->plugin_slug . '-custom-blocks',
) );
// Localize script with an array (data) containing the values of PHP functions as needed
function hello_tools_localize_scripts()
{
$id = get_the_ID(); // Changed from $post->ID in this context
$is_rtl = (apply_filters('wpml_is_rtl', NULL)) ? true : false;
if (is_object($post) && get_post_meta($id, '_icl_lang_duplicate_of', true)) {
$is_rtl = false; // if this is on a duplicate page, keep the content LTR
}
// Name of script is santized name from block.json
wp_localize_script('hello-tools-custom-cta', 'data', array(
'is_rtl' => $is_rtl,
'is_admin' => is_admin()
));
}
add_action('wp_enqueue_scripts', 'hello_tools_localize_scripts');
自定义-cta.js
JavaScript 块现在可以访问
data
并使用其内容来保存所需的标记,例如:
save({ attributes }) {
...
return (
<div className={blockClasses}>
{data.is_rtl && (
// save something different for RTL
)}
...
</div>
)
}
...
如果这就是最初导致您切换到使用 PHP 渲染的原因,那么希望您可以实现上面的建议,完全删除
hello-custom-cta-callback.php
,并使用附加变量重用现有的 save()
函数。
另请检查
custom-cta-block.json
的先前版本,了解先前如何定义属性。对于可编辑的 <RichText ../>
的 attributes,该值可以来自保存的标记 - 您可以使用类选择器设置源,例如:
"attributes" :{
...
"blurb": {
"type": "string",
"source": "text",
"selector": ".hello-custom-cta__blurb",
"default": ""
},
...
}
我尝试使用你的方法,但服务器端输出没有在我的前端页面中呈现,我不知道我做错了什么?
save: function (props) {
return null;
},
deprecated: [
{
save: function (props) {
return el(
"form",
{
class: "intelius_simple_align_left_phone_form",
action: "/redirect/impact.php",
target: "_blank",
method: "get",
},
el(
"div",
{
class: "intelius_simple_align_left_phone_relavite",
},
el("input", {
class: "intelius_simple_align_left_phone_input",
type: "type",
placeholder: "(212) 333-4567",
onkeydown: "enforceFormatIntelius_value(event)",
onkeyup: "formatToPhoneIntelius_value(event)",
name: "phone",
maxlength: "14",
}),
el("i", {
class: "usa-flag-by-phone",
}),
el("input", {
class: "intelius_simple_align_phone_btn",
type: "submit",
value: props.attributes.button_content,
})
),
el("input", {
type: "hidden",
name: "type",
value: "phone",
}),
el("input", {
type: "hidden",
name: "merchant",
value: "intelius",
}),
el("input", {
type: "hidden",
name: "source",
value: "{{SUPEREASY_ARTICLE_URL}}",
})
);
}
}
]
// Register block script and style.
register_block_type('easeware-intelius-simple-phone/simple-intelius-to-action', [
// 'style' => 'simple-intelius-to-action', // Loads both on editor and frontend.
'editor_script' => 'simple-intelius-to-action', // Loads only on editor.
'editor_style' => 'simple-intelius-to-action', // Loads only on editor.
'render_callback' => 'simple_intelius_render_form'
]);
function simple_intelius_render_form($attributes)
{
return '
<form class="intelius_simple_align_left_phone_form" action="/redirect/impact.php" target="_blank" method="get">
<div class="intelius_simple_align_left_phone_relavite">
<input class="intelius_simple_align_left_phone_input" type="type" placeholder="(212) 333-4567" name="phone" maxlength="14">
<i class="usa-flag-by-phone"></i>
<input class="intelius_simple_align_phone_btn" type="submit" value="' . esc_attr($attributes['button_content']) . '">
</div>
<input type="hidden" name="type" value="phone">
<input type="hidden" name="merchant" value="intelius">
<input type="hidden" name="source" value="{{SUPEREASY_ARTICLE_URL}}">
</form>
';
}