From d6fe720654fb74e00724b22b9d572eec37b45139 Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Fri, 21 Aug 2026 09:58:52 -0400 Subject: [PATCH 01/12] BC: Remove dependency on XML builder --- src/Element.php | 74 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 7 deletions(-) diff --git a/src/Element.php b/src/Element.php index 45c0383..7b60f99 100644 --- a/src/Element.php +++ b/src/Element.php @@ -5,9 +5,9 @@ use Stringable; -use Eightfold\XMLBuilder\Element as XMLElement; +// use Eightfold\XMLBuilder\Element as XMLElement; -class Element extends XMLElement implements Stringable +class Element implements Stringable { /** * The following attributes will be placed in this order if used in an @@ -51,22 +51,79 @@ class Element extends XMLElement implements Stringable "start" ]; - protected function omitEndTagClosingString(): string + public static function create(string $name, string|Stringable ...$content): static { - return '>'; + return new static($name, $content); + } + + public static function __callStatic(string $name, array $content = []): static + { + return new static($name, $content); + } + + private function __construct( + private string $name, + private array $content = [], + private array $properties = [], + private bool $omitEndTag = false, + ) { + } + + public function props(string ...$properties): static + { + $this->properties = $properties; + return $this; + } + + public function prop(string $prop): static + { + $this->properties[] = $prop; + return $this; + } + + public function omitEndTag(): self + { + $this->omitEndTag = true; + return $this; + } + + public function toString(): string + { + return $this->opening() + . implode('', array_map('strval', $this->content)) + . $this->closing(); + } + + public function __toString(): string + { + return $this->toString(); + } + + private function opening(): string + { + if ($this->omitEndTag) { + return '<' . $this->name . $this->propertiesString() . '>'; + } + + return '<' . $this->name . $this->propertiesString() . '>'; + } + + private function closing(): string + { + return $this->omitEndTag ? '' : 'name . '>'; } protected function propertiesString(): string { - if ($this->properties() === []) { + if ($this->properties === []) { return ''; } $ordered = []; - $other = []; + $other = []; $boolean = []; - foreach ($this->properties() as $property) { + foreach ($this->properties as $property) { [$attr, $value] = array_pad(explode(' ', $property, 2), 2, ''); if ($value === '') { @@ -75,10 +132,13 @@ protected function propertiesString(): string if (in_array($attr, self::ORDERED, true)) { $ordered[$attr] = $value; + } elseif ($attr === $value) { $boolean[$attr] = true; + } else { $other[$attr] = $value; + } } From 00da800e17f09d532d5304d618019750d9c9b626 Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Fri, 21 Aug 2026 09:59:02 -0400 Subject: [PATCH 02/12] add: toString method --- src/Document.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Document.php b/src/Document.php index cc1e1c7..168702c 100644 --- a/src/Document.php +++ b/src/Document.php @@ -57,7 +57,7 @@ public function bodyProps(string ...$props): Document return $this; } - public function __toString(): string + public function toString(): string { $pageTitle = $this->title(); if ( @@ -79,6 +79,11 @@ public function __toString(): string return $doctype . $html; } + public function __toString(): string + { + return $this->toString(); + } + private function title(): string|Stringable { return $this->title; From 82931ba9ad458009d1a2225080ef24416b7387ca Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Fri, 21 Aug 2026 12:09:29 -0400 Subject: [PATCH 03/12] fix: PHPStan --- src/Element.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Element.php b/src/Element.php index 7b60f99..8f1972b 100644 --- a/src/Element.php +++ b/src/Element.php @@ -56,12 +56,19 @@ public static function create(string $name, string|Stringable ...$content): stat return new static($name, $content); } + /** + * @param array $content + */ public static function __callStatic(string $name, array $content = []): static { return new static($name, $content); } - private function __construct( + /** + * @param array $content + * @param string[] $properties + */ + final private function __construct( private string $name, private array $content = [], private array $properties = [], From 45902037c64d3f6227feaec845af15a023858ad9 Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Sat, 22 Aug 2026 12:53:55 -0400 Subject: [PATCH 04/12] refactor: Move name attr above type --- src/Element.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Element.php b/src/Element.php index 8f1972b..399dd80 100644 --- a/src/Element.php +++ b/src/Element.php @@ -20,6 +20,7 @@ class Element implements Stringable "id", "class", "style", + "name", "type", "media", "tabindex", @@ -39,7 +40,6 @@ class Element implements Stringable "itemref", "itemprop", "title", - "name", "http-equiv", "charset", "alt", From d432add4851443e9b21f02a5e4a6665c42d7866d Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Sat, 22 Aug 2026 12:55:05 -0400 Subject: [PATCH 05/12] refactor: Select + SelectType enum --- src/Forms/Select.php | 27 +++++++++++-------------- src/Forms/SelectType.php | 9 +++++++++ tests/Forms/SelectTest.php | 41 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 17 deletions(-) create mode 100644 src/Forms/SelectType.php diff --git a/src/Forms/Select.php b/src/Forms/Select.php index fa4d951..4fdc9b2 100644 --- a/src/Forms/Select.php +++ b/src/Forms/Select.php @@ -7,6 +7,8 @@ use Eightfold\HTMLBuilder\Element; +use Eightfold\HTMLBuilder\Forms\SelectType; + class Select implements Stringable { /** @@ -14,9 +16,7 @@ class Select implements Stringable */ private array $wrapperProperties = []; - private bool $dropdown = true; - - private bool $checkbox = false; + private SelectType $type = SelectType::Dropdown; /** * @param array $options @@ -51,22 +51,19 @@ public function wrapperProps(string ...$properties): self public function dropdown(): self { - $this->dropdown = true; - $this->checkbox = false; + $this->type = SelectType::Dropdown; return $this; } public function radio(): self { - $this->dropdown = false; - $this->checkbox = false; + $this->type = SelectType::Radio; return $this; } public function checkbox(): self { - $this->checkbox = true; - $this->dropdown = false; + $this->type = SelectType::Checkbox; return $this; } @@ -88,7 +85,7 @@ private function hasSelected(): bool */ private function selected(): string|array { - if ($this->checkbox) { + if ($this->type === SelectType::Checkbox) { if (is_array($this->selected)) { return $this->selected; } @@ -115,7 +112,7 @@ private function isSelected(string $value): bool public function __toString(): string { - if ($this->dropdown) { + if ($this->type === SelectType::Dropdown) { return (string) $this->selectDropdown(); } return (string) $this->selectOther(); @@ -146,16 +143,16 @@ private function selectDropdown(): Element private function selectOther(): Element { $elements = []; - $type = 'radio'; - if ($this->checkbox) { - $type = 'checkbox'; - } + $type = $this->type === SelectType::Checkbox ? 'checkbox' : 'radio'; foreach ($this->options as $value => $content) { $value = (string) $value; $id = $this->name . '-' . $value; $label = Element::label($content)->props('for ' . $id); $input = Element::input()->omitEndTag()->props( 'id ' . $id, + ($this->type === SelectType::Checkbox) + ? 'name ' . $this->name . '[]' + : 'name ' . $this->name, 'type ' . $type, 'value ' . $value ); diff --git a/src/Forms/SelectType.php b/src/Forms/SelectType.php new file mode 100644 index 0000000..c49b5ce --- /dev/null +++ b/src/Forms/SelectType.php @@ -0,0 +1,9 @@ +Select your option
+
Select your option
html; $result = (string) Select::create( @@ -34,7 +34,7 @@ public function can_be_checkboxes(): void // phpcs: ignore public function can_be_radio_buttons(): void // phpcs: ignore { $expected = <<Select your option
+
Select your option
html; $result = (string) Select::create( @@ -49,6 +49,43 @@ public function can_be_radio_buttons(): void // phpcs: ignore $this->assertSame($expected, $result); } + #[Test] + public function dropdown_mode_is_explicit(): void // phpcs: ignore + { + $expected = << + html; + + $result = (string) Select::create( + 'Select your option', + 'select', + [ + 'value' => 'display' + ] + )->radio()->dropdown(); + + $this->assertSame($expected, $result); + } + + #[Test] + public function checkbox_mode_is_explicit(): void // phpcs: ignore + { + $expected = <<Select your option
+ html; + + $result = (string) Select::create( + 'Select your option', + 'select', + [ + 'value' => 'display' + ], + 'value' + )->radio()->checkbox(); + + $this->assertSame($expected, $result); + } + #[Test] public function can_add_properties_to_wrapper(): void // phpcs: ignore { From 641c2e3eb8e8f3ee25ac7018613c7ca1410bca1a Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Sat, 22 Aug 2026 13:35:45 -0400 Subject: [PATCH 06/12] update: Speed test table --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 8b327e4..6217001 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,16 @@ The `/comparisons` folder can be used to run performance tests locally to compar 4. PHP HTML Builder only (the Document class), and 5. PHP HTML Builder only using PSR-4 autoloading. +These results are from August 22nd, 2026 (running on PHP 8.5): + +|Configuration |Average time in milliseconds |Median time in milliseconds |Transfer size in kilobytes | +|:---|---:|---:|---:| +|1 |0.0022 |0.0020 |2.7 | +|2 |0.0151 |0.0125 |1.99 | +|3 |0.4314 |0.3025 |1.82 | +|4 |1.4446 |0.3672 |1.74 | +|5 |0.9059 |0.6750 |1.74 | + These results are from February 26th, 2024: |Configuration |Average time in milliseconds |Median time in milliseconds |Transfer size in kilobytes | From c28b76868e71c96cbd252249ac58d38abd1ca1c6 Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Sun, 23 Aug 2026 09:45:31 -0400 Subject: [PATCH 07/12] add: Comment from XML Builder --- src/Comment.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/Comment.php diff --git a/src/Comment.php b/src/Comment.php new file mode 100644 index 0000000..e9626ba --- /dev/null +++ b/src/Comment.php @@ -0,0 +1,24 @@ +content . ' -->' . "\n"; + } +} From b16c49fbfc62646ad4ce38f23296c4d5a3ea25b3 Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Sun, 23 Aug 2026 09:45:52 -0400 Subject: [PATCH 08/12] refactor: Favicons without XML Builder --- src/Components/Favicons.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Components/Favicons.php b/src/Components/Favicons.php index 095dce7..a3ec21a 100644 --- a/src/Components/Favicons.php +++ b/src/Components/Favicons.php @@ -5,8 +5,6 @@ use Stringable; -use Eightfold\XMLBuilder\Concatenate; - use Eightfold\HTMLBuilder\Element; use Eightfold\HTMLBuilder\Components\FaviconMetroColors; @@ -186,6 +184,6 @@ public function __toString(): string 'content ' . $this->appName() ); } - return (string) Concatenate::create(...$elements); + return (string) implode('', $elements); } } From 8b19e07fa3aa9d21db0c241e7e33d27935377fd6 Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Sun, 23 Aug 2026 09:46:17 -0400 Subject: [PATCH 09/12] reduce: Performance threshold --- tests/PerformanceTest.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/PerformanceTest.php b/tests/PerformanceTest.php index ddb7d0a..f3a5b58 100644 --- a/tests/PerformanceTest.php +++ b/tests/PerformanceTest.php @@ -8,10 +8,9 @@ use Eightfold\HTMLBuilder\Tests\Extensions\ElementExtension; -use Eightfold\XMLBuilder\Comment; - use Eightfold\HTMLBuilder\Document; use Eightfold\HTMLBuilder\Element; +use Eightfold\HTMLBuilder\Comment; class PerformanceTest extends TestCase { @@ -57,7 +56,7 @@ public function document_is_speedy(): void // phpcs:ignore $elapsed = $end - $start; $ms = $elapsed/1e+6; - $this->assertLessThan(1.5, $ms); + $this->assertLessThan(0.75, $ms); } #[Test] From 68a1442ac33507a735645fff8744fcc1128713e2 Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Sun, 23 Aug 2026 09:57:23 -0400 Subject: [PATCH 10/12] remove: XML Builder from performance test --- comparisons/php-html-builder-document/index.php | 10 ---------- comparisons/php-html-builder-element/index.php | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/comparisons/php-html-builder-document/index.php b/comparisons/php-html-builder-document/index.php index 8bb82a3..dd8fc60 100644 --- a/comparisons/php-html-builder-document/index.php +++ b/comparisons/php-html-builder-document/index.php @@ -6,16 +6,6 @@ $start = hrtime(true); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Contracts/Contentable.php'); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Contracts/ContentWithoutElement.php'); - -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Implementations/Properties.php'); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Implementations/Contentable.php'); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Implementations/ContentWithoutElement.php'); - -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Concatenate.php'); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Element.php'); - require_once(__DIR__ . '/../../src/Document.php'); require_once(__DIR__ . '/../../src/Element.php'); diff --git a/comparisons/php-html-builder-element/index.php b/comparisons/php-html-builder-element/index.php index 126045a..9babe6c 100644 --- a/comparisons/php-html-builder-element/index.php +++ b/comparisons/php-html-builder-element/index.php @@ -6,16 +6,6 @@ $start = hrtime(true); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Contracts/Contentable.php'); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Contracts/ContentWithoutElement.php'); - -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Implementations/Properties.php'); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Implementations/Contentable.php'); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Implementations/ContentWithoutElement.php'); - -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Concatenate.php'); -require_once(__DIR__ . '/../../vendor/8fold/php-xml-builder/src/Element.php'); - require_once(__DIR__ . '/../../src/Element.php'); $pageTitle = "Page title here"; From 552be00de7d440dfb101436f90ab7842ccc79ddc Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Sun, 23 Aug 2026 10:01:44 -0400 Subject: [PATCH 11/12] BC: Remove XML Builder --- composer.json | 3 +-- composer.lock | 68 +++++---------------------------------------------- 2 files changed, 7 insertions(+), 64 deletions(-) diff --git a/composer.json b/composer.json index f2cc3fa..861938f 100644 --- a/composer.json +++ b/composer.json @@ -10,8 +10,7 @@ } ], "require": { - "php": "^8.4", - "8fold/php-xml-builder": "^3.0" + "php": "^8.4" }, "require-dev": { "phpstan/phpstan": "^2.2", diff --git a/composer.lock b/composer.lock index 5668822..4dc3e36 100644 --- a/composer.lock +++ b/composer.lock @@ -4,64 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1fdad98a22607378979754195f90c90a", - "packages": [ - { - "name": "8fold/php-xml-builder", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/8fold/php-xml-builder.git", - "reference": "405b8bf73c538f7073a7064ecf3eb458519f4c4d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/8fold/php-xml-builder/zipball/405b8bf73c538f7073a7064ecf3eb458519f4c4d", - "reference": "405b8bf73c538f7073a7064ecf3eb458519f4c4d", - "shasum": "" - }, - "require": { - "php": "^8.4" - }, - "require-dev": { - "phpstan/phpstan": "^2.2", - "phpunit/phpunit": "^13.2", - "squizlabs/php_codesniffer": "^4.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Eightfold\\XMLBuilder\\": "./src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Josh Bruce", - "email": "josh@8fold.pro" - } - ], - "description": "A library for building XML document and element strings.", - "support": { - "issues": "https://github.com/8fold/php-xml-builder/issues", - "source": "https://github.com/8fold/php-xml-builder/tree/3.0.0" - }, - "funding": [ - { - "url": "https://github.com/8fold", - "type": "github" - }, - { - "url": "https://github.com/joshbruce", - "type": "github" - } - ], - "time": "2026-08-18T23:47:45+00:00" - } - ], + "content-hash": "b0dda89cb77a498539df68b41a4d0ad1", + "packages": [], "packages-dev": [ { "name": "myclabs/deep-copy", @@ -300,11 +244,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.2.8", + "version": "2.2.9", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e285254e60f33c21902efef4a926ca0987c06804", - "reference": "e285254e60f33c21902efef4a926ca0987c06804", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/13d6b4f347bad222da436580c8304fa6f83e6bd0", + "reference": "13d6b4f347bad222da436580c8304fa6f83e6bd0", "shasum": "" }, "require": { @@ -360,7 +304,7 @@ "type": "github" } ], - "time": "2026-08-04T22:21:45+00:00" + "time": "2026-08-22T07:38:16+00:00" }, { "name": "phpunit/php-code-coverage", From 28d5cf0d5fd366af0e4221706fed895497ab19eb Mon Sep 17 00:00:00 2001 From: Josh Bruce Date: Sun, 23 Aug 2026 10:08:37 -0400 Subject: [PATCH 12/12] BC: Change namespace to Html instead of HTML --- .../php-html-builder-document-psr4/index.php | 18 +++++++++--------- .../php-html-builder-document/index.php | 18 +++++++++--------- comparisons/php-html-builder-element/index.php | 12 ++++++------ composer.json | 4 ++-- phpstan.neon | 2 +- src/Comment.php | 2 +- src/Components/Copyright.php | 4 ++-- src/Components/FaviconMetroColors.php | 2 +- src/Components/Favicons.php | 6 +++--- src/Components/PageTitle.php | 4 ++-- src/Document.php | 4 ++-- src/Element.php | 4 +--- src/Forms/Select.php | 6 +++--- src/Forms/SelectType.php | 2 +- tests/Components/CopyrightTest.php | 4 ++-- tests/Components/FaviconsTest.php | 6 +++--- tests/DocumentBaselineTest.php | 8 ++++---- tests/ElementBaselineTest.php | 4 ++-- tests/ElementExtensionBaselineTest.php | 4 ++-- tests/Extensions/ElementExtension.php | 4 ++-- tests/Forms/SelectTest.php | 4 ++-- tests/PerformanceTest.php | 10 +++++----- 22 files changed, 65 insertions(+), 67 deletions(-) diff --git a/comparisons/php-html-builder-document-psr4/index.php b/comparisons/php-html-builder-document-psr4/index.php index 5ccbc1a..7568b70 100644 --- a/comparisons/php-html-builder-document-psr4/index.php +++ b/comparisons/php-html-builder-document-psr4/index.php @@ -95,22 +95,22 @@ $sections = []; foreach ($posts as $post) { - $sections[] = \Eightfold\HTMLBuilder\Element::section( - \Eightfold\HTMLBuilder\Element::h2($post['title']), - \Eightfold\HTMLBuilder\Element::p($post['description']), - \Eightfold\HTMLBuilder\Element::p( - \Eightfold\HTMLBuilder\Element::a($post['url']['text']) + $sections[] = \Eightfold\HtmlBuilder\Element::section( + \Eightfold\HtmlBuilder\Element::h2($post['title']), + \Eightfold\HtmlBuilder\Element::p($post['description']), + \Eightfold\HtmlBuilder\Element::p( + \Eightfold\HtmlBuilder\Element::a($post['url']['text']) ->props('href ' . $post['url']['href']) ) ); } -print \Eightfold\HTMLBuilder\Document::create( +print \Eightfold\HtmlBuilder\Document::create( $pageTitle )->body( - \Eightfold\HTMLBuilder\Element::h1($pageTitle), - \Eightfold\HTMLBuilder\Element::a('time')->props('href #bottom'), - \Eightfold\HTMLBuilder\Element::article(...$sections) + \Eightfold\HtmlBuilder\Element::h1($pageTitle), + \Eightfold\HtmlBuilder\Element::a('time')->props('href #bottom'), + \Eightfold\HtmlBuilder\Element::article(...$sections) ); $end = hrtime(true); diff --git a/comparisons/php-html-builder-document/index.php b/comparisons/php-html-builder-document/index.php index dd8fc60..493d6f5 100644 --- a/comparisons/php-html-builder-document/index.php +++ b/comparisons/php-html-builder-document/index.php @@ -96,22 +96,22 @@ $sections = []; foreach ($posts as $post) { - $sections[] = \Eightfold\HTMLBuilder\Element::section( - \Eightfold\HTMLBuilder\Element::h2($post['title']), - \Eightfold\HTMLBuilder\Element::p($post['description']), - \Eightfold\HTMLBuilder\Element::p( - \Eightfold\HTMLBuilder\Element::a($post['url']['text']) + $sections[] = \Eightfold\HtmlBuilder\Element::section( + \Eightfold\HtmlBuilder\Element::h2($post['title']), + \Eightfold\HtmlBuilder\Element::p($post['description']), + \Eightfold\HtmlBuilder\Element::p( + \Eightfold\HtmlBuilder\Element::a($post['url']['text']) ->props('href ' . $post['url']['href']) ) ); } -print \Eightfold\HTMLBuilder\Document::create( +print \Eightfold\HtmlBuilder\Document::create( $pageTitle )->body( - \Eightfold\HTMLBuilder\Element::h1($pageTitle), - \Eightfold\HTMLBuilder\Element::a('time')->props('href #bottom'), - \Eightfold\HTMLBuilder\Element::article(...$sections) + \Eightfold\HtmlBuilder\Element::h1($pageTitle), + \Eightfold\HtmlBuilder\Element::a('time')->props('href #bottom'), + \Eightfold\HtmlBuilder\Element::article(...$sections) ); $end = hrtime(true); diff --git a/comparisons/php-html-builder-element/index.php b/comparisons/php-html-builder-element/index.php index 9babe6c..a8a0939 100644 --- a/comparisons/php-html-builder-element/index.php +++ b/comparisons/php-html-builder-element/index.php @@ -95,11 +95,11 @@ $sections = []; foreach ($posts as $post) { - $sections[] = \Eightfold\HTMLBuilder\Element::section( - \Eightfold\HTMLBuilder\Element::h2($post['title']), - \Eightfold\HTMLBuilder\Element::p($post['description']), - \Eightfold\HTMLBuilder\Element::p( - \Eightfold\HTMLBuilder\Element::a($post['url']['text']) + $sections[] = \Eightfold\HtmlBuilder\Element::section( + \Eightfold\HtmlBuilder\Element::h2($post['title']), + \Eightfold\HtmlBuilder\Element::p($post['description']), + \Eightfold\HtmlBuilder\Element::p( + \Eightfold\HtmlBuilder\Element::a($post['url']['text']) ->props('href ' . $post['url']['href']) ) ); @@ -115,7 +115,7 @@

time

- +