When it comes to shopify account, user has limited fields. Like in other eCommerce they got to store multiple address and the generic fields provided during the signup form.

At the time of this blog post, i’m developing a store where there is need for customer profile picture and i got to achieve this via a middle ware using shopify customer metafield api endpoints. If you got to build this feature differently than this then i would love to read in comment section below. 🙂

The actual requirement i worked on is :

  • Feature that would eanble customer to add profile picture from account dashboard
  • Edit and remove feature of the uploaded image.

And the flow i followed is

  • Form field which would include file upload
  • On submit, ajax call which would submit the image to remote server.
  • the remote server or let’s say a middleware which would then making use of customer metafield api endpoints saves in customer metafield.
  • finally on dashboard we get that particular metafield data and serve the image as profile picture

Now let’s dive into the steps

  1. Let’s create a form field in customer account dashboard. Only the logged in customer would access to account dashboard. So let’s add the file form field in liquid template customer/account.liquid from theme code edit section.The below code first checks the customer metafield info is available. In case of availability it would show the image and edit button. [The metafield `customer.metafields.birthdayrandomizer.profilepicture` ]And if not avaibale it would present the upload image field only.
    <h2>Profile Picture</h2>
      {% if customer.metafields.birthdayrandomizer.profilepicture != blank %}
      	<img src="{{ customer.metafields.birthdayrandomizer.profilepicture }}" />
      	<button class="button btn btn--small" id="editprofilepicture">Edit</button>
      <div class="editprofile-container" style="display:none;">
        Choose profile picture
            <input id="sortpicture" data-attr="{{ customer.id }}" type="file" name="sortpic" />
            <button class="button btn btn--small" id="editupload">Upload</button><span class="uploading-status"></span>	
          <button class="button btn btn--small" id="cancel-upload">Cancel</button>
      {% else %}
        Choose profile picture
        <input id="sortpicture" data-attr="{{ customer.id }}" type="file" name="sortpic" />
        <button class="button btn btn--small" id="upload">Upload</button><span class="uploading-status"></span>
      {% endif %}
  2. .In the code snippet below, there is ajax request which is submitting our data to middleware on trigger of CTA upload button.
    $('button#upload, button#editupload').on('click', function(){
       var file_data = $('#sortpicture').prop('files')[0];
          var customer_id = $('#sortpicture').data('attr');
           var form_data = new FormData();                  
           form_data.append('file', file_data);
             url: 'https://example.com/profile_upload.php', // point to server-side PHP script 
             dataType: 'text',  // what to expect back from the PHP script, if anything
             cache: false,
             contentType: false,
             processData: false,
             data: form_data,                         
             type: 'post',
             beforeSend: function(){
              $('span.uploading-status').html('{{ 'ajax-loader.gif' | asset_url | img_tag }}').show();
             success: function(php_script_response){
               console.log(php_script_response); // display response from the PHP script, if any
               complete: function(){
        $('span.uploading-status').html('successfully uploaded');


  3. And now finally the middleware work.In this part of the development you need to host your middleware somewhere outside and as i will be receiving this post data with PHP, i have hosted in php server. Until now if you aren’t famaliar with php you can receive the jquery post data in any other relevant programming language, but still you need to enable the cross domain interaction.I will be using the private app skeleton for this task. The private app skeleton library is available via this github repo. For which we have to use private app credentials with customer data read write access. (the private app credentials are filled in conf.php file of the library)
        header("Access-Control-Allow-Origin: *");
        header("Access-Control-Allow-Methods: PUT, GET, POST");
        header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");
        error_reporting(E_ALL); ini_set('display_errors', TRUE);
        require __DIR__.'/vendor/autoload.php';
      require 'includes/DBConnection.php';
      use phpish\shopify;
      require __DIR__.'/conf.php';
      $shopify = shopify\client(SHOPIFY_SHOP, SHOPIFY_APP_API_KEY, SHOPIFY_APP_PASSWORD, true);   
        $customerid = $_POST['customerid'];
        if ( 0 < $_FILES['file']['error'] ) {
            echo 'Error: ' . $_FILES['file']['error'] . '<br>';
        else {
            $newfilname = strtotime(date("Y-m-d h:i:s")).'_'.$_FILES['file']['name'];
            if(move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $newfilname)){
                echo 'successfully uploaded';
                //upload to customer metafield data
                $profilepicture = 'http://example.com/uploads/'.$newfilname;
                # Making an API request can throw an exception
        		$customermeta = $shopify('POST /admin/customers/'.$customerid.'/metafields.json',array(),array
            			'metafield' => array
            				"namespace" => "birthdayrandomizer",
            				"key" => "profilepicture",
            				"value" => $profilepicture,
            				"value_type" => "string"
                //successful request sent to shopify store
                //insert / update in database
                	$fetch = $db->query("SELECT * FROM tbl_customerdata WHERE customer_id='".$customerid."'");
                	    $updated_at = date('Y-m-d h:i:s');
                	    $db->query("UPDATE `tbl_customerdata` SET customer_image = '$newfilname', updated_at = '$updated_at' WHERE customer_id='".$customerid."'");
                	    $db->query("INSERT INTO `tbl_customerdata` (`customer_id`,`customer_image`,`created_at`) VALUES ('" .$customerid. "','".$newfilname."','".date('Y-m-d h:i:s')."')");
            	echo $profilepicture;

    * In the above code the file type and file size isn’t compared.

    The uploaded file is stored in `/upload` directory
    The url of the file path is stored in database and is returned as a result of ajax request

  4. Below is the result screenshot of profile image upload section in account dashboard of customer.

Suman K.C

eCommerce Developer, writes about stuff related to eCommerce development. Currently based in Kathmandu, loves reading about startups & new technology, introvert nature, fond of traveling & playing futsal.

More Posts