Search Results for: app development

Shopify Tutorial PHP: Update Product’s Collection with Collect API

So you are developing a Shopify app where merchants can easily customize their product’s title, description, and even the prices. However, you forgot one thing and that is the collections.

How do you actually update the product’s collections?

In this Shopify tutorial, we’ll learn how to update the product’s collections using Collect REST API and PHP.

Video Tutorial

If you prefer to learn through a video tutorial, you may watch the following video.

Getting started

To get started, we’ll assume that you have followed our Shopify app tutorial series and you are using the same repository/client that we are using here.

Now, for this tutorial, we’ll only need the following three files.

  • index.php
  • ajax.php
  • product.php

In our product.php, we should have the following code:


<div class="card-columns">
<?php
$products = shopify_call($token, $shop_url, "/admin/api/2020-07/products.json", array(), 'GET');
$products = json_decode($products['response'], JSON_PRETTY_PRINT);

foreach ($products as $product) {
	foreach ($product as $key => $value) {
		$images = shopify_call($token, $shop_url, "/admin/api/2020-07/products/" . $value['id'] . "/images.json", array(), 'GET');
		$images  = json_decode($images['response'], JSON_PRETTY_PRINT);
		?>

			<div class="card" product-id="<?php echo $value['id']; ?>">
				<img class="card-img-top" src="<?php echo $images['images'][0]['src']; ?>" alt="Card image cap">
				<div class="card-body">
					<h5 class="card-title"><?php echo $value['title']; ?></h5>
				</div>
			</div>

		<?php
	}
}
?>
</div>

<!-- Modal -->
<div class="modal fade" id="productsModal" tabindex="-1" role="dialog" aria-labelledby="productsModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body">
        <form action="ajax.php" id="productForm">
        	<div class="form-group">
        		<label for="productName">Product Title</label>
        		<input type="text" class="form-control" id="productName" name="productName">
        	</div>
        	<div class="form-group">
        		<label for="productDescription">Product Description</label>
        		<textarea class="form-control" id="productDescription" name="productDescription" rows="7"></textarea>
        	</div>
        	<div class="form-group">
        		<select class="custom-select" id="productCollection" name="productCollection" multiple>
              <?php
                $custom_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/custom_collections.json", array(), 'GET');
                $custom_collections = json_decode($custom_collections['response'], JSON_PRETTY_PRINT);

                foreach ($custom_collections as $custom_collection) {
                  foreach ($custom_collection as $key => $value) {
                    ?>
                      <option value="<?php echo $value['id']; ?>"><?php echo $value['title']; ?></option>
                    <?php
                  }
                }

                $smart_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/smart_collections.json", array(), 'GET');
                $smart_collections = json_decode($smart_collections['response'], JSON_PRETTY_PRINT);

                foreach ($smart_collections as $smart_collection) {
                  foreach ($smart_collection as $key => $value) {
                    ?>
                      <option value="<?php echo $value['id']; ?>"><?php echo $value['title']; ?></option>
                    <?php
                  }
                }
              ?>
        		</select>
        	</div>
        </form>
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button type="button" class="btn btn-primary" id="SaveProduct" product-id=''>Save changes</button>
      </div>
    </div>
  </div>
</div>

Code language: HTML, XML (xml)

In our index.php, we should have the following code:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
    <title>WeeklyHow Shopify App</title>
  </head>
  <body>

	<div class="container">
		<?php
		include_once("inc/functions.php");
		include_once("inc/mysql_connect.php");
		include_once("header.php");
		include_once("products.php");
		?>
	</div>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>

    <script>
      var shop = '<?php echo $shop_url; ?>';

      $('div[product-id]').on('click', function (e) {
        $.ajax({
          method: 'POST',
          data: {
            url: shop,
            id: $(this).attr('product-id'),
            type: 'GET'
          },
          url:'ajax.php',
          dataType: 'json',
          success:function(json){
            console.log(json);

            $('#productName').val(json['title']);
            $('#productDescription').val(json['description']);

            $('#productCollection option').each(function(i) {
              var optionCollection = $(this).val();

              json['collections'].forEach(function(productCollection) {
                if(productCollection['id'] == optionCollection) {
                  $('#productCollection option[value=' + optionCollection + ']').attr('selected', 'selected');
                }

              });
            });


            $('#SaveProduct').attr('product-id', json['id']);
            $('#productsModal').modal('show');
          }   
        }); 
      });


      $('#productsModal').on('hide.bs.modal', function() {
        $('#SaveProduct').attr('product-id', '');
        $('#productCollection').val([]);
      });

      $('#SaveProduct').on('click', function() {
        var productID = $(this).attr('product-id');

        $.ajax({
          method: 'POST',
          data: {
            url: shop,
            id: productID,
            product: $('#productForm').serialize(),
            type: 'PUT'
          },
          url:'ajax.php',
          dataType: 'html',
          success:function(json){
            console.log(json);
          }   
        }); 
      });
    </script>
  </body>
