The problem is not in WikiMacroContentMacro: that macro always outputs a placeholder block (a GroupBlock / FormatBlock carrying data-wikimacro-id=wikimacrocontent), whether or not the wiki macro was called with content.
The placeholder is replaced later, in DefaultWikiMacroRenderer#resolveMacroContent (xwiki-platform-rendering-wikimacro-store):
private Block resolveMacroContent(MacroMarkerBlock macroBlock)
{
if (this.wikimacro.getDescriptor().getContentDescriptor() != null && this.macroContent != null) {
MetaData nonGeneratedContentMetaData = getNonGeneratedContentMetaData();
nonGeneratedContentMetaData.addMetaData(WIKIMACROCONTENT, "true");
...
returnnew MetaDataBlock(blocks, nonGeneratedContentMetaData);
}
return macroBlock; // <-- taken when the macro is called without content
}
The && this.macroContent != null guard was added by XWIKI-20820 (fixed in 15.3) to avoid an NPE in parseContent(null). But it skips the whole MetaDataBlock, not just the parsing. So when the wiki macro is called without a body:
No non-generated-content metadata is produced, so the annotated XHTML renderer doesn't output the <div class="xwiki-metadata-container" data-xwiki-non-generated-content="..."> wrapper. The CKEditor xwiki-macro plugin makes a macro region editable in-place only when it finds that data-xwiki-non-generated-content attribute, so in-place editing of the content is simply not available.
The unresolved wikimacrocontentMacroMarkerBlock is left in the output, and cleanMacroMarkers bails out entirely (it keys off the wikimacrocontent=true metadata blocks it no longer finds), so all the inner macro markers survive too.
That leftover marker becomes an empty nested macro widget in the editor. Being 0x0, ensureMacroWidgetVisible reveals the macro:<name> placeholder.
Why 15.10 and 17.5 differ
The guard is present in both versions, so the bug is the same. What changed in between is XWIKI-22834 (17.1), which removes the bogus filler BR that CKEditor adds to the empty block elements of a macro output. Before that, the empty widget accidentally had one line of height, so no placeholder was shown and you just had nothing to click on; after it, the widget really is 0x0 and the macro:<name> placeholder shows up. Same root cause, different visible symptom.
Proposed fix
Emit the metadata block whenever there is a content descriptor, and only skip the parsing when the content is null or empty. This keeps the XWIKI-20820 NPE fix intact:
private Block resolveMacroContent(MacroMarkerBlock macroBlock)
{
if (this.wikimacro.getDescriptor().getContentDescriptor() != null) {
MetaData nonGeneratedContentMetaData = getNonGeneratedContentMetaData();
nonGeneratedContentMetaData.addMetaData(WIKIMACROCONTENT, "true");
List<Block> blocks;
if (StringUtils.isEmpty(this.macroContent)) {
// The content is optional and was not provided. The metadata block is still needed, so that the
// WYSIWYG editor can offer in-place editing of the (empty) macro content.
blocks = List.of();
} else {
try {
blocks = parseContent(this.macroContent, macroBlock.isInline()).getChildren();
} catch (RenderingException e) {
blocks = this.errorBlockGenerator.generateErrorBlocks(macroBlock.isInline(),
TM_FAILEDRESOLVECONTENTPLACEHOLDER, "Failed to resolve macro content placeholder", null, e);
}
}
// We don't execute the content to make sure it's executed later in the right context (where it was passed
// to the wiki macro).
returnnew MetaDataBlock(blocks, nonGeneratedContentMetaData);
}
return macroBlock;
}
Wanted side effect: with the metadata block back, cleanMacroMarkers runs again and strips the leaked wikimacrocontent and inner macro markers. There is no API change, so no @since / Revapi work.
DefaultWikiMacroTest already asserts the beginMetaData [[non-generated-content]=[...]] events, so the unit test for a content-less call fits right next to the existing ones.
Remaining check on the editor side
After the fix the server outputs an empty<div class="xwiki-metadata-container" data-xwiki-non-generated-content="java.util.List<org.xwiki.rendering.block.Block>" data-xwiki-wikimacrocontent="true"></div>. CKEditor's Widget#initEditable calls editable.setData(editable.getHtml()) on it, which may or may not insert a <p><br></p> filler for empty data. This needs to be checked in a live editor: if no filler is inserted, the macro widget is still 0x0 and the placeholder still wins.
In that case the minimal targeted fix is in xwiki-macro/plugin.js: the rule added by XWIKI-22834 strips bogus BR elements from the macro output so that the visibility of read-only output can be measured, but a nested editable is not read-only. Making isMacroOutput() (or that br rule) return false inside a [data-xwiki-non-generated-content] element mirrors the editable flag the plugin's parser context already tracks, and keeps the filler that makes the empty editable clickable.
This message was sent by Atlassian Jira (v9.3.0#930000-sha1:287aeb6)
If image attachments aren't displayed, see this article.