PHP function (in WordPress) echoing HTML I'm really new to PHP, and a little less so in WordPress. I've created a working function that spits out some static HTML into a page template in WordPress. I'd like to know if there is a best practice for this, perhaps someone can help.

function my_html_function() {
    echo '&lt;h4&gt;Title&lt;/h4&gt;
        &lt;ul class="ref-list"&gt;
            &lt;li id="one"&gt;A list item&lt;/li&gt;
            &lt;li id="two"&gt;A list item&lt;/li&gt;
            &lt;li id="three"&gt;A list item&lt;/li&gt;
            &lt;!-- I have 30 items here... --&gt;
            &lt;li id="thirty"&gt;A list item&lt;/li&gt;
        &lt;/ul&gt;';
    }


And within my WP page template I use:

&lt;?php echo my_html_function(); ?&gt;


This HTML is static and won't be changed.
There are several issues I have with your function. Some are about your function breaking the basics about what a function is/should do, others are perhaps a tad more personal (as in: a matter of personal preference).

Functions do stuff, without it impacting the rest of the code

It seems almost silly to explicitly state this, but let me explain what I mean. A function is a unit of code, that performs a single task, that might be required to be performed several times. Functions should not have "side-effects". That's a fancy way of saying that calling a function shouldn't disrupt the rest of the code (with the exception of a function throwing an Exception, of course).

Your function, however, generates output without the caller having any means of controlling what, how and to where that output is being sent. The function assumes the caller knows that it'll send output, but that's a rather dangerous assumption to make. A simple example: cookies can't be set after any output has been sent already. Therefore:

my_html_function();
set_cookie();//&lt;-- FAILS!


The function contains an echo, and so output will be sent once a call is made. It might seem like an obvious thing to fix, but in larger projects, things like this can really trip you up, and you'll find yourself wasting hours trying to work out why the cookie isn't being set properly.

Bottom line: Functions return, they don't echo, so change the echo in your function with return, and echo in the template.

PHP stands for PHP: Hypertext Preprocessor

The important bit in this case is Preprocessor. You can use PHP to return/echo strings of markup, but why would you do that? You can embed PHP in HTML just as easily, so why not use that? If needs must, you can always use PHP to include bits and pieces of markup.

Markup isn't static

Sure, the markup your function echoes/returns is static in your case, but markup languages are, well, languages. They're not always static. It's not a big stretch to imagine a situation where you want your function to churn out a block of markup where the title value is different, or the number of list items is variable.
In those cases, you'll want to pass arguments to your function, and you'll find yourself generating markup dynamically. It's not a hard thing to do, and it's done all the time. 

To this end, you have a number of options available to you. The easiest (and in this case reasonable) approach would be to string together the markup:

/**
 * ADD THIS, DOCUMENT YOUR CODE:
 * Pass the title string and an associative array of list items
 * @param string $title
 * @param array $listItems
 * @return string
 */
function getTitleList($title, array $listItems)
{
    $title = sprintf('&lt;h4&gt;%s&lt;/h4&gt;', htmlentities($title));//&lt;-- sanitize $title, it shouldn't contain markup
    $liNodes = [];//array of li nodes
    //again, we need to sanitize all this
    foreach ($listItems as $id =&gt; $value) {
        $liNodes[] = sprintf(
            '&lt;li id="%s"&gt;%s&lt;/li&gt;',
            str_replace('"', '\'', $id),//we're using "as id delimiter, so id can't use them
            htmlentities($value)//html entities must be removed
        );
    }
    $markup = $title . '&lt;ul class="ref-list"&gt;' . implode('', $liNodes) . '&lt;/ul&gt;';
    return $markup;
}


The alternative here would be to use an actual DOM parser/builder, like the DOMDocument class, although in this case, that would be overkill IMO. As @KIKOSoftware said: sprintf is marginally slower than regular concatenation, and it could be said that it's a bit harder to use at first. If you want, you can use regular concatenation just as easily:

$title = '&lt;h4&gt;' . htmlentities($title) . '&lt;/h4&gt;';//same as sprintf above


Another thing that was pointed out to me in the comments was that, if the contents of any of your tags contains markup, then obviously htmlentities is not what you want to use. If you require your function to be flexible (and allow the insertion of nested tags), you should really look into using an actual DOMDocument-like tool. Something that enables you to build the DOM as you go (creating new nodes, setting attributes and inserting them throughout the actual DOM tree).