Giter Site home page Giter Site logo

Comments (3)

jasonknight avatar jasonknight commented on June 25, 2024

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.

from woocommerce-json-api.

jasonknight avatar jasonknight commented on June 25, 2024

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.

from woocommerce-json-api.

marksel avatar marksel commented on June 25, 2024

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!

from woocommerce-json-api.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.