Stripe 402 Error – Payment Required

Setting up Stripe for a client on WooCommerce we ran into a Stripe 402 Error. So what does a 402 error mean and how can we solve this issue? Well Let’s get into the finer details shall we.

Stripe Environment

Keys used In our case this happened using a live publishable and private key. So this meant we had to use a real credit card and enter details properly. Sometimes people run test mode and forget to use a dummy credit card for testing or forget to turn on testing. So please do check what mode you are using and use the proper payment details.

Stripe 402 Code

When the payment does fail with a Stripe 402 error it means the payment went wrong.

Stripe 402 Error

I quote Stripe:

Not all errors map cleanly onto HTTP response codes, however. When a request is valid but does not complete successfully (e.g., a card is declined), we return a 402 error code. To understand why a card is declined, refer to the list of codes in the documentation.

So as there are multiple problems that can cause this error you need to find out what the error was you had. And for that you need to get the possible decline code.

Source of the Error

We can see in the page source  what the issue is once the payment is done. To view the source just after a failure use command+alt+i on Chrome on your Mac to open the inspector for this. Sometimes it is just the wrong credit card details entered. Again, check the decline code / message.

Also, when you have error message recording turned on you can check your WooCommerce system logs. These are located at /srv/www/domain.com/shared/uploads/wc-logs  for those using Trellis. For others at wp-content/uploads/wc-logs. In our case we found:

01-24-2018 @ 13:54:48 - ====Start Log====
Error: stdClass Object
(
 [error] => stdClass Object
 (
 [message] => Your card's security code is incorrect.
 [type] => card_error
 [param] => cvc
 [code] => incorrect_cvc
 [charge] => ch_111111111111111111111
 )

)

So the client did not enter the proper security code or cvc. In other cases it could be an incorrect card number or something else related tot the payment.

Solution

Well, as soon as you have the decline code or error found in the source of the page or in your WooCommerce error logs or other payment logs you will be able to add details properly. As stated we had an issue with the cvc code. Once the client entered the proper security code the payment went through.

 

 

WooCommerce and Gutenberg – Great stuff ahead!

WooCommerce and Gutenberg.. What will happen when Gutenberg Editor gets introduced to your WooCommerce site in WordPress 5.0? Will it be Armageddon and will all product fields below the description and title field break? Do you need to deactivate Gutenberg just to keep your ecommerce business up and running?

What is Gutenberg?

Gutenberg is the new WordPress Editor. We wrote about it before at the beginning of this year actually. It will allow you to create content for posts, pages and custom post types just like WooCommerce Products using blocks. Here is a screenshot of what you see looking for blocks:

Gutenberg Blocks

 

And here one with some text added:

Text Block

Think of it as some of the Page Builders out there like Visual Composer, Beaver Builder or Divi. What is more, it will also make these options available in the customizer and perhaps frontend in the future as well.

Custom Fields and Gutenberg

As all is still under development it tends to be foggy sometimes and a lot of developers and end users are freaking out about it as it might break the way meta boxes / custom fields are used now. WooCommerce relies heavily on custom fields to add product data. And these fields may not work properly, or be moved to the new sidebar and so on. When you currently run the Gutenberg plugin to check you see it in action on a product page the WooCommerce custom fields are below it.

WooCommerce Custom Fields

But it is going to be way more integrated. Either they will be show below the block in a different way, go to the sidebar or they are going to come up with another solution.

Product Blocks

I am all for it and the sneak preview WooCommerce has shown looks very promising. And WooCommerce is working on product blocks already in their repo using a separate branch (code to be merged once done).

I installed the product blocks branch on my local WooCommerce Gutenberg Laravel Valet site and I can already see we can add a product block with ease inside a post:

Product Search Inside Woo Block

I just cannot search for my existing dummy products yet.  There seems to be a 404 issue

https://woo-guteberg.dev/index.php?rest_route=/wc/v2/products/?search=v

Here the no products found message:

Product Block Search

So I can’t go and add a product yet, but I can see we are closer than I thought and that is nice to see.

It is work in progress and perhaps my setup needs some REST API changes..? But the WooCommerce REST API is turned on though..

WooCommerce REST API

 

Well, that is something to try another time. Just like add products in x numbers and columns as Woo demoed. That I seem to not be able to do with this test branch yet.

The Future of WooCommerce with Gutenberg

I must say I am really exciting. I always found most page builder lacking a lot. Especially in the WooCommerce field. I want to be able to change the product page layout around. I want to be able to decide where the

  • product gallery,
  • description
  • cart button,
  • price and
  • other tabs with data

 

will be added. And I am positive that we will. Do see great options for the category or shop page in progress already. Rows and columns can be decided and hopefully thumbnail sizes in the future too. As for product page changes, well I expect to be able to move the mentioned elements around and WooCommerce did mention these as possibilities as well.

I expect to see way more in the upcoming weeks and months! Can’t say I am too worried. Big changes yes, but changes for the better to keep WordPress ahead of the game and compete with the likes of Shopify and Magento. And for WordPress to show others like Wix, Squarespace, Weebly and so on who’s boss. Exciting times!

Your theme contains outdated copies of some WooCommerce template files

Often when you upgrade WooCommerce you get the error Your theme contains outdated copies of some WooCommerce template files. Ianua in this case. How to resolve this issue? Well. let’s work things out shall we?

Check System Status Page

The error message Your theme contains outdated copies of some WooCommerce template files will also indicate you should check the system status page where they will show you what pages are outdated. Here the full error message:

Your theme (Ianua) contains outdated copies of some WooCommerce template files. These files may need updating to ensure they are compatible with the current version of WooCommerce. You can see which files are affected from the system status page. If in doubt, check with the author of the theme.

NB They also refer to https://docs.woocommerce.com/document/template-structure/ to learn more about the WooCommerce template structure

Outdated Templates

At the bottom of the system status page they will show you what templates are outdated.

Outdated Templates

If you are the author of the theme it will be up to you to update the files in question. If you bought the theme from another developer you should ask them for an update and then overwrite the theme according to their instructions.

Updating Theme Caveats

Now remember, just because a template got an update it does not mean the theme won’t work anymore. Two, if you would update a theme you bought by yourself you may lose the layout that was set up using it so do this only if you know what you are doing. Better to contact the theme builder before you make any changes yourself!

When to Update