</html>
Code language: HTML, XML (xml)

And for our ajax.php, we should have the following code:

<?php
require_once("inc/functions.php");
require_once("inc/mysql_connect.php");

$id = $_POST['id'];
$shop_url = $_POST['url'];

$sql = "SELECT * FROM shops WHERE shop_url='" . $shop_url . "' LIMIT 1";
$check = mysqli_query($conn, $sql);

if(mysqli_num_rows($check) > 0) {
	$shop_row = mysqli_fetch_assoc($check);

	$token = $shop_row['access_token'];

	if($_POST['type'] == 'GET') {
		$products = shopify_call($token, $shop_url, "/admin/api/2020-07/products/" . $id . ".json", array(), 'GET');
		$products = json_decode($products['response'], JSON_PRETTY_PRINT);

		$id = $products['product']['id'];
		$title = $products['product']['title'];
		$description = $products['product']['body_html'];
		$collections = array();

		$custom_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/custom_collections.json", array("product_id" => $id), 'GET');
		$custom_collections = json_decode($custom_collections['response'], JSON_PRETTY_PRINT);

		foreach ($custom_collections as $custom_collection) {
			foreach ($custom_collection as $key => $value) {
				array_push($collections, array("id" => $value['id'], "name" => $value['title']));
			}
		}

		$smart_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/smart_collections.json", array("product_id" => $id), 'GET');
		$smart_collections = json_decode($smart_collections['response'], JSON_PRETTY_PRINT);

		foreach ($smart_collections as $smart_collection) {
			foreach ($smart_collection as $key => $value) {
				array_push($collections, array("id" => $value['id'], "name" => $value['title']));
			}
		}

		echo json_encode(
			array(
				"id" => $id,
				"title" => $title,
				"description" => $description,
				"collections" => $collections
			)
		);

	} else if( $_POST['type'] == 'PUT' ) {
		$productData = array();
		$productData = proper_parse_str($_POST['product']);

		$array = array("product" => array("title" => $productData['productName'], "body_html" => $productData['productDescription']));

		$products = shopify_call($token, $shop_url, "/admin/api/2020-07/products/" . $id . ".json", $array, 'PUT');
	}
	
}
?>
Code language: PHP (php)

The scripts above should allow us to edit and save a new title and description for any of the products that we select below.

shopify products grid design

Now, what we want to do is when we select a product. A bootstrap modal should appear and allow us to select new collections for our product.

updating shopify products in bootstrap modal

Updating the product’s collection

There are two ways to update the product’s collection. One is to use the Collection API, delete the collection attached to the product, and create the deleted collection and assign all of the previous products assigned to the collection except that product that we selected. Two is to use Collect API.

Obviously, the first option is the worse way of updating the product’s collection. Why? Because it’s ugly and it’s making too many unnecessary API calls.

However, if you use collect API instead, all we needed to do is to get the collect attached to the product that we selected, delete the collect, and create a new collect with the new collection. Simple as that!

Let’s start by getting all of the collect from collect API. Open the ajax.php and update its code to the following:

<?php
require_once("inc/functions.php");
require_once("inc/mysql_connect.php");

$id = $_POST['id'];
$shop_url = $_POST['url'];

$sql = "SELECT * FROM shops WHERE shop_url='" . $shop_url . "' LIMIT 1";
$check = mysqli_query($conn, $sql);

