Month: May 2025

How to add a GST number field to WooCommerce checkout and order emails

If you’re running a WooCommerce store in India or working with B2B clients, you may need to collect GST numbers during checkout. In this tutorial, you’ll learn how to add an optional GST number field on the WooCommerce checkout page, save it with the order, and display it in the admin panel as well as in the order confirmation emails.

Step 1: Add GST Number Field to Checkout Page

Use the following code in your theme functions.php file to add a new optional field for the GST number just below the billing fields.

// Add GST Number field to checkout
add_action('woocommerce_after_checkout_billing_form', 'add_gst_field_to_checkout');
function add_gst_field_to_checkout($checkout) {
    echo '<div id="gst_number_field"><h3>' . __('GST Number (Optional)') . '</h3>';

    woocommerce_form_field('gst_number', array(
        'type'        => 'text',
        'class'       => array('form-row-wide'),
        'label'       => __('GST Number'),
        'placeholder' => __('Enter your GST number if applicable'),
        'required'    => false,
    ), $checkout->get_value('gst_number'));

    echo '</div>';
}

Step 2: Save the GST Number to Order Meta

Use the following code in your theme functions.php file to to save the entered GST number into the order’s metadata.

// Save GST number in order meta
add_action('woocommerce_checkout_update_order_meta', 'save_gst_number_order_meta');
function save_gst_number_order_meta($order_id) {
    if (!empty($_POST['gst_number'])) {
        update_post_meta($order_id, '_gst_number', sanitize_text_field($_POST['gst_number']));
    }
}

Step 3: Show GST Number on Admin Order Page

Admins should be able to view the GST number from the WooCommerce dashboard under the order details. Use the following code in your theme functions.php file.

// Show GST number in admin order page
add_action('woocommerce_admin_order_data_after_billing_address', 'display_gst_in_admin_order', 10, 1);
function display_gst_in_admin_order($order) {
    $gst_number = get_post_meta($order->get_id(), '_gst_number', true);
    if (!empty($gst_number)) {
        echo '<p><strong>' . __('GST Number') . ':</strong> ' . esc_html($gst_number) . '</p>';
    }
}

Step 4: Show GST Number in Order Emails

To include the GST number in the order emails (for both admin and customer), below the billing address section, add the following code in your theme functions.php file.

// Add GST number to emails below billing address
add_filter('woocommerce_email_customer_details_fields', 'add_gst_to_order_email', 10, 3);
function add_gst_to_order_email($fields, $sent_to_admin, $order) {
    $gst_number = get_post_meta($order->get_id(), '_gst_number', true);
    if (!empty($gst_number)) {
        $fields['gst_number'] = array(
            'label' => __('GST Number'),
            'value' => $gst_number,
        );
    }
    return $fields;
}

Note: Always test this on a staging site before applying to a live WooCommerce store. If you use custom themes or plugins that modify the checkout or email templates, adjust the code accordingly.

Plugin version of the same codes is also available on Github.

How to generate Facebook & Google product XML feed in WooCommerce without a plugin

If you’re running a WooCommerce store and want to connect your products to Facebook Catalogue or Google Merchant Center, you usually rely on a plugin. However, plugins can add bloat, slow down your website, or offer limited control.

This guide shows you how to generate a dynamic XML product feed from WooCommerce without installing any plugin. The feed is fully compatible with Facebook Commerce Manager and Google Shopping, supports both simple and variable products, and includes custom attributes like size, colour, and more.Why Build Your Own Feed?

Why build your own feed?

  • No need for extra plugins
  • Full control over structure and attributes
  • Supports all WooCommerce product types
  • Dynamically includes all variation attributes
  • Can be used for Facebook, Google, or any XML-based product platform

Step 1: Create the XML feed file

Create a new file in your website root directory name it as product-feed-xml.php. Paste the following code inside it.

<?php
require_once('wp-load.php');
ob_clean(); // Clean any prior output to prevent XML errors

header('Content-Type: application/xml; charset=utf-8');

echo '<?xml version="1.0" encoding="UTF-8"?>';
?>
<rss version="2.0" xmlns:g="http://base.google.com/ns/1.0">
<channel>
<title>Your Store Feed</title>
<link><?php echo esc_url(site_url()); ?></link>
<description>WooCommerce Product Feed</description>

<?php
$args = [
'post_type'      => ['product', 'product_variation'],
'post_status'    => 'publish',
'posts_per_page' => -1
];