If we check ianua/archive-product.php for example we will see that we added the product archive page as we wanted a specific display:

A custom WP_Query was created to load the products. This so additional html could be added for all the page elements with ease. This page was on the list of pages needing an update according to WooCommerce. It stated

ianua/archive-product.php version - is out of date. The core version is 2.0.0,

This page won’t be updated at this moment though. That is because of the custom code for one. It also is not using any WooCommerce functionality that no longer works. If the latter would have been the case we would have had to update the outdated code.

So only update if the files that need updating do not have any custom code, which will be rare if the file in question is part of the theme. Two, if there is custom, only update the functionality that is outdated or even causing (fatal) errors.

Removing the Warning

If you do want the warning not to be mentioned anymore, add the correct block with the file version number. In this case the block would be:

/**
* The Template for displaying product archives, including the main shop page which is a post type archive
*
* This template can be overridden by copying it to yourtheme/woocommerce/archive-product.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* @see      https://docs.woocommerce.com/document/template-structure/
* @author      WooThemes
* @package     WooCommerce/Templates
* @version 2.0.0
*/

As you can see the version was 2.0.0 at the time of the writing of this blog post. Of course other files have other version numbers.

WooCommerce 2.7.0 Test Drive – Dealing with Deprecated Functions and Disallowed Direct Calls

Decided to test WooCommerce 2.7.0 beta 3 locally for my Ianua Theme. As a theme author it is always important to see if a whole new version works for you or not and if not to fix the issues. I realized a lot of code for single product page display was deprecated as functions got renamed and a lot of calls could not be made directly to the $product class anymore.

Deprecated get_gallery_attachment_ids

Ran into this PHP notice on single product pages. The function:

get_gallery_attachment_ids

is now outdated and should be replaced by:

get_gallery_image_ids

Steps to Reproduce this Error

This was the actual error message delivered by xdebug so very thorough:

 PHP Notice: WC_Product::get_gallery_attachment_ids is <strong>deprecated</strong> since version 2.7! Use WC_Product::get_gallery_image_ids instead. in /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/functions.php on line 3828
 [01-Mar-2017 06:55:56 UTC] PHP Stack trace:
 [01-Mar-2017 06:55:56 UTC] PHP 1. {main}() /srv/www/ianua.imagewize.com/current/web/index.php:0
 [01-Mar-2017 06:55:56 UTC] PHP 2. require() /srv/www/ianua.imagewize.com/current/web/index.php:5
 [01-Mar-2017 06:55:56 UTC] PHP 3. require_once() /srv/www/ianua.imagewize.com/current/web/wp/wp-blog-header.php:19
 [01-Mar-2017 06:55:56 UTC] PHP 4. include() /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/template-loader.php:74
 [01-Mar-2017 06:55:56 UTC] PHP 5. include() /srv/www/ianua.imagewize.com/current/web/app/themes/ianua/base.php:80
 [01-Mar-2017 06:55:56 UTC] PHP 6. wc_get_template_part() /srv/www/ianua.imagewize.com/current/web/app/themes/ianua/single-product.php:16
 [01-Mar-2017 06:55:56 UTC] PHP 7. load_template() /srv/www/ianua.imagewize.com/current/web/app/plugins/woocommerce/includes/wc-core-functions.php:173
 [01-Mar-2017 06:55:56 UTC] PHP 8. require() /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/template.php:686
 [01-Mar-2017 06:55:56 UTC] PHP 9. do_action() /srv/www/ianua.imagewize.com/current/web/app/themes/ianua/woocommerce/content-single-product.php:48
 [01-Mar-2017 06:55:56 UTC] PHP 10. WP_Hook->do_action() /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/plugin.php:453
 [01-Mar-2017 06:55:56 UTC] PHP 11. WP_Hook->apply_filters() /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/class-wp-hook.php:323
 [01-Mar-2017 06:55:56 UTC] PHP 12. woocommerce_show_product_images() /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/class-wp-hook.php:298
 [01-Mar-2017 06:55:56 UTC] PHP 13. wc_get_template() /srv/www/ianua.imagewize.com/current/web/app/plugins/woocommerce/includes/wc-template-functions.php:840
 [01-Mar-2017 06:55:56 UTC] PHP 14. include() /srv/www/ianua.imagewize.com/current/web/app/plugins/woocommerce/includes/wc-core-functions.php:203
 [01-Mar-2017 06:55:56 UTC] PHP 15. WC_Abstract_Legacy_Product->get_gallery_attachment_ids() /srv/www/ianua.imagewize.com/current/web/app/themes/ianua/woocommerce/single-product/product-image.php:25
 [01-Mar-2017 06:55:56 UTC] PHP 16. wc_deprecated_function() /srv/www/ianua.imagewize.com/current/web/app/plugins/woocommerce/includes/legacy/abstract-wc-legacy-product.php:159
 [01-Mar-2017 06:55:56 UTC] PHP 17. _deprecated_function() /srv/www/ianua.imagewize.com/current/web/app/plugins/woocommerce/includes/wc-deprecated-functions.php:48
 [01-Mar-2017 06:55:56 UTC] PHP 18. trigger_error() /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/functions.php:3828

System Status Report

System status report did mention I had several files that were outdated. Those were all the WooCommerce files I heavily edited to display the store as I needed with custom queries and custom html and JavaScript voodo.

### WordPress Environment ###

Home URL: https://ianua.dev
 Site URL: https://ianua.dev/wp
 WC Version: 2.7.0
 Log Directory Writable: ✔
 WP Version: 4.7.2
 WP Multisite: –
 WP Memory Limit: 256 MB
 WP Debug Mode: ✔
 WP Cron: –
 Language: en_US

### Server Environment ###

Server Info: nginx/1.11.5
 PHP Version: 7.1.0-3+deb.sury.org~xenial+1
 PHP Post Max Size: 50 MB
 PHP Time Limit: 120
 PHP Max Input Vars: 1000
 cURL Version: 7.47.0
 OpenSSL/1.0.2g

SUHOSIN Installed: –
 Max Upload Size: 50 MB
 Default Timezone is UTC: ✔
 fsockopen/cURL: ✔
 SoapClient: ❌ Your server does not have the SoapClient class enabled - some gateway plugins which use SOAP may not work as expected.
 DOMDocument: ✔
 GZip: ✔
 Multibyte String: ✔
 Remote Post: ✔
 Remote Get: ✔

