diff --git a/xwiki-platform-core/xwiki-platform-ckeditor/xwiki-platform-ckeditor-plugins/src/main/webjar/xwiki-macro/plugin.js b/xwiki-platform-core/xwiki-platform-ckeditor/xwiki-platform-ckeditor-plugins/src/main/webjar/xwiki-macro/plugin.js
index 77a16133e061ea6e9255dffca78eb87b653ca670..3c0ae0df23c4a7574b5bcb9ed647be9cfda0627d 100644
--- a/xwiki-platform-core/xwiki-platform-ckeditor/xwiki-platform-ckeditor-plugins/src/main/webjar/xwiki-macro/plugin.js
+++ b/xwiki-platform-core/xwiki-platform-ckeditor/xwiki-platform-ckeditor-plugins/src/main/webjar/xwiki-macro/plugin.js
@@ -916,37 +916,49 @@
     // The passed element is of type CKEDITOR.htmlParser.element
     isMacroElement: function(element) {
       return (element.name == 'div' || element.name == 'span') &&
-        element.hasClass('macro') && element.attributes['data-macro'];
+        // The passed element doesn't always have the CKEDITOR.htmlParser.element API. This happens for instance when
+        // CKEditor checks which plugins to disable (based on the HTML elements they require). In this case the passed
+        // element only has the data (attributes, children, etc.).
+        element.hasClass?.('macro') && element.attributes['data-macro'];
     },
 
     // The passed element is of type CKEDITOR.htmlParser.element
     isMacroOutput: function(element) {
-      return element.getAscendant && element.getAscendant(function(ancestor) {
-        // The macro marker comments might have been already processed (e.g. in the case of nested editables) so we need
-        // to look for a macro output wrapper also.
-        if (CKEDITOR.plugins.xwikiMacro.isMacroElement(ancestor)) {
-          return true;
-        }
-        // Look for macro marker comments otherwise, taking into account that macro markers can be "nested".
-        var nestingLevel = 0;
-        var previousSibling = ancestor;
-        while (previousSibling.previous && nestingLevel <= 0) {
-          previousSibling = previousSibling.previous;
-          if (previousSibling.type === CKEDITOR.NODE_COMMENT) {
-            if (previousSibling.value === 'stopmacro') {
-              // Macro output end.
-              nestingLevel--;
-            } else if (previousSibling.value.substr(0, 11) === 'startmacro:') {
-              // Macro output start.
-              nestingLevel++;
-            }
-          }
-        }
-        return nestingLevel > 0;
-      });
+      // CKEDITOR.htmlParser.element#getAscendant() doesn't check the element itself, so we have to do it.
+      return isMacroElementOrBetweenMacroMarkers(element) ||
+        element.getAscendant?.(isMacroElementOrBetweenMacroMarkers);
     }
   };
 
+  /**
+   * @param {CKEDITOR.htmlParser.element} element the element to check
+   * @returns {@code true} if the given element is a macro output wrapper or is between macro marker comments,
+   *          {@code false} otherwise
+   */
+  function isMacroElementOrBetweenMacroMarkers(element) {
+    // The macro marker comments might have been already processed (e.g. in the case of nested editables) so we need to
+    // look for a macro output wrapper also.
+    if (CKEDITOR.plugins.xwikiMacro.isMacroElement(element)) {
+      return true;
+    }
+    // Look for macro marker comments otherwise, taking into account that macro markers can be "nested".
+    var nestingLevel = 0;
+    var previousSibling = element;
+    while (previousSibling.previous && nestingLevel <= 0) {
+      previousSibling = previousSibling.previous;
+      if (previousSibling.type === CKEDITOR.NODE_COMMENT) {
+        if (previousSibling.value === 'stopmacro') {
+          // Macro output end.
+          nestingLevel--;
+        } else if (previousSibling.value.substr(0, 11) === 'startmacro:') {
+          // Macro output start.
+          nestingLevel++;
+        }
+      }
+    }
+    return nestingLevel > 0;
+  }
+
   // Overwrite CKEditor's HTML parser in order to prevent it from removing empty elements from generated macro output.
   // It's important to preserve the generated macro output as is, because these empty elements are often used:
   // * to display font icons (even on the default wiki home page)