Gutenberg Block Validation Failed ( not expecting children ) - wordpress

I am developing a gutenberg Testimonials block, however when saving and trying to reload it gives me block validation failure, it seems to be expecting a block without children in the carousel-inner etc.
Expected:
<div class="wp-block-wf-testimonials"><div class="slideshow carousel slide" data-ride="carousel" data-interval="false"><div class="carousel-inner"></div><a class="carousel-control carousel-control-prev" href="#undefined" role="button" data-slide="prev"><span class="carousel-icon carousel-control-prev-icon" aria-hidden="true"></span><span class="sr-only">Previous</span></a><a class="carousel-control carousel-control-next" href="#undefined" role="button" data-slide="next"><span class="carousel-icon carousel-control-next-icon" aria-hidden="true"></span><span class="sr-only">Next</span></a></div></div>
Actual:
<div class="wp-block-wf-testimonials"><div class="slideshow carousel slide" data-ride="carousel" data-interval="false"><div class="carousel-inner"><div class="carousel-item active"><div class="quote"> sdfas </div><div class="byline"> sdf </div></div><div class="carousel-item false"><div class="quote"> fsadfa </div><div class="byline"> asdfassdfadf </div></div><div class="carousel-item false"><div class="quote"> fdsafas </div><div class="byline"> sdfasdfas </div></div></div><a class="carousel-control carousel-control-prev" href="#undefined" role="button" data-slide="prev"><span class="carousel-icon carousel-control-prev-icon" aria-hidden="true"></span><span class="sr-only">Previous</span></a><a class="carousel-control carousel-control-next" href="#undefined" role="button" data-slide="next"><span class="carousel-icon carousel-control-next-icon" aria-hidden="true"></span><span class="sr-only">Next</span></a></div></div>
Here is the attributes
attributes = {
interval: {
type: 'text',
selector: '.slideshow',
source: 'attribute',
attribute: 'data-interval',
default: 'false'
},
hideIndicators: {
type: 'text',
default: 'false'
},
viewMode: {
type: 'text',
default: 'edit',
},
testimonials: {
source: "query",
default: [{index:0, quote:"", byline:""}],
selector: ".carousel-inner .carousel",
query: {
index: {
source: "attribute",
selector: ".quote",
attribute: "index"
},
image: {
source: "attribute",
selector: "img",
attribute: "src"
},
quote: {
source: "text",
selector: ".quote"
},
byline: {
source: "text",
selector: ".byline"
}
}
}
}
Full block code: https://github.com/Panguino/WF_Testimonial
Any help would be greatly appreciated, I am new to Gutenberg, a bit new to react as well. Go easy on me =).

I think you found the solution, answering for future readers.
The Actual in the console error expects the previous HTML we saved in the save() method which is stored in the database currently and our block's save() method contains the new code. So, WordPress can't match the output thus resulting in a validation error.
Solution: You've to remove the current instance of the block and make a new one, it'll work. Though it's annoying, I hope the Gutenberg team would find a fix around this

Related

How do I properly deprecate Gutenberg block