### Database ###

WC Database Version: 2.7.0
 WC Database Prefix: wp_
 woocommerce_sessions: ✔
 woocommerce_api_keys: ✔
 woocommerce_attribute_taxonomies: ✔
 woocommerce_downloadable_product_permissions: ✔
 woocommerce_order_items: ✔
 woocommerce_order_itemmeta: ✔
 woocommerce_tax_rates: ✔
 woocommerce_tax_rate_locations: ✔
 woocommerce_shipping_zones: ✔
 woocommerce_shipping_zone_locations: ✔
 woocommerce_shipping_zone_methods: ✔
 woocommerce_payment_tokens: ✔
 woocommerce_payment_tokenmeta: ✔
 MaxMind GeoIP Database: ✔

### Security ###

Secure connection (HTTPS): ✔
 Hide errors from visitors: ❌Error messages should not be shown to visitors.

### Active Plugins (10) ###

Gravity Forms: by rocketgenius – 2.0.7
 Ianua Projects: by Imagewize – 1.2.1
 Regenerate Thumbnails: by Alex Mills (Viper007Bond) – 2.2.6
 WPML Multilingual CMS: by OnTheGoSystems – 3.6.2
 WooCommerce PayPal Express Checkout Gateway: by Automattic – 1.1.2
 WooCommerce: by Automattic – 2.7.0-beta-3
 WordPress Importer: by wordpressdotorg – 0.6.3
 WPML CMS Nav: by OnTheGoSystems – 1.4.19
 WPML String Translation: by OnTheGoSystems – 2.5.1
 WPML Translation Management: by OnTheGoSystems – 2.2.6

### Settings ###

API Enabled: ✔
 Force SSL: –
 Currency: EUR (€)
 Currency Position: left
 Thousand Separator: ,
 Decimal Separator: .
 Number of Decimals: 2
 Taxonomies: Product Types: external (external)
 grouped (grouped)
 simple (simple)
 variable (variable)
 ### WC Pages ###

Shop base: #235 - /shop/
 Cart: #236 - /cart/
 Checkout: #237 - /checkout/
 My account: #238 - /my-account/

### Theme ###

Name: Ianua
 Version: 1.0.0
 Author URL: https://ianua.com
 Child Theme: ❌ – If you're modifying WooCommerce on a parent theme you didn't build personally
 then we recommend using a child theme. See: How to create a child theme

WooCommerce Support: ✔

### Templates ###

Overrides: ianua/archive-product.php version - is out of date. The core version is 2.0.0
 ianua/woocommerce/content-single-product.php
 ianua/woocommerce/loop/loop-end.php
 ianua/woocommerce/loop/loop-start.php
 ianua/woocommerce/loop/orderby.php
 ianua/woocommerce/single-product/product-image.php version 2.6.3 is out of date. The core version is 2.7.0
 ianua/woocommerce/single-product/related.php version 1.6.4 is out of date. The core version is 2.7.0
 ianua/single-product.php version - is out of date. The core version is 1.6.4
 ianua/woocommerce/taxonomy-product_cat.php

Outdated Templates: ❌Learn how to update

So I knew there were things I had to check out or fix. Just did not realize there were quite a few issues I had to deal with.

Product Image Template

So I checked product-image.php as that is where I deal with product images as I should.

Path to file:

/site/web/app/themes/ianua/woocommerce/single-product/product-image.php

and on line 25 I had:

$attachment_ids = $product->get_gallery_attachment_ids();

and as stated get_gallery_attachment_ids is outdated or deprecated. So I replaced it by get_gallery_image_ids . And this worked and the image gallery came back again without the error notice.

get_display_price Deprecated

And then other issues showed up. The function:

get_display_price

is outdated as well. So we had to deal with this too. The exact PHP notice in brief was:

Notice: WC_Product::get_display_price is <strong>deprecated</strong> since version 2.7! Use wc_get_price_to_display instead. in /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/functions.php on line 3828

I found it inside:

/ianua.imagewize.com/site/web/app/themes/ianua/lib/extras.php

on line 1046:

 echo '<div class="six columns tab-whole product-content right"><span class="price">$' . $product->get_display_price() . '</span>';

I have it as part of an action I added as a replacement of

add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );

Just replacing it with wc_get_price_to_display() got me another error

Fatal error: Uncaught Error: Call to undefined method WC_Product_Simple::wc_get_price_to_display() in /srv/www/ianua.imagewize.com/current/web/app/themes/ianua/lib/extras.php on line 1046

So I added:

$product->get_price_html()

which worked. It was inspired by the new:

/plugins/woocommerce/templates/single-product/price.php

And this worked like a charm. Will do some more testing later on of course. But let’s move on to the other notices shall we?

product_type called directly

Then I had a product_type called directly notice. Another direct call notice stating this should not be done basically.

[01-Mar-2017 06:55:56 UTC] PHP Notice:  product_type was called <strong>incorrectly</strong>. Product properties should not be accessed directly. Please see <a href="https://codex.wordpress.org/Debugging_in_WordPress">Debugging in WordPress</a> for more information. (This message was added in version 2.7.) in /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/functions.php on line 4136

NB Woo Poly Integrations had similar issues mentioned in a ticket at their Github repo.

This was in the same extra.php file on line 1066:

 do_action( 'woocommerce_' . $product->product_type . '_add_to_cart' );

That is what happens when you use many filters. Might need to get rid of some of these soon. Anyways, I realized it now has to be

get_type()

based on /plugins/woocommerce/includes/class-wc-product-simple.php line 33. Again I may need to do some more testing.

Get_related is deprecated

Had a get_related is outdated notice:

[01-Mar-2017 08:18:11 UTC] PHP Notice:  WC_Product::get_related is <strong>deprecated</strong> since version 2.7! Use wc_get_related_products instead. in /srv/www/ianua.imagewize.com/current/web/wp/wp-includes/functions.php on line 3828

line 29 of the theme’s single-product/related.php I had

