Categories
WordPress

How To Access PODS Custom Post Types Using The WP Rest API

Recently I have been working with the WordPress Rest API to use WordPress as a data source. One of the issues that I ran into is when trying to access custom post types created with pods. When trying to access the end point for the custom post type I received the following error:
{"code":"rest_no_route","message":"No route was found matching the URL and request method","data":{"status":404}}

A quick read of the WP Rest API docs will reveal that Custom Post Types don’t have routes by default. But no worries support for WP Rest API can be added to any custom post type.

To add support for the WP Rest API to a custom post type created with PODS you need to log into your WP admin area. From the menu you select Pods Admin > Edit Pods. Edit Pods
Hover over the custom post type you want to access and then choose edit. At this point you need to decide if you want to allow access to the entire custom post type or just specific fields.

Allow access to specific fields

Click to edit the field you want to access using the WP Rest API. On the PODS Field Rest API tab you can choose to allow read access, write access, or both. PODS field Rest Access

Allow access to entire custom post type

On the PODS Rest API tab you can enable Rest API Support for the custom post type. You can check the Show All Fields to or follow the steps above to just allow read access of certain fields. You can also allow all fields to be updated using the Rest API or set the write settings individually for each field.Pods CPT Rest API Support

Access PODS Custom Post Type With WP Rest API

Now you should be able to access the custom post type using something like
https://yourdomain.com/wp-json/wp/v2/quote/
Be mindful that you must change https://yourdomain.com to the site you have the custom post type on. And change quote to the REST Base for your custom post type.

 

 

Categories
WordPress

How To Add Timestamp Links In Your Podcast Show Notes

If you don’t know I have a podcast that I do over at 2DWebsolutions with Kerry Carron. Each month we answer questions that are submitted on our site, via our app, or in the Slack group. From the beginning we added the questions discussed in the show notes. As early as episode two we started to receive feedback from listeners that it would be better if we also add the time stamp for when each question is answered. Even though it takes a lot of time and patience to get the time stamp for each question, Kerry does it each month and adds them to the show notes. At the time we thought that was the best we could do, but..

I was reading the show notes on one of the many podcasts that I listen to when I tried to go to the time stamp they had in the show notes. Do you know how frustrating it is to try to scrub to a specific time stamp?

That got me thinking that there has to be a way to make time stamps in the show notes more useful. Youtube lets you add a time stamp link in your Youtube video description, so I knew it was possible. I looked for a WordPress plugin that would add a time stamp link, but I could not find one that worked without breaking the site. So, what did I do?

I created a WordPress plugin that would add a time stamp link in the show notes on our site. After using for a while I realized that other podcasters can benefit from the plugin. These time stamps can help your listeners find the important parts of the podcast. Time stamps especially help in the cases of long episodes, episodes with segments, or episodes with especially important moments.

Watch the video to see how the Link Timestamp WordPress plugin allows you to add a time stamp link in your podcast show notes.

Powered By S3 Media Maestro

Time stamp links
Automatic Linking – 1:28
Manual linking from the editor – 2:56

I want to point out that it is for the WordPress platform and it will hyperlink to time stamps in Youtube embeds, Vimeo embeds, HTML5 audio players, and HTML5 video players. You don’t have to go to all your past show notes and manually add the time stamp link if you don’t want to. You can just use the automatic links.

Categories
Code Snippets WordPress

WooCommerce Shipping Options Based on Weight

WooCommerce shipping options based on weight can be accomplished by creating a callback function for the woocommerce_cart_shipping_packages filter. The filter hook allows you to make a change to the cart package such as conditional shipping options based on shipping class, location, or weight.

To get the weight of all the products in the shopping cart you can use the cart_contents_weight method of the WooCommerce Cart class. The code below will allow only UPS shipping method if the weight is great than 4 pounds. If the weight is below 4 pounds USPS will be the only shipping options. The shipping options can be changed on lines 15 and 30. The weight condition can be changed on line 13.

/** 
 * Shipping based on cart contents weight
 */
add_filter( 'woocommerce_cart_shipping_packages', 'ps_woocommerce_cart_shipping_packages_by_weight' );

