Click here to Skip to main content
15,888,286 members
Articles / Programming Languages / PHP

Price comparison script with Wordpress and the REST API

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
27 Mar 2013CPOL6 min read 90.6K  
Price comparison script with Wordpress and the REST API.

Hey guys, I’m back. It took me some time here to move into my new flat, but now most things are done and the most important thing: my internet connection is up. yehaa!

So today I am going to show you some stuff with wordpress and some rest webservices. I will implement a price comparison script in Wordpress, so that you can enter your affiliate links from Amazon and sell stuff on your page. The most cool thing about that will be the REST API: This will enable you to import any data into your webshop, no matter what file format you are given (CSV, XML, JSON …), no matter what programming language you are going to use.

There are a few steps needed to achieve this, but it wont be too hard.

What will you learn?

If you are not familiar with programming Wordpress plugins you will get an introduction to that. At the same time you will have some fun with REST. :)

Prerequisites

What will you need in order to be able to reproduce and understand this little tutorial? – Not that much. Pretty basic stuff, you should be familiar with rest webservices (implementing rest webservices (jersey) with Java, basic understanding of HTTP GET and POST and a little PHP. You can use our free java web services (which are included by default in this tutorial), but you are not required to do so. If you do so, you get some advantages:

  • You don’t need an appserver, just a webserver with Wordpress
  • You don’t need to program web services :)
  • You don’t need (another) database
  • The webservices are reliable, secure and free

If you use our webservices, go and get your free userpasswordToken here.

Because a picture is worth a thousand words: a small picture :)

price comparison script

price comparison script

Should be self explaining, if it’s not, go on with reading ;)

Basically, we won’t save any of our data in wordpress (or its database). Wordpress is just used as stupid front end, just showing the stuff our REST services will serve. But why use webservices? Here are some pros that we get from using webservices:

  • clean, easy to use REST API, enables you to import any data given in any format (CSV, XML, JSON,..)
  • no need to change Wordpress code / write plugins if you need to import data in new format
  • easy inclusion of data from affiliate programs (affili.net, belboon, ..)

First step – Prepare the backed – REST API

Just a quick look at the source code for our REST API (code shortened, see attachments for full source code):

PHP
@Path("/v1/pcs")
@Stateless
public class PriceComparisonService extends AuthenticatedResource {

    @POST
    @Path("deleteProduct")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public String deleteProduct(@FormParam("productId") Long productId, 
                      @FormParam("userpasswordToken") String userpasswordToken) {

        if (this.authUser(userpasswordToken)) {
            repository.deleteProduct(productId, userpasswordToken);
        }
        return null;
    }

    @GET
    @Path("getProducts")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    public String getProducts(@QueryParam("userpasswordToken") String userpasswordToken) {
        if (this.authUser(userpasswordToken)) {
            List<de.hm.entity.entities3.Product> allProducts = 
                         repository.getProductsByAuthentication(userpasswordToken);
            List<String> encodedProductList = new ArrayList<String>();
            for (Product prod : allProducts) {
                encodedProductList.add(prod.toJSONString());
            }
            JSONArray jsonArr = new JSONArray();
            jsonArr.addAll(encodedProductList);
            return jsonArr.toJSONString();
        }
        return null;
    }

    @POST
    @Path("saveProduct")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    public void saveProduct(
            @FormParam("description") String description,
            @FormParam("imageurl") String imageurl,
            @FormParam("link") String link,
            @FormParam("name") String name,
            @FormParam("price") String price,
            @FormParam("rating") String rating,
            @FormParam("seller") String seller,
            @FormParam("version") String version,
            @FormParam("userpasswordToken") String userpasswordToken) {
        if (this.authUser(userpasswordToken)) {
            de.hm.entity.entities3.Product product = new de.hm.entity.entities3.Product();
            product.setDescription(description);
            product.setImageurl(imageurl);
            product.setLink(link);
            product.setName(name);
            product.setPrice(Float.parseFloat(price));
            product.setRating(rating);
            product.setSeller(seller);
            product.setVersion(Integer.parseInt(version));
            Authentication auth = new Authentication();
            auth.setUserPasswordToken(userpasswordToken);
            product.setAuthentication(auth);
            repository.saveProduct(product);
        }
    }
}

