0

Im trying to convert the post title to an image. i created a php file in the theme folder image.php with the code UPDATE: working code

require_once($_SERVER['DOCUMENT_ROOT'] . '/wp-load.php');
$postid = $_GET["postid"];
$string = get_the_title($postid);
$im = imagecreate(100, 30);
$bg = imagecolorallocate($im, 255, 255, 255);
$textcolor = imagecolorallocate($im, 0, 0, 255);
imagestring($im, 5, 0, 0, $string, $textcolor);
header('Content-type: image/png');
imagepng($im);
imagedestroy($im);

and i call the file with

<img src="url/wp-content/themes/v2/image.php?postid=<?php echo $post->ID ?>" />

ok now to my problem: the image gets created but without the post title. Do i need to include anything else to get the_title to execute?

2 Answers 2

3

In General

The problem here is that you're calling a WordPress function within a PHP file where WordPress isn't loaded.

Including WordPress in your image.php file might work if you include the post ID

<img src="/wp-content/themes/v2/image.php?post_id=123" />

But imagine if you have 100 images on a single page, then you would be running 101 instances of WordPress!

You might try to hook into WordPress and run only minimized version of WordPress, but then we are still running PHP for each of those images.

Another approach would be to avoid any WordPress calls in your image.php file and grab only the title text:

<img src="/wp-content/themes/v2/image.php?title=Hello+World!" />

But here the danger is that anyone could create an image with any kind of text. That's not good. You could add restrictions, like checking the referrer, but that might not be "watertight".

Better approach might be to create the image files when the post title is modified. Then we can simply call the image file with:

<img src="/wp-content/uploads/titles/image-123.png" />

but with things like browser caching, we might need a cache buster:

<img src="/wp-content/uploads/titles/image-123.png?last-modified=1445683693 " />

We might also use the post title in the image file name:

<img src="/wp-content/uploads/titles/image-hello-world.png" />

The only thing here is we would need to generate those images for old posts.

Let's take a closer look at the last mentioned approach.

Implementation

Let's assume we have the GD image package installed on our server. Then we could extend the WP_Image_Editor_GD class to our needs:

class WPSE_Image_Editor_GD extends WP_Image_Editor_GD
{
    private $wpse_bgclr;
    private $wpse_txtclr;
    private $wpse_txt;

    public function wpse_new( $width = 0, $height = 0 ) 
    {
        $this->image = imagecreate( $width, $height );
        return $this;
    }

    protected function wpse_color(  $red = 0, $green = 0, $blue = 0 )
    {
        return imagecolorallocate( $this->image, (int) $red, (int) $green, (int) $blue );
    }

    public function wpse_textcolor( $red = 0, $green = 0, $blue = 0 )
    {
        $this->wpse_txtclr = $this->wpse_color( (int) $red, (int) $green, (int) $blue );
        return $this;
    }

    public function wpse_bgcolor( $red = 0, $green = 0, $blue = 0 )
    {
        $this->wpse_bgclr = $this->wpse_color( (int) $red, (int) $green, (int) $blue );
        return $this;
    }

    public function wpse_text( $text ) 
    {           
        $this->wpse_txt = imagestring( $this->image, 5, 0, 0, $text, $this->wpse_txtclr );
        return $this;
    }

}

Here we prefix our methods with wpse_ to avoid possible name collisions in the future.

It's also handy to return $this for chaining.

We can get the current upload path with:

$upload_dir = wp_upload_dir();

and to set the upload path for the generated title .png files, we could use:

$file = sprintf( '%s/wpse_titles/image-%s.png', 
    $upload_dir['basedir'], 
    strtolower( sanitize_file_name( $post->post_title ) ) 
);          

This would save the Hello World title to the file:

/wp-content/uploads/wpse_titles/image-hello-world.png

We could use the save_post_{$post_type} hook to target a specific post type updates.

But don't want to generate it on each update, so let's check if it's a file that already exists with:

if( is_file( $file ) )
    return;

Now we can use our custom class and create an instance:

$o = new WPSE_Image_Editor_GD;

and create an empty image object, color it, add the post title string to it and then save it:

    $result = $o
        ->wpse_new( 300, 60 )              // Width x height = 300 x 60
        ->wpse_bgcolor( 0, 0, 255 )        // Background color as Blue
        ->wpse_textcolor( 255, 255, 0 )    // Text color as Yellow
        ->wpse_text( $post->post_title )   // Hello World
        ->save( $file, 'image/png' );      // Save it to image-helloworld.png

Output Example

Here's an example how the image-helloworld.png image would look like:

hello world

Demo plugin

Here we add it all together in a demo plugin:

<?php
/**
 * Plugin Name:   WPSE Title Images
 * Description:   On post update, create a png file of the post title (/uploads/wpse-titles/)
 * Plugin Author: Birgir Erlendsson (birgire)
 * Plurin URI:    http://wordpress.stackexchange.com/a/206433/26350
 * Version:       0.0.2
 */
