Create HTML Elements Using PHP: html_element Class

By  on  

I love creating HTML elements using the MooTools JavaScript library. It's easy, fast, and the JavaScript code to create the element is beautiful. That got me thinking -- why don't I do this using PHP? When you build as many dynamic CMS-like websites as me, you end up having to manipulate single HTML element attributes with a bunch of if/else logic and the code can start looking ugly.

I took about a half hour to throw together the following PHP class. It's small, easy to use, and produces beautiful code--just like Moo!

The PHP

/* creates an html element, like in js */
class html_element
{
	/* vars */
	var $type;
	var $attributes;
	var $self_closers;
	
	/* constructor */
	function html_element($type,$self_closers = array('input','img','hr','br','meta','link'))
	{
		$this->type = strtolower($type);
		$this->self_closers = $self_closers;
	}
	
	/* get */
	function get($attribute)
	{
		return $this->attributes[$attribute];
	}
	
	/* set -- array or key,value */
	function set($attribute,$value = '')
	{
		if(!is_array($attribute))
		{
			$this->attributes[$attribute] = $value;
		}
		else
		{
			$this->attributes = array_merge($this->attributes,$attribute);
		}
	}
	
	/* remove an attribute */
	function remove($att)
	{
		if(isset($this->attributes[$att]))
		{
			unset($this->attributes[$att]);
		}
	}
	
	/* clear */
	function clear()
	{
		$this->attributes = array();
	}
	
	/* inject */
	function inject($object)
	{
		if(@get_class($object) == __class__)
		{
			$this->attributes['text'].= $object->build();
		}
	}
	
	/* build */
	function build()
	{
		//start
		$build = '<'.$this->type;
		
		//add attributes
		if(count($this->attributes))
		{
			foreach($this->attributes as $key=>$value)
			{
				if($key != 'text') { $build.= ' '.$key.'="'.$value.'"'; }
			}
		}
		
		//closing
		if(!in_array($this->type,$this->self_closers))
		{
			$build.= '>'.$this->attributes['text'].'</'.$this->type.'>';
		}
		else
		{
			$build.= ' />';
		}
		
		//return it
		return $build;
	}
	
	/* spit it out */
	function output()
	{
		echo $this->build();
	}
}

The class is pretty simple. When you instantiate the class, you feed it the element type. Once the element is created, you use get() to retrieve values and set() (key and value OR array key=>value) to set values. You can get rid of a specified attribute using remove() or all attribute key=>values using clear(). You can inject html_elements into other html_elements by using inject(). You can get the raw HTML of the element using build() or you can use the output() function to echo out the HTML. Important: use the "text" attribute to add text/HTML inside an element.

Example Uses


/* test case - simple link */
$my_anchor = new html_element('a');
$my_anchor->set('href','https://davidwalsh.name');
$my_anchor->set('title','David Walsh Blog');
$my_anchor->set('text','Click here!');
$my_anchor->output();
//<a href="https://davidwalsh.name" title="David Walsh Blog">Click here!</a>

/* test case - br tag */
echo '<pre>';
$my_anchor = new html_element('br');
$my_anchor->output();
//<br />

/* test case - sending an array to set */
echo '<pre>';
$my_anchor = new html_element('a');
$my_anchor->set('href','https://davidwalsh.name');
$my_anchor->set(array('href'=>'http://cnn.com','text'=>'CNN'));
$my_anchor->output();
//<a href="http://cnn.com">CNN</a>

/* test case - injecting another element */
echo '<pre>';
$my_image = new html_element('img');
$my_image->set('src','cnn-logo.jpg');
$my_image->set('border','0');
$my_anchor = new html_element('a');
$my_anchor->set(array('href'=>'http://cnn.com','title'=>'CNN'));
$my_anchor->inject($my_image);
$my_anchor->output();
//<a href="http://cnn.com" title="CNN"><img src="cnn-logo.jpg" border="0" /></a>