As you can see there is one method for saving a new product, deleting an existing one and a getter for listing all the products. Each method does one thing before it does anything else – it looks for the userpasswordToken if the user is authenticated to do anything. If he is so, he gets or saves the data with his token. This second step ensures that every user just gets his own data and not the data of another user. The methods itself are quite straight forward: just reading and writing entities to database, I won’t explain that in detail, you can have a look at the source code attached again.

Second step – WordPress adaption

First we create a file that will implement our plugin. Feel free to give it a name you like. In order to make the plugin work, you will have to enter the plugin name in the comments:

PHP
/*
 * Plugin Name: WPExtendedCompare
 */

Note: I will not say anything here about licensing. There are several Wordpress tutorials who will explain that better, if you are interested in that please consider reading a tutorial on programming Wordpress plugins.

This will be our class:

JavaScript
if (!class_exists('WPExtendedCompare')) {

    class WPExtendedCompare {

            var $settings;

            function WPExtendedCompare() {
            add_shortcode("extcomp", array(&$this, 'show_ext_comp'));
            if (is_admin()) {
                add_action('admin_menu', array(&$this, 'add_menupages'));
            }
            // further code will go here..
        }
    }
}

The settings variable would be a holder for your settings you make to your plugin, however we won’t need that right now. The function add_shortcode will create our shorttag, so that from now (if we activate our plugin) we can just write [extcomp] and Wordpress will parse whatever the function show_ext_comp returns – we will have to define that now.

JavaScript
function show_ext_comp() {
     include( 'CompForm.php' );
     $form = new CompForm($this->getData());
     $form->show();
}

So our function includes another PHP file, OK, no magic here. Then the constructor gets whatever getData() returns – again, we will have to define that. $form->show will show whatever has to be shown, see details later.

The next step will be made with two functions:

JavaScript
function getProducts($userpasswordToken = "brosef") {
    $serviceUrl = 'http://78.47.190.21:8080/pcs/webresources/v1/' + 
       'pcs/getProducts?userpasswordToken=' . $userpasswordToken;
    $curl = curl_init();
    curl_setopt($curl, 10002, $serviceUrl);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);

    $curl_response = curl_exec($curl);
    curl_close($curl);
    return json_decode($curl_response, true);
}

function getData() {
    $json = $this->getProducts();
    $rows = array();
    foreach ($json as $input) {
        $arrInput = json_decode($input, true);
        $rows[] = array(
            'imageurl' => $arrInput['imageurl'],
            'sellerurl' => $arrInput['seller'],
            'price' => $this->formatCurrency($arrInput['price']),
            'rating' => $arrInput['rating'],
            'link' => $arrInput['link'],
            'descr' => $arrInput['description'],
            'pid' => $arrInput['id'],
        );
    }

    return $rows;
}

Look at getProducts() first, because that is were the magic happens – here we call our rest api (that we have implemented in step 1) and by json_decode we give the decoded result to the function getData().
Remember – getData() returns whatever the CompForm constructor gets, so we put that into a nice little array so everything is in the right place. Have a look at CompForm.php:

PHP
<?php

class CompForm {

    private $output;
    private $template;
    private $row;

    public function __construct($data) {
        $this->template = $this->getTemplate();
        $this->row = $this->getRow();
        $this->parseParams($data);
    }

    private function getRow() {
        ob_start();
        include( 'ContactFormTemplate.html' );
        $ret = ob_get_contents();
        ob_end_clean();
        return $ret;
    }

    private function getTemplate() {
        ob_start();
        include( 'rahmen.html' );

        $ret = ob_get_contents();

        ob_end_clean();
        return $ret;
    }

    public function show() {
        echo $this->output;
    }

    public function parseParams($params) {
        $rows = "";
        $newRow = $this->row;
        foreach ($params as $row) {
            $newRow = $this->row;
            foreach ($row as $key => $val) {
                $newRow = str_replace("#" . $key . "#", $val, $newRow);
            }
            $rows .= $newRow;
        }
        $this->output = str_replace("#rows#", $rows, $this->template);
    }
}
?>

