How do I stop HTML entities in a custom meta box from being un-htmlentitied?

I have a custom meta box that is supposed to accept HTML, but the text I’m trying to input contains both double and single quotes (and ampersands), and it’s messing up the saved data – each time I reload the post, the data is duplicated with an extra single quote (and angle bracket) inserted at the end. I’m guessing its trying to “close” what it thinks is an unclosed phrase in single quotes, when really its an apostrophe.

I can temporarily fix this right now by using the html character code for my apostrophe, but (a) that is not ultimately a solution as I can’t control what other users might enter once the theme is rolled out, and (b) once the page reloads, the html character has been replaced by an apostrophe again, which means if I save any further changes, I’m back at square one.

Read More

So, how do I “escape” html content in a metabox without stripping the html tags? Is there a special wordpress function/hook/action/etc or a special metabox format I should be using, or should I just be looking this up in the PHP manual instead?

PS: It also “strips out” any html characters like &, so the post won’t validate properly because there are now plain & in the text.

UPDATE:
So who knew single vs double quotes made any difference in simple php? I managed to fix the weird duplication and “correction” of apostrophe by swapping out my quotes in my code.

My original code was this:

echo "<textarea class='meta-textarea' style='width: 100%;' cols='20' rows='2' name='" . $meta_box['name'] . "_value' value='" . $meta_box_value . "'>" . $meta_box_value . "</textarea><br />";

If I save the following phrase: <p>Blah &amp; blah 'blah'</p> into the resulting text box, it would return '><p>Blah & blah 'blah'</p>.

If I just swap out the single and double quotes in my code, like so:

echo '<textarea class="meta-textarea" style="width: 100%;" cols="20" rows="2" name="' . $meta_box['name'] . '_value" value="' . $meta_box_value . '">' . $meta_box_value . '</textarea><br />';

then it works just fine (apart from the html-entity thing, which is still a problem).

Those two lines of code together, so you can see I haven’t left out any quotes (top one works, bottom doesn’t):

echo '<textarea class="meta-textarea" style="width: 100%;" cols="20" rows="2" name="' . $meta_box['name'] . '_value" value="' . $meta_box_value . '">' . $meta_box_value . '</textarea><br />';
echo "<textarea class='meta-textarea' style='width: 100%;' cols='20' rows='2' name='" . $meta_box['name'] . "_value' value='" . $meta_box_value . "'>" . $meta_box_value . "</textarea><br />";

So, now, the question of weird duplication has been fixed (although I don’t understand why – I thought single and double quotes were interchangeable if you weren’t doing any odd substitution, etc. The remaining question is – how do I stop the text from getting htmlspecialchars_decode applied, or whatever is happening here…

Related posts

Leave a Reply

2 comments

  1. If I’m allowed to answer my own question here: I found a way to stop the conversion of my html entities back to characters by using <?php esc_textarea( $text ) ?>, as detailed by the codex here: http://codex.wordpress.org/Function_Reference/esc_textarea.

    Not sure if this is the right way of doing it, but its working. My (snipped) metabox code now looks like so:

    <?php 
      if ( $meta_box['type'] == "textarea" ) {
        $meta_box_value = esc_textarea( get_post_meta($post->ID, $meta_box['name'].'_value', true) );
        echo '<textarea class="meta-textarea" style="width: 100%;" cols="20" rows="2" name="' . $meta_box['name'] . '_value">' . $meta_box_value . '</textarea><br />';
      }
    ?>
    

    This, combined with the single/double quote thing above, works fine now.

  2. This worked for me: Use esc_html() when you save your metabox text:

    $my_data = esc_html( $_POST['my_value'] );
    
    // Update the meta field in the database.
    update_post_meta( $post_id, '_my_field', $my_data );
    

    Retrieve your metabox text as usual:

    $value = get_post_meta( $post->ID, '_my_field', true );