function ps_woocommerce_cart_shipping_packages_by_weight( $packages ) {

    $packages = array();
 
  
    $cart_items = WC()->cart->get_cart(); 
   
   if( WC()->cart->cart_contents_weight > 4){
        $packages[] = array(
            'ship_via' => array( 'ups'  ), /*Shipping methods that are available for order over 4 lbs */
            'contents' => $cart_items,
            'contents_cost' => array_sum( wp_list_pluck( $cart_items, 'line_total' ) ),
            'applied_coupons' => WC()->cart->applied_coupons,
            'destination' => array(
                'country' => WC()->customer->get_shipping_country(),
                'state' => WC()->customer->get_shipping_state(),
                'postcode' => WC()->customer->get_shipping_postcode(),
                'city' => WC()->customer->get_shipping_city(),
                'address' => WC()->customer->get_shipping_address(),
                'address_2' => WC()->customer->get_shipping_address_2()
            )
        );
    }else{
       $packages[] = array(
            'ship_via' => array('usps'), /*Shipping methods that are available for order under 4 lbs */
            'contents' => $cart_items,
            'contents_cost' => array_sum( wp_list_pluck( $cart_items, 'line_total' ) ),
            'applied_coupons' => WC()->cart->applied_coupons,
            'destination' => array(
                'country' => WC()->customer->get_shipping_country(),
                'state' => WC()->customer->get_shipping_state(),
                'postcode' => WC()->customer->get_shipping_postcode(),
                'city' => WC()->customer->get_shipping_city(),
                'address' => WC()->customer->get_shipping_address(),
                'address_2' => WC()->customer->get_shipping_address_2()
            )
        ); 
    }
      
    return $packages;
}
Categories
Code Snippets jQuery WordPress

Mobile Friendly Menu

In this tutorial I explain how to create a mobile friendly menu for the iThemes Builder theme. By default the menu will wrap on smaller screens. When the menu wraps it is not very mobile friendly.

The menu wraps on small screens.
The menu wraps on screens.

In your child theme directory create a new file for some jQuery. You can call it what you want but I am going to call it mobile_script.js. The code in this file should not run until the page loads. The script needs to be enqueued in the functions.php file.

Add Mobile Menu Functionality
After the page loads add a class to the menu and to the navigation module. The Menu label is added before the module navigation. If you click on ≡ Menu the menu items are shown or hidden. The sub-menu items are hidden until the parent item is tapped.

jQuery(document).ready(function() {

	jQuery(".builder-module-navigation .menu").addClass("mobile-menu-hidden");
	jQuery(".builder-module-navigation").addClass("mobile");
	
	jQuery(".mobile-menu-hidden").before('<div class="mobile-menu">≡ Menu</div>');
	
	jQuery(".mobile-menu").click(function(){
		jQuery(this).next().slideToggle();
	});


	jQuery(".mobile.builder-module-navigation li:has(ul)").click(function(){
		jQuery(".mobile.builder-module-navigation li ul").hide('fast');
		jQuery("ul",this).toggle();
	});

});

Style The Mobile Menu
After you add the jQuery file ≡ Menu will show above the navigation on a desktop. So in the style.css file it is hidden or told not to display.

.mobile-menu{
display: none;
}

Then the mobile navigation style is added to the main style sheet, responsive style sheet, or mobile style sheet that is available with most Builder child themes.