add_action( 'save_post_post', function( $post_id, $post )
{
    // Ignore auto save or revisions
    if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) )
        return;

    if( class_exists( 'WPSE_Image_Editor_GD' ) )
        return;

    // Get the current upload path      
    $upload_dir = wp_upload_dir();

    // Generated file path
    $file = sprintf( 
        '%s/wpse_titles/image-%s.png', 
        $upload_dir['basedir'], 
        sanitize_key( $post->post_title ) 
    );          

    // Only create it once
    if( is_file( $file ) )
        return;

    // Load the WP_Image_Editor and WP_Image_Editor_GD classes 
    require_once ABSPATH . WPINC . '/class-wp-image-editor.php';
    require_once ABSPATH . WPINC . '/class-wp-image-editor-gd.php';

    // Our custom extension
    class WPSE_Image_Editor_GD extends WP_Image_Editor_GD
    {
        private $wpse_bgclr;
        private $wpse_txtclr;
        private $wpse_txt;

        public function wpse_new( $width = 0, $height = 0 ) 
        {
            $this->image = imagecreate( $width, $height );          
            return $this;
        }

        protected function wpse_color(  $red = 0, $green = 0, $blue = 0 )
        {
            return imagecolorallocate( $this->image, (int) $red, (int) $green, (int) $blue );
        }

        public function wpse_textcolor( $red = 0, $green = 0, $blue = 0 )
        {
            $this->wpse_txtclr = $this->wpse_color( (int) $red, (int) $green, (int) $blue );                
            return $this;
        }

        public function wpse_bgcolor( $red = 0, $green = 0, $blue = 0 )
        {
            $this->wpse_bgclr = $this->wpse_color( (int) $red, (int) $green, (int) $blue );             
            return $this;
        }

        public function wpse_text( $text ) 
        {           
            $this->wpse_txt = imagestring( $this->image, 5, 0, 0, $text, $this->wpse_txtclr );
            return $this;
        }

    } // end class

    // Generate and save the title as a .png file   
    $o = new WPSE_Image_Editor_GD;

    $result = $o
        ->wpse_new( 300, 60 )              // Width x height = 300 x 60
        ->wpse_bgcolor( 0, 0, 255 )        // Background color as Blue
        ->wpse_textcolor( 255, 255, 0 )    // Text color as Yellow
        ->wpse_text( $post->post_title )   // Hello World
        ->save( $file, 'image/png' );      // Save it to image-helloworld.png

}, 10, 3 );

We might then create our own template tag, to display the image for each post:

if( function_exists( 'wpse_title_image' ) )
    wpse_title_image( $default_url = '' );

Here's an example, but in a proper plugin structure, we should be able to remove the duplicated code presented here:

/**
 * Get the current post's title image 
 *
 * @param string $default_url Default image url
 * @return string $html Html for the title image
 */
function get_wpse_title_image( $default_url = '' )
{
    $post       = get_post();
    $upload_dir = wp_upload_dir();
    $dirname    = 'wpse_titles';

    $file = sprintf( 
        'image-%s.png',
        strtolower( sanitize_file_name( $post->post_title ) ) 
    );

    $file_path = sprintf( 
        '%s/%s/%s',
        $upload_dir['basedir'], 
        $dirname,
        $file
    );      

    $file_url = sprintf( 
        '%s/%s/%s',
        $upload_dir['baseurl'], 
        $dirname,
        $file
    );          

    if( is_file( $file_path ) && is_readable( $file_path ) )
        $url = $file_url;
    else
        $url = $default_url;

    return sprintf( 
        '<img src="%s" alt="%s">', 
        esc_url( $url ),
        esc_attr( $post->post_title )
    );
}

Then you can define the following wrapper:

/**
 * Display the current post's title image 
 *
 * @uses get_wpse_title_image()
 *
 * @param string $default_url Default image url
 * @return void
 */
function wpse_title_image( $default_url = '' )
{
    echo get_wpse_title_image( $default_url );
}

Notes

This demo could be extended further, like:

  • take this into a proper plugin structure
  • adjusting the handling of the width and height of each title image.
  • auto generate images for all posts
  • do this for other post types
  • ... etc ...
12
  • thanks for your answer. your first suggestion isnt working even if i include the postid it doesnt show the title. second should work but my goal is to hide the title in source code. i guess the other solutions seems to be much more complicated Commented Oct 24, 2015 at 11:09
  • I wouldn't recommend loading WordPress for each image. You have to adjust your GET variables in your script. You're also not using any cache in your script. I think I would choose to generate the title image when the post's title is modified. It might be a little more code, but I think it's worth it ;-) @user3646085
    – birgire
    Commented Oct 24, 2015 at 14:24
  • im failing to get it done this way and you suggest doing it more complicated, i dont even know where to start :D Commented Oct 24, 2015 at 16:22
  • I updated the answer with an example plugin @user3646085
    – birgire
    Commented Oct 25, 2015 at 0:12
  • 1
    i was a little bit busy..tested again works great now thank you very much! Commented Nov 1, 2015 at 19:47
0

I think in image.php, post Id is blank, and so not getting anything. moreover - is this the only code in image.php? You need to make sure WordPress system gets loaded before calling get_the_title & pass postid from caller to image.php like - image.php?pid=223

Load Wordpress at the top of your image.php file:

require('./wp-load.php');

Grab the postid from URL param:

$postID = $_GET['pid'];

Then rest of your code goes as is.

When calling this script in image tags src, make sure to pass the correct pid

src="image.php?pid=xxx"
13
  • i edit my post i missed the first 2 lines. i already had both lines in it still doesnt work. Commented Oct 24, 2015 at 11:10
  • Can you print the output of what it gets as postid and get_the_title call? Perhaps use error_log and paste the log here
    – Arif
    Commented Oct 24, 2015 at 11:45
  • nothing in the logs. the image gets created but without the title Commented Oct 24, 2015 at 11:51
  • Log won't be automatic ... Do yourself a favor - error_log($postID); error_log($string);
    – Arif
    Commented Oct 24, 2015 at 11:53
  • Or simple print and exit after that to see what it gets
    – Arif
    Commented Oct 24, 2015 at 11:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.