All Posts by Eric Busch

Alternatives to Amazon Associates Program

You may or may not have heard that on April 21, 2020 Amazon will drastically reduce its commissions in several of their product categories in the US market.

  1. Furniture, Home, Home Improvement, Lawn & Garden, Pets Products, Pantry 8.00% 3.00%
  2. Headphones, Beauty, Musical Instruments, Business & Industrial Supplies 6.00% 3.00%
  3. Outdoors, Tools 5.50% 3.00%
  4. Grocery 5.00% 1.00%
  5. Sports 4.50% 3.00%
  6. Baby Products 4.50% 3.00%
  7. Health & Personal Care 4.50% 1.00%
  8. Amazon Fresh 3.00% 1.00%

Below you see a table of the current fee rates and a table with the upcoming changes.

As you can see commission rates for popular categories such as home improvement, furniture, lawn and garden, and pet products will see a commission rate of 8 percent per sale drop down to just 3 percent! For headphones, beauty products, and musical instruments, commission rates will go from 6 percent down to 3 percent. Some other categories even drop down to a measly 1 percent. You can always check out Amazon’s latest fees here.

If you are currently promoting products from the affected categories you will notice a decline in your commissions. If Amazon is your most important source of internet income, now is the time to evaluate and diversify your income stream for your website or blog. Don’t make Amazon the ONLY way that you earn from your site. Find and test other affiliate programs in your niche. Experiment with display advertising on your affiliate pages.

Alternatives to the Amazon USA Associates Program

Amazon’s announcement seems to only apply to their USA program. As far as we know, these changes do not affect other locales and each locale has its own commission structure. If you are promoting products in the US market and your niche is affected by these new commission structures, the following affiliate networks might be worth looking into as alternatives:

Datafeedr does support all these affiliate networks (and many others). You can browse a full list of all of the 17,000+ merchants we support.

Many large retailers often run their own in-house affiliate program, too. These are programs where you create a direct relationship with the merchant/retailer instead of going through an affiliate network.

If you think a specific retailer would be a good alternative to the Amazon Associates Program, just Google the retailer’s name along with the phrase “Affiliate Program”.

While it might take some time to replace your Amazon affiliate links with other competing offers, it could pay off… especially if you are in some of those product categories taking the biggest hit.

What do you think of Amazon’s new changes? Let us know in the comments below.

Building a WooCommerce Store Using Affiliate Feeds

A couple of weeks ago I spoke with BobWP on his WP eCommerce Show. You can find that talk here

Here are a few of the topics we discussed:

  1. What is Datafeedr and how did it come to be?
  2. Is it viable to start up an online store with just affiliate products?
  3. For new site owners, how do you get accepted by these affiliate networks with nothing selling on your site?
  4. Are there ever instances where store owners will mix affiliate products in with their own products?
  5. Is there such as thing as having too many affiliate products in your store?

Add filter to WooCommerce category metabox on Product Set “edit” page