@media screen and (max-width:767px) { 
/*********************************************
	Mobile Menu
*********************************************/
.mobile-menu {
  color: #4b9eec;
  width: auto;
  font-weight: 700;
  font-size: 1.5rem;
  cursor: pointer;
  display: block;
  padding: .65em 0;
  -webkit-font-smoothing: antialiased;
  -webkit-appearance: none;
  -webkit-transition: all .2s ease-in;
  -moz-transition: all .2s ease-in;
  -o-transition: all .2s ease-in;
  -ms-transition: all .2s ease-in;
  transition: all .2s ease-in;
  text-align: center;
}

.mobile.builder-module-navigation .mobile-menu-hidden {
	display: none;
	margin-bottom: 1em;
}

.mobile .builder-module-navigation-menu-wrapper {
	display: block;
}
.builder-module-navigation-background-wrapper {
	padding: 0;
}
.builder-module-outer-wrapper .mobile.builder-module-navigation {
	padding: 0;
}
.mobile.builder-module-navigation {
	display: block;
	line-height: 1;
	width: 100%;
}
.mobile.builder-module-navigation ul.menu {
	border-bottom: 0;
}
.mobile.builder-module-navigation ul.menu:after {
	visibility: hidden;
	display: block;
	font-size: 0;
	content: " ";
	clear: both;
	height: 0;
}
.mobile.builder-module-navigation ul {
	display: block;
	float: none;
	width: 100%;
	margin: 0;
	padding: 0;
}
.mobile.builder-module-navigation ul * {
	margin: 0;
}
.mobile.builder-module-navigation li {
	padding: 0;
	display: block;
	width: 100%;
	background-color: rgba(255, 255, 255,.8);
}

.mobile.builder-module-navigation li a,
.mobile.builder-module-navigation .current_page_item li a,
.mobile.builder-module-navigation .current-cat li a,
.mobile.builder-module-navigation .current-menu-item li a {
	color: #333333;
	font-size: 1em;
	font-weight: 600;
	text-decoration: none;
	padding: .5em 1em;
	border: 0;
	border-bottom: 1px solid #C9C9C9;
	margin: 0;
	-webkit-font-smoothing: antialiased;
}
.mobile.builder-module-navigation .current_page_item > a,
.mobile.builder-module-navigation .current-cat > a,
.mobile.builder-module-navigation .current-menu-item > a {
	color: #252525;
	background: #F5F5F5;
}
.mobile.builder-module-navigation li a:hover,
.mobile.builder-module-navigation .current_page_item li a:hover,
.mobile.builder-module-navigation .current-cat li a li a:hover,
.mobile.builder-module-navigation .current-menu-item li a:hover {
	color: #252525;
	background: #F5F5F5;
}
/* Second Level */
.mobile.builder-module-navigation li ul {
	background: #FFFFFF;
	border: 0;
	width: 100%;
	left: 0;
	position: relative;
	display: none; 
}

.mobile.builder-module-navigation li li {
	border: 0;
	width: 100%;
}
.mobile.builder-module-navigation li li a,
.mobile.builder-module-navigation .current_page_item li a,
.mobile.builder-module-navigation .current-cat li a,
.mobile.builder-module-navigation .current-menu-item li a {
	float: none;
	font-size: 1em;
	line-height: 1;
	margin: 0;
	padding-left: 2em;
}
.mobile.builder-module-navigation li li a:hover,
.mobile.builder-module-navigation li li a.sfhover {

}
.mobile.builder-module-navigation li ul ul {
	margin: 0;
}
.mobile.builder-module-navigation li:hover ul,
.mobile.builder-module-navigation li li:hover ul,
.mobile.builder-module-navigation li li li:hover ul,
.mobile.builder-module-navigation li li li li:hover ul,
.mobile.builder-module-navigation li li li li li:hover ul,
.mobile.builder-module-navigation li.sfhover ul,
.mobile.builder-module-navigation li li.sfhover ul,
.mobile.builder-module-navigation li li li.sfhover ul,
.mobile.builder-module-navigation li li li li.sfhover ul,
.mobile.builder-module-navigation li li li li li.sfhover ul {
	left: 0;
}

.builder-module-navigation .builder-module-sidebar-outer-wrapper {
  display: none;
}
}

Final Result

Example Mobile Friendly Menu

Categories
WordPress

How to Set Up Woocommerce Free Shipping On a Specific Product

The WooCommerce USPS Shipping Method and the UPS Shipping Method extensions makes it easy for you to charge your customers for shipping cost at checkout. The only problem, is that they are both a calculator for all products in the cart, and does not exclude products based on shipping classes. So an order can only use one shipping method.

Recently on a site I was working on for a designer the site needed to offer free shipping within the US on a specific product category and charge the customer for shipping on all other products. The scenario required the ability to have two different shipping methods (Free and Paid) dependent upon the products in the order and shipping location. To accomplish this task we needed the one order divided into two carts.

Create Shipping Class