I have a custom Gutenberg block (https://pastebin.com/bV2k5Ekc) in which I display text, link and an image. I want to change it so so instead of saving the image URL as a background image of the container, to use an img tag. Unfortunately - I can't manage to create the deprecation correctly - I fail at assigning the attributes parameters in the deprecation:
From this:
const {
attributes: {
mediaURL,
boxTitle,
boxDescription,
linkText,
linkHref,
linkTitle
},
className,
} = props;
let boxClass = 'cta-box';
let contentDescription = '';
if (boxDescription.length) {
boxClass += ' cta-box-description';
contentDescription = (
<p>
{boxDescription}
</p>
)
}
return (
<div className={`cta-block-box ${className}`}>
<a
className="cta-box-link"
href={linkHref}
style={{ backgroundImage: "url(" + mediaURL + ")" }}
rel="noopener noreferrer"
>
<div className={boxClass}>
<h3>
{boxTitle}
</h3>
{contentDescription}
<span className="arrow">{linkText ? linkText : linkTitle}</span>
</div>
</a>
</div>
);
},
To this (I only change what's in the return statement):
return (
<div className={`cta-block-box ${className}`}>
<a
className="cta-box-link"
rel="noopener noreferrer"
>
<img className="cta-box-image" src={linkHref} alt=""/>
<div className={boxClass}>
<h3>
{boxTitle}
</h3>
{contentDescription}
<span className="arrow">{linkText ? linkText : linkTitle}</span>
</div>
</a>
</div>
);
Which of course broke the Gutenberg element. So I added a deprecate to the blog, as much as I could following the official Wordpress documentation:
deprecated: [
{
attributes: {...this.attributes},
save: (props) => {
const {
attributes: {
mediaURL,
boxTitle,
boxDescription,
linkText,
linkHref,
linkTitle
},
className,
} = props;
console.log('dep');
console.log(props);
let boxClass = 'cta-box';
let contentDescription = '';
if (boxDescription.length) {
boxClass += ' cta-box-description';
contentDescription = (
<p>
{boxDescription}
</p>
)
}
return (
<div className={`cta-block-box ${className}`}>
<a
className="cta-box-link"
style={{ backgroundImage: "url(" + mediaURL + ")" }}
rel="noopener noreferrer"
>
<div className={boxClass}>
<h3>
{boxTitle}
</h3>
{contentDescription}
<span className="arrow">{linkText ? linkText : linkTitle}</span>
</div>
</a>
</div>
);
},
}
],
After this the editor page crashes, and I get error message in console, that attributes is not defined (displaying incorrect row in the script file). This is the "after" script contents (https://pastebin.com/dVdLMx7N).
react-dom.min.js?ver=16.13.1:125 ReferenceError: attributes is not defined
at save (cta-box2.js?f66a:242)
at Wt (blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3)
at Qt (blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3)
at block-editor.min.js?ver=4378547cec8f5157a02ead3dfc5c65b2:12
at hooks.min.js?ver=50e23bed88bcb9e6e14023e9961698c1:2
at $r (blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3)
at blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3
at Ur (blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3)
at blocks.min.js?ver=9ed25ffa009c799f99a4340915b6dc6a:3
at Array.reduce (<anonymous>)
Any help would be greatly appreciated! I suspect I'm missing some small detail, but so far I've failed to locate it. And was not able to find relevant enough information on the web.
Thanks in advance!
There are two issues in your "after" script:
The attributes do not match (and the this is actually the window object): attributes: {...this.attributes} (see line 212).
So what you used with the attributes property on line 24, should also be used with the same property on line 212. (because you only changed the output, so the block attributes remain the same)
The save output/markup also do not match — in the "before" script, you've got href={linkHref}, but in the deprecated property of the "after" script, the save output did not have that href. (see this diff)
So make sure the attributes and save output match the ones in the old/"before" script, and the following is how your code would look like, but note that I only included the main parts that need to be fixed:
// Define the attributes and use it with the root "attributes" property and
// the one in the "deprecated" property.
const blockAttributes = {
mediaID: {
type: 'number'
},
mediaURL: {
type: 'string'
},
boxTitle: {
type: 'string',
default: ''
},
// ... the rest of the attributes here.
};
registerBlockType('hswp/test-box', {
title: __('Test Box', 'modula'),
// ... your code.
attributes: blockAttributes,
// ... your code.
deprecated: [
{
attributes: blockAttributes,
save: (props) => {
// ... your code.
return (
<div className={`cta-block-box ${className}`}>
<a
className="cta-box-link"
href={linkHref}
style={{ backgroundImage: "url(" + mediaURL + ")" }}
rel="noopener noreferrer"
>
... your code.
</a>
</div>
);
},
}
],
});
Additionally, note that the PlainText component doesn't (as of writing) have a property named tagName.

Updating parent of recursive component in Vue

I've made a menu showing systems and their subsystems (can in theory be indefinitely) using a recursive component. A user can both add and delete systems, and the menu should therefore update accordingly.
The menu is constructed using a "tree"-object. This tree is therefore updated when a new system is added, or one deleted. But, I now have a problem; even though the new child component is added when the tree is rerendered, the classes of it's parent-component doesn't update. It is necessary to update this because it defines the menu-element to having children/subsystems, and therefore showing them.
Therefore, when adding a new subsystem, this is presented to the user:
<div class="">
<a href="#/Admin/364" class="item">
<i class=""></i>Testname
<div class=""></div>
</a>
</div>
Instead of this:
<div class="menu transition visible" style="display: block !important;">
<a href="#/Admin/364" class="item">
<i class=""></i>Testname
<div class=""></div>
</a>
</div>
It works fine adding a subsystem to a system which already have subsystems (since the menu-class is already present), but not when a subsystem is added to one without subsystems. In that case, the menu ends up looking like this:
The "opposite" problem also occurs on deletion, since the parent still has the menu-class:
Here's the code for the recursive component:
<template>
<router-link :to="{ name: 'Admin', params: { systemId: id } }" class="item" >
<i :class="{ dropdown: hasChildren, icon: hasChildren }"></i>{{name}}
<div :class="{ menu: hasChildren }">
<systems-menu-sub-menu v-for="child in children" :children="child.children" :name="child.name" :id="child.id" :key="child.id"/>
</div>
</router-link>
</template>
<script type = "text/javascript" >
export default {
props: ['name', 'children', 'id'],
name: 'SystemsMenuSubMenu',
data () {
return {
hasChildren: (this.children.length > 0)
}
}
}
</script>
I'm guessing this has to do with Vue trying to be efficient, and therefore not rerendering everything. Is there therefore any way to force a rerender, or is there any other workaround?
EDIT: JSFiddle https://jsfiddle.net/f6s5qzba/

how to implement custom footer in faceted search screen in 5.1.1

we need to customize footer to keep it build version in facted search screen in 5.1.1;i have followed below link.
http://pavelmakhov.com/2016/02/customize-alfresco-footer-aikau
now after implementing it entire footer was not visible.its calling faceted-search.get.js & custom widget.js;I think there is some problem with custom html file.
custom-footer.html
<div class="alfresco-footer-AlfShareFooter" data-dojo-attach-point="footerParentNode">
<span class="copyright" data-dojo-attach-point="footerContainerNode">
<a href="#" onclick="Alfresco.module.getAboutShareInstance().show(); return false;">
<img src="${logoImageSrc}" alt="${altText}" border="0"/>
</a>
<span>Buildversion:${buildVersion}</span>
<span class="licenseHolder" data-dojo-attach-point="licenseHolderNode">${licensedToLabel} ${licenseLabel}<br></span>
<span>${copyrightLabel}</span>
</span>
</div>
faceted-search.get.js
var footer = widgetUtils.findObject(model.jsonModel, "id", "ALF_STICKY_FOOTER");
logger.log("footer:"+footer);
footer.config.widgetsForFooter = [{
name: "blogs/footer/search-footer", config: {
semanticWrapper: "footer",
currentYear: new Date().getFullYear(),
buildVersion: "2.0.0",
buildDate: "4th Nov 2016"
}
}];

Display User Data with React/Meteor Application

I have been trying various methods to display data from a Meteor fetch within a React template. I don't fully understand why this is so hard to do.
When I use getMeteorData within the template it doesn't display the data when using {this.data.user._id}
getMeteorData() {
return {
user: Meteor.user()
};
},
This is the same story when using componentDidMount.
I have followed the react & meteor tutorial on the meteor website and they use props. This however feels a lot of work for simply pulling and fetching data.
This is an example of an attempt
export var MenuLoggedIn = React.createClass({
displayName: 'MenuLoggedIn',
mixins: [
Router.State, Router.Navigation
],
getMeteorData() {
return {
user: Meteor.user()
};
},
getInitialState(){
return {
avatarImagePreview: null,
avatarImage: null
};
},
render: function() {
return (
<div className="container">
<div className="menu-structure col-md-12">
{this.data.user._id}
<div className="left-menu pull-left">
<img className="logo" src="/img/logo.png"/>
<h1 className="eventburger-title">eventburger</h1>
</div>
<div className="right-menu">
<div className="search-bar">
<i className="fa fa-search"></i>
<input type="text" name="Search" placeholder="Harpist, Photographer, Caterer..."/>
</div>
{this.data
? <img src="/img/avatar.png"/>
: <img src="/img/placeholder-person.jpg"/>}
<span>{this.data}
Feeney</span>
<a href="/app/inbox">
<i className="fa fa-envelope"></i>
</a>
<a className="head-spacing" href="#" onClick={this.logout}>LOG OUT</a>
</div>
</div>
</div>
);
},
logout: function(e) {
e.preventDefault();
Meteor.logout();
window.location.href = "/login"; //Need to be moved to History
}
});
You need to use the ReactMeteorData mixin to make getMeteorData() work.
mixins: [
Router.State, Router.Navigation, ReactMeteorData
],
https://atmospherejs.com/meteor/react-meteor-data

Meteor collection not displaying

I am trying to display my Orders collection. The Orders collection schema has a select field populated from the Items collection.
I cannot seem to get the Orders collection to display on my admin's template. I have verified that I am posting to the collection with Mongol and I'm not receiving any errors in console. I have also tried displaying it in a tabular table with no luck.
Any ideas? I'm still learning meteor and have been staring at this screen for hours.. maybe need some fresh air now and a fresh look later...
/collections/orders.js
Orders = new Mongo.Collection("orders");
Orders.attachSchema(new SimpleSchema({
station: {
type: String,
label: 'Station',
max: 2,
},
itemselect: {
type: [String],
label: 'Items',
optional: false,
autoform:{
type: "select",
options : function() {
return Items.find().map(function (c) {
return {label: c.name , value: c._id}
})
}
}
}
}));
/templates/admin.html
<template name="ordersTable">
<div class="admin">
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" href="#collapse2">
<button type="button" class="btn btn-default navbar-btn">Orders</button>
</a>
</h4>
</div>
<div id="collapse2" class="panel-collapse collapse">
<div class="panel-body">
<ul>
{{#each orders}}
<li>{{> station}}</li>
{{/each}}
</ul>
</div>
<div class="panel-footer">
{{> addOrderFormAdmin}}
</div>
</div>
</div>
</div>
</template>
/templates/admin.js < This ended up being my problem..
Template.dashboard.rendered = function() {
return Orders.find();
};
**should be a helper.. so this instead:
Template.ordersTable.helpers({
orders: function () {
return Orders.find();
}
});
Insert Order Form
<template name="addOrderFormAdmin">
{{> autoformModals}} <!-- this is required for this modal to open -->
{{#afModal class="btn btn-primary" collection="Orders" operation="insert"}}
Add New Order
{{/afModal}}
</template>
Your code inside your dashboard rendered callback does not make any sense. I think you want to create a helper function for your ordersTable template instead:
Template.ordersTable.helpers({
orders: function () {
return Orders.find();
}
});
Furthermore, please note that Template.myTemplate.rendered is deprecated in Meteor version 1.0.4.2 (and later), use Template.myTemplate.onRendered instead.
Check publish and subscribe if you have removed the autopublish package. First, see if you can reach the collection through the console(on the web page, not the command line). Second, see if the collection is updated after your posts (for this you could use the command line by typing "meteor mongo" while the server is running or just download Robomongo).

Resources