diff --git a/CHANGELOG b/CHANGELOG
index 930da743e9e..82187ec51d9 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,7 @@
* 2.12.3 (2019-XX-XX)
- * fixed number formatter in Intl extra extension when using a formatter prototype
+* fixed number formatter in Intl extra extension when using a formatter prototype
+* added "html_attr" function to the HtmlExtension extension in the "extra" repositories
* 2.12.2 (2019-11-11)
diff --git a/doc/functions/html_attr.rst b/doc/functions/html_attr.rst
new file mode 100644
index 00000000000..3fc14c79fbe
--- /dev/null
+++ b/doc/functions/html_attr.rst
@@ -0,0 +1,37 @@
+``html_attr``
+================
+
+.. versionadded:: 2.x
+ The ``html_attr`` function was added in Twig 2.x.
+
+The ``html_attr`` function returns a string by joining html attributes together:
+
+.. code-block:: twig
+
+ {% set attr = {
+ id: 123,
+ disabled: true,
+ hidden: false,
+ type: 'button',
+ 'aria-expandend': 'false',
+ } %}
+
+
+ {# example output: #}
+
+.. note::
+
+ The ``html_attr`` function is part of the ``HtmlExtension`` which is not
+ installed by default. Install it first:
+
+ .. code-block:: bash
+
+ $ composer req twig/html-extra
+
+ Then, use the ``twig/extra-bundle`` on Symfony projects or add the extension
+ explictly on the Twig environment::
+
+ use Twig\Extra\Html\HtmlExtension;
+
+ $twig = new \Twig\Environment(...);
+ $twig->addExtension(new HtmlExtension());
diff --git a/extra/html-extra/src/HtmlExtension.php b/extra/html-extra/src/HtmlExtension.php
index 81868c59799..ab1b963740f 100644
--- a/extra/html-extra/src/HtmlExtension.php
+++ b/extra/html-extra/src/HtmlExtension.php
@@ -35,6 +35,7 @@ public function getFunctions()
{
return [
new TwigFunction('html_classes', 'twig_html_classes'),
+ new TwigFunction('html_attr', 'twig_html_attributes', ['needs_environment' => true, 'is_safe' => ['html']]),
];
}
@@ -83,6 +84,7 @@ public function dataUri(string $data, string $mime = null, array $parameters = [
}
namespace {
+use Twig\Environment;
use Twig\Error\RuntimeError;
function twig_html_classes(...$args): string
@@ -108,4 +110,24 @@ function twig_html_classes(...$args): string
return implode(' ', array_unique($classes));
}
+
+function twig_html_attributes(Environment $env, array $attributes): string
+{
+ $output = '';
+
+ foreach ($attributes as $attribute => $value) {
+ $attribute = \htmlspecialchars($attribute, ENT_COMPAT | ENT_HTML5, $env->getCharset(), false);
+
+ if ($value === true) {
+ $output .= ' ' . $attribute;
+ } else if (\is_string($value) || \is_numeric($value)) {
+ $value = \htmlspecialchars($value, ENT_COMPAT | ENT_HTML5, $env->getCharset(), false);
+ $output .= sprintf(' %s="%s"', $attribute, $value);
+ } else if ($value !== false) {
+ throw new RuntimeError(sprintf('The html_attr function argument value of key %d should be either a boolean, string or number, got "%s".', $attribute, \gettype($value)));
+ }
+ }
+
+ return $output;
+}
}
diff --git a/extra/html-extra/tests/Fixtures/html_attr.test b/extra/html-extra/tests/Fixtures/html_attr.test
new file mode 100644
index 00000000000..94fb045f171
--- /dev/null
+++ b/extra/html-extra/tests/Fixtures/html_attr.test
@@ -0,0 +1,15 @@
+--TEST--
+"html_attr" function
+--TEMPLATE--
+{% set attr = {
+ 'aria-expandend': 'false',
+ disabled: true,
+ hidden: false,
+ id: 123,
+ title: 'cli"