$loop = new WP_Query($args);

if ($loop->have_posts()) {
while ($loop->have_posts()) {
$loop->the_post();
$product = wc_get_product(get_the_ID());

if (!$product || !$product->is_visible()) continue;

$is_variation = $product->is_type('variation');
$parent_id = $is_variation ? $product->get_parent_id() : $product->get_id();
$parent = wc_get_product($parent_id);

// Prices
$currency = get_woocommerce_currency();
$regular_price = $product->get_regular_price();
$sale_price = $product->get_sale_price();
$price = $regular_price ?: $sale_price;

if (!$price) continue; // skip product with no price

// Other fields
$id = $product->get_id();
$title = $product->get_name();
$description = strip_tags($parent->get_short_description() ?: $parent->get_description());
$availability = $product->is_in_stock() ? 'in stock' : 'out of stock';
$condition = 'new';
$link = get_permalink($parent_id);
$image = wp_get_attachment_url($product->get_image_id() ?: $parent->get_image_id());
$category_list = wp_get_post_terms($parent_id, 'product_cat', ['fields' => 'names']);
$product_type = implode(" > ", $category_list);
$item_group_id = $is_variation ? $parent_id : '';
$brand = 'Your Brand'; // Customize if needed
?>
<item>
<g:id><?php echo $id; ?></g:id>
<title><![CDATA[<?php echo $title; ?>]]></title>
<description><![CDATA[<?php echo $description; ?>]]></description>
<link><?php echo esc_url($link); ?></link>
<g:image_link><?php echo esc_url($image); ?></g:image_link>
<g:availability><?php echo $availability; ?></g:availability>
<g:condition><?php echo $condition; ?></g:condition>
<g:price><?php echo number_format($price, 2); ?> <?php echo $currency; ?></g:price>
<?php if ($sale_price): ?>
<g:sale_price><?php echo number_format($sale_price, 2); ?> <?php echo $currency; ?></g:sale_price>
<?php endif; ?>
<g:brand><?php echo esc_html($brand); ?></g:brand>
<g:product_type><![CDATA[<?php echo $product_type; ?>]]></g:product_type>
<?php if ($item_group_id): ?>
<g:item_group_id><?php echo $item_group_id; ?></g:item_group_id>
<?php endif; ?>

<?php
// Output all variation attributes dynamically
$attributes = $product->get_attributes();
foreach ($attributes as $attribute_name => $attribute) {
$label = wc_attribute_label($attribute_name);
$value = $product->get_attribute($attribute_name);
if (!empty($value)) {
$tag_name = strtolower(preg_replace('/[^a-z0-9_]/i', '_', $label));
echo "    <g:" . esc_html($tag_name) . ">" . esc_html($value) . "</g:" . esc_html($tag_name) . ">\n";
}
}
?>
</item>
<?php
}
}
wp_reset_postdata();
?>
</channel>
</rss>

Step 2: Access and test the feed

Visit: https://yourdomain.com/product-feed-xml.php

You’ll see a fully structured XML file that can be submitted to:

You can schedule Facebook or Google to fetch your feed daily using the public feed URL: https://yourdomain.com/product-feed-xml.php and you do not need to manually upload a CSV or XML file.

WordPress custom YouTube feed plugin

The Custom YouTube Feed plugin allows WordPress site owners to display videos from multiple YouTube channels and individual videos in an attractive grid layout. The plugin features pagination, popup video playback, and automatic caching for improved performance.

Key Features

  • Multiple Channel Support: Add videos from multiple YouTube channels
  • Individual Video Support: Include specific videos by URL
  • Responsive Grid Layout: 3-column grid that adapts to screen size
  • Popup Video Player: Lightbox-style playback with Magnific Popup
  • Smart Caching: 24-hour cache to reduce API calls
  • Easy Pagination: Automatic pagination for large video collections
  • Admin Dashboard: Simple interface for managing channels and settings

Installation

  1. Upload the plugin files to your WordPress plugins directory (/wp-content/plugins/)
  2. Activate the plugin through the WordPress admin panel
  3. Navigate to Settings → YouTube Channels to configure your API key and channels

Requirements

  • WordPress 5.0 or higher
  • PHP 7.0 or higher
  • YouTube Data API v3 key (free)

Usage

Shortcode

Add videos to any post or page using the shortcode:

[youtube_videos]

