[wp-trac] [WordPress Trac] #50867: An API which encourages automatic escaping of HTML
WordPress Trac
noreply at wordpress.org
Thu Aug 6 08:37:59 UTC 2020
#50867: An API which encourages automatic escaping of HTML
-------------------------------------------------+-------------------------
Reporter: noisysocks | Owner: (none)
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting
| Review
Component: General | Version:
Severity: normal | Resolution:
Keywords: has-patch needs-unit-tests needs- | Focuses:
docs |
-------------------------------------------------+-------------------------
Description changed by noisysocks:
Old description:
> It's common in WordPress to write PHP code that assembles a large bit of
> HTML using conditional logic. A good example of this is
> [https://github.com/WordPress/gutenberg/blob/master/packages/block-
> library/src/navigation-link/index.php#L106
> render_block_core_navigation_link]. Unfortunately this type of code can
> become difficult to read and error prone. For example, we've had several
> reported XSS vulnerabilities in code like this.
>
> How do we feel about adding an API for building large bits of HTML?
>
> Attached is a patch which implements an API inspired by `createElement`
> in `@wordpress/element` and the external `classnames` JavaScript library.
>
> The primary interface is `wp_el`. It takes three arguments: an HTML tag
> name, an array of HTML attributes, and an array of child elements. You
> can nest calls to `wp_el` within each other to cleanly create deeply
> nested HTML.
>
> {{{#!php
> <?php
> echo wp_el(
> 'figure',
> array( 'class' => 'my-image' ),
> array(
> wp_el( 'img', array( 'src' =>
> 'https://pbs.twimg.com/media/Ed_W9VQXkAAtYQY?format=jpg&name=medium' ) ),
> wp_el(
> 'figcaption',
> null,
> 'A cold refreshing glass of pilk'
> ),
> )
> );
> }}}
>
> {{{
> <figure class="my-image"><img
> src="https://pbs.twimg.com/media/Ed_W9VQXkAAtYQY?format=jpg&name=medium"
> /><figcaption>A cold refreshing glass of pilk</figcaption></figure>
> }}}
>
> Optional arguments and automatic handling of non associative array values
> can be used to make usage quite succinct.
>
> {{{#!php
> <?php
> echo wp_el( 'hr' );
> echo wp_el( 'input', 'required' );
> }}}
>
> {{{
> <hr /><input required />
> }}}
>
> The key design detail is that **all strings are automatically escaped**.
> If you want to output unescaped HTML you have to do it explicitly.
>
> {{{#!php
> <?php
> echo wp_el(
> 'article',
> null,
> wp_dangerous_html( '<marquee>Unescaped HTML</marquee>' )
> );
> }}}
>
> {{{
> <article><marquee>Unescaped HTML</marquee></article>
> }}}
>
> Lastly, `wp_classnames` provides a convenient way to assemble HTML
> `class` attributes.
>
> {{{#!php
> <?php
> echo wp_el(
> 'li',
> array(
> 'class' => wp_classnames(
> array(
> 'my-link',
> 'is-current' => $post->ID === $id,
> )
> ),
> ),
> array(
> wp_el(
> 'a',
> array(
> 'href' => $post->guid,
> ),
> $post->post_name
> ),
> )
> );
> }}}
>
> {{{
> <li class="my-link"><a href="http://localhost:8888/?p=215">navigation-
> stored-in-old-way</a></li>
> }}}
>
> Thoughts? Are there alternative approaches common in the PHP ecosystem?
> Does such an API belong in Core?
New description:
It's common in WordPress to write PHP code that assembles a large bit of
HTML using conditional logic. A good example of this is
[https://github.com/WordPress/gutenberg/blob/master/packages/block-
library/src/navigation-link/index.php#L106
render_block_core_navigation_link]. Unfortunately this type of code can
become difficult to read and error prone. For example, we've had several
reported XSS vulnerabilities in code like this.
How do we feel about adding an API for **safely** building large bits of
HTML?
Attached is a patch which implements an API inspired by `createElement` in
`@wordpress/element` and the external `classnames` JavaScript library.
The primary interface is `wp_el`. It takes three arguments: an HTML tag
name, an array of HTML attributes, and an array of child elements. You can
nest calls to `wp_el` within each other to cleanly create deeply nested
HTML.
{{{#!php
<?php
echo wp_el(
'figure',
array( 'class' => 'my-image' ),
array(
wp_el( 'img', array( 'src' =>
'https://pbs.twimg.com/media/Ed_W9VQXkAAtYQY?format=jpg&name=medium' ) ),
wp_el(
'figcaption',
null,
'A cold refreshing glass of pilk'
),
)
);
}}}
{{{
<figure class="my-image"><img
src="https://pbs.twimg.com/media/Ed_W9VQXkAAtYQY?format=jpg&name=medium"
/><figcaption>A cold refreshing glass of pilk</figcaption></figure>
}}}
Optional arguments and automatic handling of non associative array values
can be used to make usage quite succinct.
{{{#!php
<?php
echo wp_el( 'hr' );
echo wp_el( 'input', 'required' );
}}}
{{{
<hr /><input required />
}}}
**The key design detail is that all strings are automatically escaped**.
If you want to output unescaped HTML you have to do it explicitly.
{{{#!php
<?php
echo wp_el(
'article',
null,
wp_dangerous_html( '<marquee>Unescaped HTML</marquee>' )
);
}}}
{{{
<article><marquee>Unescaped HTML</marquee></article>
}}}
Lastly, `wp_classnames` provides a convenient way to assemble HTML `class`
attributes.
{{{#!php
<?php
echo wp_el(
'li',
array(
'class' => wp_classnames(
array(
'my-link',
'is-current' => $post->ID === $id,
)
),
),
array(
wp_el(
'a',
array(
'href' => $post->guid,
),
$post->post_name
),
)
);
}}}
{{{
<li class="my-link"><a href="http://localhost:8888/?p=215">navigation-
stored-in-old-way</a></li>
}}}
Thoughts? Are there alternative approaches common in the PHP ecosystem?
Does such an API belong in Core? What other approaches can we take to
prevent unescaped strings from being output?
--
--
Ticket URL: <https://core.trac.wordpress.org/ticket/50867#comment:2>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list