if ( ! $related = $product->get_related( $posts_per_page ) ) {

wc_get_related_products which again caused a fatal error as it could not find the method. This was I as I had it all wrong and just need to run the function and necessary arguments. So turned it into:

if ( ! $related = wc_get_related_products( $product->get_id(), $args['posts_per_page'] )) {
 return;
}

And now all product were displaying well.

Photoswipe

There also seems to be a new file for working with sliders in single products (beta one blog post mentions it here. It is Photoswipe. Somehow the code was injected at the bottom of the page in the footer. So I added my own in woocommerce/single-product/photoswipe.php . One with only the header code:

 

<?php
/**
 * Photoswipe markup
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/single-product/photoswipe.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see https://docs.woocommerce.com/document/template-structure/
 * @author WooThemes
 * @package WooCommerce/Templates
 * @version 2.7.0
 */

This as I use my own flex slider based one. That took care of that issue. I may use it for other projects though.

Backend Product Editing Issues

What I currently do have is working on the product details does not go well. It seems I cannot switch tabs to let’s say inventory or shipping. Will do some testing on this a little later on. Could be the fact that WooCommerce 2.7.0 is beta after all. But that seems to be an Advanced Custom Fields issue as I found this JavaScript error:

Uncaught Error: Option 'ajax' is not allowed for Select2 when attached to a <select> element.
 at String.<anonymous> (select2.js?ver=3.5.2:930)
 at Function.each (jquery.js?ver=1.12.4:2)
 at constructor.prepareOpts (select2.js?ver=3.5.2:928)
 at constructor.prepareOpts (select2.js?ver=3.5.2:2601)
 at constructor.init (select2.js?ver=3.5.2:690)
 at HTMLSelectElement.<anonymous> (select2.js?ver=3.5.2:3391)
 at Function.each (jquery.js?ver=1.12.4:2)
 at jQuery.fn.init.each (jquery.js?ver=1.12.4:2)
 at jQuery.fn.init.$.fn.select2 (select2.js?ver=3.5.2:3378)
 at HTMLSelectElement.<anonymous> (wc-enhanced-select.js?ver=2.7.0:115)

 

Custom Product Tabs for WooCommerce

Sometimes you need more tabs for your products. Sometimes the descriptions tab, reviews and attributes tab are not enough. You may need a tab with directions on how to use the product, a tab on ingredients of the product or a tab displaying all available sizes. So let’s talk about adding custom product tabs for WooCommerce. How can you add an additional tab to the product page?

WooCommerce Product Tabs Filter

To add a custom product tabs for WooCommerce you can follow WooCommerce’s guidelines and add the following to your functions.php file:

add_filter( 'woocommerce_product_tabs', 'woo_new_product_tab' );
function woo_new_product_tab( $tabs ) {
 
 // Adds the new tab
 
 $tabs['test_tab'] = array(
 'title' => __( 'New Product Tab', 'woocommerce' ),
 'priority' => 50,
 'callback' => 'woo_new_product_tab_content'
 );

return $tabs;

}
function woo_new_product_tab_content() {

// The new tab content

echo '<h2>New Product Tab</h2>';
 echo '<p>Here\'s your new product tab.</p>';
 
}

You will of course have to adjust the code to your liking. So you should at least:

  • $tabs label
  • title – pick you own title
  • priority – set the priority of the tab – perhaps it should come first?
  • callback – add the name of the function loading the tab data

So something like:

$tabs['ingredients'] = array(
 'title' => __( 'Ingredients' ),
 'priority' => 10,
 'callback' => 'ianua_product_ingredients_tab'
);

should do the trick just fine.

Tab Contents Callback Function

Inside the code above we also added the function being the one loading the content in the tab:

function woo_new_product_tab_content() {

// The new tab content

echo '<h2>New Product Tab</h2>';
 echo '<p>Here\'s your new product tab.</p>';
 
}

So the filter is followed by the function loading the content. Later on we shall see we did not do the same and used a template tag woocommerce_get_template to load the code from another file.

Content to Load

What would you like to load in the tab and how would you like to display it? For that you need to create a function and add it to your functions.php file or include it somehow. You could load custom field data using a custom field added to product pages. And that is what we are going to do and that is also what most developers would do.

Creating Custom Fields

To create the custom field you could use Advanced Custom Fields (free or premium) or GenerateWP (Premium version for meta boxes) for example. Or you use the built in option and generate them on the product page. Does not look really pretty though. You can code them yourself too of course. For just one or two custom fields ACF would be overkill really but you could use it locally to generate the fields and then export them as PHP to add to your theme. AND you would need to include ACF in your theme.

Advanced Custom Fields Custom Field

To create a meta box or custom field in ACF you just to to advanced custom fields in the backend. Code I created in like a minute would be:

if( function_exists('acf_add_local_field_group') ):

acf_add_local_field_group(array (
 'key' => 'group_5881d7c5ba966',
 'title' => 'Product Page Meta Boxes',
 'fields' => array (
 array (
 'key' => 'field_5881d81b4ad68',
 'label' => 'Ingredients',
 'name' => 'ingredients',
 'type' => 'textarea',
 'instructions' => 'Fill in the ingredients for the product here',
 'required' => 0,
 'conditional_logic' => 0,
 'wrapper' => array (
 'width' => '',
 'class' => '',
 'id' => '',
 ),
 'default_value' => 'Text to be added here',
 'placeholder' => '',
 'maxlength' => '',
 'rows' => '6',
 'new_lines' => 'wpautop',
 ),
 ),
 'location' => array (
 array (
 array (
 'param' => 'post_type',
 'operator' => '==',
 'value' => 'product',
 ),
 ),
 ),
 'menu_order' => 0,
 'position' => 'normal',
 'style' => 'default',
 'label_placement' => 'top',
 'instruction_placement' => 'label',
 'hide_on_screen' => '',
 'active' => 1,
 'description' => '',
));

endif;

As stated this will not work without advanced custom fields included in your theme. So if you feel like this is overkill it would be better to add your own code.

Clean Generated Meta Box code

Coding yourself takes some time like I said and there is a site where you can generate a custom field for free. One that uses native code. It has been created by Jeremy Hixon and can be found here. I created one for WooCommerce products with a text area and the code looks like this:

 

/**
 * Generated by the WordPress Meta Box generator
 * at http://jeremyhixon.com/tool/wordpress-meta-box-generator/
 */

function ingredients_get_meta( $value ) {
 global $post;

$field = get_post_meta( $post->ID, $value, true );
 if ( ! empty( $field ) ) {
 return is_array( $field ) ? stripslashes_deep( $field ) : stripslashes( wp_kses_decode_entities( $field ) );
 } else {
 return false;
 }
}

function ingredients_add_meta_box() {
 add_meta_box(
 'ingredients-ingredients',
 __( 'Ingredients', 'ingredients' ),
 'ingredients_html',
 'post',
 'normal',
 'default'
 );
 add_meta_box(
 'ingredients-ingredients',
 __( 'Ingredients', 'ingredients' ),
 'ingredients_html',
 'product',
 'normal',
 'default'
 );
}
add_action( 'add_meta_boxes', 'ingredients_add_meta_box' );

function ingredients_html( $post) {
 wp_nonce_field( '_ingredients_nonce', 'ingredients_nonce' ); ?>

<p>Product Ingredients</p>

<p>
 <label for="ingredients_product_ingredients_text"><?php _e( 'Product Ingredients Text', 'ingredients' ); ?></label><br>
 <textarea name="ingredients_product_ingredients_text" id="ingredients_product_ingredients_text" ><?php echo ingredients_get_meta( 'ingredients_product_ingredients_text' ); ?></textarea>
 
 </p><?php
}

function ingredients_save( $post_id ) {
 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
 if ( ! isset( $_POST['ingredients_nonce'] ) || ! wp_verify_nonce( $_POST['ingredients_nonce'], '_ingredients_nonce' ) ) return;
 if ( ! current_user_can( 'edit_post', $post_id ) ) return;

if ( isset( $_POST['ingredients_product_ingredients_text'] ) )
 update_post_meta( $post_id, 'ingredients_product_ingredients_text', esc_attr( $_POST['ingredients_product_ingredients_text'] ) );
}
add_action( 'save_post', 'ingredients_save' );

/*
 Usage: ingredients_get_meta( 'ingredients_product_ingredients_text' )
*/

It does miss a couple of elements though like how many rows you would like to have and the text domain. And the meta key here is not as we have it inside the filter so that needs adjusting too. The new generator does have the text domain, but the amount of rows is not an automated option yet. Five rows are added by default. But that you could adjust that in the code yourself.

Basic Custom Field

Besides ACF or hand made meta boxes you could just use the built in version as long as aesthetics is not paramount. When you just want to add one in your product you need to make sure custom fields are active in screen options:

Custom Fields Active

and then you will see this block underneath your product text to add a new custom field:

Add a new Custom Field

Make sure the key (= name)  and value are the ones you use in your function to call them inside your theme. And that you of course save the custom field. Once that is done you can load it for all products.

Custom Callback Code

Here is the code to grab the custom field data:

global $woocommerce, $post;
if ( !empty($post->post_content) ) : ?>
 <?php $heading = apply_filters('woocommerce_product_description_heading', __('Product Description', 'woocommerce')); ?>
<h5><?php echo $heading; ?></h5>
<?php echo get_post_meta($post->ID, 'Ingredients', true); ?>
<?php endif; ?>

As you can see we use get_post_meta . That is the best way to grab a meta key or value. We added this code inside a separate ingredients.php file which we added under single-product/tabs and we load it with:

function ianua_product_ingredients_tab() {
 woocommerce_get_template( 'woocommerce/single-product/tabs/ingredients.php' );
}

but you could also add the code inside the filter itself as is shown above in the basic filter.

Styling

If your theme is styled for tabs properly already this should work and look well.  But if not you can always add specific classes andor wrap the code in a div to target that tab or all tabs more specifically. In my case so far it worked fine in several themes out of the box.

Final Custom Product Tab

So if all went well you were able to create a custom product tab for WooCommerce that is loaded under all products, either as a basic custom field, an ACF custom field or a custom generated custom field. And you added the necessary filter and function to load the tab as the next tab in line.

 

Extending WooCommerce Storefront

When you are installing the Storefront theme as discussed in our earlier post WooCommerce Storefront Theme Configuration you are given a teaser with options to extend WooCommerce Storefront. A couple of enhancements using plugins as well as possible child themes are mentioned. Let’s go through them in this post.

Storefront Enhancing Plugins

Storefront recommend a couple of plugins you can use to extend it, to make it easier to work with this theme as well enhance it with more features. Here is the list of the plugins for extending WooCommerce Storefront:

  • Powerpack ($59)
  • Mega Menus ($39)
  • Reviews ($19)
  • Pricing Tables ($19)
  • Product Hero ($19)
  • Blog Customizer ($19)
  • Parallax Hero ($19)

NB  Addons only works with Storefront

As you can see these are all commercial plugins that you need to pay for. They are not for free as WordPress is. Well, I would say WordPress is not really for free either as it will require your time and $ to make it work for your business too, but that is another debate. Do I think some of these plugins are useful?

Powerpack

Well the Powerpack is not cheap, but it is an interesting extension. It is an addon that basically allows you to customize way more elements of your theme in the customizer without the need for extra coding in a child theme or plugins. What does it allow you to do more besides what you can in Storefront is:

  • header customization including logo, cart and navigation
  • styling – adjust font families, font size color, margins and padding
  • checkout options – option to go for distraction free checkout or keep two step checkout
  • homepage editor – basic homepage editor to add calls to action and configure general layout
  • product page editor – edit product page layout

Powerpack Features

Mega Menus

Must say I find it a bit expensive for a menu enhancement, but it is a solid mega menu that offers multiple options to create a solid mega menu dropdown to show store items with or without images. And it allows you to drag and drop multiple types of widgets inside the menu from the customizer. And Magento has extensions for similar or more expensive prices.

Example:

Storefront Mega Menu

Reviews

A lot of themes have basic reviews built in when they are catering to the e-commerce crowd and there are universal WordPress review plugins out there so you do not really need this one per se. But this is a solid review plugin with multiple display options. You can

  • display it as a slider or in blocks,
  • use three styling options and there is a
  • review scope you can configure to display certain specific reviews, reviews from certain products, load the most ones recent first

Pricing Table

A lot of themes do have pricing tables built in. Either via a page builder like Visual Composer or simply as a custom post type. So what does this addon have to offer that we may like? Well, nothing much really besides the fact that the customizing can be done in the customizer. So I am not that impressed really.

Pricing Tables

Product Hero

This is more like a slider that integrates well with Storefront and WooCommerce. But frankly as I am using Revolution Slider already that can do that and more I do not see the advantage of using this Product Hero slider.

Product Hero

Blog Customizer

The blog customizer is a useful addon. What it does it that it allows you to pick a certain blog layout. You may like the classical one after another blog article look or the magazine look with several next to each other. It also allows you to move the post meta data around. This means you can decide where the sidebar with additional information goes, if the category and tag details should go to the end of the post or just below the title and so on.

However, most multi purpose themes with or without a builder or even with the builder alone will allow you to do this all. So if you are going for a page builder like Beaver Builder or the Visual Composer you can probably go without this addon.

Parallax Hero

Parallax scroll or the display of content parallax style has been popular since 2012 or s0. Designer Depot mentioned this on it in 2013 in a blog post:

parallax scroll is when content scrolls at different speeds, creating a sense of perspective and therefore depth.

Some clients really love it for blogs, others for the homepage. Well, the parallax hero can enhance your Storefront Hero header with the parallax hero scroll effect. I do (no longer ) like this effect and I think it is a bit outdated now. But it is an easy implementation of it. So if you, or your client, likes it go ahead and purchase this addon.

Child Themes

There are a whole bunch of child themes available and all for just $39 bucks. So if the style of Storefront is not appealing to you and you do not want to code your own child theme to change its looks you should have a look at the child themes available.

Storefront Child Themes

Now, I think the WooCommerce team, nowadays a part of Automattic, does a solid job coding these themes and design wise there are some really nice ones. So do have a look. The advantage here is that these all work with Storefront and saves you the extra coding. It may still be needed that you want further tweaks. In that case it is better to convert a child theme into a new version. The only downside as always is that updates for that child theme can then no longer be applied with ease. But hey if the child theme gets you closer to your goal then go for it!

Child Themes in Detail

I won’t be discussing the child themes in detail now. What I will do is that I will create a new post in the future on adding one of these child themes and my and or my client’s experience with that particular theme. This post took quite some time already and is rather large and insightful already so hope you are happy with the content for this blog post as it is for now.

WooCommerce Related products, Up-Sells and Cross-Sells Explained

When you work with WooCommerce products there are several ways to stimulate customers to buy other products. Often we talk about related or recommended products when we talk about products we want customers to buy on top of the one they are considering buying or put into their cart. In WooCommerce speak we talk about related products, up-sells and cross-sells. Let’s go through WooCommerce Related products, Up-Sells and Cross-Sells one by one here, shall we?

Related Products

Related products are products that are loaded below an individual product when they have something in common. They are related in some way. This commonality can be based on two things:

  • tags the product is tagged with
  • categories the product is under

So, to make related products work, or at least work on product pages you have to do the following. You should give your product tags so they can share those among each other and connect or relate that way. The other option is to put the products into categories. That way they can be connected by category. If you do not do either one of these related products won’t work well.

Up-Sells

Upselling means suggesting more expensive or better quality products for example. These products can be added manually to each product in the backend. You do this under product data (simple product) > linked products field:

Linked Products

When you click on the field it will ask you to add three characters so it can try to guess the product you want to connect it to:

Up-sells Search

Cross-Sells

Cross selling – suggesting product on the cart page before customers goes to the checkout – is something else. It does work in the same way as up-sells in the backend. You add cross-sells the same way. Where it differs is that cross-sells are offered in the cart view:

WooCommerce Cross-Sells

So if you would like to make customers buy other products before they go to the checkout cross-sells are the way to go.

 

Summary

Well, I think we covered WooCommerce Related products, Up-Sells and Cross-Sells pretty well here. Do make sure you use these options. They will helop you increase your sales. Displaying related products, doing cross-sells or up-sells  simply work really well. In increases your bottom line big time. That is why big stores use these techniques.

What is not covered here is trying to sell products on the checkout page nor suggested sales based on history or email campaigns suggesting products based on past sales. For that I will create another blog post or two one of these days.

 

WooCommerce – DIY One Page Checkout

To improve conversion on your WooCommerce website a one page checkout page is very useful. When you allow customers to skip the cart page and go directly to checkout this will make it easier for them to buy an item. This reduces the rate of potential customers dropping out during the buying process. A whopping one in ten people drop out because the checkout process is too long – Webcredible Poll. And that makes sense in this age of everything on demand, smartphones and Google doesn’t it. We do not like waiting. So let’s deal with this shall we? Let’s build a DIY One Page Checkout!

DIY One Page Checkout Prerequisites

There are paid plugins that help you with direct checkout, product button options and all on one checkout pages. There is for example WooCommerce Direct Checkout Pro. But this direct checkout plugin does not do all that is needed. You after all still need a checkout page that loads cart details, but not all cart view details.

There are also a couple of One Page Checkout plugins like WooCommerce One Page Checkout and One Page Shopping , but again they do not really offer what we need. The former offers custom one page checkouts while we want this to be for all products. The latter has a demo that currently is not working and support that is lacking.

There may be others that I have missed of course, but let’s go the DIY way and set all up ourselves shall we? Let’s build a DIY One Page Checkout setup.

To set up the whole one page checkout there are several things we have to take care of. To achieve better lead conversion and get your customers to buy using direct checkout you need the following:

  • Redirect to Checkout on clicking “add to cart”
  • Title change of “add to cart” to buy now or “process to checkout”
  • Add Cart or view cart details on checkout page
  • Checkout Cart Notice – Should not be loaded as it will be irrelevant

Direct Checkout

To get the add to cart button, not just add your product to the customer’s shopping cart, but send him directly to the cart you can add the following code to your theme’s functions.php

add_filter('add_to_cart_redirect', 'theme_prefix_add_to_cart_redirect');
function theme_prefix_add_to_cart_redirect() {
 global $woocommerce;
 $checkout_url = $woocommerce->cart->get_checkout_url();
 return $checkout_url;
}

This code will make the “add to cart” button redirect to the checkout page. This way the view cart is bypassed.

Product “Add to Cart” Button Change

To change the button text from “add to cart” to “proceed to checkout” or “buy not” there are two action hooks you can use. One to replace the text on the product archive page or shop page and one action to replace the text on the single product page.

To change the “add to cart” text on the single product page add the following filter:

add_filter( 'woocommerce_product_single_add_to_cart_text', 'woo_custom_cart_button_text' ); // 2.1 +
function woo_custom_cart_button_text() {
 return __( 'Proceed to Checkout', 'woocommerce' );
}

To change the “add to cart” text on the shop page add the following filter:

add_filter( 'woocommerce_product_add_to_cart_text', 'woo_archive_custom_cart_button_text' ); // 2.1 +
function woo_archive_custom_cart_button_text() {
 return __( 'Proceed to Checkout', 'woocommerce' );
}

Cart Content Display on Checkout

To load the cart view or cart contents at the top of the checkout page before the billing forms you can just add the shortcode for the cart before the checkout shortcode on the checkout page.

[woocommerce _ cart]
[woocommerce _ checkout]

NB Spacing added to avoid real display

This will then show the full cart on the checkout page. A lot easier than dealing with this using custom code. There may be a good action or filter for it, but I have not found one as of yet.

Abridged Cart View on Checkout

The issue with the cart loading as we are doing with the shortcode  is that the coupon code option will then be shown twice. To hide this in the cart display table use this CSS:

.woocommerce-checkout div.coupon {display:none;}


.woocommerce-checkout td > input.button {display:none;}

I may add an action or filter for this too at a later stage. But this CSS option does the trick and does not force you to add a checkout template to your-theme/woocommerce folder and tweak it. I prefer to avoid WooCommerce templates in child themes as you then depend on updates in WooCommerce AND the parent theme.

Hiding Cart Notice

It does not make sense to show the cart notice on the checkout page. The cart overview will be there already so no need to have this notice with a link to the cart. Especially if you have a cart icon with these options in the main navigation already. Use this CSS to hide this notice completely:

.woocommerce-checkout .woocommerce-message {display: none !important;}

Summary

And there you have it. A DIY One Page Checkout all done with all the tweaks needed:

  • direct to checkout from product or shop page
  • proceed to checkout or buy now button text
  • checkout cart notice removed
  • checkout page with cart overview

As mentioned here and there, some solutions could perhaps be replaced with better ones. Certainly the CSS tweaks would be better done as actions or filters. However until I find better and easier options these will work wonderfully well for you and me!

 

Disclaimer: All tested with Total Theme Child Theme

Keeping Local WooCommerce Site in Synch with Live Site

Been working locally on a WooCommerce site. Changed permalinks, changed the theme, using local theme supported FAQ instead of plugin based FAQ on live. Also dropped a Text based widget in favor of a menu widget and changed the slider. And some other stuff. So I changed a lot. In the meanwhile there have been orders as well as AWeber newsletter subscriptions. So how do I deal with keeping the local WooCommerce site in synch with live site?

Options to Keep Local and Production in Synch

Mind you, synchronization of files is not the issue here. That can be done with version control such as Git. Or in my case not an issue really as the client won’t update content or products so no new files will be added. The database synchronization is the issue.

Well there are three things you can do to keep your WooCommerce Stores in synch. You can export the products, variations,orders, refunds, coupons and webhooks  using the WordPress export tool and import them. Two, you can use the Customer/Order/Coupon CSV Import Suite . This way they do keep in synch. The other way is just to leave database synching alone and update the live site with file changes and update the database by activating and changing content live. Here the three options in detail with pros and cons.

WordPress Importer

This can be done using the slightly buggy WordPress Importer Tool. I have used it before for importing and exporting basic content from one site to another. I have also used table export and import. And it does offer the option to export:

  • Products
  • Variations
  • Orders
  • Refunds
  • Coupons
  • Webhooks – see docs

There will be issues though as it is kind of buggy – new tools in the works for ages – and not a WooCommerce only tool. So definitely not my first choice.

Customer/Order/Coupon CSV Import Suite

Then you think well, let’s use the WooCommerce Addon – the Customer/Order/Coupon CSV Import Suite – mentioned earlier. That should do the job. Well, not quite apparently according to Mike Jolly. Mike Jolley, a WooCommerce Developer stated in this WordPress support thread that:

I think it’s safer to move code than move data, imo anyway. Especially if it’s constantly changing.

That makes sense and shops of course do change constantly. But sometimes, and I my case, it would be nice to do so. It would be great to move all files and the database once all is done and in the meanwhile keep things in synch.

There is another bigger issue he mentions though with exporting and importing WooCommerce data. And that is worse:

The orders you import may have different IDs due to auto-incrementing IDs in the database. The problem is IDs may differ from your emails + records.

So you could later on have issues with order IDs not matching emails and records. And that would be a big problem. However, Mike Jolley talked about this 8 months ago. Seems like the latest Customer/Order/Coupon CSV Import Suite can do more now .

woocommerce customer coupon order import suite

Since June 2016 it can merge customer, order and coupon data that is. Isn’t that cool!  Still, you could of course have to cough up $79, but that certainly can be worth it in many situations including mine. The main issue I was having is a difference in orders. And this addon should help me with that.

Updating Live with Local Site Data

The final option is just to not keep the database locally and on production in synch. You could test all needed changes locally and do them on live when all is done. That does mean more downtime or maintenance time. This as you would have to move all changed files, added theme, and plugins to live first. Activate them there. Then configure them and adjust content when need be. So this option really depends on how confident you are you can do all this in the maximum downtime allotted by you and your client.

What to Choose?

Well, in my case I will probably go for leaving database synchronization alone for now. I have not tested that addon and I prefer not to spend extra $ on this project now. I may use it in the future though. And if you read this post and are a developer with experience using that addon do leave me a comment. And if you are an end user, well perhaps the addon is the right choice for you. It does sound like an awesome tool and Skyverge is a solid company.

PS I do hope Delicious Brains will have Mergebot up and running soon so I do no longer have to deal with these database synch issues – post on it here.

Footnote Image of the White Rabbit in Alice in Wonderland by John Tenniel is in the in public domain

WooCommerce Featured Products Page

Sometimes you would like to have a homepage with WooCommerce featuring products or a separate page to show of your current trending products. In that case you need to create a template that loads certain WooCommerce products. That and some code voodoo.

For the HumbleShop theme we have implemented this for a customer before. Let me show you what code is needed and what it does. If you prefer the full template see the final chapter of this post. Just remember that we load no. of featured items from the theme options page here.

Featured Products Custom Query

To load the featured products you need a custom query with arguments to load them. For that we use the WP_Query class. The custom arguments we added to it are:

  • post type
  • no of featured products per page
  • pagination
  • meta query loading the proper meta key and value
<?php
 $num = ot_get_option( 'hs_homefeatno' );
 $paged = ( get_query_var('page') ) ? get_query_var('page') : 1;
 $args = array( 'post_type' => 'product', 'posts_per_page' => $num, 'paged' => $paged );
 $args['meta_query'] = array(); 
 $args['meta_query'][] = array(
 'key' => '_featured',
 'value' => 'yes'
 );
 $loop = new WP_Query( $args );
 while ( $loop->have_posts() ) : $loop->the_post(); global $product; ?>
 <?php wc_get_template_part( 'content', 'product' ); ?>
 <?php endwhile; ?>
 </div>

With the arguments discussed further below you can start a new instance of WP_Query to load the the featured products. As you can see we added $product as a global variable. This to make the variable available outside the local scope. Reason for using WP Query is to customize the loop ( awesome Treehouse blog post on WordPress Loops) .

Post Type

WooCommerce creates the post type product so we add that as our custom post type to be loaded. It is a custom post type to be precise. WordPress has five post types or content types and they are:

  • page,
  • posts
  • attachments and
  • revisions
  • navigation menu items

WordPress allows you to add your own and WooCommerce takes care of that for us creation products.

Featured Items Theme Option

To add the no. of featured items to display we added an extra item to the theme options. You could hard code it as well, but this is much more convenient. HumbleShop uses the theme options Options Tree by Valet Designs. Their repository is here in case you want to learn more about it.

Here below the option we added:

 array(
 'id' => 'hs_homefeatno',
 'label' => 'Number of Featured Products',
 'desc' => 'Number of featured products you want to display on homepage',
 'std' => '9',
 'type' => 'text',
 'section' => 'general',
 'rows' => '',
 'post_type' => '',
 'taxonomy' => '',
 'min_max_step'=> '',
 'class' => '',
 'condition' => '',
 'operator' => 'and'
 ),

We load the number added with the code:

ot_get_option( 'hs_homefeatno' )

ot_get_option being an Options Tree option

Pagination

The $paged variable activates pagination for the featured product page. It uses the get_query_var function. The same snippet and more details can be found in this codex article. Basically it loads pagination for the current page. Without it the pagination navigation won’t work. You can add pagination links with the code below:

<nav id="home-products-nav">
 <?php previous_posts_link( '&laquo; PREV', $loop->max_num_pages) ?></li>
 <?php next_posts_link( 'MORE PRODUCTS &raquo;', $loop->max_num_pages) ?>
 </nav>

It works thanks to the earlier added pagination in the custom query.

Meta Query

Meta_Query is part of the WP_Meta_Query class. It is an argument of that class and an array at that. It can contain the meta key (custom field key) and value (custom field value). And this is needed here as we need to check whether a product is featured and if so add it to the loop.

WooCommerce Product Content

Once the loop has been started up we load the products with this WooCommerce request:

wc_get_template_part( 'content', 'product' );

WooCommerce Get Template Code is documented here and the function in detail can be checked here. It looks for the WooCommerce template in your theme root or woocommerce folder inside your theme and then grabs that content. We have woocommerce/content-product.php in the child theme that can be loaded.

NB woocommerce_get_template_part is deprecated and

wc_get_template_part

is the new WooCommerce template tag and recommended now. It has been deprecated since WooCommerce 2.1

After all that code has been added the while loop will be closed. All should be well and then content should be loaded. Pagination loading follows below it, but we covered that discussing the pagination argument for the WP_Query earlier.

Full Template Code

Here below is the full template code we use for displaying the featured posts on the homepage for our HumbleShop child theme. As you can see we load a slider as well. This and some other snippets and html tags we need to display all well. This piece of code and others you can leave out of course.

Just like any other page template you can this one to your theme’s root.

<?php
 /*
 Template Name: Homepage
 */
 get_header(); ?>

<!-- ============ -->
 <!-- MAIN SECTION -->
 <!-- ============ -->
 <div class="container">
 <section class="feat">

<?php get_template_part( 'slider', 'index' ); ?>

<div class="row">

<!-- Content -->
 <div class="col-xs-12">
 <?php while ( have_posts() ) : the_post(); ?>

<div class="row">

</div>

<div class="row">
 <div class="col-xs-12">
 <?php do_action('woocommerce_before_shop_loop'); ?>
 </div>

<div class="products clearfix">
 <?php
 $num = ot_get_option( 'hs_homefeatno' );
 $paged = ( get_query_var('page') ) ? get_query_var('page') : 1;
 $args = array( 'post_type' => 'product', 'posts_per_page' => $num, 'paged' => $paged );
 $args['meta_query'] = array();
 $args['meta_query'][] = array(
 'key' => '_featured',
 'value' => 'yes'
 );

$loop = new WP_Query( $args );
 while ( $loop->have_posts() ) : $loop->the_post(); global $product; ?>

<?php wc_get_template_part( 'content', 'product' ); ?>

<?php endwhile; ?>
 </div>
 <nav id="home-products-nav">
 <?php previous_posts_link( '&laquo; PREV', $loop->max_num_pages) ?></li>
 <?php next_posts_link( 'MORE PRODUCTS &raquo;', $loop->max_num_pages) ?>
 </nav>
 </div><!--/.products-->

<?php wp_link_pages( array( 'before' => '<div class="page-links">' . __( 'Pages:', 'humbleshop' ), 'after' => '</div>' ) ); ?>
 <?php edit_post_link( __( 'Edit', 'humbleshop' ), ' <p class="text-center"><i class="fa fa-pencil"></i>', '</p>' ); ?>
 <?php endwhile; // end of the loop. ?>
 </div>

</div>
 <?php
 $brand = ot_get_option( 'hs_brand' );
 $brandlist = ot_get_option( 'hs_brandlist' );

if ($brandlist) { ?>
 <h5 class="subhead theme brands"><strong><?php echo $brand; ?></strong></h5>

<div class="tab-brand">
 <div id="flexcarousel-brands" class="flexslider">
 <ul class="slides">

<?php foreach($brandlist as $key => $value) {
 echo '<li>';
 if ($value['hs_brandimage']) {
 echo '<img src="'.$value['hs_brandimage'].'" alt="'.$value['title'].'" />';
 } else {
 echo '<img src="http://cambelt.co/200x100" />';
 }
 echo '</li>';
 } ?>

</ul>
 </div>
 </div>
 <?php } ?>

</section>
 </div>

<?php get_footer(); ?>