So all the products that could qualify for free shipping are assigned a shipping class.

Add Shipping Class To Product1

 

In this example I am calling the shipping class freepromo.

Configure Free Shipping

Then free shipping is enabled in the WooCommerce Shipping Settings. Configure Additional ShippingThen the USPS and UPS shipping methods are enabled and configured. At this point every time a customer is in the US they will get free shipping. If they are not in the US they will be given a choice of UPS and USPS shipping rates.

So we still need to set up:

  • Free shipping only for products being shipped in the US with the freepromo shipping class
  • USPS and UPS shipping options for customers not in the US buying the freepromo products
  • USPS and UPS shipping options for customers purchasing all other products.
  • Free shipping and USPS and UPS shipping options for customers that purchase freepromo and non-freepromo products in one order.

There is a free plugin called Multiple Packages for WooCommerce. The plugin does work but it does not allow for additional shipping options for products with the freepromo shipping class that don’t qualify for free shipping. It also makes free shipping available to the product that does not have the freepromo shipping class.

To allow all four use cases we need to add a little code to functions.php or a site specific plugin.

/** Seperate freepromo products from other Items - forcing multiple carts **/
add_filter( 'woocommerce_cart_shipping_packages', 'ps_two_shipping_methods_in_cart' );

function ps_two_shipping_methods_in_cart( $packages ) {
   $packages = array();
   $freepromo_items = array();
   $regular_items = array();
   $freeshipclass= 'freepromo';
   $shipto = array(
                'country' => WC()->customer->get_shipping_country(),
                'state' => WC()->customer->get_shipping_state(),
                'postcode' => WC()->customer->get_shipping_postcode(),
                'city' => WC()->customer->get_shipping_city(),
                'address' => WC()->customer->get_shipping_address(),
                'address_2' => WC()->customer->get_shipping_address_2()
    );

    // Sort freepromo from regular
    foreach ( WC()->cart->get_cart() as $item ) {
        if ( $item['data']->needs_shipping() ) {
            if ( $item['data']->get_shipping_class() == $freeshipclass ) {
                $freepromo_items[] = $item;
            } else {
                $regular_items[] = $item;
            }
        }
    }

//If product qualifies for free shipping
    if ( $freepromo_items && WC()->customer->get_shipping_country() =='US' ) {
        $packages[] = array(
            'ship_via' => array( 'free_shipping'  ),
            'contents' => $freepromo_items,
            'contents_cost' => array_sum( wp_list_pluck( $freepromo_items, 'line_total' ) ),
            'applied_coupons' => WC()->cart->applied_coupons,
            'destination' => $shipto
        );
    }elseif ( $freepromo_items ) { //if product does qualify for free shipping but customer is not in US
        $packages[] = array(
            'ship_via' => array( 'usps','ups'  ), //available shipping methods for international
            'contents' => $freepromo_items,
            'contents_cost' => array_sum( wp_list_pluck( $freepromo_items, 'line_total' ) ),
            'applied_coupons' => WC()->cart->applied_coupons,
            'destination' => $shipto
        );
    }


//If product does not qualify for free shipping
    if ( $regular_items ) {
        $packages[] = array(
        	'ship_via' => array( 'usps','ups'  ),
            'contents' => $regular_items,
            'contents_cost' => array_sum( wp_list_pluck( $regular_items, 'line_total' ) ),
            'applied_coupons' => WC()->cart->applied_coupons,
            'destination' => $shipto
        );
    }   
   
    return $packages;
}

In the code shown above you will need to change the shipping class name and the available shipping methods in the ship_via array.

Here are some examples of what the cart looks like in different scenarios:

This image shows the cart for a product that does not belong to the freepromo class.
This image shows the cart for a product that does not belong to the freepromo class.

 

shippingclassint
Based on the freepromo restrictions the customer does not qualify for free shipping of the freepromo product because they are not in the US.

 

US customer is ordering a  product that has the freepromo shipping class and one product that pays shipping.
US customer is ordering a product that has the freepromo shipping class and one product that pays shipping.

 

Note: The code shown above is code from the Multiple Packages for WooCommerce plugin that I modified to meet the requirements of the project.