if(mysqli_num_rows($check) > 0) {
	$shop_row = mysqli_fetch_assoc($check);

	$token = $shop_row['access_token'];

	if($_POST['type'] == 'GET') {
		$products = shopify_call($token, $shop_url, "/admin/api/2020-07/products/" . $id . ".json", array(), 'GET');
		$products = json_decode($products['response'], JSON_PRETTY_PRINT);

		$id = $products['product']['id'];
		$title = $products['product']['title'];
		$description = $products['product']['body_html'];
		$collections = array();

		$custom_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/custom_collections.json", array("product_id" => $id), 'GET');
		$custom_collections = json_decode($custom_collections['response'], JSON_PRETTY_PRINT);

		foreach ($custom_collections as $custom_collection) {
			foreach ($custom_collection as $key => $value) {
				array_push($collections, array("id" => $value['id'], "name" => $value['title']));
			}
		}

		$smart_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/smart_collections.json", array("product_id" => $id), 'GET');
		$smart_collections = json_decode($smart_collections['response'], JSON_PRETTY_PRINT);

		foreach ($smart_collections as $smart_collection) {
			foreach ($smart_collection as $key => $value) {
				array_push($collections, array("id" => $value['id'], "name" => $value['title']));
			}
		}

		echo json_encode(
			array(
				"id" => $id,
				"title" => $title,
				"description" => $description,
				"collections" => $collections
			)
		);

	} else if( $_POST['type'] == 'PUT' ) {
		$productData = array();
		parse_str($_POST['product'], $productData);

		$array = array("product" => array("title" => $productData['productName'], "body_html" => $productData['productDescription']));

		$products = shopify_call($token, $shop_url, "/admin/api/2020-07/products/" . $id . ".json", $array, 'PUT');

		$collects = shopify_call($token, $shop_url, "/admin/api/2020-07/collects.json", array('product_id' => $id), 'GET');
		$collects = json_decode($collects['response'], JSON_PRETTY_PRINT);

		foreach ($collects as $collect) {
			foreach ($collect as $key => $value) {
				$collects = shopify_call($token, $shop_url, "/admin/api/2020-07/collects/" . $value['id'] .".json", array(), 'DELETE');
			}
		}

	}
	
}
?>
Code language: PHP (php)

In the code above, we first get the collects assigned to our selected product and then loop through each collect using foreach and then delete each collect. These are just basics and you should be able to follow along 🙂

Next, we’ll use POST endpoint to create the new collect.

<?php
require_once("inc/functions.php");
require_once("inc/mysql_connect.php");

$id = $_POST['id'];
$shop_url = $_POST['url'];

$sql = "SELECT * FROM shops WHERE shop_url='" . $shop_url . "' LIMIT 1";
$check = mysqli_query($conn, $sql);

if(mysqli_num_rows($check) > 0) {
	$shop_row = mysqli_fetch_assoc($check);

	$token = $shop_row['access_token'];

	if($_POST['type'] == 'GET') {
		$products = shopify_call($token, $shop_url, "/admin/api/2020-07/products/" . $id . ".json", array(), 'GET');
		$products = json_decode($products['response'], JSON_PRETTY_PRINT);

		$id = $products['product']['id'];
		$title = $products['product']['title'];
		$description = $products['product']['body_html'];
		$collections = array();

		$custom_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/custom_collections.json", array("product_id" => $id), 'GET');
		$custom_collections = json_decode($custom_collections['response'], JSON_PRETTY_PRINT);

		foreach ($custom_collections as $custom_collection) {
			foreach ($custom_collection as $key => $value) {
				array_push($collections, array("id" => $value['id'], "name" => $value['title']));
			}
		}

		$smart_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/smart_collections.json", array("product_id" => $id), 'GET');
		$smart_collections = json_decode($smart_collections['response'], JSON_PRETTY_PRINT);

		foreach ($smart_collections as $smart_collection) {
			foreach ($smart_collection as $key => $value) {
				array_push($collections, array("id" => $value['id'], "name" => $value['title']));
			}
		}

		echo json_encode(
			array(
				"id" => $id,
				"title" => $title,
				"description" => $description,
				"collections" => $collections
			)
		);

	} else if( $_POST['type'] == 'PUT' ) {
		$productData = array();
		parse_str($_POST['product'], $productData);

		$array = array("product" => array("title" => $productData['productName'], "body_html" => $productData['productDescription']));

		$products = shopify_call($token, $shop_url, "/admin/api/2020-07/products/" . $id . ".json", $array, 'PUT');

		$collects = shopify_call($token, $shop_url, "/admin/api/2020-07/collects.json", array('product_id' => $id), 'GET');
		$collects = json_decode($collects['response'], JSON_PRETTY_PRINT);

		foreach ($collects as $collect) {
			foreach ($collect as $key => $value) {
				$collects = shopify_call($token, $shop_url, "/admin/api/2020-07/collects/" . $value['id'] .".json", array(), 'DELETE');
			}
		}


		if( count($productData['productCollection'] ) > 0) {
			for ($i = 0; $i < count($productData['productCollection']); $i++) { 
				if(count($productData['productCollection']) >= 0 && count($productData['productCollection']) <= 1) {
					$value = $productData['productCollection'];
				} else {
					$value = $productData['productCollection'][$i];
				}
				

				$collects = shopify_call($token, $shop_url, "/admin/api/2020-07/collects.json", array('collect' => array('product_id' => $id, 'collection_id' => $value)), 'POST');
			}
		}
	}
	
}
?>
Code language: PHP (php)

