Your cart is currently empty!
Tag: gst reporting
Automate GST Reports for WooCommerce Using Google Sheets + Apps Script
Step-by-step automation — from WooCommerce to monthly GST report, no manual exports.
What This Solves
If you manage a WooCommerce store on WordPress, this guide will help you:
- Extract completed order data from your WordPress site
- Sync it into Google Sheets via Apps Script
- Auto-generate a GST-compliant monthly report
- Email it — as a downloadable Google Sheet — every month
No plugins. No third-party tools. Full control.
Step 1: Create
export_orders.php
in Your WooCommerce SiteWhat It Does
This script connects directly to your WordPress backend using core WooCommerce functions to fetch order data in CSV format.
Where to Place It
- Upload this to your theme root or a protected folder like:
/wp-content/export/export_orders.php
Access via:
https://yourdomain.com/wp-content/export-secure/export_orders.php?token=your_secure_token_here
Ensure it’s not publicly browsable without restrictions (add basic auth or token check in production).
export_orders.php
<?php // CONFIGURE YOUR SECRET TOKEN BELOW define('EXPORT_TOKEN', 'your_secure_token_here'); // Block unauthorized access if (!isset($_GET['token']) || $_GET['token'] !== EXPORT_TOKEN) { http_response_code(403); exit('Unauthorized access'); } // Load WordPress core require_once($_SERVER['DOCUMENT_ROOT'] . '/wp-load.php'); // Ensure WooCommerce is active if (!class_exists('WooCommerce')) { exit('WooCommerce is not active'); } // Fetch all orders $args = array( 'post_type' => 'shop_order', 'post_status' => array_keys(wc_get_order_statuses()), 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC', ); $orders = get_posts($args); $csv_data = []; // Process each order foreach ($orders as $post) { $order = wc_get_order($post->ID); $data = $order->get_data(); // Basic order info $row = [ 'Order_ID' => $order->get_id(), 'Order_Status' => $order->get_status(), 'Payment_Method' => $data['payment_method_title'] ?? 'NA', 'Total' => $data['total'] ?? 0, 'Tax_Total' => $data['total_tax'] ?? 0, 'Shipping_Total' => $data['shipping_total'] ?? 0, 'COD_Charges' => get_post_meta($order->get_id(), '_cod_charges', true) ?: 0, 'Invoice_Number' => get_post_meta($order->get_id(), '_wcpdf_invoice_number', true) ?: 'NA', 'Invoice_Date' => get_post_meta($order->get_id(), '_wcpdf_invoice_date_formatted', true) ?: 'NA', 'Date_Created' => $data['date_created']->date('Y-m-d H:i:s'), 'Date_Modified' => $data['date_modified']->date('Y-m-d H:i:s'), ]; // Flatten billing info foreach ($data['billing'] as $key => $val) { $row['Billing_' . ucfirst($key)] = $val; } // Flatten shipping info foreach ($data['shipping'] as $key => $val) { $row['Shipping_' . ucfirst($key)] = $val; } // Line items foreach ($order->get_items() as $item) { if (!is_a($item, 'WC_Order_Item_Product')) continue; $product = $item->get_product(); if (!$product) continue; $product_row = $row; $product_row['Product_Name'] = $product->get_name(); $product_row['Quantity'] = $item->get_quantity(); $product_row['Size'] = $product->get_attribute('pa_size'); $product_row['Color'] = $product->get_attribute('pa_color'); $product_row['Rate'] = $product->get_price(); // Sanitize all data foreach ($product_row as $k => $v) { $product_row[$k] = is_scalar($v) ? $v : json_encode($v); } $csv_data[] = $product_row; } } // Serve CSV in memory if (!empty($csv_data)) { header('Content-Type: text/csv'); header('Content-Disposition: attachment; filename="exported_orders.csv"'); $output = fopen('php://output', 'w'); fputcsv($output, array_keys($csv_data[0])); foreach ($csv_data as $row) { fputcsv($output, $row); } fclose($output); exit; } else { echo "No orders to export."; }
Add authentication if this is accessible from the web (e.g., API key via URL parameter or Basic Auth header).
Step 2: Connect Google Apps Script
- Open a Google Sheet
- Go to
Extensions → Apps Script
- Paste the
updateData()
function to pull this CSV and store it in a sheet calledData
- Follow with
generateSalesReport()
andgenerateGSTReport()
functions (see earlier messages)
Update the
url
inupdateData()
like this:var url = "https://yourdomain.com/wp-content/export-secure/export_orders.php?token=your_secure_token_here"
1. Import Orders from Your Endpoint
Use this function to:
- Fetch live order data via
UrlFetchApp
- Parse CSV
- Filter for only
"completed"
orders - Overwrite your
"Data"
sheet with filtered results
function updateData() { const url = "https://yourdomain.com/wp-content/export-secure/export_orders.php?token=your_secure_token_here"; const response = UrlFetchApp.fetch(url); const csvData = Utilities.parseCsv(response.getContentText()); const completed = csvData.filter((row, i) => i === 0 || row[2] === 'completed'); const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data") || SpreadsheetApp.getActiveSpreadsheet().insertSheet("Data"); sheet.clear(); sheet.getRange(1, 1, completed.length, completed[0].length).setValues(completed); }
2. Create a “Sales Report” Sheet
This formats your filtered data, assigns serial numbers (
Sno
), and builds a structured report with invoice numbers like:function generateSalesReport() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const dataSheet = ss.getSheetByName("Data"); const salesSheet = ss.getSheetByName("Sales Report") || ss.insertSheet("Sales Report"); salesSheet.clear(); const data = dataSheet.getDataRange().getValues(); // Sort and structure the report data.sort((a, b) => (a[0] - b[0]) || new Date(b[62]) - new Date(a[62])); const header = data[0].concat(["Sno", "Invoice Date", "Invoice Number"]); const salesData = []; const orderMap = {}; for (let i = 1; i < data.length; i++) { const row = data[i]; const id = row[0]; const date = new Date(row[62]); const sno = orderMap[id] || Object.keys(orderMap).length + 1; orderMap[id] = sno; const invoiceNo = Utilities.formatDate(date, Session.getScriptTimeZone(), "yy-MM") + "-" + id + "-" + ("000000" + sno).slice(-7); salesData.push(row.concat([sno, date, invoiceNo])); } salesSheet.getRange(1, 1, 1, header.length).setValues([header]); salesSheet.getRange(2, 1, salesData.length, header.length).setValues(salesData); }
3. Generate the GST Report for Previous Month
This function:
- Filters last month’s sales
- Groups by order ID
- Computes invoice-level GST
- Creates a new sheet file in Drive
- Emails it as an attachment
function generateGSTReport() { updateData(); generateSalesReport(); const salesSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sales Report"); const data = salesSheet.getDataRange().getValues(); const today = new Date(); const prevMonthStart = new Date(today.getFullYear(), today.getMonth() - 1, 1); const prevMonthEnd = new Date(today.getFullYear(), today.getMonth(), 0, 23, 59, 59, 999); const filtered = data.filter(row => new Date(row[69]) >= prevMonthStart && new Date(row[69]) <= prevMonthEnd); const orders = {}; filtered.forEach(row => { const id = row[0]; const total = parseFloat(row[11]); const tax = parseFloat(row[12]); const name = row[40] + ' ' + row[41]; const state = row[57]; if (!orders[id]) { orders[id] = { orderId: id, invoiceDate: row[69], invoiceNumber: row[70], customerName: name, totalSum: 0, totalTaxSum: 0, totalCount: 0, shippingState: state, }; } orders[id].totalSum += total; orders[id].totalTaxSum += tax; orders[id].totalCount++; }); const rows = [["Order ID", "Invoice Date", "Invoice Number", "Customer Name", "Total Amount", "GST Amount", "Shipping State", "Source State", "GST Rate", "GSTN"]]; Object.values(orders).forEach(o => { rows.push([ o.orderId, o.invoiceDate, o.invoiceNumber, o.customerName, (o.totalSum / o.totalCount).toFixed(2), (o.totalTaxSum / o.totalCount).toFixed(2), o.shippingState, "MH", "12%", "27ABICS6682G1ZU" ]); }); const label = Utilities.formatDate(prevMonthStart, Session.getScriptTimeZone(), "MMM-yy"); const newSheet = SpreadsheetApp.create("GST Report_" + label); newSheet.getSheets()[0].getRange(1, 1, rows.length, rows[0].length).setValues(rows); const folder = DriveApp.getFolderById("your-folder-id"); const file = DriveApp.getFileById(newSheet.getId()); folder.addFile(file); DriveApp.getRootFolder().removeFile(file); const total = Object.values(orders).reduce((a, o) => a + parseFloat(o.totalSum / o.totalCount), 0).toFixed(2); const gst = Object.values(orders).reduce((a, o) => a + parseFloat(o.totalTaxSum / o.totalCount), 0).toFixed(2); GmailApp.sendEmail("you@example.com", `GST Report - ${label}`, `Please find attached the GST report for { enter your GST#}.\nTotal Orders: ${rows.length - 1}\nSales: ₹${total}\nGST: ₹${gst}\n${newSheet.getUrl()}`, { attachments: [file] }); }
Folder Setup Summary
File Location Purpose export_orders.php
/wp-content/export/
Outputs WooCommerce orders in CSV format Google Sheet Any Stores raw data + reports Apps Script Inside Google Sheet Automates pull, processes GST, emails output GST Report Folder Google Drive Archives the monthly reports Example Output (Final Email)
Subject: GST Report – Apr 2025
Body:Please find attached the GST report for GSTN:xxxxxxxxxxxx. Total Orders: 42 Total Sales: ₹3,24,870.00 GST Collected: ₹38,090.00 Report Link: [view on Google Sheets]
Warning: We’ve prepared this script for our internal reporting and hence, you may have adjust references to columns.
Feel free to share your queries in comment.
Can WordPress Be Faster Than Shopify? Yes — If You Know What You’re Doing.
Shopify is built for simplicity. It’s hosted, optimized, and largely hands-off.
But WordPress? It’s raw power. You get full control — but that means speed is your responsibility.If you configure WordPress right, it can be faster, leaner, and more flexible than Shopify. But it won’t happen by accident.
Here’s a no-BS breakdown of what makes WordPress fast — and how to outpace Shopify at its own game.
1. Hosting: Where Speed Begins
Shopify runs on optimized infrastructure. You need to match that firepower.
- Choose LiteSpeed or NGINX-based hosts like Hostinger, Cloudways, or Rocket.net
- Go for Managed WordPress Hosting if you don’t want to tweak configs yourself
- Avoid oversold shared hosting — it’s speed poison
2. Database Hygiene
Shopify manages your DB behind the scenes. WordPress? You need to keep it lean.
- Delete old post revisions, transients, spam comments
- Use tools like WP-Optimize or Advanced Database Cleaner
- Run periodic optimization queries or cron jobs
A bloated
wp_posts
table is one of the top killers of admin speed.3. Caching: The Equalizer
Without caching, WordPress hits the database for every request. Don’t let it.
- Page caching: WP Rocket, LiteSpeed Cache, or W3 Total Cache
- Browser caching: Enable via
.htaccess
or plugin - Object caching: Use Redis or Memcached if supported
Shopify caches by default. WordPress can, but only if you configure it.
4. Themes That Don’t Suck
Your theme matters more than you think.
- Use themes like GeneratePress, Blocksy, or Kadence
- Avoid multipurpose themes with 10MB of JS
- Run GTmetrix or PageSpeed on the demo before you install
Don’t fall for pretty — fall for fast.
5. Content Optimization: Images First
Images are usually the heaviest thing on any site.
- Use WebP, resize before upload, compress everything
- Lazy load images below the fold
- Avoid sliders and background videos unless they’re critical to your UX
Shopify compresses images automatically. You’ll have to do this on WordPress — but you can do it better.
6. Use a CDN
Static assets shouldn’t fly across continents.
- Use Cloudflare, BunnyCDN, or Fastly
- Set cache rules smartly — don’t cache dynamic cart or checkout pages
- Serve fonts, images, and scripts from edge servers
This is where WordPress can outscale Shopify — you choose your stack.
7. Technical Wins Most People Ignore
- Minify & combine CSS/JS
- Enable GZIP or Brotli compression
- Use latest PHP (8.2+)
- Set
cache-control
andexpires
headers properly - Remove unused plugins and themes — don’t just deactivate
Speed is cumulative. Every millisecond matters.
8. Server-Side Power Moves (for advanced users)
- Enable OPcache
- Run scheduled DB maintenance via cron
- Monitor TTFB (Time to First Byte) with tools like GTmetrix or New Relic
- Avoid WooCommerce unless you need eCommerce. It’s heavier than pure WP.
Don’t Expect WordPress to Be Fast by Default
It isn’t. That’s the trade-off for power and control.
But when configured right, WordPress can outperform Shopify — especially for blogs, content-heavy sites, or stores that need flexibility.TL;DR – WordPress Can Be Faster Than Shopify If:
- Your hosting is solid
- You cache everything smartly
- You don’t overload with plugins
- You optimize your images and scripts
- You stay in control of what loads and when
Would love to hear your view in comments.
Auto-Fetch Shopify Orders into Google Sheets Using Apps Script
Sync orders with pagination, filters & timestamp — no plugins.
What You’ll Need
- Shopify access token (
shpat_...
) - Your store name (e.g.,
yourstore
) - A Google Sheet
Step-by-Step Instructions
1. Open Your Google Sheet
Go to Extensions → Apps Script
2. Paste the Script
Replace credentials:
const SHOPIFY_STORE_NAME = 'yourstore'; const SHOPIFY_ACCESS_TOKEN = 'shpat_xxxxxxxxxxxxxxxx';
Then paste the full script below that handles:
- Sheet setup
- Pagination (
page_info
) - Timestamp-based incremental sync
- Field mapping
const SHOPIFY_STORE_NAME = 'your-store-name'; // Replace with your Shopify store name const SHOPIFY_ACCESS_TOKEN = 'shpat_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; // Replace with your access token function fetchShopifyOrders() { const spreadsheet = SpreadsheetApp.getActiveSpreadsheet(); let ordersSheet = spreadsheet.getSheetByName("Orders") || spreadsheet.insertSheet("Orders"); let lastFetchSheet = spreadsheet.getSheetByName("lastfetchtime") || spreadsheet.insertSheet("lastfetchtime"); let lastFetchTime = lastFetchSheet.getRange('A1').getValue(); if (isNaN(new Date(lastFetchTime).getTime())) lastFetchTime = null; let url = `https://${SHOPIFY_STORE_NAME}.myshopify.com/admin/api/2023-01/orders.json?limit=50&order=processed_at asc`; url += lastFetchTime ? `&created_at_min=${new Date(lastFetchTime).toISOString()}&status=any` : `&status=any`; const options = { method: 'get', headers: { "Content-Type": "application/json", "X-Shopify-Access-Token": SHOPIFY_ACCESS_TOKEN } }; let pageInfo = null; let ordersFetched = 0; if (!lastFetchTime) { const headers = ["Order Name", "Date", "Status", "Invoice Value", "GST", "Shipping Charges", "Shipping State", "Fulfillment Status", "Fulfillment Date", "Refunded", "Delivery Status", "AWB/Tracking Number", "Customer Name", "Customer Address", "Product Details"]; ordersSheet.clear(); ordersSheet.appendRow(headers); } do { let fetchUrl = pageInfo ? `https://${SHOPIFY_STORE_NAME}.myshopify.com/admin/api/2023-01/orders.json?limit=50&page_info=${pageInfo}` : url; const response = UrlFetchApp.fetch(fetchUrl, options); const data = JSON.parse(response.getContentText()); const orders = data.orders; if (!orders.length) break; orders.forEach(order => { const rowData = [ order.name, order.created_at, order.financial_status, order.total_price, order.total_tax, order.shipping_lines.length > 0 ? order.shipping_lines[0].price : 0, order.shipping_address?.province || 'Unknown', order.fulfillment_status || 'Unfulfilled', order.fulfillments[0]?.created_at || 'Pending', order.refunds.length > 0 ? 'Yes' : 'No', order.fulfillments.length > 0 ? 'Shipped' : 'Pending', order.fulfillments[0]?.tracking_numbers[0] || 'Pending', order.shipping_address?.name || 'Unknown', order.shipping_address ? `${order.shipping_address.address1}, ${order.shipping_address.city}, ${order.shipping_address.province} - ${order.shipping_address.zip}, ${order.shipping_address.country}` : 'Unknown', order.line_items.map(item => `${item.title} (Qty: ${item.quantity})`).join(', ') ]; ordersSheet.appendRow(rowData); }); Utilities.sleep(1000); const linkHeader = response.getHeaders()['Link']; pageInfo = linkHeader?.includes('rel="next"') ? (linkHeader.match(/<([^>]+)>;\s*rel="next"/)?.[1].split('page_info=')[1]) : null; ordersFetched += orders.length; } while (pageInfo); lastFetchSheet.getRange('A1').setValue(new Date()); }
3. Run the Script Once
- Select
fetchShopifyOrders
- Click ▶️ Run
- Approve OAuth access
- Orders appear in “Orders” sheet
- Timestamp is stored in “lastfetchtime”
4. What It Pulls
Each row includes:
- Order ID & Date
- Payment status & invoice value
- GST & shipping charges
- Fulfillment status + date
- Tracking number
- Customer name & address
- Product summary (
Product A (Qty: 2)
)
5. How It Works
- First run → pulls all orders
- Future runs → pulls only new orders
- Handles Shopify pagination with
page_info
- Sleeps between requests to stay within API limits
- Writes last fetch timestamp to avoid duplicates
Optional Upgrades
Set time-driven trigger (daily/weekly)
Add error logging or Slack/email alerts
Link to dashboards or Data Studio
Security Tip
Never share your
shpat_
key publicly.
Use private sheets or store secrets inPropertiesService
.- Shopify access token (
WP Speed Tip #10 – Lazy Load Like a Pro (And Know When It’s Not Working)
Why It Matters
Lazy loading delays the loading of images until they’re visible on screen.
It’s a no-brainer for speed — especially for image-heavy pages.But here’s the truth:
- Just having
loading="lazy"
in HTML doesn’t guarantee it works. - Some themes/plugins load images via background CSS or JS — bypassing lazy load.
- Improper lazy load can break LCP (Largest Contentful Paint) — killing Core Web Vitals.
The Fix: Confirm Lazy Load Actually Works
Step 1: Check Your Source Code
Open your site → right-click → View Page Source
Look for this inside your
<img>
tags:<img src="image.webp" loading="lazy" alt="..." />
If it’s missing, your theme or plugin isn’t enabling native lazy loading.
Step 2: Use Browser DevTools (Real Check)
- Right-click → Inspect → Network tab
- Reload page with throttling (3G or “Slow 3G”)
- Scroll slowly — watch image requests appear as you scroll
If images load before they appear, lazy loading is not working.
How to Force Lazy Load (If Missing)
Option 1: Use Native WordPress Lazy Loading (Enabled by default in WP 5.5+)
Just make sure your theme outputs standard
<img>
tags — no weird JS-based rendering.Option 2: Manually Add
loading="lazy"
In your theme files (loop, templates, etc.):
<img src="<?php echo $image_url; ?>" loading="lazy" alt="<?php echo $alt_text; ?>">
Option 3: Use a Lightweight Plugin
- Native Lazyload (by Google)
- LiteSpeed Cache (built-in lazyload + fine-tuning)
- Perfmatters (paid, but very effective)
When Not to Use Lazy Load
- On hero images above the fold — they delay LCP
- For logo or brand trust icons
- Background images loaded via
CSS: background-image
(not lazy-loaded by default)
Pro Tip:
Use the
fetchpriority
attribute for hero/primary images:<img src="banner.webp" fetchpriority="high" alt="Hero Image">
Real-World Impact
After replacing JS-based image lazy load with native lazy loading, CLS dropped by 30% and LCP improved from 3.4s to 1.7s.
That wraps up the first 10 tips. Next series coming:
“Real-World WordPress Speed Makeovers (Case Studies + Fixes)”- Just having
WP Speed Tip #9 – Clean Up Unused Plugins and Themes (Don’t Just Deactivate Them)
Why It Matters
Many WordPress users think deactivating a plugin is enough.
It’s not.
Even deactivated plugins:
- Stay in your file system
- Show up in plugin scans
- Are vulnerable to exploits if not updated
- Slow down admin functions like plugin checks and updates
Same goes for themes: that old bloated theme you “tested once” is still sitting in
/wp-content/themes/
.What Happens If You Don’t Clean Up:
- You get bloated update requests on every admin load
- Security risk increases (unused but exposed code = attack surface)
- Backup size increases unnecessarily
- Site scans take longer
- You forget what’s active and what’s not
The Fix: Delete, Don’t Deactivate
Go to:
Dashboard → Plugins → Installed Plugins
- Deactivate anything you’re not using
- Then click “Delete”
- Repeat for all except what’s active and critical
For themes:
Dashboard → Appearance → Themes
- Keep only:
- Your active theme (e.g. GeneratePress/Blocksy)
- One fallback default (e.g. Twenty Twenty-Four)
- Delete the rest
Pro Tip: Delete Sample Content Too
- “Hello World” post
- “Sample Page”
- Default comment
- Unused image sizes in Media Library
- Unused shortcodes or plugin junk left behind (like from Elementor)
Bonus: Use This WP-CLI Command (for advanced users)
wp plugin delete plugin-slug wp theme delete theme-slug
Fastest way to clean up large installs.
Real-World Impact
A client site with 21 deactivated plugins dropped its backup file size from 340MB to 95MB just by deleting unused ones.
Bookmark this tip. Next:
“Tip #10 – Lazy Load Like a Pro (and Know When It’s Not Working)”Setting Up Your Playground (Your First React App)
Quick Recap from the previous post
In our last post, you discovered why React was created — to fix the messiness of pure JavaScript by making UI building faster, smarter, and reusable through components and the Virtual DOM.
Now it’s time to get your hands dirty. In this post, we’ll guide you step-by-step in setting up your React playground so you can start building real things.
Why “Playground”?
Think of your React setup like a digital art studio:
- You install the tools (like brushes and colors)
- You create a canvas (React project)
- And from there, you can make anything — websites, apps, games, or tools
Tools You’ll Need
Tool What It Does Node.js Allows you to run JavaScript outside a browser NPM or Yarn Lets you install packages like React VS Code The code editor where you write your React magic Terminal Like a command-line remote control for your studio Step 1: Install Node.js
Go to https://nodejs.org and download the LTS version. This will install both Node and NPM.
Open PowerShell on Windows or Terminal app on Mac/Linux To verify:
node -v # This checks if Node.js is installed, and shows the version. Example: v20.5.1 npm -v # This checks if npm (Node Package Manager) is installed, and shows its version. Example: 10.2.0
Step 2: Create a New React App
Use Vite (fast and modern) or Create React App (classic and beginner-safe).
Option A: Using Vite (Recommended)
npm create vite@latest my-react-app # This creates a new React project named "my-react-app" using Vite. # You'll be asked to pick a framework — choose "React" and then "JavaScript" (not TypeScript, for now). # Use npx vite@latest # As a fallback if 'npm create vite@latest' doesn't work cd my-react-app # This moves you into the project folder you just created. npm install # This installs all the required packages (React, Vite, etc.) listed in package.json. npm run dev # This starts a local development server. # Open your browser and visit http://localhost:5173 to see your first React app live!
Option B: Using Create React App (slower)
npx create-react-app my-react-app # This downloads and sets up a full React project named "my-react-app" using Create React App. # It may take a few minutes the first time. cd my-react-app # Move into the project directory. npm start # Starts the development server. # Open your browser and visit http://localhost:3000 to see your app running!
Pro Tip for Beginners
- If
npm start
ornpm run dev
doesn’t open your browser, just go to the link shown in your terminal (usuallyhttp://localhost:3000
orhttp://localhost:5173
). - You can stop the server anytime by pressing
Ctrl + C
in your terminal.
Step 3: Open in VS Code
- Open VS Code
- Click
File > Open Folder
and selectmy-react-app
- Your React app is ready!
Step 4: Explore the Files
src/App.jsx
→ Where you’ll start writing your componentspublic/index.html
→ The single page your React app lives inpackage.json
→ List of tools your app uses
What You Just Did
- Installed Node & React
- Created a working React project
- Ran your first React app in the browser (
localhost:5173
orlocalhost:3000
) - Took your first real step into the world of frontend dev
Try This
Open
src/App.jsx
and change:<h1>Hello React</h1>
to
<h1>Hello! I built my first React app!</h1>
Save → Browser updates instantly
This is the magic of React!
What’s Next?
In the next post:
“Understanding Components – Your Building Blocks”
We’ll start writing your first custom React components and begin building your UI piece-by-piece.WP Speed Tip #8 – Remove WooCommerce Dashboard Bloat for Faster Admin
Why It Matters
WooCommerce is great — but the default install clutters your admin dashboard with:
- Analytics blocks you never use
- Marketing suggestions
- Extensions you didn’t ask for
- Admin scripts and styles loading even when not needed
All this:
- Slows down your dashboard
- Eats up memory on shared hosting
- Distracts you from real work
The Fix: Disable WooCommerce Admin Junk
add_filter( 'woocommerce_admin_disabled', '__return_true' );
This disables the entire new admin interface (called
wc-admin
) including:- WooCommerce Analytics
- Marketing hub
- Inbox notices
- Background data sync
Your dashboard becomes lighter, faster, and less annoying.
Optional Cleanup – Remove WooCommerce Styles/Blocks
remove_action( 'admin_enqueue_scripts', 'wc_enqueue_admin_styles' ); remove_action( 'admin_enqueue_scripts', 'wc_admin_assets' );
Only do this if you don’t need advanced reports or order analytics in the dashboard.
Extra Bloat to Consider Removing:
- Jetpack integration (not required for Woo)
- WooCommerce’s built-in “Marketing” menu
- WooCommerce Blocks plugin (if not using Gutenberg for products)
Use the “Disable WooCommerce Bloat” plugin if you prefer a click-to-disable interface.
Real Impact
After disabling
wc-admin
, dashboard load time dropped from 3.4s to under 1.2s on a modest shared host.Less RAM use, fewer background AJAX calls, and a cleaner experience.
What You Still Keep After Disabling
- Orders
- Products
- Coupons
- Standard Woo settings
- Email functionality
- Checkout and cart – untouched
Bonus: Enable Admin Only When Needed
if ( current_user_can('administrator') ) { add_filter( 'woocommerce_admin_disabled', '__return_true' ); }
So it only disables for admins, or only on staging/dev.
Bookmark this tip. Coming up next:
“Tip #9 – Clean Up Unused Plugins and Themes (Don’t Just Deactivate Them)”WP Speed Tip #7 – Self-Host Fonts to Eliminate External Requests
Why It Matters
Most WordPress sites use Google Fonts by default. Here’s what happens:
- Each font = 2–3 extra external requests
- These block rendering until fonts are downloaded
- You lose Core Web Vitals points (especially on mobile)
Google Fonts are “free,” but they make your site wait.
Self-hosting = no waiting.What’s Wrong with Using Google Fonts?
- Fonts are fetched from
fonts.googleapis.com
andfonts.gstatic.com
- Adds DNS lookup, TLS handshake, and 100–200ms+ delay
- CLS (Cumulative Layout Shift) increases if fallback fonts are shown first
The Fix: Self-Host Your Fonts
Option 1: Use System Fonts (Fastest)
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
Native to all major OS. No downloads. Zero delay.
Option 2: Self-Host Custom Fonts (Like Roboto, Inter, etc.)
Step-by-Step:
- Download the font from Google Fonts
- Use Google Webfonts Helper to:
- Get
.woff2
versions (smallest + fastest) - Generate
@font-face
CSS
- Get
- Upload fonts to:
/wp-content/themes/your-theme/fonts/
- Paste this
@font-face
CSS into your theme’sstyle.css
:
@font-face { font-family: 'Inter'; src: url('/wp-content/themes/your-theme/fonts/inter.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
font-display: swap;
is critical — it shows fallback font immediately, avoiding CLS.- Replace all theme font references with your custom font.
What Not to Do
- Don’t leave both Google Fonts and self-hosted fonts active
- Don’t upload
.ttf
or.otf
— use.woff2
only
Real Impact
Before self-hosting:
- 6 external font requests
- CLS penalty
- Render delay on mobile
After:
- 0 external requests
- Instant font rendering
- Fewer layout shifts
Pro Tip:
If using GeneratePress, Blocksy, or Kadence, they all allow custom font uploads via their settings panel — no code needed.
Bookmark this tip. Next up:
“Tip #8 – Remove WooCommerce Dashboard Bloat for Faster Admin”Build Your Own WordPress Theme from Scratch — Here’s the Full Roadmap
Hey there, fellow builder.
If you’re tired of bloated themes, messy page builders, and slow-loading sites — you’re not alone.
I was in the same boat. That’s why I started learning how to build a WordPress theme from scratch.And now, I’m documenting the entire process for people like you — bloggers, devs, solopreneurs — who want speed, control, and freedom.
So here’s the full roadmap. Bookmark this post — every point below will become its own blog post with live code, screenshots, and examples.
Phase 1: Set Up Your Playground (Pick One)
1. Local vs Server — Which One’s for You?
We’ll compare LocalWP (super simple) vs a Server setup (more control).
TL;DR – Use LocalWP if you want to get started quickly. Use Server if you’re building for real-world deployment.
2. Installing WordPress (LocalWP & Server Guide)
Whichever you choose, this post will walk you through installing WordPress from scratch.
Phase 2: Build the Theme (The Fun Begins)
3. Your First Barebones Theme
Create your own folder. Add two files:
style.css
andindex.php
. Boom — it’s a theme.4. Add a Header & Footer (Don’t Repeat Yourself)
Split your layout cleanly. Bring in
get_header()
andget_footer()
.5. Understand the Template Hierarchy (Secret Weapon)
Why is WordPress showing the wrong layout? This will help you fix that forever.
6. Master the Loop (Your Theme’s Heartbeat)
The magic behind showing posts. Learn
have_posts()
,the_post()
,the_title()
and friends.7. Enqueue CSS & JS (The Right Way)
Don’t dump
<link>
or<script>
into yourheader.php
. WordPress has a better way.8. Build a Blog Index with Excerpts
Show post title, excerpt, and a “Read More” link. Just like a clean blog homepage should.
9. Design the Single Post Layout
Add featured images, meta (author/date), and next/prev post links.
10. Style It Without Bloat
Keep it lightweight. No frameworks. Use just CSS and learn to make things beautiful.
11. Add Menus and Sidebars
Turn your site into a real website with navigation and optional widgets.
12. Make It Responsive (Mobile-First)
Mobile visitors matter. We’ll cover responsive layout, images, and hamburger menus.
13. Custom Page Templates
Want a custom layout for your homepage or landing page? This is how you do it.
14. Prep Your Theme for Use or Sale
Add
screenshot.png
, cleanup your code, license it, and zip it for real-world use.Phase 3: Go Beyond Basics
15. Add a Custom Homepage with Featured Posts
Build a beautiful, minimal homepage without page builders.
16. Deploy Your Theme to a Live Server
Move your theme from local to production. No mess, no errors.
What’s Next?
In future posts, we may cover:
- SEO basics for theme devs
- Gutenberg compatibility
- Adding WooCommerce support
- Theme customizer (for end users)
- Releasing to the WordPress repo or ThemeForest
Let’s Keep It Interactive
If you’re following this series:
- Drop a comment or message me what setup you’re using (LocalWP or Server).
- I’ll tailor the next tutorial based on the most common choices.
- Share what kind of site you’re trying to build — blog, store, portfolio?
Let’s do this. No builders. No bloat. Just pure control.
🔔 Next post: Local vs Server – Which is Right for You? (Publishing soon)
Why Serious Entrepreneurs Should Avoid Bluehost (And What to Use Instead)
If you’re building a real business — whether it’s a blog, a store, or a startup — your hosting provider is not just a technical detail. It’s your foundation. And Bluehost? It’s a trap disguised as a budget-friendly solution. Here’s why it’s not fit for serious creators.
1. Cheap Hosting Comes at a Cost
Yes, Bluehost is cheap. That’s the bait. But once you’re in, the real cost shows up as:
- Sluggish website speeds
- Frequent downtime
- Weak security
- Support that disappears when you need it most
These aren’t minor glitches. They directly impact your conversions, SEO rankings, and user trust.
2. Not Built for Growth
You might think: I’ll start cheap and upgrade later.
Here’s the problem — Bluehost isn’t designed to grow with you. Whether you’re running a content-heavy blog, an e-commerce site, or even a basic portfolio, you’ll quickly hit performance ceilings.You’ll waste hours debugging server issues instead of building your business.
3. Bloated Backend and Aggressive Upsells
Bluehost’s dashboard is packed with clutter. Need a simple task done? Expect delays.
And every time you log in, you’ll be pitched add-ons and upgrades you don’t need. It’s built to extract money — not to help you scale.4. Migration Pain Is Real
Once you realize Bluehost is holding you back, getting out isn’t easy — especially if you’re not a developer. Their infrastructure isn’t migration-friendly, and their support won’t lift a finger.
5. Better Alternatives Exist
You don’t need enterprise-grade hosting, but you do need reliability.
Here are some solid options that respect your business:- Cloudways – Great balance of control and performance
- SiteGround – Strong support and performance
- FastComet – Reliable with global datacenters
- VPS (e.g., DigitalOcean, Linode) – For developers or those ready to scale with custom setups
Build on a Strong Foundation
Bluehost is fine for hobby sites and student projects — not for brands aiming to scale. If you’re serious about building a business, skip Bluehost. Save yourself the frustration and start with hosting that’s built to grow with you.
© 2025 the-playbook.in. All rights reserved.