If you have a lot of categories (like I have on you may find that scrolling and finding the category you are looking for is time-consuming. Here’s what the default WooCommerce category metabox looks like on a Product Set “edit” page:

You can use the Post Category Filter plugin to add a filter to your WooCommerce category box to make it easy to filter your long list of WooCommerce categories to something more manageable.

Here’s what the end result looks like:

Simple as that!

GDPR, WordPress & You – A Webinar

This morning SiteGround did a 1-hour webinar about GDPR. In the webinar their senior legal advisor Maya Stoyanova talked about the procedures you need to follow in order to run a GDPR-compliant business and the changes you may need to undertake to comply with the new regulations.

If you are running a WordPress website (which you probably are), there were many relevant questions regarding GDPR and WordPress and what steps you need to take to get compliant.

The webinar was NOT SiteGround-specific so even if you are not hosted with SiteGround, it doesn’t matter. It’s all very relevant.

Check it out:

I would also keep an eye on SiteGround’s Blog for a summary and transcripts of the webinar in the next few days.

Here is the related blog post.

3 Custom WooCommerce Buy Buttons

There are lots of fun things you can do to WooCommerce [Buy Now] and [Add to Cart] buttons.

Here I’ll show you a few ways you can customize WooCommerce buttons which appear in The Loop (Shop Frontpage, Shop Category pages, etc…). You can add the code snippets below to a Custom Plugin.

First, let’s see how buttons look like be default. Here is a screenshot of 3 products on a category page. All 3 of these products are External (or Affiliate) products so they display a greyed out [Buy Now] button.

Default Button Display in WooCommerce Loop

Add Highlighting to Buttons for Products On Sale

This one will format the WooCommerce buttons by highlighting the buttons for products which are on sale.

Here’s what that would look like:

The custom code for that looks like this:

<?php /** * Add highlighting to an add to cart button for WooCommerce products which are on sale. * * @param string $html * @param WC_Product $product * @param array $args * * @return string */ function mycode_display_highlighted_add_to_cart_button_for_products_on_sale( $html, $product, $args ) { if ( ! $product->is_on_sale() ) { return $html; } $extra_class = ' alt'; $extra_text = ' SALE'; $url = $product->add_to_cart_url(); $quantity = isset( $args['quantity'] ) ? $args['quantity'] : 1; $class = isset( $args['class'] ) ? $args['class'] . $extra_class : 'button' . $extra_class; $attributes = isset( $args['attributes'] ) ? wc_implode_html_attributes( $args['attributes'] ) : ''; $text = $product->add_to_cart_text() . $extra_text; $format = '<a href="%1$s" data-quantity="%2$s" class="%3$s" %4$s>%5$s</a>'; return sprintf( $format, esc_url( $url ), esc_attr( $quantity ), esc_attr( $class ), $attributes, esc_html( $text ) ); } add_filter( 'woocommerce_loop_add_to_cart_link', 'mycode_display_highlighted_add_to_cart_button_for_products_on_sale', 20, 3 );

Remove Buy/Add Buttons

In some cases you may want to remove the buttons altogether. This might be useful for the next few code snippets.

Here’s how to remove the Buy/Add buttons from your WooCommerce Loops.

<?php /** * Remove the action which adds [Add to Cart] & [Buy Now] buttons * to the WooCommerce Product Loop */ function mycode_remove_add_to_cart_from_loop() { remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart' ); } add_action( 'init', 'mycode_remove_add_to_cart_from_loop' );

Add [More Details] Button Linking to Single Product Page

Now that the Buy/Add button is gone, we can add some other buttons to The Loop.

Here we will add a [More Details] button which links to the single product page.

While it’s not that exciting, we will build on this in the following examples. But if you like this, here’s the code:

<?php /** * Adds an action to the loop to display a [More Details] button * to the WooCommerce Product Loop which links to the Single Product Page. */ function mycode_add_more_details_button_to_single() { add_action( 'woocommerce_after_shop_loop_item', 'mycode_display_more_details_button_to_single' ); } add_action( 'init', 'mycode_add_more_details_button_to_single' ); /** * Display [More Details] button HTML with a link to the Single Product Page. * * @global WC_Product $product */ function mycode_display_more_details_button_to_single() { global $product; $url = $product->get_permalink(); $text = __( 'More Details', 'mycode' ); $title = sprintf( __( 'View more details about %s', 'mycode' ), $product->get_name() ); $class = sprintf( 'button add_to_cart_button product_type_%s', $product->get_type() ); $format = '<a href="%1$s" title="%2$s" class="%3$s">%4$s</a>'; printf( $format, esc_url( $url ), esc_attr( $title ), esc_attr( $class ), esc_html( $text ) ); }

Link Directly to External/Affiliate Site from [More Details] Button

The one is strictly for External/Affiliate products. This adds a new [More Details] button which links directly to the external/affiliate website instead of your single product page.

This looks very similar to the default functionality of WooCommerce.

And here’s the custom code:

<?php /** * Adds an action to the loop to display a [More Details] button * to the WooCommerce Product Loop which links to an External/Affiliate product. */ function mycode_add_more_details_button_to_external() { add_action( 'woocommerce_after_shop_loop_item', 'mycode_display_more_details_button_to_external' ); } add_action( 'init', 'mycode_add_more_details_button_to_external' ); /** * Display [More Details] button HTML with a link to an External/Affiliate product. * * @global WC_Product_External $product */ function mycode_display_more_details_button_to_external() { /** * @var WC_Product_External $product */ global $product; if ( 'external' != $product->get_type() ) { return; } $url = $product->get_product_url(); $text = __( 'Buy Now', 'mycode' ); $title = sprintf( __( 'View more details about %s', 'mycode' ), $product->get_name() ); $class = sprintf( 'button add_to_cart_button product_type_%s', $product->get_type() ); $format = '<a href="%1$s" title="%2$s" class="%3$s" target="_blank">%4$s</a>'; printf( $format, esc_url( $url ), esc_attr( $title ), esc_attr( $class ), esc_html( $text ) ); }

Add Price to Button

Here we will add the product’s price (regular or sale price) to the button. This helps prices stand out a bit more.

Here’s the custom code for that:

<?php /** * Adds an action to the loop to display a [Buy $199.99] button containing the price * to the WooCommerce Product Loop which links to an External/Affiliate product. */ function mycode_add_more_details_button_to_external_with_price() { add_action( 'woocommerce_after_shop_loop_item', 'mycode_display_more_details_button_to_external_with_price' ); } add_action( 'init', 'mycode_add_more_details_button_to_external_with_price' ); /** * Display [Buy $199.99] button HTML containing the price with a link to an External/Affiliate product. * * @global WC_Product_External $product */ function mycode_display_more_details_button_to_external_with_price() { /** * @var WC_Product_External $product */ global $product; if ( 'external' != $product->get_type() ) { return; } $url = $product->get_product_url(); $price = wc_price( $product->get_price() ); $text = sprintf( __( 'Buy %s', 'mycode' ), $price ); $title = sprintf( __( 'Buy %s', 'mycode' ), $product->get_name() ); $class = sprintf( 'button add_to_cart_button product_type_%s', $product->get_type() ); $format = '<a href="%1$s" title="%2$s" class="%3$s" target="_blank">%4$s</a>'; printf( $format, esc_url( $url ), esc_attr( $title ), esc_attr( $class ), $text ); }

Add Merchant’s Name to Button

Here’s another one that works well for External/Affiliate products. We can also add the merchant’s name to the button.

And here’s the code:

<?php /** * Adds an action to the loop to display a [Buy at Acme] button containing the merchant's name * to the WooCommerce Product Loop which links to an External/Affiliate product. */ function mycode_add_more_details_button_to_external_with_merchant_name() { add_action( 'woocommerce_after_shop_loop_item', 'mycode_display_more_details_button_to_external_with_merchant_name' ); } add_action( 'init', 'mycode_add_more_details_button_to_external_with_merchant_name' ); /** * Display [Buy at Acme] button containing the merchant's name in the * WooCommerce Product Loop which links to an External/Affiliate product. * * @global WC_Product_External $product */ function mycode_display_more_details_button_to_external_with_merchant_name() { /** * @var WC_Product_External $product */ global $product; if ( 'external' != $product->get_type() ) { return; } $url = $product->get_product_url(); $merchant = $product->get_attribute( 'pa_merchant' ); $text = $merchant ? sprintf( __( 'Buy at %s', 'mycode' ), $merchant ) : __( 'Buy Now', 'mycode' ); $title = sprintf( __( 'View more details about %s', 'mycode' ), $product->get_name() ); $class = sprintf( 'button add_to_cart_button product_type_%s', $product->get_type() ); $format = '<a href="%1$s" title="%2$s" class="%3$s" target="_blank">%4$s</a>'; printf( $format, esc_url( $url ), esc_attr( $title ), esc_attr( $class ), esc_html( $text ) ); }

Those are all for the WooCommerce Loop but if you want to make similar customizations on the Single Product Page, you would want to use the woocommerce_after_single_product_summary hook.

Using OAuth 1.0 with the WordPress API & Custom Endpoints

This very long article covers setting up OAuth 1.0 to work with the core version of the WordPress API.

We will be generating client keys, oauth tokens, a custom endpoint and allowing access to our API only from those whom we have manually authenticated via OAuth.

Before we begin, I have 2 local installs of WordPress:


This is our main API website that our client will make requests to.


This is our client website that will make requests to the API website.

I have listed quite a few resources that I used to put together this tutorial at the bottom of the article. In some cases, I’ve just copied the code or steps. If you get stuck or want more info, I highly encourage you to read those resources. They will definitely be worth your time!

Get some coffee and let’s begin!

Test to make sure you can connect to the API.

Add the following code to your plugin on your client site.

Change the $url value to match the URL of the API site’s URL. So it will be something like

Mine is installed on my local machine that’s why the URL is http://wp-api-main/wp-json

Then create a new page and add this shortcode to the page [test_api_connection]

Open the page and you should see content like this:

    [name] => WP-API Main
    [description] => Just another WordPress site
    [url] => http://wp-api-main
    [home] => http://wp-api-main
    [namespaces] => Array
            [0] => oembed/1.0
            [1] => wp/v2

    [authentication] => Array

    [routes] => Array
            [/] => Array
                    [namespace] => 
                    [methods] => Array
                            [0] => GET

                    [endpoints] => Array
                            [0] => Array
                                    [methods] => Array
                                            [0] => GET
// ...

Here’s what mine looks like:

The thing to notice is that the [authentication] is an empty array. Let’s change that part.

Now go to your main API site and install and activate the “WordPress REST API – OAuth 1.0a Server” plugin.

Once installed and activated, go to Users > Applications and click the [Add New] button.

On the “Add Application” page you will fill in some values. “Consumer Name” and “Description” can be whatever you wish. Just put something that makes sense.

I’m not sure what the Callback does at this time so I just inserted something like “http://wp-api-main/auth/success”.

After you have filled in all 3 fields, click the [Add Consumer] button.

Now you will see that the Client has a Client Key and Client Secret under the “OAuth Credentials” section.

Copy those for later.

Client Key (consumer_key):


Client Secret (consumer_secret):


Now if you go back to the new page you created on your Client site which has the shortcode, the [authentication] array should have some values in it.

Now we need to hook up these keys with our client so that our client can then make subsequent authenticated API requests to our API site.

The details behind this process are complicated and covered in detail in some of the resource links I share at the bottom of this article especially on

The method I found the easiest to use the above keys is with an app like Postman or Paw. Postman is free and also has a Chrome extension if you aren’t on a Mac. I’ll use Postman in this tutorial because it’s free.

For these next steps, I relied heavily on It contains more background on this process. Definitely worth the read!

If you have questions about these next few steps, check that article, too.

Open the Postman app.

In the “Get” request URL field enter the URL of the main API website’s /oauth1/request path. I have entered


Under Authorization Type, choose OAuth 1.0

Enter the Consumer Key (ie. the Client Key) and Consumer Secret (ie. the Client Secret).

Click the [Update Request] button. This will automatically fill in the timestamp field and the Nonce field.

Your request URL will have been update to something like this:


Then click the [Send] button.

Scroll down to see the response. You should see something like this:


Save that string somewhere. We will need these 2 initial OAuth tokens:





Next, we will use the “oauth_token” value we just got and construct a URL like this (on our Main API site):


Load the URL in your browser.

You will get a login-type screen which has a message like “Howdy eric,
“Client API Connection” would like to connect to WP-API Main.”

Click the [Authorize] button.

The next screen will have a message like this: “Your verification token is PvHs1j8ol5FqVd4QPv0eGt9t

verification token


Copy that token down… we’ll need that later, too!

The last step is to get our access token.

So in Postman, enter this URL into the request URL field:


This time you will need to fill in your:

  • Consumer Key
  • Consumer Secret
  • Token
  • Token Secret

Clicking the [Update Request] button will fill in the nonce and timestamp and your request URL will be transformed into something like this:


Next click the [Params] button to the right of the request URL.

Add 1 new row to the params. Set the key to “oauth_verifier” and the value to “PvHs1j8ol5FqVd4QPv0eGt9t” (which is the value we got in the previous step.

Then click the [Send] button. Note that you may need to click the [Update Request] again and then click [Send].

After you scroll down you will see your new tokens.






You can now disregard your old oauth_token and oauth_token_secret tokens. You won’t need the old ones anymore. You only need these new ones. Additionally, you can disregard your oauth_verifier code as well. You shouldn’t need that code any more.

OK, we are done with Postman and we now have the necessary OAuth tokens we need in order to make an authenticated API request.

The only thing is, our main API site does not require authentication yet. So let’s force it to require authentication.

On your main API site, install the Disable Rest API plugin.

So now we have 2 plugins installed on our main API site:

  • WP REST API – OAuth 1.0a Server
  • Disable REST API

Let’s make sure our API now requires authentication. Go to the test page you created on your client site and load the page again.

You should now see a 401 “rest_cannot_access” message like this.

Excellent! I bet you’ve never been so happy to see a 401 message. 🙂

So, now that we have the keys to get around that restriction and authenticate, let’s do so.

But we’re not out of the woods yet… unfortunately, not even close.

The next bit of code mostly comes from this Sitepoint article. Please refer to that for more details. In our case, we will make a class that handles sending the proper headers to an API that requires authentication. Time to get more coffee… I’ll be here when you get back.

We are going to create a new shortcode so that we can add it to our page with the other shortcode.

Let’s first go to our page and modify our page so it looks like this:



Then we need to add a new shortcode to our plugin so we can start testing our OAuth connection.

Here’s our new shortcode:

A few things to take note of…

We added a $method variable and set it to ‘GET‘. That matches our wp_remote_get() call.

We added the various keys that we created to a $keys array.

Then we passed the $keys, $url and $method variables as parameters to our new OAuth_Authorization_Header() class. More on that in a second.

We get the $header value from the get_header() method and then added our authorization header array to a new $args array.

Lastly, we modified our call to wp_remote_get() by adding the $args array as the second parameter to the function.

The rest of the shortcode code is the same as our first one.

OK, so what about the new OAuth_Authorization_Header class?

Well, it’s a modified and simplified version of the class in the Sitepoint article which is itself a modified and simplified version of the code from a Twitter WordPress HTTP client. Love me some open source!

Here’s the basic OAuth_Authorization_Header class without documentation or checks to ensure all the required data is present… it’s a starting point. Be sure to validate the incoming arguments.

So now when you load the page with your shortcodes on your client site, you should have one ‘access denied’ message and one with a successful response.

The last thing I want to do is set up a custom endpoint on my API site and make that custom endpoint protected. Currently, all of our endpoints are private because we installed the Disable REST API plugin. But what if you just want a single custom endpoint to be private, not all endpoints?

Here’s how we can do that.

First, disable the Disable REST API plugin on your main API site.

After you do that, now both your shortcodes on your client site should load a successful response like this:

Next, create a custom plugin on your main API site and add the following code to your plugin:

Basically, this creates a new endpoint and returns an array if successfully called.

Let’s tweak our URLs in our client plugin:

In the client plugins we have this:

$url = 'http://wp-api-main/wp-json';

Let’s change that to this to make a request to a specific endpoint:

$url = 'http://wp-api-main/wp-json/myapiplugin/v2/greeting';

Be sure to change the $url variable in BOTH shortcodes.

Then refresh the page on your client site with the shortcodes. You should now see 2 successful responses.

Perfect! Now, let’s make that new endpoint private so only authenticated clients can access it.

Change the Main API plugin to this:

You see we have added a new item to array in the third parameter of the call to register_rest_route(). We have added:

'permission_callback' => 'myapiplugin_permission_callback',

Then we added a new function to our plugin that returns ‘true‘ if the current user can update core WordPress or false if the user can not. Who is this user that “current_user_can” is referring to? That user is our client who we have granted permissions to through the OAuth key exchange (back in the Postman section of this article).

So now that we have added this new authentication code to our plugin, let’s go back to our client shortcode page and reload that page.

Now you should see 1 access denied message and one success message.

And now you have successfully set up OAuth1 with your WordPress API so that a client that you have explicitly granted access to can call a private endpoint that you have set up.


Here are some of the articles I referenced when putting my article together. They were a huge help so if you are looking for more information about some of these steps, do check these out:

2 Normalizing brand names when importing affiliate data feed into WooCommerce

WooCommerce is great for importing data feeds into and using for your datafeed-driven affiliate store. However, one of the frustrations of using data feeds is data inaccuracy. We (datafeedr) try to normalize data before it hits our database, we can’t normalize everything.

That’s why it’s important for users to be able to normalize information before it gets inserted into your store.

In the normalizing brand names documentation article we just published, you can learn how to normalize all of your product’s brand names.

So instead of those new shoes you just imported being listed under the brand names “Nike Co.” or “Nike Inc” or “Nike International”, now they can all simply be listed with the brand name “Nike”.

1 2 3