There is a simple (not very complex) parser, that will parse every value from our JSON data into the array. It just substitutes every #key# in the templates with the value of key (value and key in terms of : indexing key in the JSON structure and the resulting value). The templates are very simple (and not very elegant :P ), you can make better ones :) I will not explain the templates – it is obvious.

Some hooks are still required to be made in order to test our plugin:

JavaScript
function add_menupages() {

    add_options_page("Price Compare Settings", "Price Compare Settings", 
      "manage_options", 'pcs-options', array(&$this, 'my_plugin_options'));
}

function my_plugin_options() {
    if (!current_user_can('manage_options')) {
        wp_die(__('You do not have sufficient permissions to access this page.'));
    }
    include 'wpcompare_add_product.php';
}

This will add a menu item in the settings menu with a form to add manually products to our price comparison plugin.

See wpcompare_add_product.php (code has been shortened, see archive for full source code):

XML
<html>
    <form class="form-style" method="post" 
             action="http://78.47.190.21:8080/pcs/webresources/v1/pcs/saveProduct/">
        <table>
            <tr>
                <td><div>product name</div></td>
                <td><div><input type="text" name="name" 
                  id="name" value="" /></div></td>
            </tr>
            <tr>
                <td><div>description</div></td>
                <td><div><input type="text" name="description" 
                  id="description" value="" /></div></td>
            </tr>
            <tr>
                <td><div>image (url)</div></td>
                <td><div><input type="text" name="imageurl" 
                  id="imageurl" value="" /></div></td>
            </tr>
            <tr>
                <td><div>link</div></td>
                <td><div><input type="text" name="link" 
                  id="link" value="" /></div></td>
            </tr>
            <tr>
                <td><div>price</div></td>
                <td><div><input type="text" name="price" 
                  id="price" value="" /></div></td>
            </tr>
            <tr>
                <td><div>rating</div></td>
                <td><div><input type="text" name="rating" 
                  id="rating" value="" /></div></td>
            </tr>
            <tr>
                <td><div>seller (url)</div></td>
                <td><div><input type="text" name="seller" 
                   id="seller" value="" /></div></td>
            </tr>

        </table>
        <input type="hidden" name="userpasswordToken" 
           id="userpasswordToken" value="brosef" />
        <input type="hidden" name="version" id="version" value="1" />	
        <input type="submit" value="save product"/>
    </form>
</html>

This will directly call our REST API and post the params to the saveProduct method – notice the name of the input fields, which are each just equal to the names of the fields in the rest service. No confirmation after clicking the button (this is your homework ;) ), but the post is being performed, just have a look at the price comparison script! To do so, just create a new Wordpress page and add the shortcode we defined: [extcomp]. That’s it! You can see a live demo here.

Conclusion

You just implemented some simple REST web services with jersey and called that REST API into your own Wordpress plugin. good work!

What’s next?

In order to make this stuff useable there are a few things left:

  • different templates
  • You may want to list your products with some different data – let’s say you need to list delivery costs in another column. So the templates should be editable (I mean editable in a “convenient” way, means not to go and edit source code but have a nice form which adds fields).

  • import different file formats and automated import using cronjob
  • In reality you won’t add every single product manually. You will get an XML or anything similar (CSV, JSON, etc..) and want that get imported automatically every 60 minutes or something.. There is a quick way for solving this in an elegant way through the REST API :)

  • ordering and filtering / grouping products for different tables
  • You may want to sell dog food on one page and cat food on another. So ideally you would just drop a Wordpress page with: [extcomp dogfood] or [extcomp catfood] to show two different product comparison tables with different products. A better way could be to achieve that using filtering and / or ordering: [extcomp filter=dogfood orderby=price desc] (SQL like)

  • clean uninstall
  • There is some code missing which will blow our stuff out of Wordpress if we don’t need our little price comparison script anymore.

These and more will follow in my next post :)See you then!

Attachments

The post Price comparison script with Wordpress and REST API appeared first on webservice-junkies.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Junior)
Germany Germany
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
-- There are no messages in this forum --