AngularJS WordPress Theme: Display Post Content with ngBindHtml

This is the second post of a series about building WordPress themes with AngularJS and WP REST API (WP API).

In the last screenshot of my previous post Using AngularJS And JSON API In Your WordPress Theme, you might be wondering why the post content displayed with the HTML tag, which looks like this:

Screenshot 5 from Using AngularJS and JSON API in your WordPress theme

This is not a bug, I left it intentionally to extend the series to another topic: ngBindHTML directive.

The name of ngBindHTML directive indicates that it is for binding HTML to the view. I bet you must be eager to try it by update the content.html to:

If so, you’ll be disappointed that not only the post content disappears, but also there comes an error to you console: The console error when using ngBindHtml From the error log the almighty AngularJS told us that the HTML we bound to the div might be “unsafe”. It’s very lucky to have AngularJS to get our back. It even provides an module called ngSanitize to sanitize the data in our code.

When use ngBindHtml, ensure that $sanitize is available

Use ngBindHtml with ngSanitize module is the best practice when binding raw HTML to an element. Let’s keep updating our project files.

1. Download the ngSanitize module

Use bower install angular-sanitize to download the scripts, or get the files from GitHub repo.

2. Enqueue the scripts in functions.php

  • Line 15-19: register the script
  • Line 24: add angularjs-sanitize to the script dependencies.

3. Update our scripts

  • Line 1: add ngSanitize to the module dependencies.

Now we get the content displayed as usual in the single post view. Use ngBindHtml with ngSanitize is the best practice You can get the complete theme files from the project repository on GitHub.

Bypass sanitization for values you know are safe

When I said use ngSanitize module is the best practice to bind raw HTML to an element, you must be wondering if there are other ways to do so? The answer is yes of course, and here comes the trustAsHTML method from $sce service (documentation).

Please note you can only use trustAsHTML without ngSanitize module when you are 1000% sure the values are safe. In other words, you should NEVER do that.  

1. Create a custom filter in the scripts.js

  • Line 1: I remove the ngSanitize to show that we can use trustAsHTML without it. But the best practice is you should always add this module when use ng-bind-html directive.
  • Line 5-9: the custom filter. We create a filter called toTrusted, and when we pass text to it, it will interpret the text as HTML rather than escaped it.

2. Pass post content through filter

  • Line 2: post.content | toTrusted: the left side of the pipe |, is the value to evaluate; the right side of the pipe, is the filter we’d like to use, which is toTrusted in this case.

You’ll get the same result as the previous screenshot, our post content will be parsed as HTML rather than escaped text. Get complete theme files using trustAsHtml to filter post content on this branch of my repo.


When work with values input by users, security is the top priority we should keep in mind. As developers come from WordPress world, we are all familiar with the importance of escaping all the things and the built-in functions to sanitize and validate user inputs in WordPress.

In AngularJS, master the $sce service would be a good start to building a secure client app. The sample chapter of the ng-book might be helpful for you. Enjoy the reading and I’ll be here if you need any assistance about this tutorial.

Share the post:Tweet about this on TwitterShare on Google+1Share on Facebook0Share on LinkedIn1
I'm a senior web developer helping clients build their websites to grow businesses. Currently I'm based in Taipei, Taiwan. I write things about WordPress, AngularJS and life. Whenever you'd like to find someone to talk about these topics, just get in touch!

37 Comments

