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
- 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> <p> {% 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> </div> {% 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 %} </p>
- .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]; if(file_data){ var customer_id = $('#sortpicture').data('attr'); var form_data = new FormData(); form_data.append('file', file_data); form_data.append('customerid',customer_id); $.ajax({ 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(){ //$('button.submit-br-form').attr('disabled','disabled'); $('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'); location.reload(); } }); } });
- 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)
<?php session_start(); 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."'"); if($fetch->num_rows){ //udpate $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."'"); }else{ //insert $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 - Below is the result screenshot of profile image upload section in account dashboard of customer.
2 Comments
-
-
Josh
July 4, 2019
I’ve followed all these steps but when i upload the image in shopify as a customer the form just resets, what should the folder containing the repo clone and profile_upload.php look like in the host? I installed skeleton using gitbash and followed the steps, then I put all the files inside a sub directory in my cpanel domain and swapped the example url’s in the code to go to the right place, my conf file has my api key, store, and api password, step 2 I pasted in a tag at the bottom of customer/account.liquid with the updated URL, profile_upload.php is in the same folder as conf.php and the other .php files, the only other folders are vendor and uploads. Would really appreciate any help / a bit of a breakdown on steps 2 and 3.
Suman K.C
July 4, 2019
Hi Josh,
when you said “..the form just resets” i hope this means your page reloads and nothing happens, comes up with the same form being reset. This means you have to take care at ajax form submission or at on click upload button.
It depends on the form structure you have created. I suggest you to have the same form structure (double check on your button type) and on second code snippet when you click on upload button the form should be prevented from submittion. I hope this will help you.
Thank you for reaching out.
Leave a Reply