diff --git a/README.md b/README.md
new file mode 100644
index 0000000..2f48b4e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+# HTML Markup Indenter
+
+Don't you just hate it when your beautiful HTML markup is mutilated due to a templating language? (I'm looking at you, [Timber](https://www.upstatement.com/timber/))
+
+Use this plugin to indent the HTML markup output by WordPress using the [Dindent](https://github.com/gajus/dindent) library. Only does its thing when you are not logged in.
+
+## Installation
+
+### Composer (with [Bedrock](https://roots.io/bedrock/))
+
+```sh
+composer require joppuyo/html-markup-indenter
+```
+
+### Classic
+
+1. Upload the plugin folder to the /wp-content/plugins/ directory
+2. Activate the plugin through the **Plugins** menu in WordPress
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..e852fd2
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,6 @@
+{
+ "name": "joppuyo/html-markup-indenter",
+ "type": "wordpress-plugin",
+ "description": "Indents the HTML markup output by WordPress",
+ "license": "GPL-3.0-or-later"
+}
diff --git a/html-markup-indenter.php b/html-markup-indenter.php
new file mode 100644
index 0000000..0774ace
--- /dev/null
+++ b/html-markup-indenter.php
@@ -0,0 +1,33 @@
+indent($final);
+ }
+}, 0);
+
diff --git a/library/dindent/CHANGELOG b/library/dindent/CHANGELOG
new file mode 100755
index 0000000..cf738d0
--- /dev/null
+++ b/library/dindent/CHANGELOG
@@ -0,0 +1,3 @@
+0.0.1 / 2014-02-22
+
+* Rewritten the engine.
\ No newline at end of file
diff --git a/library/dindent/LICENSE b/library/dindent/LICENSE
new file mode 100755
index 0000000..41da83f
--- /dev/null
+++ b/library/dindent/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2013-2014, Anuary (http://anuary.com/)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the Anuary (http://anuary.com/) nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ANUARY BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/library/dindent/README.md b/library/dindent/README.md
new file mode 100755
index 0000000..86ad6d7
--- /dev/null
+++ b/library/dindent/README.md
@@ -0,0 +1,212 @@
+# Dindent
+
+[![Build Status](https://travis-ci.org/gajus/dindent.png?branch=master)](https://travis-ci.org/gajus/dindent)
+[![Coverage Status](https://coveralls.io/repos/gajus/dindent/badge.png?branch=master)](https://coveralls.io/r/gajus/dindent?branch=master)
+[![Latest Stable Version](https://poser.pugx.org/gajus/dindent/version.png)](https://packagist.org/packages/gajus/dindent)
+[![License](https://poser.pugx.org/gajus/dindent/license.png)](https://packagist.org/packages/gajus/dindent)
+
+Dindent (aka., "HTML beautifier") will indent HTML for development and testing. Dedicated for those who suffer from reading a template engine produced markup.
+
+## Abuse Case
+
+Dindent will not sanitize or otherwise manipulate your output beyond indentation.
+
+If you are looking to remove malicious code or make sure that your document is standards compliant, consider the following alternatives:
+
+* [HTML Purifier](https://github.com/Exercise/HTMLPurifierBundle)
+* [DOMDocument::$formatOutput](http://www.php.net/manual/en/class.domdocument.php)
+* [Tidy](http://www.php.net/manual/en/book.tidy.php)
+
+If you need to indent your code in the development environment, beware that earlier mentioned libraries will attempt to fix your markup (that's their primary purpose; indentation is a by-product).
+
+## Regex
+
+There is a [good reason not to use regular expression to parse HTML](http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454). However, DOM parser will rebuild the whole HTML document. It will add missing tags, close open block tags, or remove anything that's not a valid HTML. This is what Tidy does, DOM, etc. This behavior is undesirable when debugging HTML output. Regex based parser will not rebuild the document. Dindent will only add indentation, without otherwise affecting the markup.
+
+The above is also the reason why [Chrome DevTools](https://developers.google.com/chrome-developer-tools/) is not a direct replacement for Dindent.
+
+## Use
+
+```php
+$indenter = new \Gajus\Dindent\Indenter();
+$indenter->indent('[..]');
+```
+
+In the above example, `[..]` is a placeholder for:
+
+```html
+
+
+
+
+
+ and
elements as inline.
+
+ ./dindent.php --input="./input.html" --block="span,em"
+ Indent "input.html" file treating and elements as block.
+```
+
+## Known issues
+
+* Does not treat comments nicely and IE conditional blocks.
+
+## Installation
+
+The recommended way to use Dindent is through [Composer](https://getcomposer.org/).
+
+```json
+{
+ "require": {
+ "gajus/dindent": "2.0.*"
+ }
+}
+```
diff --git a/library/dindent/bin/dindent.php b/library/dindent/bin/dindent.php
new file mode 100755
index 0000000..f4d69bd
--- /dev/null
+++ b/library/dindent/bin/dindent.php
@@ -0,0 +1,67 @@
+ and elements as inline.
+
+ ./dindent.php --input="./input.html" --block="span,em"
+ Indent "input.html" file treating and elements as block.
+';
+
+exit;
+}
+
+if (!isset($options['input'])) {
+ error('Missing "input" parameter.');
+} else if (!file_exists($options['input'])) {
+ error('"input" file does not exist.');
+}
+
+$indenter = new \Gajus\Dindent\Indenter(isset($options['indentation_character']) ? array('indentation_character' => $options['indentation_character']) : array());
+
+if (isset($options['inline'])) {
+ foreach (explode(',', $options['inline']) as $element_name) {
+ $indenter->setElementType($element_name, \Gajus\Dindent\Indenter::ELEMENT_TYPE_INLINE);
+ }
+}
+
+if (isset($options['block'])) {
+ foreach (explode(',', $options['block']) as $element_name) {
+ $indenter->setElementType($element_name, \Gajus\Dindent\Indenter::ELEMENT_TYPE_BLOCK);
+ }
+}
+
+$output = $indenter->indent(file_get_contents($options['input']));
+
+echo $output;
\ No newline at end of file
diff --git a/library/dindent/composer.json b/library/dindent/composer.json
new file mode 100755
index 0000000..c3b0705
--- /dev/null
+++ b/library/dindent/composer.json
@@ -0,0 +1,27 @@
+{
+ "name": "gajus/dindent",
+ "version": "2.0.2",
+ "description": "HTML indentation library for development and testing.",
+ "keywords": ["HTML", "indent", "format"],
+ "homepage": "https://github.com/gajus/dindent",
+ "type": "library",
+ "license": "BSD-3-Clause",
+ "authors": [
+ {
+ "name": "Gajus Kuizinas",
+ "email": "gk@anuary.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.3",
+ "ext-mbstring": "*"
+ },
+ "require-dev": {
+ "satooshi/php-coveralls": "dev-master"
+ },
+ "autoload": {
+ "psr-4": {
+ "Gajus\\Dindent\\": "src/"
+ }
+ }
+}
diff --git a/library/dindent/phpunit.xml b/library/dindent/phpunit.xml
new file mode 100755
index 0000000..b61c71f
--- /dev/null
+++ b/library/dindent/phpunit.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+ ./tests/
+
+
+
+
+
+ ./src/
+
+
+
\ No newline at end of file
diff --git a/library/dindent/src/Exception/DindentException.php b/library/dindent/src/Exception/DindentException.php
new file mode 100755
index 0000000..defa624
--- /dev/null
+++ b/library/dindent/src/Exception/DindentException.php
@@ -0,0 +1,10 @@
+ ' '
+ ),
+ $inline_elements = array('b', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'cite', 'code', 'dfn', 'em', 'kbd', 'strong', 'samp', 'var', 'a', 'bdo', 'br', 'img', 'span', 'sub', 'sup'),
+ $temporary_replacements_script = array(),
+ $temporary_replacements_inline = array();
+
+ const ELEMENT_TYPE_BLOCK = 0;
+ const ELEMENT_TYPE_INLINE = 1;
+
+ const MATCH_INDENT_NO = 0;
+ const MATCH_INDENT_DECREASE = 1;
+ const MATCH_INDENT_INCREASE = 2;
+ const MATCH_DISCARD = 3;
+
+ /**
+ * @param array $options
+ */
+ public function __construct (array $options = array()) {
+ foreach ($options as $name => $value) {
+ if (!array_key_exists($name, $this->options)) {
+ throw new Exception\InvalidArgumentException('Unrecognized option.');
+ }
+
+ $this->options[$name] = $value;
+ }
+ }
+
+ /**
+ * @param string $element_name Element name, e.g. "b".
+ * @param ELEMENT_TYPE_BLOCK|ELEMENT_TYPE_INLINE $type
+ * @return null
+ */
+ public function setElementType ($element_name, $type) {
+ if ($type === static::ELEMENT_TYPE_BLOCK) {
+ $this->inline_elements = array_diff($this->inline_elements, array($element_name));
+ } else if ($type === static::ELEMENT_TYPE_INLINE) {
+ $this->inline_elements[] = $element_name;
+ } else {
+ throw new Exception\InvalidArgumentException('Unrecognized element type.');
+ }
+
+ $this->inline_elements = array_unique($this->inline_elements);
+ }
+
+ /**
+ * @param string $input HTML input.
+ * @return string Indented HTML.
+ */
+ public function indent ($input) {
+ $this->log = array();
+
+ // Dindent does not indent ', $input);
+ }
+ }
+
+ // Removing double whitespaces to make the source code easier to read.
+ // With exception of / CSS white-space changing the default behaviour, double whitespace is meaningless in HTML output.
+ // This reason alone is sufficient not to use Dindent in production.
+ $input = str_replace("\t", '', $input);
+ $input = preg_replace('/\s{2,}/', ' ', $input);
+
+ // Remove inline elements and replace them with text entities.
+ if (preg_match_all('/<(' . implode('|', $this->inline_elements) . ')[^>]*>(?:[^<]*)<\/\1>/', $input, $matches)) {
+ $this->temporary_replacements_inline = $matches[0];
+ foreach ($matches[0] as $i => $match) {
+ $input = str_replace($match, 'ᐃ' . ($i + 1) . 'ᐃ', $input);
+ }
+ }
+
+ $subject = $input;
+
+ $output = '';
+
+ $next_line_indentation_level = 0;
+
+ do {
+ $indentation_level = $next_line_indentation_level;
+
+ $patterns = array(
+ // block tag
+ '/^(<([a-z]+)(?:[^>]*)>(?:[^<]*)<\/(?:\2)>)/' => static::MATCH_INDENT_NO,
+ // DOCTYPE
+ '/^]*)>/' => static::MATCH_INDENT_NO,
+ // tag with implied closing
+ '/^<(input|link|meta|base|br|img|source|hr)([^>]*)>/' => static::MATCH_INDENT_NO,
+ // self closing SVG tags
+ '/^<(animate|stop|path|circle|line|polyline|rect|use)([^>]*)\/>/' => static::MATCH_INDENT_NO,
+ // opening tag
+ '/^<[^\/]([^>]*)>/' => static::MATCH_INDENT_INCREASE,
+ // closing tag
+ '/^<\/([^>]*)>/' => static::MATCH_INDENT_DECREASE,
+ // self-closing tag
+ '/^<(.+)\/>/' => static::MATCH_INDENT_DECREASE,
+ // whitespace
+ '/^(\s+)/' => static::MATCH_DISCARD,
+ // text node
+ '/([^<]+)/' => static::MATCH_INDENT_NO
+ );
+ $rules = array('NO', 'DECREASE', 'INCREASE', 'DISCARD');
+
+ foreach ($patterns as $pattern => $rule) {
+ if ($match = preg_match($pattern, $subject, $matches)) {
+ $this->log[] = array(
+ 'rule' => $rules[$rule],
+ 'pattern' => $pattern,
+ 'subject' => $subject,
+ 'match' => $matches[0]
+ );
+
+ $subject = mb_substr($subject, mb_strlen($matches[0]));
+
+ if ($rule === static::MATCH_DISCARD) {
+ break;
+ }
+
+ if ($rule === static::MATCH_INDENT_NO) {
+
+ } else if ($rule === static::MATCH_INDENT_DECREASE) {
+ $next_line_indentation_level--;
+ $indentation_level--;
+ } else {
+ $next_line_indentation_level++;
+ }
+
+ if ($indentation_level < 0) {
+ $indentation_level = 0;
+ }
+
+ $output .= str_repeat($this->options['indentation_character'], $indentation_level) . $matches[0] . "\n";
+
+ break;
+ }
+ }
+ } while ($match);
+
+ $interpreted_input = '';
+ foreach ($this->log as $e) {
+ $interpreted_input .= $e['match'];
+ }
+
+ if ($interpreted_input !== $input) {
+ throw new Exception\RuntimeException('Did not reproduce the exact input.');
+ }
+
+ $output = preg_replace('/(<(\w+)[^>]*>)\s*(<\/\2>)/', '\\1\\3', $output);
+
+ foreach ($this->temporary_replacements_script as $i => $original) {
+ $output = str_replace('', $original, $output);
+ }
+
+ foreach ($this->temporary_replacements_inline as $i => $original) {
+ $output = str_replace('ᐃ' . ($i + 1) . 'ᐃ', $original, $output);
+ }
+
+ return trim($output);
+ }
+
+ /**
+ * Debugging utility. Get log for the last indent operation.
+ *
+ * @return array
+ */
+ public function getLog () {
+ return $this->log;
+ }
+}
diff --git a/library/dindent/tests/CLITest.php b/library/dindent/tests/CLITest.php
new file mode 100755
index 0000000..8091763
--- /dev/null
+++ b/library/dindent/tests/CLITest.php
@@ -0,0 +1,23 @@
+assertSame('Missing "input" parameter.', static::exec('--foo'));
+ }
+ public function testInputFileDoesNotExist () {
+ $this->assertSame('"input" file does not exist.', static::exec('--input="./bar.html"'));
+ }
+
+ public function testIndentOutput () {
+ $this->assertSame('', static::exec('--input=' . escapeshellarg(__DIR__ . '/sample/input/0-empty-block.html')));
+ }
+
+ static public function exec ($arguments) {
+ return shell_exec('php ' . escapeshellarg(__DIR__ . '/../bin/dindent.php') . ' ' . $arguments);
+ }
+
+ public function indentProvider () {
+ return array_map(function ($e) {
+ return array(pathinfo($e, \PATHINFO_FILENAME));
+ }, glob(__DIR__ . '/input/*.html'));
+ }
+}
\ No newline at end of file
diff --git a/library/dindent/tests/IndenterTest.php b/library/dindent/tests/IndenterTest.php
new file mode 100755
index 0000000..e439c10
--- /dev/null
+++ b/library/dindent/tests/IndenterTest.php
@@ -0,0 +1,80 @@
+ 'bar'));
+ }
+
+ /**
+ * @expectedException Gajus\Dindent\Exception\InvalidArgumentException
+ * @expectedExceptionMessage Unrecognized element type.
+ */
+ public function testSetInvalidElementType () {
+ $indenter = new \Gajus\Dindent\Indenter();
+ $indenter->setElementType('foo', 'bar');
+ }
+
+ /*public function testSetElementTypeInline () {
+ $indenter = new \Gajus\Dindent\Indenter();
+ $indenter->setElementType('foo', \Gajus\Dindent\Indenter::ELEMENT_TYPE_BLOCK);
+
+ $output = $indenter->indent('X
');
+
+ die(var_dump( $output ));
+ }*/
+
+ public function testIndentCustomCharacter () {
+ $indenter = new \Gajus\Dindent\Indenter(array('indentation_character' => 'X'));
+
+ $indented = $indenter->indent('
');
+
+ $expected_output = 'X
';
+
+ $this->assertSame($expected_output, str_replace("\n", '', $indented));
+ }
+
+ /**
+ * @dataProvider logProvider
+ */
+ public function testLog ($token, $log) {
+ $indenter = new \Gajus\Dindent\Indenter();
+ $indenter->indent($token);
+
+ $this->assertSame(array($log), $indenter->getLog());
+ }
+
+ public function logProvider () {
+ return array(
+ array(
+ '
',
+ array(
+ 'rule' => 'NO',
+ 'pattern' => '/^(<([a-z]+)(?:[^>]*)>(?:[^<]*)<\\/(?:\\2)>)/',
+ 'subject' => '
',
+ 'match' => '
',
+ )
+ )
+ );
+ }
+
+ /**
+ * @dataProvider indentProvider
+ */
+ public function testIndent ($name) {
+ $indenter = new \Gajus\Dindent\Indenter();
+
+ $input = file_get_contents(__DIR__ . '/sample/input/' . $name . '.html');
+ $expected_output = file_get_contents(__DIR__ . '/sample/output/' . $name . '.html');
+
+ $this->assertSame($expected_output, $indenter->indent($input));
+ }
+
+ public function indentProvider () {
+ return array_map(function ($e) {
+ return array(pathinfo($e, \PATHINFO_FILENAME));
+ }, glob(__DIR__ . '/sample/input/*.html'));
+ }
+}
\ No newline at end of file
diff --git a/library/dindent/tests/bootstrap.php b/library/dindent/tests/bootstrap.php
new file mode 100755
index 0000000..5b74df6
--- /dev/null
+++ b/library/dindent/tests/bootstrap.php
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/library/dindent/tests/sample/input/1-empty-block-inside-another-block.html b/library/dindent/tests/sample/input/1-empty-block-inside-another-block.html
new file mode 100755
index 0000000..ce46191
--- /dev/null
+++ b/library/dindent/tests/sample/input/1-empty-block-inside-another-block.html
@@ -0,0 +1,6 @@
+