Image array returning wrong images on some occasions
Closed this issue · 3 comments
Hi Jason,
I hope you can help me out on this one :-)
I just downloaded a new version of your API. I can't find the reason and can't find a bug in your code... but on one product, and only that one, the image array is returning the wrong (and only 3 out of 6) images. The featured image array is returning the right image.
I removed the real website url, but could PM it to you if you wish to have it.
The urls it should return are 3 the following:
http://website.nl/wp-content/uploads/2013/07/SK055-schuin-vooraanzicht.jpg
http://website.nl/wp-content/uploads/2013/07/SK055-vooraanzicht.jpg
http://website.nl/wp-content/uploads/2013/07/SK055-achteraanzicht.jpg
The product id is 211 and the returned object is the following (xCode..):
2013-10-13 22:26:33.802 Test[8704:a0b] Images array is: (
{
alt = "";
caption = "";
description = "";
filename = "SK082 vooraanzicht met licht";
id = 265;
metadata = {
file = "2013/07/SK082-vooraanzicht-met-licht.jpg";
height = 667;
"image_meta" = {
aperture = 0;
camera = "";
caption = "";
copyright = "";
"created_timestamp" = 0;
credit = "";
"focal_length" = 0;
iso = 0;
"shutter_speed" = 0;
title = "";
};
sizes = {
medium = {
file = "SK082-vooraanzicht-met-licht-300x300.jpg";
height = 300;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK082-vooraanzicht-met-licht-300x300.jpg";
width = 300;
};
"shop_catalog" = {
file = "SK082-vooraanzicht-met-licht-150x150.jpg";
height = 150;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK082-vooraanzicht-met-licht-150x150.jpg";
width = 150;
};
"shop_single" = {
file = "SK082-vooraanzicht-met-licht-300x300.jpg";
height = 300;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK082-vooraanzicht-met-licht-300x300.jpg";
width = 300;
};
"shop_thumbnail" = {
file = "SK082-vooraanzicht-met-licht-90x90.jpg";
height = 90;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK082-vooraanzicht-met-licht-90x90.jpg";
width = 90;
};
thumbnail = {
file = "SK082-vooraanzicht-met-licht-150x150.jpg";
height = 150;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK082-vooraanzicht-met-licht-150x150.jpg";
width = 150;
};
};
url = "http://website.nl/wp-content/uploads/2013/07/SK082-vooraanzicht-met-licht.jpg";
width = 667;
};
"mime_type" = "image/jpeg";
"parent_id" = 211;
path = "2013/07/SK082-vooraanzicht-met-licht.jpg";
publishing = inherit;
slug = "sk082-vooraanzicht-met-licht";
type = attachment;
},
{
alt = "";
caption = "";
description = "";
filename = "SK055 vooraanzicht met licht";
id = 266;
metadata = {
file = "2013/07/SK055-vooraanzicht-met-licht.jpg";
height = 667;
"image_meta" = {
aperture = 0;
camera = "";
caption = "";
copyright = "";
"created_timestamp" = 0;
credit = "";
"focal_length" = 0;
iso = 0;
"shutter_speed" = 0;
title = "";
};
sizes = {
medium = {
file = "SK055-vooraanzicht-met-licht-300x300.jpg";
height = 300;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK055-vooraanzicht-met-licht-300x300.jpg";
width = 300;
};
"shop_catalog" = {
file = "SK055-vooraanzicht-met-licht-150x150.jpg";
height = 150;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK055-vooraanzicht-met-licht-150x150.jpg";
width = 150;
};
"shop_single" = {
file = "SK055-vooraanzicht-met-licht-300x300.jpg";
height = 300;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK055-vooraanzicht-met-licht-300x300.jpg";
width = 300;
};
"shop_thumbnail" = {
file = "SK055-vooraanzicht-met-licht-90x90.jpg";
height = 90;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK055-vooraanzicht-met-licht-90x90.jpg";
width = 90;
};
thumbnail = {
file = "SK055-vooraanzicht-met-licht-150x150.jpg";
height = 150;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK055-vooraanzicht-met-licht-150x150.jpg";
width = 150;
};
};
url = "http://website.nl/wp-content/uploads/2013/07/SK055-vooraanzicht-met-licht.jpg";
width = 667;
};
"mime_type" = "image/jpeg";
"parent_id" = 211;
path = "2013/07/SK055-vooraanzicht-met-licht.jpg";
publishing = inherit;
slug = "sk055-vooraanzicht-met-licht";
type = attachment;
},
{
alt = "";
caption = "";
description = "";
filename = "SK052 vooraanzicht met licht";
id = 267;
metadata = {
file = "2013/07/SK052-vooraanzicht-met-licht.jpg";
height = 667;
"image_meta" = {
aperture = 0;
camera = "";
caption = "";
copyright = "";
"created_timestamp" = 0;
credit = "";
"focal_length" = 0;
iso = 0;
"shutter_speed" = 0;
title = "";
};
sizes = {
medium = {
file = "SK052-vooraanzicht-met-licht-300x300.jpg";
height = 300;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK052-vooraanzicht-met-licht-300x300.jpg";
width = 300;
};
"shop_catalog" = {
file = "SK052-vooraanzicht-met-licht-150x150.jpg";
height = 150;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK052-vooraanzicht-met-licht-150x150.jpg";
width = 150;
};
"shop_single" = {
file = "SK052-vooraanzicht-met-licht-300x300.jpg";
height = 300;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK052-vooraanzicht-met-licht-300x300.jpg";
width = 300;
};
"shop_thumbnail" = {
file = "SK052-vooraanzicht-met-licht-90x90.jpg";
height = 90;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK052-vooraanzicht-met-licht-90x90.jpg";
width = 90;
};
thumbnail = {
file = "SK052-vooraanzicht-met-licht-150x150.jpg";
height = 150;
"mime-type" = "image/jpeg";
url = "http://website.nl/wp-content/uploads/2013/07/SK052-vooraanzicht-met-licht-150x150.jpg";
width = 150;
};
};
url = "http://website.nl/wp-content/uploads/2013/07/SK052-vooraanzicht-met-licht.jpg";
width = 667;
};
"mime_type" = "image/jpeg";
"parent_id" = 211;
path = "2013/07/SK052-vooraanzicht-met-licht.jpg";
publishing = inherit;
slug = "sk052-vooraanzicht-met-licht";
type = attachment;
}
)
You can easily format json code by putting json on a single line, then pasting the json, then on a new line, put three more
Like this:
{
"my" : "JSON"
}
Which in your window will look like this:
{
"my" : "JSON"
}
Give me a minute and I will write up some ideas on why it might be doing that.
Okay, let's look at this problem from a debuggers perspective.
- Inconsistent bug: Only happens sometimes, or once
This usually means a misconfiguration on the object in quesition...sometimes. But let's find out what the API is actually doing.
To get the images, we start here in WCAPI/Product.php
:
<?php
public function asApiArray() {
include WCAPIDIR."/_globals.php";
$attributes_to_send = parent::asApiArray();
$attributes_to_send['categories'] = $this->categories;
$attributes_to_send['tags'] = $this->tags;//wp_get_post_terms($this->_actual_model_id,'product_tag');
$attributes_to_send['reviews'] = $this->reviews;
$attributes_to_send['variations'] = $this->variations;
$attributes_to_send['images'] = $this->images;
$attributes_to_send['featured_image'] = $this->featured_image;
return $attributes_to_send;
}
As you see, we are calling $this->images
. However, in the class declarations at the top, we can see that there is no such member variable. Therefore it must be served by __get
and __set
right? But they aren't in the Product.php class file, maybe they are inherited?
So, we are interested in __get
in the Base class, conviently WCAPI/Base.php
<?php
public function __get( $name ) {
Helpers::debug(get_called_class() . "::__get $name");
$meta_table = $this->actual_meta_attributes_table;
$model_table = $this->actual_model_attributes_table;
$s = $this->actual_model_settings;
if ( isset( $meta_table[$name] ) ) {
$desc = $meta_table[$name];
if ( isset($desc['getter']) && is_callable( $desc['getter'] )) {
$value = call_user_func($desc['getter'], $desc);
}
if ( isset ( $this->_meta_attributes[$name] ) ) {
return $this->_meta_attributes[$name];
} else {
return '';
}
} else if ( isset( $model_table[$name] ) ) {
if ( isset( $this->_model_attributes[$name] ) ) {
return $this->_model_attributes[$name];
} else {
return '';
}
} else if ( isset( $s['has_many'] ) && $this->inArray( $name, array_keys($s['has_many']) ) ) {
return $this->loadHasManyAssociation($name);
} else if ( isset( $s['belongs_to'] ) && $this->inArray( $name, array_keys($s['belongs_to']) ) ) {
return $this->loadBelongsToAssociation($name);
}
} // end __get
Now, we don't see any reference to images here, but we see some were has_many
and belongs_to
there. In this case, Base is still using an old settings path, $this->actual_model_settings
, I'll need to update that. The new path by the way is $self->settings, but nevermind that, I will fix it for the next commit.
The model_settings come from the inheritor, so back to WCAPI/Product.php
:
public static function getModelSettings() {
include WCAPIDIR."/_globals.php";
$table = array_merge( Base::getDefaultModelSettings(), array(
'model_table' => $wpdb->posts,
'meta_table' => $wpdb->postmeta,
'model_table_id' => 'id',
'meta_table_foreign_key' => 'post_id',
'model_conditions' => "WHERE post_type IN ('product','product_variation') AND post_status NOT IN ('trash','auto-draft')",
'has_many' => array(
'order_items' => array('class_name' => 'OrderItem', 'foreign_key' => 'order_id'),
...
'images' => array(
'class_name' => 'Image',
'foreign_key' => 'post_parent',
'conditions' => array(
"post_type = 'attachment'",
"post_mime_type IN ('image/jpeg','image/png','image/gif')"
),
'connect' => function ($product,$image) {
include WCAPIDIR."/_globals.php";
Helpers::debug("Product::image::connect");
$ms = $image->getModelSettings();
$fkey = 'post_parent';
$sql = "UPDATE {$ms['model_table']} SET {$fkey} = %s WHERE ID = %s";
$sql = $wpdb->prepare($sql,$product->_actual_model_id, $image->_actual_model_id);
Helpers::debug("connection sql is: $sql");
$wpdb->query($sql);
$product_gallery = get_post_meta($product->_actual_model_id,"_product_image_gallery",true);
Helpers::debug("product_gallery as fetched from meta: $product_gallery");
if ( empty( $product_gallery ) ) {
Helpers::debug("product_gallery is empty!");
$product_gallery = array();
} else if ( ! strpos(',', $product_gallery) == false ) {
Helpers::debug("product_gallery contains a comma!");
$product_gallery = explode(',',$product_gallery);
} else {
Helpers::debug("product_gallery is empty!");
$product_gallery = array($product_gallery);
}
Helpers::debug( "Product Gallery is: " . var_export($product_gallery,true) ) ;
if ( ! in_array($image->_actual_model_id, $product_gallery) ) {
Helpers::debug("id {$image->_actual_model_id} is not in " . join(",",$product_gallery) );
$product_gallery[] = $image->_actual_model_id;
$product_gallery = join(",",$product_gallery);
Helpers::debug("Updating {$product->_actual_model_id}'s' _product_image_gallery to $product_gallery");
update_post_meta($product->_actual_model_id,'_product_image_gallery',$product_gallery);
} else {
Helpers::debug("In Array failed.");
}
}
),
...
'variations' => array(
'class_name' => 'Product',
'foreign_key' => 'post_parent',
'conditions' => array(
"post_type = 'product_variation'",
),
),
),
)
);
$table = apply_filters('WCAPI_product_model_settings',$table);
return $table;
}
Inside of the has many, we have a declaration for images
. So this is how images are found. But wait! This is all wrong.
'foreign_key' => 'post_parent',
'conditions' => array(
"post_type = 'attachment'",
"post_mime_type IN ('image/jpeg','image/png','image/gif')"
),
Well, this is actually wrong, because images don't belong to posts in this way, they are part of the gallery, you'll see that this is the way it is setup here in the connect function, but we are still connecting them by post_parent, which is wrong.
How do we fix this?
Well, simply:
<?php
'images' => array(
'class_name' => 'Image',
'sql' => function ($product) {
include WCAPIDIR."_globals.php";
$product_gallery = get_post_meta($product->_actual_model_id,"_product_image_gallery",true);
if ( empty( $product_gallery) ) { return null; }// this means no association, and will make it stop looking.
$img = new Image();
$s = $img->getModelSettings();
$sql = "SELECT {$s['model_table_id']} FROM {$s['model_table']} WHERE {$s['model_table_id']} IN ($product_gallery)";
return $sql;
},
'connect' => function ($product,$image) {
I have pushed up the latest code.
Wow... Jason, Thanks a bunch, I wouldn't have found this without your help.
I'll test it but I'm sure it'll work :)
You're awesome!