Admin Settings

  1. API Key: Enter your YouTube Data API key (required)
  2. Videos Per Channel: Set how many videos to show from each channel
  3. Channel URLs: Add YouTube channel URLs (supports all URL formats)
  4. Individual Videos: Add specific video URLs

Cache Management

The plugin automatically caches videos for 24 hours. You can manually clear the cache from the admin panel.

Customization

CSS Styling

The plugin includes default CSS that can be overridden in your theme’s stylesheet. Key classes:

  • .youtube-videos-grid – The main video container
  • .youtube-video – Individual video items
  • .youtube-pagination – Pagination controls

JavaScript

The plugin uses Magnific Popup for video playback. Customize the popup behavior by modifying the initialization in the shortcode output.

GitHub Repository

View on GitHub

Support

For support, feature requests, or bug reports, please open an issue on GitHub.

License

GPLv2 or later

Fetch data from Google Sheet and show in HTML using PHP

This documentation explains how to use the provided PHP code to fetch data from Google Sheets and display it in a custom layout using HTML/CSS.

Setup Instructions

1. Get Your Google Sheet ID

  1. Open your Google Sheet in a web browser
  2. Look at the URL in the address bar – it will look like:
https://docs.google.com/spreadsheets/d/BmzaSyBzQ0cRTrbf_vxrB75nh8AoV3BtawPiiCQ/edit#gid=0

The long string between /d/ and /edit is your Sheet ID (in this example: BmzaSyBzQ0cRTrbf_vxrB75nh8AoV3BtawPiiCQ)

2. Create a Google API Key

  1. Go to the Google Cloud Console
  2. Create a new project or select an existing one
  3. Navigate to “APIs & Services” > “Library”
  4. Search for “Google Sheets API” and enable it
  5. Go to “APIs & Services” > “Credentials”
  6. Click “Create Credentials” and select “API key”
  7. Copy your new API key
  8. (Optional) Restrict the API key to only work with the Sheets API for security

3. Configure the PHP Code

Replace these values in the code:

$sheetID = "BmzaSyBzQ0cRTrbf_vxrB75nh8AoV3BtawPiiCQ"; // Your Sheet ID
$apiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // Your API Key
$rows_count = 8; // Number of rows to display

4. Sheet Configuration

Your Google Sheet must have a named range or sheet tab that matches what you put in the API URL (in this example: Sheet1)

Make sure your Sheet is either:

  • Publicly accessible (set to “Anyone with the link can view”)
  • Or shared with the email address associated with your API key

Here is the entire code.

<?php
// Google Sheets API configuration
$sheetID = "BmzaSyBzQ0cRTrbf_vxrB75nh8AoV3BtawPiiCQ"; // Replace with your actual Sheet ID
$apiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; // Replace with your API Key
$apiURL = "https://sheets.googleapis.com/v4/spreadsheets/$sheetID/values/Sheet1?key=$apiKey";

$rows_count = 8; // Number of rows to be displayed

// Fetch the Google Sheets data
$response = file_get_contents($apiURL);
$data = json_decode($response, true);
if (isset($data['values']) && count($data['values']) > 1) {
for ($i = 1; $i <= min($rows_count, count($data['values']) - 1); $i++) {	

// Get the column wise data from Google Sheet, if no value then show N/A
$column_1 = isset($data['values'][$i][0]) ? htmlspecialchars($data['values'][$i][0]) : "N/A";
$column_2 = isset($data['values'][$i][1]) ? htmlspecialchars($data['values'][$i][1]) : "N/A";
$column_3 = isset($data['values'][$i][2]) ? htmlspecialchars($data['values'][$i][2]) : "N/A";
$column_4 = isset($data['values'][$i][3]) ? htmlspecialchars($data['values'][$i][3]) : "N/A";
$column_5 = isset($data['values'][$i][4]) ? htmlspecialchars($data['values'][$i][4]) : "N/A";
?>

<?php } ?>
<div class="row">
<div><?php echo $column_1;?></div>
<div><?php echo $column_2;?></div>
<div><?php echo $column_3;?></div>
<div><?php echo $column_4;?></div>
<div><?php echo $column_5;?></div>
</div>
<?php } ?>

Disable WordPress Comment System Completely

Here’s a comprehensive function to completely disable the WordPress comment system:

<?php
// Completely disable WordPress comments and related functionality
function disable_comments_system() {
    // Disable support for comments and trackbacks in post types
    foreach (get_post_types() as $post_type) {
        if (post_type_supports($post_type, 'comments')) {
            remove_post_type_support($post_type, 'comments');
            remove_post_type_support($post_type, 'trackbacks');
        }
    }
    
    // Close comments on all existing posts
    update_option('close_comments_for_old_posts', 1);
    update_option('close_comments_days_old', 0);
    update_option('comment_registration', 1);
    update_option('default_ping_status', 'closed');
    update_option('default_comment_status', 'closed');
    
    // Redirect any comment feed requests to homepage
    add_action('template_redirect', function() {
        if (is_comment_feed()) {
            wp_redirect(home_url(), 301);
            exit;
        }
    });
    
    // Remove comments page from admin menu
    add_action('admin_menu', function() {
        remove_menu_page('edit-comments.php');
        remove_submenu_page('options-general.php', 'options-discussion.php');
    });
    
    // Remove comments links from admin bar
    add_action('wp_before_admin_bar_render', function() {
        global $wp_admin_bar;
        $wp_admin_bar->remove_menu('comments');
    });
    
    // Remove dashboard comments widget
    add_action('wp_dashboard_setup', function() {
        remove_meta_box('dashboard_recent_comments', 'dashboard', 'normal');
    });
    
    // Disable comments REST API endpoint
    add_filter('rest_endpoints', function($endpoints) {
        unset($endpoints['/wp/v2/comments']);
        unset($endpoints['/wp/v2/comments/(?P<id>[\d]+)']);
        return $endpoints;
    });
    
    // Remove comment form completely (front-end)
    add_filter('comments_open', '__return_false', 20, 2);
    add_filter('pings_open', '__return_false', 20, 2);
    add_filter('comments_array', '__return_empty_array', 10, 2);
    
    // Remove comment-reply script
    add_action('wp_enqueue_scripts', function() {
        wp_deregister_script('comment-reply');
    }, 100);
    
    // Remove comment form from templates
    add_action('init', function() {
        // Remove comment-reply script
        remove_action('wp_head', 'feed_links_extra', 3);
        
        // Remove comment form from wp_head
        remove_action('wp_head', 'feed_links', 2);
        
        // Remove comment form from content
        remove_filter('the_content', 'wpautop');
        add_filter('the_content', function($content) {
            if (is_singular()) {
                $content = preg_replace('/<div[^>]+id="respond"[^>]*>.*?<\/div>/is', '', $content);
                $content = preg_replace('/<h3[^>]+id="reply-title"[^>]*>.*?<\/h3>/is', '', $content);
                $content = preg_replace('/<form[^>]+id="commentform"[^>]*>.*?<\/form>/is', '', $content);
            }
            return $content;
        });
    });
}
add_action('init', 'disable_comments_system');

// Remove comment form from theme templates (additional safety)
add_filter('theme_page_templates', function($templates) {
    unset($templates['comments.php']);
    return $templates;
});

// Hide comments in admin for all post types
add_action('admin_init', function() {
    $post_types = get_post_types();
    foreach ($post_types as $post_type) {
        if (post_type_supports($post_type, 'comments')) {
            remove_post_type_support($post_type, 'comments');
            remove_post_type_support($post_type, 'trackbacks');
        }
    }
});
?>
  1. Add this code to your theme’s functions.php file or in a custom plugin
  2. The function will:
    • Remove comment support from all post types
    • Close comments on all existing posts
    • Disable comments and pingbacks by default
    • Remove comment-related admin menu items
    • Remove comment links from the admin bar
    • Remove the comments dashboard widget
    • Disable the comments REST API endpoints
    • Redirect comment feeds to the homepage

Additional Steps for Stubborn Comment Forms

If the comment form still appears after adding this code:

  1. Check your theme files: Some themes hard-code the comment form. Look in these files:
    • comments.php
    • single.php
    • page.php
    • content-single.php
    • Any files with comment_form() calls
  2. Add CSS to hide comments (as last resort)
add_action('wp_head', function() {
    echo '<style>
        #comments, #respond, .comments-area, .comment-respond, 
        .comment-form, .comments-title, .comment-list {
            display: none !important;
        }
    </style>';
});
  1. Check for any other plugins that might be adding comment functionality.

This enhanced solution should remove all traces of the comment system, including forms that appear when logged in as an admin.

© 2025 Wavesdream Blog

Theme by Anders NorénUp ↑