Search code examples
node.jswordpressimagebase64url

Wordpress is removing 'data' attribute from base64 encoded image when using wp_insert_post


Edit 1

This is not about the browser. This happens if I'm not logged in. When I logged in, it works perfectly. Sorry for the rush.

I know it strange and doesn't make any sense also hard to explain.

As the title said browser causes this problem but I'm not sure about it.

So I have an image service that reads some data from somewhere and creates images by the read data. Then it does a few things and returns the images in base64 format so I can use the images in my web site. This process begins as soon as I open a page on my web site.

The problem is that if I open the page on Safari it works properly but today I tried to open the page on Chrome and images didn't load. So I checked the images and saw that there's no data attribute at the beginning of the data URI.

Let me explain with an example;

Here's my code while creating the HTML template

  presets += `<div class="icon"> <img src="data:image/png;base64,${icon}"></div>`
  presets += `<p class="name">${name}</p>`
  presets += `<div class="image"> <img src="data:image/png;base64,${image}"/></div>`

I'm doing a few things and then returning this data and on postman and safari I'm getting this result:

<div class="icon"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA{ ... }"></div>

So this is fine. Nothing's wrong with that.

But when I opened the page on Chrome or Opera I'm getting this;

<div class="icon"> <img src="image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA{ ... }"></div>

See? No data attribute. I'm inserting a post in Wordpress and this is the content of the post. Why is that happening? I hope I've explained my self clearly.

Edit 2

This is the function that I used to insert a post

function programmatically_create_post($title, $content, $slug)
{

    // Setup the author,
    $author_id = 4;

    // If the page doesn't already exist, then create it
    if (!the_slug_exists($slug)) {

            // Set the post ID so that we know the post was created successfully
            wp_insert_post( 
                    array(  
                            'post_title'            =>      $title,
                            'post_content'          =>      $content,
                            'comment_status'        =>      'closed',
                            'ping_status'           =>      'closed',
                            'post_author'           =>      $author_id,
                            'post_name'             =>      $slug,  
                            'post_status'           =>      'publish',
                            'post_type'             =>      'post', 
                            'page_template'         =>      'dynamic-post.php',
                            'post_category'         =>      array(1,60)
                         )
            );
            // Redirect user to the post after the post created
            wp_redirect(get_site_url() . '/blog/' . $slug);
            exit();
            // Otherwise, we'll stop
    } else {
            return;
    } // end if

} // end programmatically_create_post

Solution

  • Well, this was a nightmare to find, but I think I've resolved it after digging through the WordPress code which hooks in through wp_insert_post. Please add this to your functions.php file and check it works:

    add_filter('kses_allowed_protocols', function ($protocols) {
        $protocols[] = 'data';
    
        return $protocols;
    });
    

    Essentially internally in WordPress there's a filter which checks the protocol of any URL's in the content and strips any which it doesn't like. By default the supported list doesn't support the data protocol. The above function just adds it to the list of supported protocols.

    This filter does not run if you're an administrator, which is probably why you're seeing this issue only when logged out.