Have any ideas for this class? Share them!

Recent Features

  • By
    CSS @supports

    Feature detection via JavaScript is a client side best practice and for all the right reasons, but unfortunately that same functionality hasn't been available within CSS.  What we end up doing is repeating the same properties multiple times with each browser prefix.  Yuck.  Another thing we...

  • By
    Write Simple, Elegant and Maintainable Media Queries with Sass

    I spent a few months experimenting with different approaches for writing simple, elegant and maintainable media queries with Sass. Each solution had something that I really liked, but I couldn't find one that covered everything I needed to do, so I ventured into creating my...

Incredible Demos

  • By
    CSS Vertical Center with Flexbox

    I'm 31 years old and feel like I've been in the web development game for centuries.  We knew forever that layouts in CSS were a nightmare and we all considered flexbox our savior.  Whether it turns out that way remains to be seen but flexbox does easily...

  • By
    Prevent Page Zooming in Mobile Browsers

    Ever since I got my iPhone, I've been more agreeable in going places that my fiancee wants to go. It's not because I have any interest in checking out women's shoes, looking at flowers, or that type of stuff -- it's because my iPhone lets...

Discussion

  1. Nice! Just a thought, shouldn’t it be:

    $my_image->inject($my_anchor);
    

    – or –

    $my_anchor->grab($my_image);
    
  2. @Richard: I don’t think so. I’m injecting the image into the link. If you say that because Moo does things that way, you’re right — I’ve never liked that part of Moo element handling. :)

  3. david

    Why not create functions for the elements instead of building the elements piece by piece, this requires a lot of code. And after all it only builds static html.

    # $my_anchor = new html_element('br');  
    # $my_anchor->output(); 
    

    vs

    <br>
    
  4. This is pretty nice :)

    I think that using something like this could be a life saver in the future, making it a lot easier to make the move from one standard to another, e.g. from html 4 to html 5, or to xhtml as another example – since one would only need to change the tag output one place.

    One could also build helpers uppon this, to save some typing. An example would be from the CodeIgniter framework (http://codeigniter.com/user_guide/helpers/html_helper.html).

    Of course you’d have the overhead from all the php, but there’s always caching :)

    Anyway, I thought I’d just drop a few lines.. you got a really nice blog here, keep up the good work :)

  5. Good work and useful. I try it as soon as. Thank you.

  6. Keith Twombley

    How is this any better than using php’s already built-in methods to output plain html?

  7. @Keith: I don’t know if I’d call it “better.” It’s just a tool to keep code more organized.

  8. Why not return the current instance of the class on the set function? Then you could chain the calls similar to mootools/jQuery (in PHP5, naturally):

    $el = new html_element();
    $el->set('href','http://…')->set('title','…')->set('text','Click here!')->output();
    
  9. @Mark: Great idea. I split them apart in my examples to make the idea seem easier, but that would definitely work.

  10. You could also add a magic __toString method (php5) so you could just do print $my_anchor

  11. It is a great way to build HTML elements, really simple code with a lot of power. The problem is in the principle, why are you generating HTML elements? This type of architecture would be better suited for dynamic FORM generation.

  12. You can create dynamic forms with this. It’s just not limited to forms only. There may be many reasons that you need programmatic control over how HTML is built and this just provides a nice, simple method to do it.

  13. @Richard,

    Yes you could use the method provided for a lot of applications, I never said you could not. I was merely suggesting a practical use for it. In an enterprise level application, you would not want to have all your HTML generated from PHP, that would take millions of lines of code. You would want a strong template system.

    @David,
    I really like the way you structure your code. It reminds me of SimpleXML.

  14. @Sam: Of course you wouldn’t want to do all of your XHTML like that. Forms would be a good usage. Thank you for the compliment!

  15. Convenience functions could also be made to make it shorter for the most common ones:

    $el = new html_element();
    $el->href(‘http://…’)->title(,’…’)->text(‘Click here!’)->output();

  16. Thanks for the class David! Here are my alterations… My goal was to make it a little more like Prototype JS element creation.

    /**
     * Create an element
     */
    class Element {
        private $type;
        private $unaryTagArray = array('input', 'img', 'hr', 'br', 'meta', 'link');
        private $attributeArray;
        private $innerHtml;
    
        /**
         * Constructor
         *
         * @param <type> $type
         * @param <type> $attributeArray
         * @param <type> $unaryTagArray
         */
        public function __construct($type, $attributeArray = array()) {
            $this->type = strtolower($type);
    
            foreach($attributeArray as $attribute => $value) {
                $this->setAttribute($attribute, $value);
            }
    
            return $this;
        }
    
        /**
         * Get one of the element's attributes
         *
         * @param <type> $attribute
         * @return <type>
         */
        public function getAttribute($attribute) {
            return $this->attributeArray[$attribute];
        }
    
        /**
         * Set an array, can pass an array or a key, value combination
         *
         * @param <type> $attribute
         * @param <type> $value
         */
        function setAttribute($attribute, $value = "") {
            if(!is_array($attribute)) {
                $this->attributeArray[$attribute] = $value;
            }
            else {
                $this->attributeArray = array_merge($this->attributeArray, $attribute);
            }
    
            return $this;
        }
    
        /**
         * Remove an attribute from an element
         *
         * @param <type> $attribute
         */
        function removeAttribute($attribute) {
            if(isset($this->attributeArray[$attribute])) {
                unset($this->attributeArray[$attribute]);
            }
    
            return $this;
        }
    
        /**
         * Clear all of the element's attributes
         */
        function clearAttributes() {
            $this->attributeArray = array();
    
            return $this;
        }
    
        /**
         * Insert an element into the current element
         *
         * @param <type> $object
         */
        function insert($object) {
            if(@get_class($object) == __class__) {
                $this->innerHtml .= $object->build();
            }
    
            return $this;
        }
    
        /**
         * Set the innerHtml of an element
         *
         * @param <type> $object
         * @return <type>
         */
        function update($object) {
            $this->innerHtml = $object;
    
            return $this;
        }
    
        /**
         * Builds the element
         *
         * @return <type>
         */
        function build() {
            // Start the tag
            $element = "<".$this->type;
    
            // Add attributes
            if(count($this->attributeArray)) {
                foreach($this->attributeArray as $key => $value) {
                    $element .= " ".$key."=\"".$value."\"";
                }
            }
    
            // Close the element
            if(!in_array($this->type, $this->unaryTagArray)) {
                $element.= ">\n".$this->innerHtml."\n</".$this->type.">\n";
            }
            else {
                $element.= " />\n";
            }
    
            return $element;
        }
    
        /**
         * Echoes out the element
         *
         * @return <type>
         */
        function __toString() {
            return $this->build();
        }
    }
    
    • Hey Kirk, Thanks for the upgrade – your version is looking and working much better for me.

  17. Fred

    This seems to be the sort of thing I am looking for. In my application I will have an html form into which users enter search parameters. php gets the parameters and uses them to query mysql. That’s the easy part, the tricky part is that I want php to present the data from the query within html tags, specifically I want to feed the information into java applet I suppose by using the tag within tags. It seems that php html_element class should make this possible, but I have a hard time wrapping my head around the concept.

    • I would check into using simple dom parser. Works for manipulating html/xhtml from a file or stored aready in a string. I use Simple DOM parser to manipulate and help clean up my template output before echo-ing out to the screen. It’s also great for quickly assembling screen scraping and scripts… aka, news, weather, etc.

  18. Cool topic, I will try to use it my self

  19. Johnny

    This is a very useful tool. But how would I go about creating a form and then adding inputs to that form?

  20. Ashik

    I was searching for this code..
    It is very useful for my WYSIWYG model content management system..
    Thanks

  21. Daniel Phillips

    Line 55 should be:

    $this->set('text', $object->build());
    

    As otherwise you risk an undefined index of the attributes array (text)

  22. Daniel Phillips

    Sorry, make that line 55 should be:

    if(!isset($this->attributes['text'])){
    	$this->attributes['text'] = $object->build();
    }else{
    	$this->attributes['text'].= $object->build();
    }
    

    Otherwise you could overwrite the previous elements text output

  23. type = strtolower($type);
    		$this->self_closers = $self_closers;
    		$this->set('style',"");
    	}
    	
    	/* get */
    	function get($attribute)
    	{
    		return $this->attributes[$attribute];
    	}
    	
    	/* set -- array or key,value */
    	function set($attribute,$value = '')
    	{
    		if(!is_array($attribute))
    		{
    			$this->attributes[$attribute] = $value;
    		}
    		else
    		{
    			$this->attributes = array_merge($this->attributes,$attribute);
    		}
    	}
    	
    	/* remove an attribute */
    	function remove($att)
    	{
    		if(isset($this->attributes[$att]))
    		{
    			unset($this->attributes[$att]);
    		}
    	}
    	
    	/* clear */
    	function clear()
    	{
    		$this->attributes = array();
    	}
    	
    	/* inject */
    	function inject($object)
    	{
    		if(@get_class($object) == __class__)
    		{
    			$this->attributes['text'].= $object->build();
    		}
    	}
    	function  setStyle($cssAt,$value){
    		$this->set("style",$this->get("style")."$cssAt:$value;");
    		
    	}
    	function appendChild($child){
    		$this->children[count($this->children)]= $child;
    	}
    	/* build */
    	function build()
    	{
    		//start
    		$build = 'type;
    		$text="";
    		//add attributes
    		if(count($this->attributes))
    		{
    			foreach($this->attributes as $key=>$value)
    			{
    				if($key != 'text') { $build.= ' '.$key.'="'.$value.'"'; }
    				else{$text=$value;}
    			}
    		}
    		
    		//closing
    		if(!in_array($this->type,$this->self_closers))
    		{
    			$build.= '>';
    			
    			$build.=$text;
    			foreach ($this->children as $child){
    				
    				$build.=$child->build();
    			}
    			$build.='type.'>';
    		}
    		else
    		{
    			$build.= ' />';
    		}
    		
    		//return it
    		return $build;
    	}
    	
    	/* spit it out */
    	function output()
    	{
    		echo $this->build();
    	}
    }
    
    • i have added appendChild ,setStyle function

  24. Acebone

    When a value contains a quote sign, you end up with something like this:

    That won’t work, so I’ve modified the set function of the original code with this:

    function set($attribute,$value = '')
    	{
    		if(!is_array($attribute))
    		{
    			$this->attributes[$attribute] = str_replace('"', '"', $value);
    		}
    		else
    		{
    			foreach($attribute as $key => $val){
    				$attribute[$key] = str_replace('"', '"', $val);
    			}
    			$this->attributes = array_merge($this->attributes,$attribute);
    		}
    	}
  25. Acebone

    Correction:

    When a value contains a quote sign, you end up with something like this:

    <input value=”here “is a quote sign”>

  26. Tanner

    gotta love your code, and thanks for it, but still think jquery is better than mootools. :)

  27. I think a markup like this would be quicker and easier to use. I _just_ started working on this project, so if you guys have any ideas, please don’t hesitate to make contributions :)

     "wrapper"), function(){
      Html::h1("Hello, World", array("class" => "title"));
      Html::ul(array("class" => "links", function(){
        foreach(array(1,2,3) as $x)
          Html::li(function() use($x) {
            Html::a("Link {$x}", "#{$x}");
          });
      });
    });
    
    ?>
    

    Open source on Github at https://github.com/naomik/htmlgen

    • Well, the comment form butchered my code paste, but you can see it on github. Cheers :)

  28. Ken

    This code is great for what I am trying to do, but Im just learning this stuff as I go and I can’t figure out a way to wrap the output into a function, then call that functions through a jquery onclick event.

    Any help would be great.

    Thanks

    • This guy really needs to fix his code snippets; they’re all getting massacred :(

  29. TeMc

    tagnames should be validated, and text and attribute values MUST be escaped with htmlspecialchars().

  30. Hello Gentlemen, ladies! Good Night;
    How would I use this class to generate a

    a
    b
    c


    Please wait return!
    thank you

  31. Just a thought, the separate method calls for adding each attribute to the element seems superfluous. How about one __construct call…something like:

    $a = new html_element(“img”, array( “src” => “http://blah”, “title” => “this”, “alt” => “that”) );

    And perhaps a default for whether or not to output it or return it, which could be edited.

  32. Hi there,

    I just wrote some lines php to get all these stuff done…
    http://code.google.com/p/phpcreatehtml/

    This will give you the possibility to write html stuff just like this:

    $div = html::tag("div")
                    ->class("wrap");
    
    $h1 = html::tag('h1')
                    ->html("WORKS!");
    $span = html::tag('span')
                    ->html("Lars Echterhoff Medientechnik");
    $out = html::tag('a')
                    ->href("mailto:hallo@echterhoff.it")
                    ->class("mailme")
                    ->addClass("formore")
                    ->html("Text")
                    ->addhtml(" me!")
                    ->append($h1)
                    ->append($span)
                    ->appendTo($div);
            
                                    
    print_r($out->toArray());
    print_r($out->toString());
    

    toString() is also integrated as magic method.

    Everything together wrapped in a nice small class ready to use.
    If you have any ideas or bugs, feel free to post them at code.google.

    Lars

  33. I think DOMDocument is a better way to generate HTML elements.

    saveHTML(); //Outputs the generated source code
    ?>

    See this article: http://www.webspeaks.in/2012/06/how-to-generate-html-elements-using-php.html

    • Manny Fleurmond

      One disadvantage to DOMDocument I’ve seen after looking at it is that it outputs a complete HTML page. The code in this article is good for outputting individual elements

  34. Matt Pettis

    Thanks for this — googled for it, this came up, and I am going to use your code. So far, so good!

  35. Dade

    In case of sending an array to set, why not adding an empty array?

    
    
  36. Manny Fleurmond

    Two suggestion for attributes:
    – Sanitize the value of the attribute
    – If the attribute is set to false or Null, don’t output it

  37. Using as is in a wordpress plugin and seems flawless thus far. Thanks much for sharing.

  38. I created a class like this as well, I created a diff class for a couple commonly used tags, like anchor and span etc. Using the constructor method. Also I used the __call magic method so that I can just use

     $a = new A();
    $a->setHref('my_url.php');
    print($a);
    //prints 
    
  39. Rico Mossesgeld

    “Newbie” coder here. Great stuff! Isn’t this overkill however? Why should this be handled through its own class? Can’t a mere function (with the attributes as an array parameter) already do this?

  40. Maybe my work fits to you :)

    Basically is the same, I did an full abstraction of a TAG element and then create almost all HTML elements. The good thing is that with this you can manipulate and get element like JS DOM, you can find and get elements by ID, TAG and CLASS. If you like, take a look ;)

    It need a little more work, but, is almost finished :)

    https://github.com/klan1/k1.lib-dom

  41. mbpluda

    Hello, its 2022 but I just found this nice code.
    How about if I want to use it to generate a menú recursively?

    I can get it to work just for level 0 (no recursive) and level 1 (inside recursive function), but then I can’t add more items as child.

    something like

    $li -> inject(recursive($galho["id"], $ramos, $id));
    

    will add an inside this li, but no more depth items

    thanks!

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!