• Fix orphan image attachments in wordpress/woocommerce

    I ended up with a load of orphan image attachments. By which i mean the post_parent of the image attachment was 0. This is bad in one particular situation. Although all the images were in use on posts, Google has a habit of indexing the attachment pages as well and often these are not themed and do not contain the info you want end users to see, For example http://example.org/product/attachment/1234/. Its possible to use plugins to add no-index no-follow meta tags to the attachment pages that will remove them from search. But this seemed a bit half-arsed. Plugins such as Yoast SEO have options to redirect attachment pages back to the parent post. But this is useless if the post_parent is 0.

    So i came up with the following quick hack to run on the server from a ssh prompt.

    $sapi_type = php_sapi_name(); 
    if (substr($sapi_type, 0, 3) == 'cgi') 
    { die("You are using CGI PHP\n"); } 
    require ( ABSPATH . 'wp-admin/includes/image.php' ); 
    $args = array( 'posts_per_page' => 1000,
            'offset'           => 0,
            'category'         => '',
            'category_name'    => '',
            'orderby'          => 'date',
            'order'            => 'DESC',
            'include'          => '',
            'exclude'          => '',
            'meta_key'         => '',
            'meta_value'       => '',
            'post_type'        => 'product',
            'post_mime_type'   => '',
            'post_parent'      => '',
            'author'           => '',
            'post_status'      => 'publish',
            'suppress_filters' => true
    $posts = get_posts($args);
    foreach ($posts as $post) {
       // Get post title
       $post_thumbnail_id = get_post_thumbnail_id( $post->ID );
       $parentid = wp_get_post_parent_id( $post_thumbnail_id );
       if($parentid == 0)
                            'ID' =>  $post_thumbnail_id,
                            'post_parent' =>  $post->ID

    This script finds each post of post_type, gets the featured image ID, then looks up this to see if the post_parent is 0. If it is 0 it sets the post_parent of the image to the post ID determined before. The first few lines ensure that this script is only executable from the command line/ssh prompt so that if you leave this on your web-server it cannot be executed by the http process. However i would encourage removing it directly after use.

    The things to note with this are:-

    1. This will run on the first 1000 posts, if you need more, probably best to create an outer loop and use that offset parameter
    2. post_type is set to “product” this is good for woocommerce product posts, for regular posts make this “post”
  • Quick and dirty wordpress to twitter feed with images

    I wanted a really quick and dirty implementation of a wordpress blog post to twitter feed and came up with the following. i didn’t even bother to implement this as a plugin (although you could quite easily and this is really where it belongs). But just as a proof of concept i added the code to the functions.php file in my theme

    The basic principle is to hook the new post event which is
    add_action( 'publish_post', 'post_published_notification', 10, 2 );

    This is fired every time a post is published so you can then feed the data on to twitter. I also wanted to send embedded images to twitter, so i used the posts thumbnail as the image source. For the engine to actually speak to twitter i used codebird.

    I’ve broken it down into 3 functions the first one is substrwords() which is a helper function that takes a string and ensures it is no longer than $maxchars but terminates on a word boundry.
    Next we have twitterpost() this does the actual post to twitter. Ensure you set your twitter API keys and secrets for this to work. The final function is the post_published_notification() function. This is what gets fired from the action callback. It gets the post and finds the attached image. Really it should check that an image is attached and not blindly assume that it is. But i will leave this as an exercise for the reader to implement.

    The actual implementation looks something like :-

    require_once('codebird.php'); < /code>
    function substrwords($text, $maxchar) {
        $end = '...';
        if (strlen($text) > $maxchar || $text == '') {
            $words = preg_split('/\s/', $text);
            $output = '';
            $i = 0;
            while (1) {
                $length = strlen($output) + strlen($words[$i]);
                if ($length > $maxchar) {
                } else {
                    $output. = " ".$words[$i];
            $output. = $end;
        } else {
            $output = $text;
        return $output;
    function twitterpost($url, $posttxt, $imglink) {
        $consumerKey = "";
        $consumerSecret = "";
        $accessToken = "";
        $accessTokenSecret = "";
        $posttxt = $url." ".substrwords($posttxt, 114);
        \Codebird\ Codebird::setConsumerKey($consumerKey, $consumerSecret);
        $cb = \Codebird\ Codebird::getInstance();
        $cb->setToken($accessToken, $accessTokenSecret);
        $params = array(
            'status' => $posttxt,
            'media[]' => $imglink
        $reply = $cb->statuses_updateWithMedia($params);
    function post_published_notification($ID, $post) {
        $type = get_post_type($post);
        if ($type != "post") {
        $title = $post->post_title;
        $permalink = get_permalink($ID);
        $image = wp_get_attachment_image_src(get_post_thumbnail_id($post->ID));
        $imgurl = $image[0];
        twitterpost($permalink, $title, $imgurl);
    add_action('publish_post', 'post_published_notification', 10, 2);