Submit a comment
  • These tutorials are awesome! Learn a lot. I am also reading the NG-BOOK and trying to build an AngularJS wp theme. Please keep sharing and can’t wait for the next post!!

  • I have been using the filter method for over a year now, and its been working pretty great.. did have to change it up a couple versions ago, but I like the control it gives me (as any filter would).

    I might try the module approach for smaller projects.

  • Roy,

    In fact, I learned the filter method from your Angular WordPress theme (and lots of stuff about Angular + WordPress).

    Thank you for those great and in-depth tutorials!

    • Hey Dominic, Thanks for the kind words. Just sharing my learning path might be helpful for newcomers. 😉

  • Hi Yoren,

    I find a way to embed WordPress shortcode but ng-bind-html to not work with that shortcode in content of a post. Do you have any idea to do that ?

    Thanks

    • Hey Quang, which shortcode you’re trying to work with?
      (sorry that Akismet treated your comment as spam.)

  • Hi

    First of all thank you very much for your posts, they are extremely helpful.

    I have a question though, so how about the tag for posts? Does the REST API or the Angular provide an easy way to find and set the excerpt based on the read more tag, just like it’s naturally done in PHP or should we take the high road and run regexp matching to detect and set the read more link on the main blog page? I hope my question is quite clear.

    • Hi Hue, the best alternative I can think of is that, we can add an extra field to the WP API responses for the custom excerpt we set by the tag. Regarding how to get the custom excerpt content, please refer to the get_extended() function in WordPress.

      • Thank you, as always, worked like a charm and now I can have default wordpress behaviour. Here is the code I used to add the custom data to the JSON api v2 in case anyone else needs it:


        function my_rest_prepare_post( $data, $post, $request ) {
        $_data = $data->data;
        $_data['content_extended'] = get_extended ( get_the_content() );
        $data->data = $_data;
        return $data;
        }
        add_filter( 'rest_prepare_post', 'my_rest_prepare_post', 10, 3 );

        Now, according to my templates, I can access to the post content which comes before the more tag like this {{post.content_extended.main}}, and it even automatically adds the (more…) link.

          • You are more than welcome. Today I noticed that the snippet above does not return the rendered shortcodes due to using get_the_content() instead of the_content()

            To get the shortcode to work use this code instead:

            $content = apply_filters( 'the_content', get_the_content() );
            $content = str_replace( ']]>', ']]>', $content );
            $_data['content_extended'] = get_extended( $content );
            
          • That’s pretty cool! Now we figured out a way to render shortcodes in post content. Updated: Actually we can access content with rendered shortcode by accessing the “rendered” content field.

          • Yup you’re absolutely right! It was just a reminder to myself that, if not considering the more tag, shortcodes actually has been rendered by default.

  • Ok

    The sanitization method mentioned here works just fine when we are GETting content from the WP API.

    But what about when we are POSTing to the api? I am using ui-tinymce to get the tinymce plugin work well with angular, it even has a built in “trusted” option which makes the tinymce editor obey the $sce on the front end to sanitize the content being posted.

    But this causes an issue. How about embed codes? If I paste an iframe HTML code (say youtube video embed code) and publish a new post on the front end, the code will be encoded into escaped html and I can only see the html code, not content of the iframe embedded.

    If I use the tinymce embed plugin, I can see the video in my editor, but once I hit the post button, none of the content is being passed to API/DB and I get a post with empty content. (The same thing happens when I use TinyMCE image tools, the normal images would be posted, but if I edit the image using the image tools, the content is not longer being passed when I post it)

    Any ideas on that?

    I am using the tinymce from their website, since the wordpress tinymce needs jQuery as a dependency and I am doing my best to finish my project without jQuery. (It’s huge learning curve, but totally worth it!)

    By the way I am using restangular to deal with JSON output.

    Here is a link the ui-tinymce directive for angular:
    https://github.com/angular-ui/ui-tinymce

    If you wish to discuss it directly, feel free to email me to the email I use for commenting here.

    • Hey Hue,

      So can I make sure a few things first?

      1. You’ve built a form on the front end (your theme or a stand alone app) to submit posts to WordPress?
      2. If so, have you been authenticated in the WP install?
      3. Can you get any debug info to see if the content “did” been submitted to WP?

      Talk soon!

      • Hey Yoren, Thanks for getting back to me.

        1) Yes it’s on the front end of wordpress theme, (mainly running on an index.php file having ng-view with html binding, just as suggested in your post) the rest is managed via WP API V2 and angularJS

        The form is actually an inline tinyMCE editor being initiated on a contentEditable div

        2) Yes, using cookie authentication with WP Nonce, sending x-headers via restangular

        3) I did, no errors, but I ran into the following conclusion

        So, basically ng sanitizer does not allow iframes of any sort at all, and it does not even support whitelisting for iframes, at least for now, or as far as I have gathered by googling, this is a huge bummer, since as of WP theme development, no more iframes.

        There is hopefully one way around this limitation (or better say security concern) and that is using oEmbeds for the sites supported by wordpress (here is a list: http://bit.ly/1cs0gfd)

        So as long as the link being pasted into the front end editor is from one of those supported sites, and the link sits on a separate line with no further characters or white spaces before or after it, it is going to be rendered into an iframe AFTER the form is submitted.

        That is one thing that oEmbed does in combinations with WP and tinyMCE.

        Now, If i were to use the tinyMCE that comes along with WordPress, it would automatically take care of the pasted link even before submitting the post. But this means that I have to enqueue jQuery too, which is something I am really trying to avoid as of now.

        What I suggest, and am trying to do now is using my own version of oEmbed on my front end editor to render the video once the link is pasted, at the same time avoiding the iframe being submitted once hit the publish button, which is right now a huge challenge.

        Any thoughts? Sorry this got a bit long, but any answers/suggestions would help.

        • Hi, Hue,

          Thanks for your sharing! I’m pretty impressed by what you’ve done so far, so keep me posted when the project is on.

          So can we say the situation is that you want both:

          1. The oEmbed link can be displayed right away in the editor, and
          2. When submitted to WP, the oEmbed link won’t be saved as an Iframe (maybe just kept as a link), so the ng-sanitize won’t be an issue.

          The first one is much difficult to me because it would need a much advanced JS skill. Can you tell me which files to look at, maybe I can contribute my two cents.

          As to the second one, how about we use some WP hooks (filters or actions) to prevent the oEmbed links being converted to iframes “after” the content is submitted, but “before” it gets inserted into the database?

          • Thanks, sure thing I will keep you posted once it’s online.

            1- correct
            2- correct

            > Both of these phases can be accomplished using regex and tinyMCE events such as beforeSetContent and getContent, and yes you are right, it requires lots of work.

            > Currently I am studying the wordpress core and tinyMCE plugins to find out how they have done it on their own projects. They are so many files and in so many different places, you need to google them if you are interested.

            > Is there any filters or hooks to help us do so while everything is being done in pure JS?

          • Hey Hue,

            Just spent a couple of minutes tried to figure how tinyMCE works with WordPress. Still not much progress, I’ll be focused on the “wpview” plugin for tinyMCE. Do you think it’s the right place I should go?

          • Hi

            The wpview is an interesting plugin, it has lots of good examples on how tinyMCE handles different events, (I am not sure what this plugin does though)

            This post is also a very good example of handling events for previewing shortcodes in the editor:
            https://generatewp.com/take-shortcodes-ultimate-level/

            None of these examples use the enter key event to process the preview of the links (or shortcodes) or maybe they do and I have not found it yet.

            The wordpress plugin that I am looking for is the one responsible for previewing the [[embed]] shortcode in wordpress, that one previews the iframe super fast and paste and some keyboard events.

            Have you found this one yet?

          • Thanks for finding this file.

            This is the main piece of the puzzle, just binding the shortcodes to the wordpress specific view created for wordpress tinyMCE.

            To tell you the truth I am giving up on the wordpress methods for dealing with tinyMCE.

            Since we are in angular and vanilla JS, and wordpress has dealt with tinyMCE methods in it’s own invented way (as said on top of the file you just mentioned “this API is “experimental” meaning that it will probably change”).

            I believe we are going to have to reinvent part of the wheel, just as I have done so with bringing the media manager to the front end.

          • Hi Hue, Yup I think we should do it our own way since it will be very helpful when we’re switching to a standalone AngularJS app (rather than a WP theme).

          • Yes I believe we should.

            By the way, I am a veteran theme developer/designer working in themeforest for more than 5 years.

            If you would like to cooperate on this project, please contact me via email.

            It’s going to be a commercial project, and I have big plans for it, but it’s getting out of hands, it’s not a one man show. I am gathering a team of good designers and developers to bring my idea to life.

            Right now it’s in the prototyping phase and I am testing different things to measure the possibilities of making it to the commercial market.

            So please let me know if you are interested, and we will talk more about it.

  • hey am kind of stuck in getting the single post with an ID, This is my error “Failed to load resource: the server responded with a status of 404 (Not Found)” cross checked all of the code can’t seem to get the solution

    Note using angular 1.4.8

    • Hey Oscar, the 404 error might be cause because you didn’t enable the permalink for your WP install, can you make sure you set the right structure and try again?

  • Hello!

    Thank you for these wonderful tutorials! I am working with an Ionic Framework android app that fetches data from WordPress through WP API. I successfully got it rendering the HTML from the body of my posts nicely. However, I recently published a post that has a table in it and the table is not being responsive to the mobile screen. How can I fix this?

    • Hi Charles, I suppose the table should work fine with your CSS unless you use JavaScript to apply a certain CSS style till the table shows. Maybe check the CSS for your table first, then investigate your HTML or JavaScript.

  • Hi Charles,
    Nice article, Are you planning to develope WordPress theme in react js? I’m eagerly waiting for such article. I’m new to WordPress and react js. I’m not able to start.

Submit a comment

Your email address will not be published. Required fields are marked *