Home > Back-end >  Wordpress PhP rendering user code gotten by ACF's get_field() function in iframe
Wordpress PhP rendering user code gotten by ACF's get_field() function in iframe

Time:01-05

eMy wordpress site has a custom post type called tool, which has three custom fields called html, css, and js. This tool post type is displayed on my site with a custom template, and a shortcode that renders the contents of the html, css, and js fields in an iframe. This shortcode is created by a function in my functions.php file, and a simplified version of this function looks like this:

function renderTool() {
return '
<html>

  <head>

    <script

      src="https://kit.fontawesome.com/c48c422dea.js"

      crossorigin="anonymous"

    ></script>

    <style>

      .container {background:blue;}

    </style>

  </head>

  <body>

    <div id="container" >

      <div id="tool" >

      <iframe src="data:text/html;charset=utf-8,' . 
  '<html>
    <head>
      <style>' . htmlspecialchars(get_field("css")) . '</style>
      <script>' . htmlspecialchars(get_field("js")) . '</script>
    </head>
    <body>' . htmlspecialchars(get_field("html")) . '</body>
  </html>'
        . '"></iframe>

      </div>

      <div  id="bar">

         <i ></i>

      </div>

    </div>

    <script>

      function myfunction() {

console.log("hello world");

         }

           </script>

  </body>

  </html>';
}

The problem with this code is that when i use the shortcode which runs this function, it only renders the css, and the html and js are rendered in plain text.

I chatted with openai's chatgpt about it and it recommended me to store the iframe contents in a seperate html file and then to set the iframe src to this html file as such:


$css = htmlspecialchars(get_field("css"));

$js = htmlspecialchars(get_field("js"));

$html = htmlspecialchars(get_field("html"));

// Create the inner document and save it to a separate file

$inner_document = '

  <html>

    <head>

      <style>

        '. $css .' 

      </style>

      <script>

        '. $js .' 

      </script>

    </head>

    <body>

      '. $html .' 

    </body>

  </html>

';

file_put_contents('inner-document.html', $inner_document);

// Use the inner document as the src for the iframe

return '<iframe src="inner-document.html"></iframe>';

This soultion i already dislike because it just seems like it is complicating things even more. When i did try to use this code, the iframe instead rendered the page i was on and an equally broken iframe in it. iframeception.

Another thing i tried was passing the html that should be in the iframe inside a urlencode as such: (this is a snippet, this code would replace the iframe in my current approach)

<iframe src="data:text/html;charset=utf-8,' . urlencode(
  '<html>
    <head>
      <style>' . htmlspecialchars(get_field("css")) . '</style>
      <script>' . htmlspecialchars(get_field("js")) . '</script>
    </head>
    <body>' . htmlspecialchars(get_field("html")) . '</body>
  </html>'
        ) . '"></iframe>

This just rendered it as raw text into the correct html elements at least (view https://prnt.sc/4I24tFgxQ56m)

To clarify further, these get_field() functions are from a wordpress plugin called acf, view the documentation here: https://www.advancedcustomfields.com/resources/get_field/

From all of this information i concluded that the error must stem from the string literals not properly being escaped and therefore conflict with/ cause the rest of the values to be returned in string format. Yet i was hoping that the htmlspecialchars was gonna solve it, but it only helped with rendering CSS. In my current solution, I put all the code I want to render inside the iframe's source using a data URL, the iframe closing tag comes after the content of the iframe therefore.

So you can further visualize what i am trying to convey, here is the link to the page that is suffering this bug: https://tropical.team/tools/calculator. It is posible i still have some testing code on here so you will see something a bit diffrent than i described but i will try to change it to this when i get back.

I chatted with chatGPT for over 3 hours yesterday but concluded that when i realized that it started going in circles. I doubt there is a replacement for the get_field function, or an argument that would help with this, but if there is do tell me, i also have yet to integrate validation for those html, css, and js fields, so for now, just expect proper code being passed.

CodePudding user response:

Instead of passing the html as a data url, a better approach is to use the srcdoc attribute of the iframe. This allows you to pass a string (the html) to it and render it properly. You will have to keep the htmlspecialchars function because otherwise the double quotes that may be returned by get_field as it is user submitted would end the srcdoc value string.

  • Related