In the above code, we need to check if the collections selected by the merchant is more than one. If it is, then we’ll loop through each collections and create the collect using the value of product ID and collection ID.

If you’re wondering why there is a condition inside the loop, it’s because the productData variable can create two-dimensional arrays especially if the length of the array is more than 1. So we need to make sure we get both values regardless of the array length.

With everything saved, we should be able to update the product’s collections. BUT! Unfortunately, the built-in parse_str() function is not going to work if there are two or more query strings with the same name.

For example, let’s say we have the following query string:

https://weeklyhow.com/?id=1&id=2&id=3
Code language: JavaScript (javascript)

If we use the built-in parse string function, the function will only return the last value which is 3.

So if we use the same function, it’ll most likely not create the first collects.

To fix that, we’ll have to use the following function provided by Evan K from php.net:

function proper_parse_str($str) {
  # result array
  $arr = array();

  # split on outer delimiter
  $pairs = explode('&', $str);

  # loop through each pair
  foreach ($pairs as $i) {
    # split into name and value
    list($name,$value) = explode('=', $i, 2);
   
    # if name already exists
    if( isset($arr[$name]) ) {
      # stick multiple values into an array
      if( is_array($arr[$name]) ) {
        $arr[$name][] = $value;
      }
      else {
        $arr[$name] = array($arr[$name], $value);
      }
    }
    # otherwise, simply stick it in a scalar
    else {
      $arr[$name] = $value;
    }
  }

  # return result array
  return $arr;
}
Code language: PHP (php)

You can copy the above function and paste it either on the very top of ajax.php or inside the functions.php.

Once you’re done copying the code, we should then be able to use it instead of the parse_str() function.

<?php
require_once("inc/functions.php");
require_once("inc/mysql_connect.php");

$id = $_POST['id'];
$shop_url = $_POST['url'];

$sql = "SELECT * FROM shops WHERE shop_url='" . $shop_url . "' LIMIT 1";
$check = mysqli_query($conn, $sql);

if(mysqli_num_rows($check) > 0) {
	$shop_row = mysqli_fetch_assoc($check);

	$token = $shop_row['access_token'];

	if($_POST['type'] == 'GET') {
		$products = shopify_call($token, $shop_url, "/admin/api/2020-07/products/" . $id . ".json", array(), 'GET');
		$products = json_decode($products['response'], JSON_PRETTY_PRINT);

		$id = $products['product']['id'];
		$title = $products['product']['title'];
		$description = $products['product']['body_html'];
		$collections = array();

		$custom_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/custom_collections.json", array("product_id" => $id), 'GET');
		$custom_collections = json_decode($custom_collections['response'], JSON_PRETTY_PRINT);

		foreach ($custom_collections as $custom_collection) {
			foreach ($custom_collection as $key => $value) {
				array_push($collections, array("id" => $value['id'], "name" => $value['title']));
			}
		}

		$smart_collections = shopify_call($token, $shop_url, "/admin/api/2020-07/smart_collections.json", array("product_id" => $id), 'GET');
		$smart_collections = json_decode($smart_collections['response'], JSON_PRETTY_PRINT);

		foreach ($smart_collections as $smart_collection) {
			foreach ($smart_collection as $key => $value) {
				array_push($collections, array("id" => $value['id'], "name" => $value['title']));
			}
		}

		echo json_encode(
			array(
				"id" => $id,
				"title" => $title,
				"description" => $description,
				"collections" => $collections
			)
		);

	} else if( $_POST['type'] == 'PUT' ) {
		$productData = array();
		$productData = proper_parse_str($_POST['product']);

		$array = array("product" => array("title" => urldecode($productData['productName']), "body_html" => urldecode($productData['productDescription'])));
		
		$products = shopify_call($token, $shop_url, "/admin/api/2020-07/products/" . $id . ".json", $array, 'PUT');

		$collects = shopify_call($token, $shop_url, "/admin/api/2020-07/collects.json", array('product_id' => $id), 'GET');
		$collects = json_decode($collects['response'], JSON_PRETTY_PRINT);

		foreach ($collects as $collect) {
			foreach ($collect as $key => $value) {
				$collects = shopify_call($token, $shop_url, "/admin/api/2020-07/collects/" . $value['id'] .".json", array(), 'DELETE');
			}
		}


		if( count($productData['productCollection'] ) > 0) {
			for ($i = 0; $i < count($productData['productCollection']); $i++) { 
				if(count($productData['productCollection']) >= 0 && count($productData['productCollection']) <= 1) {
					$value = $productData['productCollection'];
				} else {
					$value = $productData['productCollection'][$i];
				}
				

				$collects = shopify_call($token, $shop_url, "/admin/api/2020-07/collects.json", array('collect' => array('product_id' => $id, 'collection_id' => $value)), 'POST');
			}
		}
	}
	
}
?>
Code language: PHP (php)

