Drupal fails to render correctly a webform block which is included in the computed token field on the main form.
Here are the steps to reproduce the issue:
1. Install Drupal 8: drush qd --no-server --account-pass=admin
2. Enable modules: cd *drupal*/drupal && drush -y en webform block_token
3. Enable sub-modules: drush -y en webform_ui webform_examples
4. Apply patch for block_token by: cd quick-drupal-*/drupal/modules/block_token; patch -p1 < <(curl -s https://www.drupal.org/files/issues/0001-2899439-by-kenorb-Fixes-rendering-issue-for-blocks.patch)
5. Run PHP builtin server: drush rs
6. Open: http://127.0.0.1:8888/ and login as admin/admin.
7. Go to /admin/structure/block and in Content (or anywhere else) - Place block, choose Webform, then select Contact Webform, in Pages select 'Hide for the listed pages' with empty list (to hide it by default), and tick 'Create the token for this block', then Save.
8. Import the following webform, or create a new one with Computed token field with block token: [block_token:webform:webform]
computed_webform:
'#type': computed_token
'#title': 'Computed Webform'
'#display_on': form
'#value': '[block_token:webform:webform]'
9. Verify the webform at: /form/computed-form
After above steps, you should see the form which includes Contact form which is rendered incorrectly (input elements are missing). See the screenshot. I've also tested different webforms, the html elements are always filtered out, despite there isn't any filter setup.
Although the form is rendered correctly at some point in Renderer.php by adding the following code in doRender:
1. Edit: core/lib/Drupal/Core/Render/Renderer.php and go to renderRoot()
2. Before final return, add this code:
echo($output); exit;
Here is the backtrace for this tokenized block, at above point when it's rendered correctly:
renderRoot()(block_token.module:60); // WORKS HERE
block_token_block_render()(block_token.module:148);
block_token_tokens()(:);
call_user_func_array()(ModuleHandler.php:402);
invokeAll()(Token.php:304);
generate()(Token.php:196);
replace()(WebformTokenManager.php:67);
replace()(WebformComputedBase.php:77);
replaceTokens()(WebformElementBase.php:661); // WORKS HERE
prepare()(WebformComputedBase.php:61);
prepare()(WebformElementManager.php:149);
invokeMethod()(WebformSubmissionForm.php:1560);
prepareElements()(WebformSubmissionForm.php:382);
form()(EntityForm.php:115);
buildForm()(WebformSubmissionForm.php:294);
buildForm()(:);
call_user_func_array()(FormBuilder.php:514);
retrieveForm()(FormBuilder.php:271);
buildForm()(EntityFormBuilder.php:48);
getForm()(Webform.php:895);
getSubmissionForm()(WebformController.php:83);
addForm()(:);
call_user_func_array()(EarlyRenderingControllerWrapperSubscriber.php:123); // WORKS HERE
Drupal\Core\EventSubscriber\{closure}()(Renderer.php:584);
executeInRenderContext()(EarlyRenderingControllerWrapperSubscriber.php:124);
wrapControllerExecutionInRenderContext()(EarlyRenderingControllerWrapperSubscriber.php:97);
Drupal\Core\EventSubscriber\{closure}()(:);
call_user_func_array()(HttpKernel.php:144);
handleRaw()(HttpKernel.php:64);
handle()(Session.php:57);
handle()(KernelPreHandle.php:47);
handle()(PageCache.php:99);
pass()(PageCache.php:78);
handle()(ReverseProxyMiddleware.php:47);
handle()(NegotiationMiddleware.php:50);
handle()(StackedHttpKernel.php:23);
handle()(DrupalKernel.php:656);
handle()(index.php:19);
include()(d8-rs-router.php:67);
However in the final output, the block is rendered incorrectly as follow:
Here is the generated incorrect html code:
<div id="block-webform" class="block block-webform block-webform-block">
<h2>Webform</h2>
<div class="content">
<div class="js-form-item form-item js-form-type-textfield form-type-textfield js-form-item-name form-item-name">
Your Name
</div>
<div class="js-form-item form-item js-form-type-email form-type-email js-form-item-email form-item-email">
Your Email
</div>
<div class="js-form-item form-item js-form-type-textfield form-type-textfield js-form-item-subject form-item-subject">
Subject
</div>
<div class="js-form-item form-item js-form-type-textarea form-type-textarea js-form-item-message form-item-message">
Message
<div class="form-textarea-wrapper">
</div>
</div>
<div data-drupal-selector="edit-actions" class="form-actions webform-actions js-form-wrapper form-wrapper" id="edit-actions">
</div>
</div>
</div>
which has missing input elements and lots of new line characters.
Comment | File | Size | Author |
---|---|---|---|
#22 | 2901761-webform-demo.gif | 485.38 KB | kenorb |
#19 | 0001-Issue-2901761-by-kenorb-Computed-field-fails-to-rend.patch | 949 bytes | kenorb |
| |||
#17 | 0001-Issue-2901761-by-kenorb-Computed-field-fails-to-rend.patch | 1.96 KB | kenorb |
#15 | 0001-Issue-2901761-by-kenorb-Computed-field-fails-to-rend.patch | 1.98 KB | kenorb |
#8 | 2901761-webform-after-patch.png | 90.98 KB | kenorb |
Comments
Comment #2
kenorb CreditAttribution: kenorb commentedComment #3
kenorb CreditAttribution: kenorb commentedComment #4
kenorb CreditAttribution: kenorb commentedComment #5
kenorb CreditAttribution: kenorb commentedComment #6
kenorb CreditAttribution: kenorb commentedComment #7
kenorb CreditAttribution: kenorb commentedConfirmed it's the issue with Webform, will provide patch shortly.
Comment #8
kenorb CreditAttribution: kenorb commentedAttaching patch which fixes the rendering issue. Basically when '#markup', Drupal strips all the html tags (Xss), so it's not possible to use full features of html in computed field values such as block tokens.
The solution is based on suggestion from this post from Pass raw html to #markup thread.
Webform before applying the patch:
Webform after applying the patch:
Comment #9
kenorb CreditAttribution: kenorb commentedI'm not sure if any of the states needs to be updated.
As I'm testing on one page, but I've got these errors:
with the configuration described in the main thread, but it may not be related to this patch.
Comment #10
kenorb CreditAttribution: kenorb commentedDespite #9, I've tested on clean installation of Drupal by following below steps and it works fine:
1. Install Drupal 8:
drush qd --no-server --account-pass=admin
2. Enable modules:
cd *drupal*/drupal && drush -y en webform block_token
3. Enable sub-modules:
drush -y en webform_ui webform_examples
4. Run this to apply the patch:
(cd modules/block_token && patch -p1 < <(curl -s https://www.drupal.org/files/issues/0001-2899439-by-kenorb-Fixes-rendering-issue-for-blocks.patch))
5. Run PHP builtin server:
drush rs
6. Open: http://127.0.0.1:8888/ and login as admin/admin.
7. Go to /admin/structure/block and in Content (or anywhere else) - Place block, choose Webform, then select Contact Webform, in Pages select 'Hide for the listed pages' with empty list (to hide it by default), and tick 'Create the token for this block', then Save.
8. Now go to /admin/structure/webform/manage/example_element_states, 'Add element' under 'Checkbox example' group of 'Computed token' type field with any title and use [block_token:webform:webform] as a value. Then under 'Conditional logic' add 'Visible/All/Please check this box/Checked' condition, then Save.
9. Now go to the form at /form/example-element-states to confirm the Contact form will appear when clicking on 'Checkbox example'. If it's not, make sure you've applied correctly the patch from point 4th.
Comment #11
kenorb CreditAttribution: kenorb commentedThe error at #9 was related to the patch, since my form which was the value of computed token was wrongly encoded.
So I had this incorrect HTML code (part of computed token):
which has wrongly encoded double-quotes causing the parsing problem on web browser like data-drupal-states="{". In order to fix it, the double quote (") should be encoded as a ".
After applying this new patch, the HTML code is correctly encoded:
I also removing processValue() method which it seems it's not used anymore in this class.
Comment #13
kenorb CreditAttribution: kenorb commentedRe-attaching patch in the corrected format.
Comment #15
kenorb CreditAttribution: kenorb commentedRe-testing updated patch.
Comment #17
kenorb CreditAttribution: kenorb commentedTesting another patch with slight change.
Comment #19
kenorb CreditAttribution: kenorb commentedSimplifies patch.
Comment #20
jrockowitz CreditAttribution: jrockowitz commented@kenorb A webform can't be nested inside webform. More accurately an HTML form can't be nested in an HTML form.
@see https://stackoverflow.com/questions/379610/can-you-nest-html-forms
I am not going to be able to commit this patch.
Comment #21
jrockowitz CreditAttribution: jrockowitz commentedComment #22
kenorb CreditAttribution: kenorb commentedThe patch works in my case. I'm not using it exactly as form within form, but the main form isn't used for submit, it's just used as a AJAX trigger (selector with conditional logic) to display another subform. The main won't be used at all, because the main submit button is hidden, so only displayed webform (within computed token) can be submitted.
Here is the demo:
The patch is very simple and without it, my triggered webform isn't rendered correctly, so I'll have to keep my patch anyway.
My Webform configuration: