Posts and Pages Tagged ‘wordpress’

Page Builder data lost after migration Last updated:18 August 2016

I’ve spent a lot of time this morning looking into an issue with a client site migration where Page Builder data was lost after the migration.

I have migrated many many WordPress sites by exporting the database, replacing the old URL with the new URL in the exported SQL and re-importing. Never had an issue. But in this case I did, and it’s related to how Page Builder stores data. This data is serialized, and the serialization stores both the data and its length. So a snippet of stored data looks like this:

s:160:"<p><img class="alignleft size-full wp-image-2348" src="http://test.co.uk/wp-content/uploads/2014/05/Tulips.jpg" alt="Tulips" width="200" height="150" /></p>"

Super…so if you run a global replace on the domain name you end up with this:

s:160:"<p><img class="alignleft size-full wp-image-2348" src="http://production.co.uk/wp-content/uploads/2014/05/Tulips.jpg" alt="Tulips" width="200" height="150" /></p>"

Which looks fine, but it isn’t because the serialization is now incorrect as the length of the serialized string has changed from 160 characters to 166 characters. Result: lost Page Builder data.

The correct update should be:

s:166:"<p><img class="alignleft size-full wp-image-2348" src="http://production.co.uk/wp-content/uploads/2014/05/Tulips.jpg" alt="Tulips" width="200" height="150" /></p>"

Clearly doing this is impracticable and fortunately there’s a plugin that handles this which is WP Migrate DB.

Getting the lowest level category (or custom taxonomy) for a WordPress post Last updated:6 June 2014

Working on a client project which applies a hierarchical custom taxonomy to a custom post type I needed to find the lowest level set for the post. Assuming that there is only one hierarchy applied to the post the following does the trick, for categories (running on the single post page):

$categories = get_categories();
$parents = array();
if($categories){
	foreach ($categories as $category){
		$ids[] = $category->term_id;//read the category ids into an array
		if ($category->parent) $parents[] = $category->parent;//read the parent ids into an array
	}
}		
$low_categories =  array_diff ($ids,$parents);//get the ids which are not parents
$lowest_category = array_shift($low_categories);//read the first id (just in case there's more than one)

If you’re working with a custom taxonomy called, say, ‘classification’ then this becomes:

$post_classifications = get_the_terms($get_the_ID,'classification');
if($post_classifications){
	foreach ($post_classifications as $post_classification){
		$ids[] = $post_classification->term_id;
		if ($post_classification->parent) $parents[] = $post_classification->parent;
	}
}		
$low_class =  array_diff ($ids,$parents);
$classification = array_shift($low_class);

Hope this helps someone else…

Multiple images on WP e-Commerce product pages Last updated:21 April 2014

Dismayed this morning to find that WP e-Commerce does not support multiple images on a product page unless you pay for the “gold cart” option. Since I’m basically stingy, I did it myself. Here’s how:

Original fix, WP3.5, WPEC 3.8.7.6

I replaced this code in wpsc-single_product.php:

   <?php if ( wpsc_the_product_thumbnail() ) : ?>
      <a rel="<?php echo wpsc_the_product_title(); ?>" class="<?php echo wpsc_the_product_image_link_classes(); ?>" href="<?php echo wpsc_the_product_image(); ?>">
         <img class="product_image" id="product_image_<?php echo wpsc_the_product_id(); ?>" alt="<?php echo wpsc_the_product_title(); ?>" title="<?php echo wpsc_the_product_title(); ?>" src="<?php echo wpsc_the_product_thumbnail(get_option('product_image_width'),get_option('product_image_height'),'','single'); ?>"/>
      </a>
      <?php if ( function_exists( 'gold_shpcrt_display_gallery' ) )
         echo gold_shpcrt_display_gallery( wpsc_the_product_id() );
      ?>
   <?php else: ?>

with this code:

   <?php if ( wpsc_the_product_thumbnail()) ://if the product has any images...
      if (has_post_thumbnail()): //...display the thumbnail if there is one...?>
         <a rel="lightbox[<?php echo wpsc_the_product_title(); ?>]" class="<?php echo wpsc_the_product_image_link_classes(); ?>" href="<?php echo wpsc_the_product_image(); ?>">
         <?php echo get_the_post_thumbnail(wpsc_the_product_id(),'thumbnail',array('alt' => wpsc_the_product_title(),'title' => wpsc_the_product_title() ));?>
         </a>
      <?php endif;
      sb_get_images_for_product(wpsc_the_product_id());//...and then display all the rest of the images
else: ?>

I’ve used the standard WP function get_the_post_thumbnail() instead of the WP e-commerce function wpsc_the_product_thumbnail() simply to ensure a consistent display of thumbnails. So, I’m displaying the product thumbnail and then using a custom function sb_get_images_for_product() to retrieve any other images associated with the product. This function effectively replaces the gold_shpcrt_display_gallery() function for which you have to pay. I saved sb_get_images_for_product() in the functions.php (located in the theme folder). This function retrieves all images attached to the post and then displays any which are not the thumbnail – we’ve already displayed that. Here’s the code (last tested against WP 3.5):

function sb_get_images_for_product($id){
   global $wpdb;
   $post_thumbnail = get_post_thumbnail_id();//read the thumbnail id
   $attachments = $wpdb->get_results($wpdb->prepare("SELECT * FROM $wpdb->posts WHERE post_parent = $id AND post_type = 'attachment' ORDER BY menu_order ASC",$id));
   foreach ($attachments as $attachment){
      if ($attachment->ID <> $post_thumbnail){//if we haven't already got the attachment as the post thumbnail
         $image_attributes = wp_get_attachment_image_src($attachment->ID,'thumbnail');?>
	<a rel="lightbox[<?php echo wpsc_the_product_title(); ?>]" href="<?php echo $attachment->guid; ?>" class="<?php echo wpsc_the_product_image_link_classes(); ?>">
	<img src="<?php echo $image_attributes[0]; ?>" alt="<?php echo wpsc_the_product_title(); ?>"/>
	</a>
   <?php }		
   }
}

Note that WP 3.3 changed the way images work and messed up the WP e-commerce product images on version 3.8.7.4, with the result that it's possible to have a product without a product thumbnail. This is fixed with WP e-commerce version 3.8.7.6. However, I've added the if (has_post_thumbnail()) condition in the first code snippet above to trap this. Thanks to Brian for flagging this up.

Updated 21 April 2014, tested against WP 3.9, WPSC 3.8.13.4

Somewhere along the line, in conjunction with core WP galleries, WPEC has changed the way additional images are handled, and the fix above no longer works. Now try making this replacement in wpsc-single_product.php. Change this:

<?php
if ( function_exists( 'gold_shpcrt_display_gallery' ) )
   echo gold_shpcrt_display_gallery( wpsc_the_product_id() );
?>

with this:

<?php
	sb_get_images_for_product(wpsc_the_product_id());//...and then display all the rest of the images
?>

and add this to your functions.php:

function sb_get_images_for_product($id){
   $post_thumbnail = get_post_thumbnail_id();//read the thumbnail id
   
   $atts = get_post_meta($id,'_wpsc_product_gallery');
   
   $attachments = $atts[0];
   
   foreach ($attachments as $attachment){
      if ($attachment<> $post_thumbnail){//if we haven't already got the attachment as the post thumbnail
         $image_attributes = wp_get_attachment_image_src($attachment,'post-thumbnail');
		 $full_image_attributes = wp_get_attachment_image_src($attachment,'full');
		 ?>
	<a rel="lightbox[<?php echo wpsc_the_product_title(); ?>]" href="<?php echo $full_image_attributes[0]; ?>" class="<?php echo wpsc_the_product_image_link_classes(); ?>">
	<img src="<?php echo $image_attributes[0]; ?>" alt="<?php echo wpsc_the_product_title(); ?>"/>
	</a>
   <?php }		
   }
}

Querying WordPress serialized custom post data Last updated:20 March 2013

Had a bit of a head-scratcher on this one this afternoon…

I have a couple of custom post types set up, category and product, and a number of custom field attached to each of these, managed by Elliot Condon’s outstanding Advanced Custom Fields plugin. In this case, I have a Relationship field defined on product, which allows the user to assign a product to one or more category. All very lovely, but I then started on a situation where I wanted to show all products which were related to a given category.

The WP codex is a little light on examples, here, but I eventually triumphed with the following:

$args = array( 
   'post_type' 		=> 'product', 
   'posts_per_page'	=> -1,
   'meta_query'  	=> array(
			      array(
				     'key'           => 'category',
				     'value'         => '"'.$category.'"',//quotes to make sure category 23 does not match category 123, 230 etc
				     'compare'       => 'LIKE'
			      )
			   )
);
//get products
$wp_query = new WP_Query( $args );

To explain this a little, ‘category’ is the meta_key assigned to the field on product, and $category is the ID of the category that I’m passing in. It took me a little while to understand the SQL generated here. What happens is that meta_query casts the serialized data into characters, like this, where $category = 23:

SELECT wp_posts.* FROM wp_posts INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) WHERE 1=1 
AND wp_posts.post_type = 'product' 
AND (wp_posts.post_status = 'publish' OR wp_posts.post_status = 'private') 
AND ( (wp_postmeta.meta_key = 'category' AND CAST(wp_postmeta.meta_value AS CHAR) LIKE '%\"23\"%') ) 
GROUP BY wp_posts.ID 
ORDER BY wp_posts.post_date DESC

Once I realised what was going on it then becomes straightforward to use LIKE to find matching records. However, there’s a potential gotcha in there, which, in my example, would manifest if there was another category with and ID of 123, 230, 2300 etc etc. Without the quotes wrapped around my $category variable here, then the query would return products linked to any of these categories as well. It seems as if meta_query should allow an ‘in_array’ type comparison here, as the existing approach feels a bit clunky.

WordPress wp_ajax returning 0 error Last updated:19 June 2012

This morning I spent a little time constructing an ajax call from a front-end page (not an admin page) using wp_ajax. As is my wont, I tested this in Firefox and all was well. I used the WP codex.

Then I tried it in Opera and it failed, no response whatsoever, just a 0 in the ajax response. Seemed odd that Opera should have a problem, tried it in Chrome, same thing. Lots of Googling later, saw loads of similar questions being asked, no answers…

I then looked at the code in wp_ajax, and all became clear…

I had entries in my functions.php as follows:

 add_action('wp_ajax_myfunction', 'myfunction');
 
 function myfunction() {
    //stuff
 }

So if I pass an action of ‘myfunction’ to wp_ajax it should call the hook at the top of the above code, which in turn calls myfunction(), right? Only if you are logged on to WordPress at the time! If you aren’t logged in, wp_ajax calls the hook wp_ajax_nopriv_myfunction. And that’s why it worked for me in Firefox, because I was also logged on through Firefox. Nowhere is this mentioned in the codex, that I can see.

Having identified this it’s then simple to add another hook to your functions.php:

 add_action('wp_ajax_nopriv_myfunction', 'myfunction');

Hope this saves someone an hour or so…