Now, query strings are encoded to URL text formatting that’s why before we save the new title and description, we’ll have to decode the title and description back to a normal text format using urldecode() function.

Now if we save all of our scripts and run the app, we should then be able to update the collections without any problem. Awesome!

Updating shopify product collection in bootstrap modal

Conclusion

Updating a product’s collection can be a hassle especially if the products are attached to not just a custom collection, but also to a smart collection. However, with collect API, we should be able to update the product’s collection without doing too much unnecessary API calls.

We hope that you learned how to update your products using collect API. If you have encountered any issues or errors, let us know in the comments below and we’ll try to help out! 🙂

Videoder Premium Downloader APK Latest Version 14.5 (Updated)

Videoder Premium APK for android is one of the best downloaders for downloading youtube videos in 2020. The free version of Videoder APP will only let you download videos but with Videoder premium, you will be able to download videos with no ads.

If you have been using YouTube downloaders for a long time then you may probably know already that Videoder is not available in the PlayStore. This is due to its violation of the PlayStore policies. So if you want to use this app, it is highly recommended to download directly from their official site.

What is Videoder?

Videoder is a free video downloader and converter for both android devices and PC.

Videoder was officially founded by Rahul Verma back in 2013 with the support of his team Varun, a full stack developer who is involved in both backend and frontend development of Videoder. Surbhi Singla is also part of Rahul’s team. She manages all of the operations involved in Videoder including brand promotion and marketing.

Up until now, Videoder is believed to be one of the most known video downloaders online.

Download Videos Everywhere

Videoder Premium APK supports over 50+ websites that stream videos and music including most of the popular sites like:

  • YouTube
  • Facebook
  • Instagram
  • Dailymotion
  • Twitter
  • Hotstar
  • voot
  • vidme
  • 9Anime
  • Soundcloud
  • 9gag
  • AudioBoom
  • IMDB
  • Funny Or Die
  • Liveleak
  • TED
  • Vine
  • Vimeo
  • VK
  • SonyLiv
  • Viu
  • RuTube
  • Youku
  • TVF Play
  • TikTok
  • Ozee
  • and more!

If one of your favorite streaming websites is not available in the list, you may contact Videoder and they will add them for just you!

New Features

Videoder Premium APK offers the following new features:

YouTube Playlist Downloader
YouTube Playlist Downloader

Videoder Premium APK allows you to download videos all at once with its YouTube Playlist Downloader feature

Download YouTube videos
Download YouTube videos

Download youtube videos to your phone or pc with Videoder for free.

Built-in Browser & Ad-Blocker
Built-in Browser & Ad-Blocker

Download videos on the go with built-in browser and with no interruptions thanks to Ad-block feature.

Insanely Fast Download
Insanely Fast Download

Videoder uses multiple network connections to boost your downloading speed.

Download Videoder Premium APK for Android

Videoder Premium APK is currently supporting Android devices, Windows PC and MAC. You may also download videos from YouTube Red using Videoder Premium.

To start downloading videos online, click the download button below.

How To Install Videoder Premium APK?

Step 1

Download Videoder Premium APK. If your browser warns you on downloading APK outside PlayStore, ignore it as you are downloading from the official Videoder site.

Videoder Download for Android and PC

Step 2

Wait for the app to be downloaded in the notifications panel. Once the download is complete, tap on the completed notification to install.

Tap to install Videoder

Step 3

Your settings may not allow you to install the APK outside Play Store. If you see the popup as shown below, tap on SETTINGS and follow the next instructions.

Go to your settings menu

Step 4

Go to ‘ Settings -> Security -> Unknown Sources ‘ and turn it on. You may turn this off again if you’ve finished installing videoder.

Switch on the unknown sources

Step 5

Go back to Downloads and open the downloaded and complete the installation. Do not forget to turn off Unknown Sources once the installation is complete.

Youtube downloader Videoder successfully installed

Conclusion

There’s no doubt that Videoder is one of the most used downloaders and converter online. But if for some reason the app doesn’t allow you to download then there are Videoder alternatives that you can use.

If you have encountered any issues. Don’t hesitate to let us know in the comments below. We’d love to help out!

Disclosure: This article may contain affiliate links, which means we may receive a commission if you click a link and purchase something that we have recommended.