<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ WordPress - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ WordPress - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 22:20:14 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/wordpress/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Headless WordPress Frontend with Astro SSR on Cloudflare Pages ]]>
                </title>
                <description>
                    <![CDATA[ This tutorial shows you how to run WordPress as a headless CMS with an Astro frontend deployed to Cloudflare Pages. For a project I was recently working on, the requirement was to use WordPress as the ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-headless-wordpress-frontend-with-astro-ssr-on-cloudflare-pages/</link>
                <guid isPermaLink="false">69e65d6ec9501dd0100e2105</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Astro ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cloudflare ]]>
                    </category>
                
                    <category>
                        <![CDATA[ headless cms ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Tech With RJ ]]>
                </dc:creator>
                <pubDate>Mon, 20 Apr 2026 17:07:58 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/605584805f8d5121697263ca/87087639-b2d1-4641-a2c9-f8f369b49406.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>This tutorial shows you how to run WordPress as a headless CMS with an Astro frontend deployed to Cloudflare Pages.</p>
<p>For a project I was recently working on, the requirement was to use WordPress as the site's backend. Content management, blog posts, and media were all handled through the WordPress admin. The frontend was open: it could be a theme, a template, or something customized through Elementor.</p>
<p>I could've built the same result in Elementor, but the process would've been slower and harder to maintain. Drag-and-drop works until the design gets specific, and then every small tweak costs more time than it should.</p>
<p>As a full stack developer, writing code turned out to be faster for me and produced cleaner output. Tools like Claude Code make the iteration cycle even tighter. So I kept the requirement –&nbsp;WordPress as the backend – and decided to build the frontend separately in code.</p>
<p>I wanted to share how I did this so that, if you're facing similar requirements, you'll know the way forward.</p>
<p>By the end of this tutorial, you'll have:</p>
<ul>
<li><p>A WordPress install serving content through its REST API on a subdomain</p>
</li>
<li><p>An Astro SSR frontend rendering the content on the root domain</p>
</li>
<li><p>A Cloudflare Pages deployment triggered on every git push</p>
</li>
<li><p>Security hardening for a headless WordPress setup</p>
</li>
<li><p>Draft post preview working across both systems</p>
</li>
</ul>
<p><strong>Prerequisites:</strong> You should be comfortable with the command line, have basic familiarity with WordPress admin, and know enough JavaScript to read and write simple functions.</p>
<p>To follow along, you'll need a WordPress installation, a GitHub account, and a Cloudflare account.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-why-headless-wordpress">Why Headless WordPress?</a></p>
</li>
<li><p><a href="#heading-the-architecture">The Architecture</a></p>
</li>
<li><p><a href="#heading-why-astro">Why Astro?</a></p>
</li>
<li><p><a href="#heading-infrastructure-setup">Infrastructure Setup</a></p>
<ul>
<li><p><a href="#heading-step-1-move-dns-to-cloudflare">Step 1: Move DNS to Cloudflare</a></p>
</li>
<li><p><a href="#heading-step-2-create-the-cms-subdomain">Step 2: Create the CMS Subdomain</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-wordpress-configuration">WordPress Configuration</a></p>
<ul>
<li><p><a href="#heading-tell-wordpress-it-lives-on-the-subdomain">Tell WordPress it Lives on the Subdomain</a></p>
</li>
<li><p><a href="#heading-must-use-plugin-redirect-and-preview">Must-Use Plugin: Redirect and Preview</a></p>
</li>
<li><p><a href="#heading-clean-up-plugins">Clean Up Plugins</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-the-astro-frontend">The Astro Frontend</a></p>
<ul>
<li><p><a href="#heading-astroconfigmjs">astro.config.mjs</a></p>
</li>
<li><p><a href="#heading-env">.env</a></p>
</li>
<li><p><a href="#heading-srclibwordpressjs">src/lib/wordpress.js</a></p>
</li>
<li><p><a href="#heading-srcmiddlewarejs">src/middleware.js</a></p>
</li>
<li><p><a href="#heading-srclayoutslayoutastro">src/layouts/Layout.astro</a></p>
</li>
<li><p><a href="#heading-srcpagesblogindexastro">src/pages/blog/index.astro</a></p>
</li>
<li><p><a href="#heading-srcpagesblogslugastro">src/pages/blog/[slug].astro</a></p>
</li>
<li><p><a href="#heading-srcpagessitemapxmlts">src/pages/sitemap.xml.ts</a></p>
</li>
<li><p><a href="#heading-srcstylesglobalcss">src/styles/global.css</a></p>
</li>
</ul>
</li>
<li><p><a href="#heading-cicd-with-cloudflare-pages">CI/CD with Cloudflare Pages</a></p>
</li>
<li><p><a href="#heading-final-thoughts">Final Thoughts</a></p>
</li>
<li><p><a href="#heading-good-to-know">Good to Know</a></p>
</li>
</ul>
<h2 id="heading-why-headless-wordpress">Why Headless WordPress?</h2>
<p>Headless WordPress separates content management from content delivery. WordPress keeps doing what it handles well: storing content and giving editors a familiar admin interface. A separate frontend handles rendering, routing, and performance.</p>
<p>A few situations where this split pays off:</p>
<ul>
<li><p>Your content team is trained on WordPress and moving them elsewhere would slow everyone down. Headless preserves their workflow and gives you a modern frontend.</p>
</li>
<li><p>Your site needs a design or interaction pattern that a WordPress theme or page builder struggles to deliver. Custom dashboards, interactive tools, data-driven layouts, or integrations with non-WordPress APIs all fit here.</p>
</li>
<li><p>You want edge delivery and modern tooling without rebuilding content management from scratch. WordPress handles content and media well. A JavaScript frontend on a CDN handles delivery well. Headless lets each side do its job.</p>
</li>
<li><p>You need the same content across multiple surfaces. One WordPress install feeds a marketing site, a mobile app, and an internal dashboard through the same REST API.</p>
</li>
</ul>
<p>Headless is not a fit for every site. Skip it if your site is a simple brochure, if one person does everything in the admin, or if you have no developer time to maintain a second codebase. A regular WordPress theme is the better answer there.</p>
<h2 id="heading-the-architecture">The Architecture</h2>
<p>The term "headless" means you strip WordPress of its frontend responsibility. Instead of WordPress generating and serving HTML pages to visitors, it only stores and serves content through its REST API. A separate frontend framework, in this case Astro, handles what the visitor actually sees.</p>
<img src="https://cdn.hashnode.com/uploads/covers/605584805f8d5121697263ca/0508174b-0740-47cf-a780-943a0c254ae1.png" alt="Diagram of a headless WordPress setup with Cloudflare Pages and Astro SSR fetching content via the WordPress REST API, with GitHub auto-deploy and a CMS subdomain for editors." style="display:block;margin:0 auto" width="7093" height="1017" loading="lazy">

<p>When a visitor loads a page, the request hits Cloudflare Pages, which runs the Astro server. Astro fetches the relevant content from WordPress via the REST API, builds the HTML, and returns it to the visitor. WordPress never touches the visitor's browser.</p>
<p>Content editors log into the WordPress admin at the CMS subdomain. They write, publish, and manage content as they normally would. The moment they publish, the content is live. There's no rebuild step because Astro fetches fresh data on every request.</p>
<p>The REST API has been built into WordPress since version 4.7. You don't need a GraphQL plugin, a paid headless CMS service, or any extra infrastructure.</p>
<h2 id="heading-why-astro">Why Astro?</h2>
<p>You could use Next.js, Nuxt, or SvelteKit here as well. But I chose Astro because its defaults fit this use case.</p>
<p>Astro compiles components to plain HTML and ships zero JavaScript to the browser by default. You only add client-side JavaScript where you explicitly need it.</p>
<p>For a CMS-driven site, most pages need none. SSR mode means every request fetches fresh data from WordPress at runtime, so content changes go live immediately without a rebuild. Cloudflare has an official adapter that handles the build output. Tailwind v4 integrates through a Vite plugin with no config file needed.</p>
<p>If WordPress wasn't a requirement, I would have used Next.js with Payload CMS. Payload gives you a fully typed CMS built in TypeScript that sits inside the same Next.js project, with more control over your content schema from day one. But the requirement was WordPress, and for a WordPress REST API frontend, Astro is the faster and cleaner choice.</p>
<h2 id="heading-infrastructure-setup">Infrastructure Setup</h2>
<p>Here's my setup: domain at Namecheap, WordPress on Hostinger shared hosting, and a Google Workspace email. The steps below apply to any host, whether shared hosting with cPanel or hPanel, a VPS with Apache or Nginx, or a self-managed server.</p>
<h3 id="heading-step-1-move-dns-to-cloudflare">Step 1: Move DNS to Cloudflare</h3>
<p>First, you'll need to move your domain's nameservers to Cloudflare. This gives you free DDoS protection, SSL, and the ability to attach a custom domain to Cloudflare Pages.</p>
<p>Before switching, verify that all DNS records transferred correctly, including your website A or CNAME records. For email, get your MX, SPF, DKIM, and DMARC values from your email provider's admin panel and add them to Cloudflare DNS first, otherwise email breaks during propagation.</p>
<h3 id="heading-step-2-create-the-cms-subdomain">Step 2: Create the CMS Subdomain</h3>
<p>Move WordPress to <code>cms.yourdomain.com</code> so the root domain is free for Astro. In Cloudflare DNS, add an A record pointing <code>cms</code> at your server IP, or a CNAME if your host uses a CDN hostname. Then create the subdomain in your hosting panel pointing to the same WordPress directory.</p>
<p>One thing people miss: your server needs its own SSL certificate for the connection between Cloudflare and your origin to work. Cloudflare handles SSL at its edge, but if the origin has no certificate, you get a 525 error.</p>
<p>On Hostinger, this isn't automatic for new subdomains. Install it manually through hPanel. On cPanel, use Let's Encrypt. On a VPS, use Certbot.</p>
<p>Moving WordPress off the root domain also means <code>/wp-admin</code> no longer exists at your main domain, which reduces exposure. But the default login path is still <code>/wp-admin</code> on the subdomain. That is the first thing you should change — more on this in the Good to Know section at the end.</p>
<h2 id="heading-wordpress-configuration">WordPress Configuration</h2>
<h3 id="heading-tell-wordpress-it-lives-on-the-subdomain">Tell WordPress it Lives on the Subdomain</h3>
<p>In <code>wp-config.php</code>, before the "That's all, stop editing!" comment:</p>
<pre><code class="language-php">define('WP_HOME',    'https://cms.yourdomain.com');
define('WP_SITEURL', 'https://cms.yourdomain.com');
</code></pre>
<p>WordPress admin is now at <code>cms.yourdomain.com/wp-admin</code>. The old path at the root domain stops working. That's intentional.</p>
<h3 id="heading-must-use-plugin-redirect-and-preview">Must-Use Plugin: Redirect and Preview</h3>
<p>WordPress has a folder called <code>mu-plugins</code> inside <code>wp-content</code>. Files placed there are treated as must-use plugins. They load automatically on every request, before regular plugins, and there is no way to activate or deactivate them through the admin UI. This makes them the right place for behaviour you never want accidentally turned off.</p>
<p>Create <code>wp-content/mu-plugins/headless-redirect.php</code>:</p>
<pre><code class="language-php">&lt;?php
/*
Plugin Name: Headless Redirect
Description: Redirects frontend visitors to the Astro site and rewires the WordPress preview link.
*/

add_action('template_redirect', function() {
    if (is_user_logged_in()) return;
    if ($_SERVER['HTTP_HOST'] === 'cms.yourdomain.com') {
        wp_redirect('https://yourdomain.com', 302);
        exit;
    }
});

add_filter('preview_post_link', function(\(link, \)post) {
    $token = HEADLESS_PREVIEW_SECRET;
    \(type  = \)post-&gt;post_type;
    return 'https://yourdomain.com/preview?type=' . \(type . '&amp;id=' . \)post-&gt;ID . '&amp;token=' . $token;
}, 10, 2);
</code></pre>
<p>The <code>template_redirect</code> action fires when WordPress is about to render a page. If the visitor isn't logged in and the request is on the CMS subdomain, it redirects them to the main frontend. Logged-in editors pass through to the admin normally. REST API requests to <code>/wp-json/...</code> don't go through <code>template_redirect</code> at all, so they are unaffected.</p>
<p>The <code>preview_post_link</code> filter changes what happens when an editor clicks Preview on a draft post. By default, WordPress previews using its own theme, which in a headless setup renders blank.</p>
<p>This filter replaces that URL with a request to your Astro <code>/preview</code> page, passing the post ID, post type, and a secret token. Your Astro preview page uses those values to fetch the draft via the REST API and renders it exactly as it would appear live.</p>
<h3 id="heading-clean-up-plugins">Clean Up Plugins</h3>
<p>Now it's time to remove everything that renders the frontend: page builders, caching plugins, and hosting onboarding plugins.</p>
<p>But you'll want to keep Akismet, Wordfence, and Yoast SEO. Yoast adds SEO meta and Open Graph data directly to the REST API response, which your Astro pages read through <code>post.yoast_head_json</code>.</p>
<p>Then switch the active theme to a lightweight default. WordPress requires one active, but nobody sees it.</p>
<h2 id="heading-the-astro-frontend">The Astro Frontend</h2>
<p>Start with <code>pnpm create astro@latest</code>, then install the Cloudflare adapter and Tailwind:</p>
<pre><code class="language-bash">pnpm add @astrojs/cloudflare
pnpm add -D @tailwindcss/vite tailwindcss
</code></pre>
<h3 id="heading-astroconfigmjs">astro.config.mjs</h3>
<pre><code class="language-js">import { defineConfig } from 'astro/config'
import cloudflare from '@astrojs/cloudflare'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  output: 'server',
  adapter: cloudflare({ imageService: 'passthrough' }),
  vite: { plugins: [tailwindcss()] },
})
</code></pre>
<p><code>output: 'server'</code> puts Astro into full SSR mode. Without it, Astro pre-renders pages at build time, which breaks dynamic routes like <code>/blog/[slug]</code> that depend on WordPress content that didn't exist at build time.</p>
<p><code>imageService: 'passthrough'</code> is required specifically for Cloudflare Workers. Astro's default image service uses Sharp, which depends on <code>child_process</code> and <code>fs</code>. Those Node.js built-ins don't exist in the Cloudflare Workers runtime. The deployment fails with a module resolution error. Setting passthrough skips image processing entirely and renders standard <code>&lt;img&gt;</code> tags instead.</p>
<h3 id="heading-env">.env</h3>
<pre><code class="language-bash">WORDPRESS_API_URL=https://cms.yourdomain.com
</code></pre>
<p>Add this same variable in Cloudflare Pages project settings under Environment Variables before deploying.</p>
<h3 id="heading-srclibwordpressjs">src/lib/wordpress.js</h3>
<p>This file is the single place all WordPress API calls go through. Centralising them means if the API URL or authentication changes, you update one file.</p>
<p>The <code>_embed</code> parameter is important. By default, a post response only includes the post data. Featured images, author details, and categories are separate entities with their own IDs. Without <code>_embed</code>, you would need additional API requests to fetch each one. Adding it inlines all that related data into the same response.</p>
<p><code>cache: 'no-store'</code> on every fetch call is not optional. Cloudflare Workers runs a fetch cache internally that's separate from HTTP <code>Cache-Control</code> headers. Without disabling it, Cloudflare caches your WordPress API responses at the edge. An editor publishes a post and sees the old version on the frontend because the cached response is being served.</p>
<pre><code class="language-js">const WP_URL = import.meta.env.WORDPRESS_API_URL

const fetchWP = (path) =&gt;
  fetch(`\({WP_URL}\){path}`, { cache: 'no-store' }).then((r) =&gt; r.json())

export const getPosts = (page = 1, perPage = 10) =&gt;
  fetchWP(`/wp-json/wp/v2/posts?_embed&amp;per_page=\({perPage}&amp;page=\){page}`)

export const getPostBySlug = async (slug) =&gt; {
  const posts = await fetchWP(`/wp-json/wp/v2/posts?_embed&amp;slug=${slug}`)
  return posts[0]
}

export const getCategories = () =&gt;
  fetchWP(`/wp-json/wp/v2/categories`)

export const getPostsByCategory = (categoryId, page = 1) =&gt;
  fetchWP(`/wp-json/wp/v2/posts?_embed&amp;categories=\({categoryId}&amp;page=\){page}`)

export const getAllPostsForSitemap = () =&gt;
  fetchWP(`/wp-json/wp/v2/posts?_fields=slug,modified&amp;per_page=100`)
</code></pre>
<p>The sitemap function uses <code>_fields</code> instead of <code>_embed</code> to fetch only the fields it needs, keeping that request lightweight.</p>
<h3 id="heading-srcmiddlewarejs">src/middleware.js</h3>
<p>Middleware runs on every request before the page handler. This one adds <code>Cache-Control: no-store</code> to every SSR response so Cloudflare doesn't cache the rendered HTML pages.</p>
<pre><code class="language-js">export function onRequest(_context, next) {
  return next().then(response =&gt; {
    const newResponse = new Response(response.body, response)
    newResponse.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate')
    newResponse.headers.set('CDN-Cache-Control', 'no-store')
    return newResponse
  })
}
</code></pre>
<p>The original Response from Astro has immutable headers, so you can't call <code>.headers.set()</code> on it directly. The fix is to construct a new Response using the original body and response as the init argument. The new Response has mutable headers, so <code>.set()</code> works. <code>CDN-Cache-Control</code> is a Cloudflare-specific header that controls caching at the edge independently from the standard <code>Cache-Control</code> header.</p>
<h3 id="heading-srclayoutslayoutastro">src/layouts/Layout.astro</h3>
<p>Every page goes through this layout. HTML structure, meta tags, and global imports live here so you don't repeat them on every page.</p>
<pre><code class="language-astro">---
interface Props {
  title: string
  description?: string
}
const { title, description = '' } = Astro.props
---
&lt;!doctype html&gt;
&lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
    &lt;title&gt;{title}&lt;/title&gt;
    &lt;meta name="description" content={description} /&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;slot name="nav" /&gt;
    &lt;main id="main-content"&gt;&lt;slot /&gt;&lt;/main&gt;
    &lt;slot name="footer" /&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p>Named slots let the navbar and footer sit outside <code>&lt;main&gt;</code>, keeping the HTML landmark structure correct for accessibility.</p>
<h3 id="heading-srcpagesblogindexastro">src/pages/blog/index.astro</h3>
<pre><code class="language-astro">---
import Layout from '../../layouts/Layout.astro'
import { getPosts, getCategories, getPostsByCategory } from '../../lib/wordpress'

const page = Number(Astro.url.searchParams.get('page') ?? 1)
const categoryId = Astro.url.searchParams.get('category')

const [posts, categories] = await Promise.all([
  categoryId ? getPostsByCategory(categoryId, page) : getPosts(page, 10),
  getCategories(),
])
---
&lt;Layout title="Blog"&gt;
  &lt;nav&gt;
    &lt;a href="/blog"&gt;All&lt;/a&gt;
    {categories.map((cat) =&gt; (
      &lt;a href={`/blog?category=${cat.id}`}&gt;{cat.name}&lt;/a&gt;
    ))}
  &lt;/nav&gt;

  &lt;ul&gt;
    {posts.map((post) =&gt; {
      const image   = post._embedded?.['wp:featuredmedia']?.[0]?.source_url
      const imageAlt = post._embedded?.['wp:featuredmedia']?.[0]?.alt_text ?? ''
      return (
        &lt;li&gt;
          {image &amp;&amp; &lt;img src={image} alt={imageAlt} /&gt;}
          &lt;a href={`/blog/${post.slug}`} set:html={post.title.rendered} /&gt;
          &lt;div set:html={post.excerpt.rendered} /&gt;
        &lt;/li&gt;
      )
    })}
  &lt;/ul&gt;

  {page &gt; 1 &amp;&amp; &lt;a href={`/blog?page=${page - 1}`}&gt;Previous&lt;/a&gt;}
  &lt;a href={`/blog?page=${page + 1}`}&gt;Next&lt;/a&gt;
&lt;/Layout&gt;
</code></pre>
<p><code>Promise.all</code> fetches posts and categories in parallel. The category filter reads from the URL query string so the same page handles both <code>/blog</code> and <code>/blog?category=5</code> without separate routes.</p>
<p>Featured images live inside <code>post._embedded['wp:featuredmedia'][0]</code> because <code>_embed</code> inlines the media object into the post response.</p>
<h3 id="heading-srcpagesblogslugastro">src/pages/blog/[slug].astro</h3>
<pre><code class="language-astro">---
import Layout from '../../layouts/Layout.astro'
import { getPostBySlug } from '../../lib/wordpress'

const { slug } = Astro.params
const post = await getPostBySlug(slug)
if (!post) return Astro.redirect('/404')

const image    = post._embedded?.['wp:featuredmedia']?.[0]?.source_url
const imageAlt = post._embedded?.['wp:featuredmedia']?.[0]?.alt_text ?? ''
const author   = post._embedded?.author?.[0]?.name
const seoTitle = post.yoast_head_json?.title ?? post.title.rendered
const seoDesc  = post.yoast_head_json?.og_description ?? ''
---
&lt;Layout title={seoTitle} description={seoDesc}&gt;
  &lt;article&gt;
    &lt;h1 set:html={post.title.rendered} /&gt;
    &lt;p&gt;{author} · {new Date(post.date).toLocaleDateString()}&lt;/p&gt;
    {image &amp;&amp; &lt;img src={image} alt={imageAlt} /&gt;}
    &lt;div set:html={post.content.rendered} /&gt;
  &lt;/article&gt;
&lt;/Layout&gt;
</code></pre>
<p>Use <code>set:html</code> for WordPress content, not <code>{post.content.rendered}</code>. Astro treats curly brace expressions as text and escapes the HTML, so you see raw tags printed on the page instead of rendered content.</p>
<p>Always guard with <code>if (!post) return Astro.redirect('/404')</code>. If someone visits a slug that doesn't exist, the API returns an empty array. Without the guard, accessing properties on <code>undefined</code> throws an error that crashes the Cloudflare Worker and returns a 500.</p>
<p><code>post.yoast_head_json</code> is available when Yoast SEO is active. It contains the computed SEO title and description that Yoast generates. Using it means the SEO work done in WordPress carries over to the Astro frontend automatically.</p>
<h3 id="heading-srcpagessitemapxmlts">src/pages/sitemap.xml.ts</h3>
<pre><code class="language-ts">import type { APIRoute } from 'astro'
import { getAllPostsForSitemap } from '../lib/wordpress'

export const GET: APIRoute = async () =&gt; {
  const posts = await getAllPostsForSitemap()

  const urls = [
    { loc: 'https://yourdomain.com/', lastmod: new Date().toISOString() },
    { loc: 'https://yourdomain.com/blog/', lastmod: new Date().toISOString() },
    ...posts.map((p) =&gt; ({
      loc: `https://yourdomain.com/blog/${p.slug}/`,
      lastmod: p.modified,
    })),
  ]

  const xml = `&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"&gt;
\({urls.map((u) =&gt; `  &lt;url&gt;\n    &lt;loc&gt;\){u.loc}&lt;/loc&gt;\n    &lt;lastmod&gt;${u.lastmod}&lt;/lastmod&gt;\n  &lt;/url&gt;`).join('\n')}
&lt;/urlset&gt;`

  return new Response(xml, { headers: { 'Content-Type': 'application/xml' } })
}
</code></pre>
<p>This generates fresh XML on every request, so the sitemap always reflects currently published posts without a rebuild.</p>
<h3 id="heading-srcstylesglobalcss">src/styles/global.css</h3>
<pre><code class="language-css">@import "tailwindcss";

@theme {
  --color-brand: #your-color;
  --font-sans: 'Your Font', sans-serif;
}
</code></pre>
<p>Tailwind v4 uses CSS-first configuration through the <code>@theme</code> block. CSS variables defined here become Tailwind utilities automatically. <code>--color-brand</code> becomes <code>bg-brand</code>, <code>text-brand</code>, and so on. No <code>tailwind.config.js</code> needed.</p>
<h2 id="heading-cicd-with-cloudflare-pages">CI/CD with Cloudflare Pages</h2>
<p>With the Astro code in place, the last piece is getting it deployed. Cloudflare Pages connects directly to GitHub, so you don't have to maintain a separate pipeline.</p>
<p>Here are the steps:</p>
<ol>
<li><p>Push your repo to GitHub.</p>
</li>
<li><p>Go to Cloudflare Pages, create a project, connect it to your GitHub repository.</p>
</li>
<li><p>Set the build command to <code>pnpm build</code> and the output directory to <code>dist</code>.</p>
</li>
<li><p>Under Environment Variables, add <code>WORDPRESS_API_URL</code> pointing to <code>https://cms.yourdomain.com</code>.</p>
</li>
<li><p>Deploy.</p>
</li>
</ol>
<p>After the first deploy, every push to <code>main</code> triggers a new deployment automatically. Cloudflare runs the build, and within minutes the new version is live globally. Content updates in WordPress go live immediately, since Astro fetches from WordPress on every request. A developer pushing code and an editor publishing a post are completely independent operations.</p>
<h2 id="heading-final-thoughts">Final Thoughts</h2>
<p>This setup exists because of the specific requirement that the content team was already on WordPress and changing that was not on the table.</p>
<p>If you're starting fresh with no CMS in place, this is probably not the stack you want. Go with something like Next.js and Payload CMS where the backend and frontend are designed to work together from the start.</p>
<p>But if your situation matches where content editors are already familiar with WordPress, and you need a custom frontend that a page builder can't deliver cleanly, then this separation makes sense.</p>
<p>Pros:</p>
<ul>
<li><p>Content editors keep using WordPress. No retraining, no migration.</p>
</li>
<li><p>The frontend has full control over design and behaviour. No theme or plugin constraints.</p>
</li>
<li><p>Deployments are automatic on every push. Content changes go live immediately without a rebuild.</p>
</li>
<li><p>No added cost for most sites. WordPress stays on its existing host. Cloudflare Pages is free within generous limits, and scales to $5 per month on the Workers Paid plan if you outgrow them.</p>
</li>
</ul>
<p>Cons:</p>
<ul>
<li><p>Two systems to maintain instead of one. You operate the WordPress install (updates, plugins, backups) and maintain the Astro codebase separately.</p>
</li>
<li><p>The WordPress REST API has limitations. Complex content structures or real-time features need more work to handle compared to a purpose-built headless CMS.</p>
</li>
<li><p>Adapter and deployment target are tied together. @astrojs/cloudflare v13 drops Pages support in favor of Workers, so staying on Pages means staying on v12. Details in the Good to Know section.</p>
</li>
<li><p>Frontend changes require a developer. With Elementor, anyone with admin access could adjust layouts directly in the browser. Here, any visual change outside of content goes through code, which means it goes through you.</p>
</li>
</ul>
<p>The stack is WordPress on existing hosting, Astro on Cloudflare Pages, with GitHub as the bridge between development and production. It solves a specific problem cleanly. Outside of that problem, there are better options.</p>
<h2 id="heading-good-to-know">Good to Know</h2>
<p><strong>Change the default login URL immediately.</strong> Every bot targets <code>/wp-login.php</code> and <code>/wp-admin</code>. Install WPS Hide Login and move it to something custom. Anyone hitting the default paths gets a 404.</p>
<p><strong>Remove the</strong> <code>/wp-json/wp/v2/users</code> <strong>endpoint.</strong> It returns a public list of usernames. In headless mode you get author data through <code>_embed</code> and have no use for this endpoint. Add to the mu-plugin:</p>
<pre><code class="language-php">add_filter('rest_endpoints', function($endpoints) {
    unset($endpoints['/wp/v2/users']);
    unset($endpoints['/wp/v2/users/(?P&lt;id&gt;[\d]+)']);
    return $endpoints;
});
</code></pre>
<p><strong>Disable XML-RPC and enable 2FA.</strong> Add <code>add_filter('xmlrpc_enabled', '__return_false')</code> to the mu-plugin — you aren't using it in headless mode and it's a common brute force target. Enable Wordfence's Brute Force Protection and add two-factor authentication through WP 2FA for all admin accounts.</p>
<p><strong>Don't upgrade</strong> <code>@astrojs/cloudflare</code> <strong>to v13 if you deploy via Cloudflare Pages git-push CI.</strong> v12 outputs <code>dist/_worker.js</code> which Pages CI expects. v13 outputs a different format for <code>wrangler deploy</code> — Pages CI falls back to serving the <code>dist</code> folder as a static site and every SSR route returns 404 with no helpful error message.</p>
<p><strong>The v12 adapter throws a deprecation warning on</strong> <code>entrypointResolution</code><strong>.</strong> Silence it by adding <code>entrypointResolution: 'auto'</code> to the adapter options. Test before committing — it changes how the build locates the Worker entry file.</p>
<p><strong>Custom Post Types follow the same pattern.</strong> Register the CPT with <code>show_in_rest: true</code> and a <code>rest_base</code>, and it shows up at <code>/wp-json/wp/v2/your-base</code>. The same fetch helpers, <code>_embed</code>, and slug routing work exactly the same way.</p>
<p><strong>The REST API returns pagination headers.</strong> The raw response includes <code>X-WP-Total</code> and <code>X-WP-TotalPages</code> headers before you call <code>.json()</code>. If you want proper previous/next pagination, read those instead of guessing whether a next page exists.</p>
<p><strong>Wrap API calls in try/catch.</strong> If WordPress is unreachable, an unhandled fetch throws and returns a 500. A try/catch returns an empty page instead, which is a much better failure mode.</p>
<p><strong>Preview auth uses Application Passwords.</strong> WordPress 5.6 added Application Passwords under Users → Profile. That's what <code>WP_APP_USER</code> and <code>WP_APP_PASSWORD</code> in your <code>.env</code> should point to — not your regular admin password. Generate one per environment. Define the preview token as a constant in <code>wp-config.php</code> (<code>define('HEADLESS_PREVIEW_SECRET', '...')</code>) and reference that constant in the mu-plugin — never hardcode secrets in version-controlled files.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ What WordPress Development Looks Like in the Age of AI ]]>
                </title>
                <description>
                    <![CDATA[ Building a website with WordPress used to take a lot of time. You had to install the platform, choose a theme, add plugins, write all the content by hand, and make sure everything worked well together. Even skilled developers spent hours setting up a... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/what-wordpress-development-looks-like-in-the-age-of-ai/</link>
                <guid isPermaLink="false">689bd6ecfb63224ae4bf0fce</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Manish Shivanandhan ]]>
                </dc:creator>
                <pubDate>Wed, 13 Aug 2025 00:06:04 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1755043537289/20e17529-88fd-4fbd-94c4-69cf72d8a470.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Building a website with <a target="_blank" href="https://wordpress.com/">WordPress</a> used to take a lot of time. You had to install the platform, choose a theme, add plugins, write all the content by hand, and make sure everything worked well together.</p>
<p>Even skilled developers spent hours setting up a basic site. This process was slow and often frustrating, especially for new users.</p>
<p>But that’s changing. Artificial intelligence is now playing a big role in how WordPress sites are built. It takes care of the boring, time-consuming parts like writing content or designing pages, so that developers and site owners can focus on the parts that really matter.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-the-pain-of-starting-from-scratch">The Pain of Starting from Scratch</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-ai-is-changing-wordpress-development">How AI Is Changing WordPress Development</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-ai-in-the-wordpress-workflow">AI in the WordPress Workflow</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-ai-tools-for-wordpress">AI Tools for WordPress</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-10web-website-builder-in-action">10Web Website Builder in Action</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-ai-matters-for-wordpress-developers-and-hosts">Why AI Matters for WordPress Developers and Hosts</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-future-of-wordpress-with-ai">The Future of WordPress with AI</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h2 id="heading-the-pain-of-starting-from-scratch"><strong>The Pain of Starting from Scratch</strong></h2>
<p>If you’ve ever installed WordPress on a fresh hosting account, you know what it’s like. After setup, you see an empty dashboard with no content and no design.</p>
<p>From there, you have to search for a theme, install plugins, add some demo content, and try to figure out how it all fits together. Most users get stuck early in this process.</p>
<p>For new site owners, this can feel overwhelming. They don’t want to build every page manually. They just want a working website that fits their business. But most hosting companies still provide a blank WordPress install and expect users to do everything from there.</p>
<p>That leads to frustration. And for many hosting companies, it leads to churn. New customers sign up, don’t know what to do, and give up before launching their site.</p>
<h2 id="heading-how-ai-is-changing-wordpress-development"><strong>How AI Is Changing</strong> WordPress <strong>Development</strong></h2>
<p>In the last two years, AI tools have started to shift how websites are created. Platforms like v0 and <a target="_blank" href="https://lovable.dev/">Lovable</a> showed that you could describe your business and get a working site generated in seconds. These tools are fast and exciting. But they had a downside: they weren’t built for WordPress.</p>
<p>So users had to choose between fast results and long-term flexibility. WordPress is still the most powerful content management system in the world, and runs over 40% of all websites.</p>
<p>WordPress has thousands of themes, plugins, and developers who can extend it in any direction. But until recently, WordPress didn’t offer the instant setup that AI tools could. That’s the gap AI is now closing.</p>
<h2 id="heading-ai-in-the-wordpress-workflow"><strong>AI in the WordPress Workflow</strong></h2>
<p>Today, AI is being used inside WordPress itself. It helps create sites faster, easier, and with fewer mistakes. Instead of starting from zero, developers now begin with a site that’s already built with pages, layout, images, and text included.</p>
<p>This saves hours of time. You don’t have to install the same plugins or write placeholder content over and over. Instead, you can focus on what really matters: making the site faster, more secure, and easier to use.</p>
<p>Even better, AI can continue helping after the site is live. It can improve SEO, fix design problems, suggest better headlines, and more. Site owners can talk to a built-in assistant that helps them make updates just by typing what they want.</p>
<p>This changes the job of a WordPress developer. But doesn’t remove the need for developers – it makes them more powerful. Now they can spend their time solving real problems instead of doing the same setup tasks again and again.</p>
<h2 id="heading-ai-tools-for-wordpress"><strong>AI Tools for Wordpress</strong></h2>
<p>The rise of AI inside the WordPress ecosystem has opened the door to a <a target="_blank" href="https://wordpress.com/plugins/browse/ai">new generation of tools</a>, ones that don’t just speed up development but also rethink how websites get built, edited, and maintained.</p>
<p>Rather than starting from a blank canvas, these tools give you a solid foundation in seconds. And just as importantly, they do so without locking users into closed ecosystems.</p>
<p>One of the most widely used WordPress building tools today is <a target="_blank" href="https://10web.io/">10Web</a>, which takes the idea of AI-native website creation a step further compared to other tools that help with individual tasks like text generation or layout tweaks. </p>
<p>With 10Web, you describe your business, and within seconds, it generates a complete website with design, content, structure, and e-commerce-ready pages. For hosting providers, this AI site generation is delivered through a fully white-labeled WordPress plugin that integrates directly into their infrastructure, branded and automated. It runs on the host’s stack and allows further edits via a drag-and-drop interface or an AI Co-Pilot.</p>
<p>The company is backed by <a target="_blank" href="https://en.wikipedia.org/wiki/Andrew_Ng">Andrew Ng</a>, often called the father of modern deep learning, making it a serious contender in shaping the future of WordPress development.</p>
<p> What sets 10Web apart is its integration into the hosting provider’s provisioning flow. Instead of being another plugin or third-party builder, it becomes part of the WordPress provisioning process itself.</p>
<p>For developers and infrastructure providers, this means clients get a fully working site at signup, without any extra integrations or tools required. You can use 10Web’s AI-native <a target="_blank" href="https://10web.io/website-builder-api/hosting-solution/">website builder</a> to generate WordPress sites for your clients, under your own brand.</p>
<h2 id="heading-10web-website-builder-in-action">10Web Website Builder in Action</h2>
<p>Let’s put the tool to the test and see if it delivers. On the home page, click “Generate AI Website”.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754551438284/4364bc8c-663f-440d-a2f9-65a28cc918ea.png" alt="10web home page" class="image--center mx-auto" width="2000" height="1022" loading="lazy"></p>
<p>It should take you to the page to describe your requirements.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754558287205/3ffd7809-0a7a-48ef-a9b1-d005b2ddc20b.png" alt="10web prompt" class="image--center mx-auto" width="2060" height="1100" loading="lazy"></p>
<p>My prompt was simply “Generate a simple portfolio website with projects, about, testimonials, and contact us options.”</p>
<p>Let’s wait for the skeleton first. Here’s what it’ll look like:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754557451670/06064fee-150a-4ed4-b1f4-742d49f8f8b8.png" alt="10web website skeleton" class="image--center mx-auto" width="3348" height="1874" loading="lazy"></p>
<p>I have the option to customize settings here. Once you’re done with that, click “Generate”.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754557455746/7104452d-d3b5-41fd-bdc6-81cd6bc1f1b2.png" alt="10web customisation view" class="image--center mx-auto" width="3344" height="1870" loading="lazy"></p>
<p>It took a minute, but this is what the platform delivered:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/ifc6gOtMttw" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<p>Quite a stunning website. I have the option to fully customize it, and the created website is mobile responsive by default. It has automated 10-12 hours of developer effort in a few minutes.</p>
<p>Once a website is generated, you still have full control over your website. You can use prompts to make additional changes to your pages or use the native WordPress admin panel within 10Web to edit individual pages similar to a self-hosted WordPress site.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1754896934567/3ee6e353-1e2c-43ac-9a6c-57b814b0ad97.png" alt="Edit Pages" class="image--center mx-auto" width="3028" height="1748" loading="lazy"></p>
<p>10Web acts as an enabling layer to speed up your WordPress development while giving you full control of your website.</p>
<h2 id="heading-why-ai-matters-for-wordpress-developers-and-hosts"><strong>Why AI Matters for WordPress Developers and Hosts</strong></h2>
<p>The impact of this shift is felt on two fronts: the individual developer’s workflow and the hosting provider’s business model.</p>
<p>For developers, these AI tools reduce the time spent on low-level tasks. Instead of writing placeholder content or tweaking basic layout elements, developers can now focus on performance, accessibility, security, and high-value customizations. </p>
<p>AI gives them a head start and more mental space to do what truly matters. It’s no longer about building every piece by hand but curating, editing, and optimizing what’s already there.</p>
<p>For hosting providers, offering a blank WordPress install is no longer enough. User expectations have changed. People want a site that’s ready to go, one they can edit, not just one they have to build from the ground up.</p>
<p>With AI-powered builders and plugins baked into their offering, hosts can provide real value on day one. This reduces support tickets, increases activation rates, and gives users a sense of momentum. More importantly, it lets providers differentiate in a crowded market.</p>
<p>The old model of “sell hosting and leave the rest to the user” is fading. The new model is all about packaging infrastructure with outcomes.</p>
<h2 id="heading-open-source-alternatives">Open Source Alternatives</h2>
<p>While platforms like 10Web offer a seamless, integrated way to build AI-powered WordPress sites, they’re not the only option. For developers who prefer more transparency, or the ability to customize every layer of the stack, open source AI tools can be an attractive path.</p>
<p>Projects like <a target="_blank" href="https://playground.wordpress.net/">WordPress Playground AI</a>, and <a target="_blank" href="https://app.codewp.ai/login">CodeWP</a> are community-driven solutions that bring AI-assisted content generation, image creation, and even block-level design suggestions directly into the WordPress editor. Because they’re open source or built with open APIs, you’re free to host models yourself, extend features, or integrate with other workflows without being tied to a single vendor.</p>
<p>The trade-off is that open source AI solutions often require more setup and technical know-how. You may need to configure your own AI backend, manage API keys for services like OpenAI or Hugging Face, and handle updates manually. But in return, you get better flexibility, and the ability to adapt the tools to your exact needs.</p>
<h2 id="heading-the-future-of-wordpress-with-ai"><strong>The Future of</strong> WordPress <strong>with AI</strong></h2>
<p>We’re at the beginning of a bigger shift. In the coming years, WordPress won’t just be a place to build sites. It will be a platform that helps run, grow, and evolve them.</p>
<p>AI will play a central role in that evolution. It will help personalize content, track performance in real-time, and recommend design or structure changes based on user behavior. We’ll see more tools that learn from how visitors interact with a site and offer ways to improve it without needing a developer to log in.</p>
<p>This means smarter marketing, faster publishing, and less guesswork. Developers will become strategists. Site owners will become editors instead of builders. And hosting providers will evolve into true partners in online growth.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>WordPress has always been about freedom. Freedom to build what you want, extend how you like, and scale as needed. That hasn’t changed. But now, that freedom comes with a boost. With AI built into the stack, developers and site owners don’t have to choose between power and speed. They get both.</p>
<p>AI doesn’t replace the developer. It empowers them. It doesn’t remove the need for creativity. It gives creators a head start. And it doesn’t lock users into closed systems. It opens the door to faster, better, and more flexible websites built on the world’s most popular platform.</p>
<p>Hope you enjoyed this article. You can <a target="_blank" href="https://linkedin.com/in/manishmshiva">find me on Linkedin</a> to stay in touch.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Create a WordPress Website ]]>
                </title>
                <description>
                    <![CDATA[ Building a website might seem daunting, but WordPress makes it accessible to everyone. With WordPress, you can create a professional website tailored to your needs, whether it’s for a personal blog, a small business, or an online store. The platform’... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-a-wordpress-website/</link>
                <guid isPermaLink="false">6791307b3bc9c704716dadd4</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Wed, 22 Jan 2025 17:52:59 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1737568134192/7ab11a8b-9d79-496b-b5c5-06f324a62670.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Building a website might seem daunting, but WordPress makes it accessible to everyone. With WordPress, you can create a professional website tailored to your needs, whether it’s for a personal blog, a small business, or an online store. The platform’s flexibility and ease of use have made it one of the most popular website-building tools worldwide.</p>
<p>We just published a <strong>beginner-friendly WordPress course</strong> on the freeCodeCamp.org YouTube channel to guide you through every step of creating a WordPress website. Whether you’re starting from scratch or looking to refine your skills, this course equips you with all the tools and knowledge you need to succeed. And best of all, the course was developed by me!</p>
<h3 id="heading-what-youll-learn-in-this-course">What You’ll Learn in This Course</h3>
<p>In this comprehensive course, you’ll go from zero to a fully functioning WordPress website. Here’s what you’ll cover:</p>
<ul>
<li><p><strong>Getting Started with WordPress:</strong></p>
<ul>
<li><p>Understand what WordPress is and why it’s a great choice for building websites.</p>
</li>
<li><p>Learn how to get a domain name and hosting, essential for making your site accessible online.</p>
</li>
</ul>
</li>
<li><p><strong>Installing and Setting Up WordPress:</strong></p>
<ul>
<li><p>Step-by-step guidance on installing WordPress and setting up your site.</p>
</li>
<li><p>Learn how to create a custom email for your domain.</p>
</li>
</ul>
</li>
<li><p><strong>Customizing Your Website:</strong></p>
<ul>
<li><p>Explore the WordPress dashboard and configure important settings.</p>
</li>
<li><p>Learn how to install plugins to add features and functionalities to your site.</p>
</li>
<li><p>Install and customize a theme to give your site the exact look and feel you want.</p>
</li>
</ul>
</li>
<li><p><strong>Building and Personalizing Your Website:</strong></p>
<ul>
<li><p>Use <strong>Elementor</strong>, a powerful page builder, to create visually stunning pages without writing code.</p>
</li>
<li><p>Add logos, menus, and custom HTML elements to make your website unique.</p>
</li>
<li><p>Customize pages like "About" and "Contact," including creating and updating a contact form.</p>
</li>
</ul>
</li>
<li><p><strong>Making Your Site Responsive:</strong></p>
<ul>
<li>Learn how to ensure your website looks great on all devices, from desktops to smartphones.</li>
</ul>
</li>
<li><p><strong>Adding a Blog:</strong></p>
<ul>
<li><p>Set up a blog on your site and create posts using an AI content creator.</p>
</li>
<li><p>Customize your blog layout to align with your website’s design.</p>
</li>
</ul>
</li>
</ul>
<h3 id="heading-course-highlights">Course Highlights</h3>
<ul>
<li><p><strong>Hands-On Learning:</strong> Each section includes practical, step-by-step instructions to help you build your site as you follow along.</p>
</li>
<li><p><strong>No Coding Required:</strong> Perfect for beginners, this course leverages WordPress tools and plugins to simplify the process.</p>
</li>
<li><p><strong>Professional Tips:</strong> Learn best practices for site design, responsiveness, and functionality to create a polished and professional website.</p>
</li>
</ul>
<h3 id="heading-why-take-this-course">Why Take This Course?</h3>
<p>By the end of the course, you’ll have a fully customized WordPress website and the confidence to manage and update it independently. Whether you’re a business owner, a creative professional, or someone who wants an online presence, this course will empower you to bring your vision to life.</p>
<p>Ready to get started? Watch the full course on <a target="_blank" href="https://youtu.be/R4v_7hh4Yys">freeCodeCamp.org’s YouTube channel</a> (1-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/R4v_7hh4Yys" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use WPScan to Keep Your WordPress Site Secure ]]>
                </title>
                <description>
                    <![CDATA[ Over 40% of the web is powered by WordPress. But this makes this popular CMS an attractive target for hackers. So if you run a WordPress site, you’ll need to make sure it’s secure. And this isn’t just a technical task, but is also a key responsibilit... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-wpscan-to-keep-your-wordpress-site-secure/</link>
                <guid isPermaLink="false">6751e08319cee0c3e45cb876</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ethicalhacking ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Marco Venturi ]]>
                </dc:creator>
                <pubDate>Thu, 05 Dec 2024 17:18:59 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1732705985906/49090646-5b75-40f4-ad55-473d723b4237.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Over 40% of the web is powered by WordPress. But this makes this popular CMS an attractive target for hackers.</p>
<p>So if you run a WordPress site, you’ll need to make sure it’s secure. And this isn’t just a technical task, but is also a key responsibility from several points of view such as brand reputation, data breach, and business continuity.</p>
<p>One tool that stands out in the WordPress ecosystem is <strong>WPScan.</strong> It’s a security scanner that’s specifically designed for WordPress. It comes with both a paid and free license, according to your needs. It is also pre-installed in Kali Linux distributions.</p>
<p>So whether you’re a seasoned website admin or a website owner looking to improve your site's security, WPScan can help you identify vulnerabilities before attackers exploit them.</p>
<p>Before going ahead, one very important thing: the purpose of this article is to help individuals and organizations strengthen the security of their WordPress websites by effectively utilizing WPScan.</p>
<p>While this tool is incredibly powerful in identifying vulnerabilities, it’s important to emphasize that any unauthorized use of WPScan—such as scanning websites without proper permission—is not only unethical but also illegal.</p>
<p>My goal in sharing this information is to empower site administrators and developers to proactively secure their websites, safeguard their data, and create a safer online environment for everyone.</p>
<h3 id="heading-what-well-cover">What we’ll cover:</h3>
<ol>
<li><p><a class="post-section-overview" href="#heading-what-is-wpscan">What is WPScan?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-scan-your-wordpress-site-using-wpscan">How to Scan Your WordPress Site Using WPScan</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-to-do-with-wpscan-results">What to do with WPScan Results</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-limitations-of-wpscan">Limitations of WPScan</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-best-practices-for-using-wpscan">Best Practices for Using WPScan</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-monitor-results-effectively">How to Monitor Results Effectively</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ol>
<h2 id="heading-what-is-wpscan">What is WPScan?</h2>
<p>WPScan is a command-line tool that helps you identify potential vulnerabilities in your WordPress installation. It’s like a security guard for your website, keeping an eye on outdated plugins, misconfigurations, and other common issues.</p>
<p>What makes WPScan unique is its focus on WordPress. It uses a database maintained by security experts, which is updated regularly to track thousands of known vulnerabilities in WordPress core, plugins, and themes.</p>
<h3 id="heading-what-can-wpscan-do">What Can WPScan Do?</h3>
<p>Here are just a few things WPScan can help you with:</p>
<ul>
<li><p>Detecting outdated WordPress core versions.</p>
</li>
<li><p>Identifying vulnerabilities in plugins and themes.</p>
</li>
<li><p>Enumerating users (for example, discovering usernames).</p>
</li>
<li><p>Testing for weak passwords (using a dictionary attack).</p>
</li>
<li><p>Finding exposed sensitive files (like backups or debug logs).</p>
</li>
</ul>
<p>Let’s see now the most common commands you can use.</p>
<h2 id="heading-how-to-scan-your-wordpress-site-using-wpscan">How to Scan Your WordPress Site Using WPScan</h2>
<h3 id="heading-1-basic-scan"><strong>1. Basic Scan</strong></h3>
<p>A basic scan provides an overview of your WordPress site's security by identifying key vulnerabilities or misconfigurations. It can detect the WordPress core version and flag it if it's outdated, highlighting potential risks like SQL injection or cross-site scripting (XSS) vulnerabilities associated with older versions.</p>
<p>The scan might also reveal publicly accessible backup files (for example, <code>.sql</code> or <code>.zip</code>) or debug files like <code>debug.log</code>, which could expose sensitive information such as database credentials or server paths.</p>
<p>It can flag missing or improperly configured HTTP security headers, such as Strict-Transport-Security (HSTS) or Content-Security-Policy (CSP), which are critical for protecting against protocol downgrade attacks and unauthorized script execution.</p>
<p>Open directories that expose your site's file structure and potentially vulnerable plugins or themes may also be flagged if they are identified in public metadata.</p>
<p>These findings provide a starting point to address fundamental security gaps.</p>
<pre><code class="lang-bash">wpscan --url http://yourwebsite.com
</code></pre>
<p>This is what you’ll see on your terminal when you run this command:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733225875769/0b1daa21-a258-41e3-88c1-62b9a7a23554.png" alt="Results of basic scan with WPScan" class="image--center mx-auto" width="2688" height="1006" loading="lazy"></p>
<h3 id="heading-2-enumerating-users"><strong>2. Enumerating Users</strong></h3>
<p>User enumeration is a process of identifying usernames on your WordPress site. Knowing these usernames can help attackers target specific accounts for brute-force attacks.</p>
<p>To enumerate users, run:</p>
<pre><code class="lang-bash">wpscan --url http://yourwebsite.com --enumerate u
</code></pre>
<p>The output will show usernames:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733226140065/3650be6a-e8e6-4c8b-a183-f986643c8ac2.png" alt="3650be6a-e8e6-4c8b-a183-f986643c8ac2" class="image--center mx-auto" width="2678" height="454" loading="lazy"></p>
<p>If you find default usernames like <code>admin</code>, you should replace them with something unique and secure.</p>
<p>Here are some best practice for usernames:</p>
<ul>
<li><p><strong>Avoid default names</strong>: Replace default usernames like <code>admin</code> or <code>user</code> with something unique and not easily guessable.</p>
</li>
<li><p><strong>Rename vulnerable usernames</strong>: To change a username, you can create a new user with administrator privileges, transfer ownership of posts or content, and then delete the old user.</p>
</li>
<li><p><strong>Use role-based usernames carefully</strong>: Avoid naming accounts after their roles (for example, <code>editor</code>, <code>manager</code>), as these can be easy targets.</p>
</li>
<li><p><strong>Implement login lockouts</strong>: Combine secure usernames with plugins that lock accounts after repeated failed login attempts.</p>
</li>
<li><p><strong>Enable Two-Factor Authentication (2FA)</strong>: Adding 2FA ensures that even if a username is guessed, the account remains secure.</p>
</li>
</ul>
<h3 id="heading-3-checking-plugins-and-themes"><strong>3. Checking Plugins and Themes</strong></h3>
<p>Plugins and themes can have security issues. WPScan can list all installed plugins and themes, along with any associated vulnerabilities.</p>
<p>For plugins, run this:</p>
<pre><code class="lang-bash">wpscan --url http://yourwebsite.com --enumerate p
</code></pre>
<p>It’ll have an output like this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733226282550/d428be3a-5b0d-410d-979a-2c65e3fb7846.png" alt="Results of plugin scan" class="image--center mx-auto" width="2678" height="618" loading="lazy"></p>
<p>For themes, run this:</p>
<pre><code class="lang-bash">wpscan --url http://yourwebsite.com --enumerate t
</code></pre>
<p>It’ll have output similar to this:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733226484963/ae2ded5c-2d71-41db-8b1e-4a74df3dd94d.png" alt="Results of theme scan" class="image--center mx-auto" width="2694" height="998" loading="lazy"></p>
<p>Look for outdated versions or known vulnerabilities in the results, and update or replace those components immediately.</p>
<p>Let’s look at some common security issues in plugins and themes.</p>
<p>First, we have <strong>Cross-Site Scripting (XSS)</strong>. Insecure input handling in plugins or themes can allow attackers to inject malicious scripts, potentially stealing user information or taking over admin sessions. A poorly secured WordPress site with an XSS vulnerability can allow attackers to steal session cookies, potentially gain unauthorized admin access, inject malicious redirects, take users to phishing sites, display deceptive content, tricking users into providing sensitive information.</p>
<p>There’s also <strong>SQL Injection</strong>. Poorly written plugins or themes can enable attackers to manipulate database queries, exposing sensitive data or damaging your site. SQL injection vulnerabilities can be exploited to dump sensitive data, bypass authentication, and modify or delete data</p>
<p>Some plugins or themes might include malicious code—intentionally or due to poor security—that grants attackers unauthorized access to your site, known as <strong>backdoors</strong>. Once installed, a backdoor can grant persistent access, enable arbitrary file uploads, undermine site integrity, and steal sensitive data.</p>
<p>There’s also <strong>Remote Code Execution (RCE)</strong> – vulnerabilities that allow attackers to execute arbitrary code on your server, often leading to full control of your site or server. Once attackers gain RCE access, they can create admin users, exfiltrate data, launch further attacks, and privilege escalation.</p>
<h4 id="heading-best-practices">Best Practices:</h4>
<ul>
<li><p>Always keep plugins and themes updated to the latest versions.</p>
</li>
<li><p>Remove any unused or inactive plugins and themes, as these can still pose a risk.</p>
</li>
<li><p>Ensure plugins and themes are downloaded from trusted, reputable sources and have a history of active maintenance.</p>
</li>
<li><p>Consider using security plugins to monitor changes to plugin or theme files and detect suspicious activity.</p>
</li>
</ul>
<h3 id="heading-4-password-testing"><strong>4. Password Testing</strong></h3>
<p>WPScan can test for weak passwords by attempting a brute-force attack using a wordlist:</p>
<pre><code class="lang-bash">wpscan --url http://yourwebsite.com --passwords /path/to/passwords.txt
</code></pre>
<p>and this is the output on your command line:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1733229769208/699aebbe-576d-4bb6-a626-2a1139822f2d.png" alt="Password testing output" class="image--center mx-auto" width="2708" height="280" loading="lazy"></p>
<h4 id="heading-what-is-brute-forcing">What is Brute-Forcing?</h4>
<p>Brute-forcing is a method attackers use to guess passwords by systematically trying every possible combination until the correct one is found. When combined with a <strong>wordlist</strong>—a file containing a collection of commonly used passwords—brute-forcing becomes much faster and more efficient.</p>
<p>A typical wordlist might include:</p>
<ul>
<li><p><strong>Simple passwords</strong> like <code>123456</code>, <code>password</code>, and <code>qwerty</code>.</p>
</li>
<li><p><strong>Common patterns</strong> such as <code>Spring2024!</code> or <code>welcome123</code>.</p>
</li>
<li><p><strong>Leaked passwords</strong> from previous data breaches.</p>
</li>
</ul>
<p>By simulating this type of attack, WPScan can identify accounts that use weak passwords, allowing you to address vulnerabilities proactively.</p>
<p>Weak passwords make brute-forcing easier and faster. A short or predictable password might be guessed in seconds, while a longer, complex password with unique elements is exponentially harder to crack.</p>
<h4 id="heading-how-to-create-strong-passwords">How to Create Strong Passwords</h4>
<p>Strong passwords are your first line of defense against brute-force attacks. Here are key characteristics of strong passwords:</p>
<ul>
<li><p><strong>Length</strong>: At least 12–16 characters long.</p>
</li>
<li><p><strong>Complexity</strong>: Use a mix of uppercase and lowercase letters, numbers, and special characters.</p>
</li>
<li><p><strong>Uniqueness</strong>: Avoid reusing passwords across multiple accounts.</p>
</li>
<li><p><strong>Unpredictability</strong>: Avoid dictionary words, common phrases, or personal information like birthdays.</p>
</li>
</ul>
<h4 id="heading-strategies-for-generating-strong-passwords">Strategies for Generating Strong Passwords</h4>
<p>There are various measures you can take to create strong passwords. First, use a password generator<strong>.</strong> Tools like LastPass and Bitwarden can create and store highly complex passwords for you.</p>
<p>You should also use pass phrases (instead of just regular passwords). Combine random, unrelated words with numbers and symbols, such as <code>Sky#Tree!Motorbike12</code>.</p>
<p>Finally, avoid patterns that might be easily guessed by an attacker. Don’t use sequential or keyboard patterns like <code>abcdef</code> or <code>qwerty</code>.</p>
<h4 id="heading-use-tools-to-manage-passwords">Use Tools to Manage Passwords</h4>
<p>Managing strong passwords can be challenging. Password managers simplify this by securely storing and autofilling your credentials. Popular options include:</p>
<ul>
<li><p><strong>Bitwarden</strong></p>
</li>
<li><p><strong>LastPass</strong></p>
</li>
</ul>
<p>These tools also have features like password auditing to detect reused or weak passwords.</p>
<h4 id="heading-use-two-factor-authentication-2fa">Use Two-Factor Authentication (2FA)</h4>
<p>Two-factor authentication (2FA) adds an additional layer of security by requiring users to verify their identity through a second factor beyond the password. This can include:</p>
<ul>
<li><p><strong>One-time codes</strong> sent via email or SMS.</p>
</li>
<li><p><strong>App-generated codes</strong> from tools like Google Authenticator or Authy.</p>
</li>
<li><p><strong>Biometric verification</strong>, such as fingerprints or facial recognition.</p>
</li>
</ul>
<p>Even if an attacker guesses your password through brute-forcing, 2FA prevents them from accessing your account without secondary verification. This additional step makes brute-forcing impractical, as attackers would also need to compromise your 2FA device or method.</p>
<h5 id="heading-how-to-implement-2fa-in-wordpress">How to Implement 2FA in WordPress</h5>
<ol>
<li><p>Install a WordPress plugin such as <strong>Google Authenticator</strong>.</p>
</li>
<li><p>Require all user accounts, especially administrators, to enable 2FA.</p>
</li>
<li><p>Offer backup codes or recovery options in case users lose access to their 2FA device.</p>
</li>
<li><p>Test and make sure that 2FA works reliably for all user roles before making it mandatory.</p>
</li>
</ol>
<h4 id="heading-the-importance-of-password-hygiene">The Importance of Password Hygiene</h4>
<p>By using strong passwords and implementing 2FA, you can significantly reduce the effectiveness of brute-force attacks.</p>
<p>WPScan’s password testing feature can help you identify weak credentials. It also underscores the critical need for proactive password hygiene and additional security layers to keep your WordPress site secure.</p>
<h2 id="heading-what-to-do-with-wpscan-results"><strong>What to Do with WPScan Results</strong></h2>
<p>WPScan reports provide actionable insights into your site’s security. Here’s what you can do with the information:</p>
<p>First, update WordPress core, plugins, and themes: Keep everything updated to patch vulnerabilities.</p>
<p>Second, address configuration issues: Fix misconfigured file permissions, insecure HTTP headers, and other warnings.</p>
<p>Here are a couple of remediation examples you can apply:</p>
<ul>
<li><p><strong>Directory indexing</strong>: If WPScan detects open directories, disable directory browsing by adding this line to your <code>.htaccess</code> file:</p>
<pre><code class="lang-apache">  <span class="hljs-attribute"><span class="hljs-nomarkup">Options</span></span> -Indexes
</code></pre>
</li>
<li><p><strong>File permissions</strong>: Ensure critical files like <code>wp-config.php</code> are read-only by setting permissions to <code>440</code> or <code>400</code> using the command:</p>
<pre><code class="lang-bash">  chmod 400 wp-config.php
</code></pre>
</li>
</ul>
<p>You should also harden all user accounts. You can do this in several ways:</p>
<ul>
<li><p><strong>Update weak passwords</strong>: Use strong, unique passwords for all user accounts (refer to the password testing section for tips).</p>
</li>
<li><p><strong>Remove unused accounts</strong>: Delete inactive accounts, especially those with administrator privileges.</p>
</li>
<li><p><strong>Rename predictable usernames</strong>: Change usernames like <code>admin</code> to something less obvious.</p>
</li>
</ul>
<p>Make sure you also secure any sensitive files: If WPScan finds exposed files like <code>debug.log</code>, delete or secure them. Delete unnecessary files or old backups.</p>
<p>For files you need to keep, move them to a directory outside the web root. You can also protect files with <code>.htaccess</code>, by blocking access to sensitive files using <code>Deny</code> and <code>Allow</code> rules:</p>
<pre><code class="lang-apache"><span class="hljs-section">&lt;Files wp-login.php&gt;</span>
    <span class="hljs-attribute"><span class="hljs-nomarkup">Order</span></span> <span class="hljs-literal">Deny</span>,<span class="hljs-literal">Allow</span>
    <span class="hljs-attribute"><span class="hljs-nomarkup">Deny</span></span> from <span class="hljs-literal">all</span>
    <span class="hljs-attribute"><span class="hljs-nomarkup">Allow</span></span> from <span class="hljs-number">123.456.789.000</span>
<span class="hljs-section">&lt;/Files&gt;</span>
</code></pre>
<h2 id="heading-limitations-of-wpscan">Limitations of WPScan</h2>
<p>WPScan is a powerful too, but it does have some limitations. Just be aware of them so you can take other measures to protect your WP sites.</p>
<h3 id="heading-1-known-vulnerabilities-only"><strong>1. Known Vulnerabilities Only</strong></h3>
<p>WPScan relies on its database of known vulnerabilities, so it won’t catch zero-day exploits or custom vulnerabilities.</p>
<p>Here are some tips on how you can mitigate this issue:</p>
<ul>
<li><p><strong>Stay informed</strong>: Monitor WordPress security blogs, vulnerability databases like CVE or WPVulnDB, and community forums for emerging threats.</p>
</li>
<li><p><strong>Use a Web Application Firewall (WAF)</strong>: Tools like Cloudflare or Sucuri can block suspicious activities and attempts to exploit unknown vulnerabilities.</p>
</li>
<li><p><strong>Conduct manual security reviews</strong>: Periodically review your site for unusual behavior or unauthorized changes, particularly in critical files like <code>wp-config.php</code> or your database.</p>
</li>
</ul>
<h3 id="heading-2-no-real-time-protection"><strong>2. No Real-Time Protection</strong></h3>
<p>WPScan a diagnostic tool, not a firewall or intrusion detection system. For real-time protection, it’s a good idea to combine WPScan with other tools.</p>
<p>Some steps you can take are:</p>
<ul>
<li><p><strong>Install security plugins</strong>: Use specific security plugins to provide continuous monitoring, malware scanning, and firewall protection.</p>
</li>
<li><p><strong>Monitor activity logs</strong>: Set up activity tracking to identify suspicious login attempts, file changes, or unauthorized user actions.</p>
</li>
</ul>
<h3 id="heading-3-resource-intensive"><strong>3. Resource-Intensive</strong></h3>
<p>Scanning large sites with many plugins and themes can be time-consuming and may impact server performance.</p>
<p>There are various strategies you can adopt to mitigate this such as scheduling scans during low-traffic periods to minimize disruption to site visitors. You can also perform scans on a staging copy of your site rather than directly on the live environment.</p>
<h3 id="heading-4-learning-curve"><strong>4. Learning Curve</strong></h3>
<p>As a command-line tool, WPScan can be intimidating for less technical users. However, the documentation is excellent, and with practice, you’ll become proficient.</p>
<p>If the CLI is overwhelming for you, try pairing WPScan with security plugins that offer GUI-based scanning and reporting.</p>
<h2 id="heading-best-practices-for-using-wpscan">Best Practices for Using WPScan</h2>
<p>To get the most out of WPScan, you’ll want to to tailor its usage to your site’s specific needs and establish a robust strategy for monitoring results. Here’s how you can maximize its effectiveness:</p>
<h3 id="heading-choose-the-right-scans-for-your-site">Choose the Right Scans for Your Site</h3>
<p>WPScan offers a variety of scan options, from basic scans to targeted vulnerability checks for plugins, themes, and user accounts. Choosing the right scans depends on the type of site you manage and the sensitivity of the data it handles.</p>
<p><strong>For small, low-traffic sites</strong>:</p>
<ul>
<li><p>Prioritize basic scans to check WordPress core, plugins, and themes for updates and vulnerabilities.</p>
</li>
<li><p>Run scans monthly or after major updates.</p>
</li>
<li><p>Use user enumeration (<code>--enumerate u</code>) if you suspect weak passwords or default usernames.</p>
</li>
</ul>
<p><strong>For medium-sized business sites</strong>:</p>
<ul>
<li><p>In addition to basic scans, include plugin and theme enumeration (<code>--enumerate p,t</code>) to ensure all components are secure.</p>
</li>
<li><p>Weekly scans to stay ahead of emerging threats.</p>
</li>
<li><p>Combine WPScan with activity log plugins to track user actions and file changes.</p>
</li>
</ul>
<p><strong>For high-traffic or e-commerce sites</strong>:</p>
<ul>
<li><p>Perform comprehensive scans, including user enumeration (<code>--enumerate u</code>), file enumeration (<code>--enumerate f</code>), and password brute-force testing (if allowed).</p>
</li>
<li><p>Daily or weekly scans to minimize risk.</p>
</li>
<li><p>Implement additional measures like 2FA for admin accounts, a web application firewall (WAF), and security headers to reinforce your site.</p>
</li>
</ul>
<p><strong>For sites handling sensitive data</strong>:</p>
<ul>
<li><p>Prioritize all available scans, including those for exposed files and configuration vulnerabilities.</p>
</li>
<li><p>Weekly scans with real-time monitoring via a security plugin.</p>
</li>
<li><p>Use staging environments to test security settings without affecting production.</p>
</li>
</ul>
<h3 id="heading-should-you-use-all-scans"><strong>Should You Use All Scans?</strong></h3>
<p>While it may seem beneficial to use every scan WPScan offers, there are various factors to consider.</p>
<p>First, think about your site’s size and your resources. For smaller sites, running all scans can be overkill and resource-intensive.</p>
<p>You’ll also want to focus on scans that address your site's most likely vulnerabilities. For example, an e-commerce site should prioritize user and payment security over exhaustive file enumeration.</p>
<p>Compliance requirements are also important to take into consideration. If you’re subject to regulations like GDPR, ensure you scan for and address vulnerabilities related to data protection.</p>
<h2 id="heading-how-to-monitor-results-effectively">How to Monitor Results Effectively</h2>
<p>Monitoring WPScan results is important. It helps you fix vulnerabilities, of course, but it also helps you create a system to track changes over time and stay vigilant.</p>
<h3 id="heading-set-up-reporting"><strong>Set Up Reporting</strong></h3>
<p>You can save scan results to files using the <code>--output</code> flag:</p>
<pre><code class="lang-bash">wpscan --url http://example.com --output /path/to/report.txt
</code></pre>
<p>Then review the reports regularly and compare them to previous scans to identify recurring issues or new vulnerabilities.</p>
<h3 id="heading-create-an-action-plan"><strong>Create an Action Plan</strong></h3>
<p>It’s a good idea to categorize vulnerabilities based on severity (for example, critical, moderate, low).</p>
<p>This allows you to address high-severity issues (like outdated plugins with known exploits) immediately. Then you can schedule lower-priority tasks, such as file permission adjustments or minor configuration changes, for routine maintenance.</p>
<h3 id="heading-track-trends-over-time"><strong>Track Trends Over Time</strong></h3>
<p>Use tools like spreadsheets or a project management app (for example, Trello, Asana) to log vulnerabilities, fixes, and follow-up actions.</p>
<p>Make sure you analyze recurring issues to identify patterns, such as frequent plugin vulnerabilities, and consider replacing problematic components.</p>
<h3 id="heading-automate-notifications"><strong>Automate Notifications</strong></h3>
<p>If you schedule scans using cron jobs, set up email alerts or notifications to review results without delay.</p>
<p>Use security plugins with real-time monitoring to notify you of suspicious activities in between WPScan checks.</p>
<h3 id="heading-communicate-with-your-team"><strong>Communicate with Your Team</strong>:</h3>
<p>You’ll want to make sure you share reports with relevant team members, such as developers or site administrators, so everyone is aware of potential vulnerabilities.</p>
<p>It’s also a good idea to establish protocols for immediate action if critical vulnerabilities are discovered.</p>
<p>By choosing scans based on your site’s specific needs and implementing a structured approach to monitoring results, you can ensure WPScan is used effectively. Also, make sure you tailor the tool to your risk profile, track vulnerabilities over time, and integrate its findings into a broader security strategy.</p>
<p>This approach not only improves your site’s security posture but also minimizes resource use and effort while delivering maximum protection.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>WPScan is an invaluable tool for anyone managing a WordPress site. It simplifies the process of identifying vulnerabilities and provides clear, actionable recommendations to strengthen your site’s security.</p>
<p>By integrating WPScan into your workflow and following best practices, you can reduce the risk of attacks and keep your WordPress site safe. Security is a continuous journey, and tools like WPScan make it easier to stay ahead of potential threats.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Integrate WordPress as a Headless CMS with Next.js – With Code Examples ]]>
                </title>
                <description>
                    <![CDATA[ When building a dynamic blog website, it's common to fetch data from a content source, such as a CMS (Content Management System) like WordPress. Recently, I faced the challenge of integrating WordPress into my existing Next.js project. I had a blog h... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/integrate-wordpress-with-nextjs/</link>
                <guid isPermaLink="false">66fd0d6ead9b41bdb1ef70fd</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Next.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ cms ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Chidera ]]>
                </dc:creator>
                <pubDate>Wed, 02 Oct 2024 09:07:58 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1727738740919/4dd5ea12-6e0c-4df9-8b8d-fc4f168b89c5.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When building a dynamic blog website, it's common to fetch data from a content source, such as a CMS (Content Management System) like WordPress.</p>
<p>Recently, I faced the challenge of integrating WordPress into my existing Next.js project. I had a blog hosted on WordPress and wanted to migrate it to my Next.js app.</p>
<p>I needed a solution that would allow me to use WordPress as a headless CMS. The goal was simple: leverage the power of WordPress for managing content while utilizing a modern frontend framework for displaying it.</p>
<p>In this article, we’ll walk through how to integrate WordPress to a Next JS app.</p>
<h2 id="heading-why-use-a-headless-cms">Why Use a Headless CMS?</h2>
<p>A headless CMS separates the content management (back-end) from the presentation layer (front-end). This gives developers more flexibility over how content is delivered and displayed, without being restricted by traditional themes or layouts.</p>
<p>It's great for performance, and scalability, offering more control over how content is rendered on the frontend. In this case, you’ll use WordPress as your content management system but display the content in a more modern and performant way using Next.js.</p>
<h2 id="heading-what-is-nextjs">What is Next.js?</h2>
<p>If you are yet to come across Next.js, it's a powerful React-based framework that makes building optimized, server-side rendered (SSR) applications much easier.</p>
<p>It offers a bunch of features out of the box like file-based routing, API routes, static site generation (SSG), and incremental static regeneration (ISR). All these make it a great choice for creating fast, SEO-friendly websites.</p>
<h2 id="heading-how-to-connect-wordpress-and-nextjs">How to Connect WordPress and Next.js</h2>
<p>When using WordPress as a headless CMS, there are two primary ways to connect your Next.js application to your WordPress backend:</p>
<ol>
<li><p><strong>WP REST API</strong>: WordPress comes with a built-in REST API, which allows you to retrieve content from WordPress in JSON format.</p>
</li>
<li><p><strong>WPGraphQL</strong>: WordPress supports headless content management through the use of GraphQL (with plugins such as <a target="_blank" href="https://www.wpgraphql.com/">WPGraphQL</a>), making it easy to query and retrieve specific content, like blog posts, for use in a front-end framework like React.</p>
</li>
</ol>
<p>While the REST API is popular, we’ll to go with WPGraphQL because it allows for more precise queries and flexibility. With GraphQL, you can ask for exactly the data you need, which can reduce the amount of data transferred and improve performance.</p>
<h3 id="heading-steps-to-connect-wordpress-and-nextjs-using-wpgraphql">Steps to Connect WordPress and Next.js Using WPGraphQL</h3>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727738853280/6e07d4f5-d4c7-40a8-9355-804251707593.png" alt="WPGraphQL WordPress plugin page" class="image--center mx-auto" width="739" height="529" loading="lazy"></p>
<p>The first thing you need to do is to install the WPGraphQL plugin on your WordPress site. This plugin enables GraphQL API functionality within WordPress. You can install the plugin like any other by navigating to the WordPress admin dashboard.</p>
<p>First, go to <strong>Plugins</strong> and select <strong>Add New</strong>. Then, search for <strong>WPGraphQL</strong>, and once you find it, simply install and activate the plugin.</p>
<p>After installing and activating the plugin, the GraphQL IDE will appear on the WordPress dashboard. Here, you can test various queries you may need for your frontend development.</p>
<p>Let's move on to the frontend.</p>
<h3 id="heading-how-to-fetch-data-from-wpgraphql-in-nextjs">How to Fetch Data from WPGraphQL in Next.js</h3>
<p>In your Next.js project, you'll need to fetch data from the GraphQL API. Here’s a simple example using <code>graphql-request</code>:</p>
<p>1. Install <code>graphql-request</code> to make it easy to query the GraphQL API:</p>
<pre><code class="lang-bash">npm install graphql-request
</code></pre>
<p>2. In your Next.js component, create a GraphQL query to fetch the blog posts:</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">import</span> BlogHeader <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/blog/BlogHeader'</span>;
<span class="hljs-keyword">import</span> BlogNewsletter <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/blog/BlogNewsletter'</span>;
<span class="hljs-keyword">import</span> BlogPosts <span class="hljs-keyword">from</span> <span class="hljs-string">'@/components/blog/BlogPosts'</span>;
<span class="hljs-keyword">import</span> Link <span class="hljs-keyword">from</span> <span class="hljs-string">'next/link'</span>;
<span class="hljs-keyword">import</span> React <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;

<span class="hljs-keyword">import</span> { request, gql } <span class="hljs-keyword">from</span> <span class="hljs-string">"graphql-request"</span>;

<span class="hljs-keyword">const</span> query = gql<span class="hljs-string">`
{
  posts(first: 10) {
    edges {
      node {
        id
        title
        excerpt
        content
        date
        author {
          node {
            id
            name            
          }
        }
        date
        slug
        featuredImage {
          node {
            sourceUrl
          }
        }
        categories {
          edges {
            node {
              name
            }
          }
        }
      }
    }
  }
}
`</span>

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getStaticProps</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> posts: <span class="hljs-built_in">any</span> = <span class="hljs-keyword">await</span> request(<span class="hljs-string">'https://blog.intercity.ng/graphql'</span>, query);

    <span class="hljs-keyword">return</span> {
      props: { posts }
    }
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">'Error fetching posts:'</span>, error);
    <span class="hljs-keyword">return</span> {
      props: {
        posts: []
      }
    };
  }
}

<span class="hljs-keyword">const</span> Index = <span class="hljs-function">(<span class="hljs-params">{ posts }: { posts: <span class="hljs-built_in">any</span> }</span>) =&gt;</span> {

  <span class="hljs-keyword">return</span> (
    &lt;main className=<span class="hljs-string">"relative pb-10 pt-10 lg:pt-0 lg:mt-[-3%]"</span>&gt;
      &lt;div className=<span class="hljs-string">'t40-container w-full'</span>&gt;
        &lt;BlogHeader /&gt;
        &lt;BlogPosts posts={posts} /&gt;
        &lt;BlogNewsletter /&gt;
      &lt;/div&gt;
    &lt;/main&gt;
  )
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Index
</code></pre>
<p>In the code above, your Next.js app fetches blog posts from your WordPress backend using GraphQL and displays them on the frontend. The GraphQL query is created to retrieve post details like the title, author, content, and featured image.</p>
<p>Using Next.js <code>getStaticProps</code>, the data is fetched at build time and passed as props to the component. The blog posts are rendered through custom components like <code>BlogHeader</code>, <code>BlogPosts</code>, and <code>BlogNewsletter</code>, making the page dynamic and efficient.</p>
<p>This demonstrates how WordPress can be used as a headless CMS for a Next.js application. Now that you have successfully integrated WordPress as a headless CMS in your Next.js application, you can continue fetching more data from the GraphQL API to enhance the functionality of your app.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>By using WordPress as a headless CMS and Next.js for the frontend, we can build a fast, SEO-friendly blog while taking advantage of WordPress’s powerful content management features.</p>
<p>Using WPGraphQL allowed us to efficiently fetch only the data we needed, giving us more control and improving the site's performance.</p>
<p>I hope this was useful. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use WordPress with AI Tools ]]>
                </title>
                <description>
                    <![CDATA[ WordPress is the most popular way to make websites. I just created a new course for the freeCodeCamp.org YouTube channel that will teach you how to use WordPress. Plus, you'll learn how to use AI tools from Hostinger to create blog content more quick... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-wordpress-with-ai-tools/</link>
                <guid isPermaLink="false">664399bfa45525e59896b5be</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 14 May 2024 17:05:03 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1715706274261/a669b3bd-ecf1-4eeb-be90-a2fc1a59a068.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>WordPress is the most popular way to make websites. I just created a new course for the freeCodeCamp.org YouTube channel that will teach you how to use WordPress. Plus, you'll learn how to use AI tools from Hostinger to create blog content more quickly and efficiently.</p>
<p>WordPress is a content management system (CMS) that allows you to create and manage websites easily, even if you don't have any coding experience. Whether you're starting a personal blog, a business website, or an online store, WordPress offers the flexibility and features to get your site up and running.</p>
<p><a target="_blank" href="https://hostinger.com/student-signup">Hostinger</a> provided a grant to make this course possible.</p>
<p>This course is designed to take you from a complete beginner to a confident WordPress user. Here's a brief summary of what you'll learn:</p>
<ul>
<li><p>Overview of the course and the benefits of using WordPress.</p>
</li>
<li><p>Choosing and registering a domain name, and finding the right hosting plan.</p>
</li>
<li><p>Setting up your WordPress site on Hostinger.</p>
</li>
<li><p>Setting up professional email accounts.</p>
</li>
<li><p>Navigating the WordPress admin panel.</p>
</li>
<li><p>Using AI tools to design a professional logo.</p>
</li>
<li><p>Customizing your site to make it unique.</p>
</li>
<li><p>Creating and publishing blog posts and articles.</p>
</li>
<li><p>Using AI tools to generate content.</p>
</li>
<li><p>Basics of search engine optimization.</p>
</li>
<li><p>Advanced AI content creation features.</p>
</li>
<li><p>Customizing the layout and design of your articles page.</p>
</li>
<li><p>Personalizing your home page and header.</p>
</li>
<li><p>Further customization for improved user experience.</p>
</li>
<li><p>Ensuring reliable email delivery.</p>
</li>
<li><p>Creating and managing email newsletters.</p>
</li>
<li><p>Advanced home page customization techniques.</p>
</li>
<li><p>Optimizing page URLs for better SEO and user experience.</p>
</li>
<li><p>Final tips and resources for your WordPress journey.</p>
</li>
</ul>
<p>AI tools can significantly speed up the process of creating and managing your WordPress site. From designing logos to generating content, these tools can help you create professional-quality work with less effort. Hostinger's AI tools are user-friendly and designed to integrate seamlessly with WordPress, making them perfect for beginners.</p>
<p>Watch the full course on <a target="_blank" href="https://www.youtube.com/watch?v=2mrxvLvz_rk">the freeCodeCamp.org YouTube channel</a> (1-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/2mrxvLvz_rk" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Publish Google Docs to WordPress in an SEO-Optimized Way ]]>
                </title>
                <description>
                    <![CDATA[ WordPress is a popular content management system (CMS) known for its flexibility and user-friendly interface. But its built-in editor is not ideal for collaborative editing. Many publishers who work with writers need collaborative writing and editing... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/publish-google-docs-to-wordpress/</link>
                <guid isPermaLink="false">66bb8acb6b3bd8d6bf25ae4c</guid>
                
                    <category>
                        <![CDATA[ Google Docs ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SEO ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vikram Aruchamy ]]>
                </dc:creator>
                <pubDate>Mon, 26 Feb 2024 23:21:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2024/02/fcc-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>WordPress is a popular content management system (CMS) known for its flexibility and user-friendly interface. But its built-in editor is not ideal for collaborative editing.</p>
<p>Many publishers who work with writers need collaborative writing and editing features. This is where Google Docs comes into the picture. It’s a collaborative platform, enabling multiple users to write and edit simultaneously. </p>
<p>Google Docs also offers powerful formatting tools, simplifying the content creation process before transferring it to WordPress for publishing.</p>
<p>However, <a target="_blank" href="https://www.docstowp.pro/">converting Google Docs to WordPress</a> can add an extra step to your publishing workflow and requires some attention to detail.</p>
<p>This tutorial explores four seamless methods to bridge that gap and streamline your publishing journey:</p>
<ul>
<li>Manually converting using the copy-paste method</li>
<li>Publishing with SEO optimization using the <a target="_blank" href="https://workspace.google.com/marketplace/app/docs_to_wp_pro/346830534164">Docs to WP Pro</a> add-on</li>
<li>Using the WordPress Gutenberg editor </li>
<li>Using the Markdown conversion method</li>
</ul>
<h2 id="heading-using-the-simple-copy-paste-method">Using the Simple Copy Paste Method</h2>
<p>In this simple copy-paste approach, you can copy the contents from Google Docs and navigate to WordPress to create a new post, then paste in the content.</p>
<p>But when pasting content into WordPress, you may encounter some issues that require manual adjustments, especially if your WordPress site is using the Classic Editor.</p>
<p>First of all, you may have issues with spacing – for example, WordPress adds extra line breaks, as you can see in the image below:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-145.png" alt="Image" width="600" height="400" loading="lazy">
<em>Unnecessary link breaks added by Wordpress</em></p>
<p>Second, you may have to remove or clean up messy code – WordPress adds unnecessary span tags to the content.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-144.png" alt="Image" width="600" height="400" loading="lazy">
<em>Unnecessary span tags</em></p>
<p>Finally, you may have to manually upload images to the Media library and include them in your posts, as it's not done automatically.</p>
<p>The spacing issues and the messy code can <a target="_blank" href="https://www.cloudflare.com/en-in/learning/performance/how-website-speed-boosts-seo/">affect your website performance</a>. HTML counts toward your overall page weight, so unnecessary code slows your page down, impacting both user experience and SEO. </p>
<p>Images also need to be manually compressed before uploading to the WordPress Media library.</p>
<p>Also, the native Google Docs doesn’t offer options for SEO optimization or the use of reusable blocks to add boilerplate content. So using this method requires more manual work for publishing from Google Docs to WordPress. </p>
<h2 id="heading-using-docs-to-wp-pro-add-on">Using Docs to WP Pro add-on</h2>
<p>The Google Docs add-on Docs to WP Pro can help you publish SEO-optimized posts from Google Docs to WordPress.</p>
<p><a href="https://workspace.google.com/marketplace/app/docs_to_wp_pro/346830534164?pann=b" target="_blank"><img src="https://workspace.google.com/static/img/marketplace/en/gwmBadge.svg?" alt="My image" width="600" height="400" loading="lazy"></a></p>
<p>The add-on allows you to configure the site once and includes additional capabilities, such as letting you create reusable blocks for content like <em>FAQs</em>, <em>Author bios</em>, and <em>affiliate disclaimers</em>. Beyond these, the add-on provides the following functionalities:</p>
<h3 id="heading-automated-internal-linking">Automated Internal Linking</h3>
<p>Adding <a target="_blank" href="https://ahrefs.com/seo/glossary/internal-link">internal links</a> to your article is crucial for enhancing user experience and SEO. After creating content, identifying potential keywords and adding relevant internal links is essential.</p>
<p>But manually managing this process can be challenging, especially with a large number of articles and multiple authors. It becomes difficult to identify all potentially related articles without a comprehensive overview of your site, leading to more guesswork.</p>
<p>The Docs to WP Pro add-on can automate internal linking by automatically identifying and linking relevant keywords within your content to related posts on your site. This saves you time and effort and can help improve the SEO of your content by creating relevant internal links.</p>
<h3 id="heading-related-posts-suggestions">Related Posts Suggestions</h3>
<p>Including a few related posts at the end of articles enhances reader engagement, increases <a target="_blank" href="https://www.semrush.com/blog/dwell-time/">dwell time</a>, and improves overall user experience.</p>
<p>For this use case, the tool suggests topics that can be added as <em>related posts</em>. These suggestions include additional contextual data for the target posts, such as <em>Relevance score</em>, <em>Number of incoming links</em>, <em>Post published on</em>, and <em>Post update on</em>.</p>
<p>This information helps you link to the most recent articles when you have multiple articles on closely related topics and ensures a balanced distribution of internal links.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-146.png" alt="Image" width="600" height="400" loading="lazy">
<em>Suggestions for Related posts</em></p>
<h3 id="heading-seo-optimization">SEO Optimization</h3>
<p>Apart from internal linking, the tool also supports other <a target="_blank" href="https://www.freecodecamp.org/news/wordpress-seo/">SEO optimizations</a> and seamlessly integrates with RankMath and Yoast.</p>
<p>The tool allows you to add a focus keyword and checks the content against it, suggesting optimizations such as the presence of the focus keyword in the title, subheadings, and image alt text. </p>
<p>The tool also evaluates whether the keyword is naturally integrated into the content or if it is overly used.</p>
<p>Additionally, the add-on provides useful information such as Flesch reading scores, content length, and reading time, helping you improve the readability of your content.</p>
<h3 id="heading-image-handling">Image Handling</h3>
<p>The add-on offers effortless image handling by automatically <a target="_blank" href="https://www.freecodecamp.org/news/image-optimization-558d9f449e3/">compressing images</a> before publishing to the WordPress media library. This ensures a sleek media library and enhances your site's loading time.</p>
<p>It also enables you to add featured images directly from Google Docs to your WordPress posts. It can also automatically generate Alt Text for your images, contributing to improved accessibility and SEO.</p>
<p>The add on has a free version with paid features. </p>
<h2 id="heading-using-the-wordpress-gutenberg-editor">Using the WordPress Gutenberg Editor</h2>
<p>Another option for publishing Google Docs to WordPress without additional add-ons is the WordPress Gutenberg editor. When you paste the Google Docs content into the <a target="_blank" href="https://www.wpbeginner.com/beginners-guide/how-to-use-the-new-wordpress-block-editor/">Gutenberg editor</a>, you won't encounter formatting issues such as extra line breaks or span tags.</p>
<p>This proves helpful when your content doesn't include images. But if your content contains images, the Gutenberg editor presents a few challenges. </p>
<p>After pasting the content into WordPress, checking the HTML code reveals that the image source is set to the location of the image in your Google Drive. This implies that you are hosting the images through your personal Google Drive, which is not recommended from a security standpoint.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2024/02/image-147.png" alt="Image" width="600" height="400" loading="lazy">
<em>Images hosted from your Google account</em></p>
<p>Also, deleting the image from your Google Drive or the Google Docs containing the image will result in the image disappearing from your website. This means you have to check your entire website and delete any links of images from your Google Drive.</p>
<p>An alternative approach is to upload the images manually to your WordPress media library and use those images in your posts. This adds some manual work and is error-prone. Also, the images must be manually compressed before uploading to the media library.</p>
<h2 id="heading-markdown-conversion-method">Markdown Conversion Method</h2>
<p>You can <a target="_blank" href="https://www.docstomarkdown.pro/">convert Google Docs to Markdown</a> format using the free and open source add on <a target="_blank" href="https://workspace.google.com/marketplace/app/docs_to_markdown/700168918607">Docs to Markdown</a>. The free tool will convert your fully formatted Google Doc to Markdown format (.md). You can paste this Markdown text into your WordPress editor for perfectly formatted text without any additional line breaks or span tags.</p>
<p>This option is also most useful <em>only</em> if your content doesn't include images. If your content does have images, it requires manual work to compress and upload your images into your WordPress media library and update the HTML accordingly.</p>
<p>Also, this method doesn't include built-in SEO features.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Transferring content from Google Docs to WordPress efficiently is essential for a smooth workflow. </p>
<p>This tutorial has presented four methods: manual copy-paste, using the Docs to WP Pro add-on, using WordPress Gutenberg editor and Markdown conversion method. </p>
<p>Each method has its own advantages and disadvantages, so the best choice for you will depend on your specific needs and preferences.</p>
<ul>
<li><strong>Manual copy-paste</strong> is a simple option but requires manual adjustments for formatting and images.</li>
<li><strong>Docs to WP Pro</strong> offers features like automated internal linking, SEO optimizations and image handling, but may require additional investment.</li>
<li><strong>WordPress Gutenberg editor</strong> is a best option for the text only posts, but if you have images, then it requires additional work to host your images on WordPress media library. </li>
<li><strong>Converting to Markdown</strong> preserves formatting but requires manual image handling and lacks SEO optimization features.</li>
</ul>
<p>Consider factors like the amount of content you create, your budget, and your technical expertise when making your decision.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Create a WordPress Store that Sells Real AI-Generated Products ]]>
                </title>
                <description>
                    <![CDATA[ The combination of artificial intelligence (AI) and web development has revolutionized the way we create and manage online content.   I just created and released a course on the freeCodeCamp.org YouTube channel that will teach you how to use AI to he... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/create-a-wordpress-store-that-sells-real-ai-generated-products/</link>
                <guid isPermaLink="false">66b201b7a8b92c9329236431</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 07 Nov 2023 15:52:15 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/11/aiwordpress2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>The combination of artificial intelligence (AI) and web development has revolutionized the way we create and manage online content.  </p>
<p>I just created and released a course on the freeCodeCamp.org YouTube channel that will teach you how to use AI to help create an e-commerce store powered by WordPress. You will use AI for everything from creating content to creating actual products to sell.</p>
<p>Whether you're looking to create an e-commerce platform or simply trying to expand your web development skills, this course offers insights into leveraging WordPress alongside AI. I will demonstrate everything from the initial setup of hosting and domain to the customization of WordPress themes and pages.  </p>
<p>In addition to teaching you how to quickly set up a WordPress store, I'll show you how to use AI to create sticker designs. You will learn how to add the stickers to your store as actual physical products that people can buy. And you don't even have to deal with shipping anything yourself.</p>
<p>Here are the sections covered in this course:</p>
<ul>
<li>Introduction</li>
<li>Set up hosting and domain</li>
<li>Set up WordPress with AI</li>
<li>Set up email</li>
<li>Start customizing WordPress</li>
<li>Create logo with AI</li>
<li>Update WordPress pages and store</li>
<li>Create images for site using AI</li>
<li>Update home page</li>
<li>Customize menus</li>
<li>Customize blog posts</li>
<li>Use AI to create sticker designs</li>
<li>Add products to store</li>
<li>Change look of cart</li>
<li>Add payment processing and shipping</li>
<li>Test an order and set up billing method on Printful</li>
<li>Create your first order</li>
<li>Conclusion</li>
</ul>
<p>By the end of this course, you'll not only have acquired the skills to create an AI-assisted WordPress e-commerce site but also the confidence to explore the limitless possibilities that AI and web development hold. </p>
<p>Watch the full course on <a target="_blank" href="https://www.youtube.com/watch?v=16BWeTg7mA0">the freeCodeCamp.org YouTube channel</a> (1-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/16BWeTg7mA0" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ The Ultimate Guide to High Performance WordPress ]]>
                </title>
                <description>
                    <![CDATA[ There are many strategies you can do to increase the performance of your WordPress websites and other websites. In this guide, we'll show you how to identify and fix performance issues for good. This guide combines over 20 years of experience of fine... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/the-ultimate-guide-to-high-performance-wordpress/</link>
                <guid isPermaLink="false">66b206a0297cd6de0bd54694</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Tue, 15 Aug 2023 14:35:11 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/wordpressop.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>There are many strategies you can do to increase the performance of your WordPress websites and other websites. In this guide, we'll show you how to identify and fix performance issues for good. This guide combines over 20 years of experience of fine-tuning servers, CDNs, and website code to deliver high performance WordPress sites.</p>
<p>This guide was put together by the team at InMotion Hosting. They offer web hosting, servers, and cloud WordPress hosting. </p>
<p>I created a course based on this guide (and other resources) to teach people how to improve the performance of their WordPress and non-WordPress websites. You can watch the course below or <a target="_blank" href="https://www.youtube.com/watch?v=enb5kTJwV_s">on the freeCodeCamp.org YouTube channel</a>. InMotion Hosting provided a grant to make this video course possible. Right after the video embed you can start reading the guide.</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/enb5kTJwV_s" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p>Here are the top steps you can take right now to get immediate performance results:</p>
<ul>
<li>Setting Your Performance Goals</li>
<li>Understanding a Website Request</li>
<li>DNS Configuration &amp; CDNs</li>
<li>Server Configuration &amp; Tuning for WordPress</li>
<li>Caching Techniques</li>
<li>Optimizing the WordPress Application</li>
<li>Monitoring &amp; Adjusting</li>
</ul>
<p>Website performance is a critical factor in the success of any website, and optimizing your website for speed should be a top priority. This guide is an invaluable resource for anyone looking to optimize their website's performance and gain a competitive edge in the online marketplace. By following the practical advice and best practices outlined in this guide, you can improve your website's performance and provide your users with a fast, efficient, and enjoyable online experience.</p>
<h2 id="heading-setting-your-performance-goals">Setting Your Performance Goals</h2>
<p>Determining goals for optimizing a website's speed and performance is crucial to achieving desired outcomes. Here are some steps to help you establish clear goals and objectives:</p>
<ul>
<li><strong>Define your purpose:</strong> Start by understanding why you want to optimize your site's speed and performance. Is it to enhance user experience, reduce bounce rates, improve conversion rates, or achieve better search engine rankings? Clarifying your purpose will guide your goal-setting process.</li>
<li><strong>Analyze current performance:</strong> Use tools like Google Lighthouse, Google PageSpeed Insights, Google Search Console, or WebPageTest to evaluate your website's current speed and performance. Identify areas where improvements are needed, such as slow loading times, excessive page weight, or high server response times. These insights will help you prioritize and set specific goals.</li>
<li><strong>Prioritize metrics:</strong> Determine which performance metrics are most important for your website. Common metrics include page load time, time to first byte (TTFB), render start time, and interactive time. Align these metrics with your purpose to identify the most critical areas for improvement.</li>
<li><strong>Set measurable targets:</strong> Establish specific, measurable, achievable, relevant, and time-bound (SMART) goals. For example, set a goal to reduce page load time by 30% within three months or achieve a TTFB of under 200 milliseconds. Clear targets will provide a benchmark for progress and help you stay focused.</li>
<li><strong>Consider user expectations:</strong> Understand your target audience's expectations and browsing behavior. Different websites may require different levels of optimization based on their user base. Consider factors like device usage (mobile vs. desktop), geographic location, and connection speeds to tailor your goals accordingly.</li>
<li><strong>Break it down:</strong> Divide your optimization goals into smaller, actionable tasks. For instance, optimizing image sizes, minifying CSS and JavaScript, leveraging browser caching, or implementing a content delivery network (CDN). Breaking down goals into manageable steps makes them more achievable and allows for incremental improvements.</li>
<li><strong>Monitor and iterate:</strong> Regularly monitor your website's performance using performance monitoring tools or website analytics. Track progress towards your goals and identify areas that need further optimization. Continuously iterate your strategies to adapt to changing technologies and user expectations.</li>
</ul>
<p>By following these steps, you can establish well-defined goals for optimizing your website's speed and performance. Remember, the goals should be aligned with your website's purpose, measurable, and adaptable to evolving needs.</p>
<h2 id="heading-performance-testing-tools">Performance Testing Tools</h2>
<p>There are many testing tools available online to gauge your website performance. In this section, we want to get a website to rank better on Google, so we will use Google's tools to achieve our goals. There are also some other pretty awesome optimization tools such as GTMetrix, Pingdom, and many others.</p>
<h3 id="heading-google-lighthouse">Google Lighthouse</h3>
<p>Before we explain how to assess your site prior to optimizing, let’s go over a quick outline of how the different pieces are weighted in the Lighthouse tests. The <a target="_blank" href="https://googlechrome.github.io/lighthouse/scorecalc/">Lighthouse Scoring Calculator</a> gives this information at a glance, and even allows you to plug in your own scores to understand how your overall PageSpeed score is calculated.</p>
<p>Inside Chrome’s Developer Tools (DevTools), you can use the code inspector to get to the Open Source Extension for Google Lighthouse. It is helpful because it runs tests right within your browser, and generates a report for you on how well the website you are looking at stacks up for both mobile and desktop versions. This test gives you information about performance, accessibility, best practices, and SEO.</p>
<table><colgroup><col></colgroup><tbody><tr><td><p><span>Tip:</span><span> When performing a test with DevTools, you want to use an </span><span>incognito window</span><span> or </span><span>guest account</span><span>, as browser extensions typically interfere with the test and skew the results.</span></p></td></tr></tbody></table>

<p><img src="https://lh3.googleusercontent.com/D2CQPF9AM7a1yPNRcV4giv33JURmZUqlL835A-B0lWNlIpdZzjbYWGJQCxAJvZFkYbKeRbGmf9eI8GqgZF7cm4VXVr2LXnQgyEwhYngtNVCCrdWnonMvHPiqTTkqCh9QnZLL4EW0aFkl5S1NlzHOW9A" alt="Image" width="600" height="400" loading="lazy"></p>
<p><em>Example of what this report looks like in your browser</em></p>
<p>Google Lighthouse also provides an “opportunity” list with items you can optimize on your page to improve your site's pagespeed, and by proxy, improve the performance scoring of your page.</p>
<p><img src="https://lh5.googleusercontent.com/Ici_9dLO67AFC2jm0mLxBmc4V2MZE6CTA4x-1dtU8D35zbQQBL8nNR9CjSX8S-Ry3p1JWGXXnvb5o6IX8eH77-Je74mkR7vRDzNDQvy4AA_i3AENwott94NwxzndVstIPLSz2Xvi0nbQDUhOOeNSRI8" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-pagespeed-insights">PageSpeed Insights</h3>
<p><a target="_blank" href="https://pagespeed.web.dev/">PageSpeed Insights</a> (PSI) is an online tool that tests your site and then delivers a score for both mobile devices and desktop computers. You will see a score and a breakdown of the metrics used to determine your site performance. PSI will also provide a breakdown of the issues causing any slowdowns to the performance of your site. Recommendations are provided on actions you can take to improve performance. PSI uses simulations and real-world data (when available) to provide its scores.</p>
<p><img src="https://lh3.googleusercontent.com/yCrObZfCoAkmCcuLpMa4TfevoIDlt9N94a2G-0s0VoS14OJLsWcvFXKbuLY_ljfJ-sG4xO_3bppSa-AiCAkrMnCnxU7yGdzhcbQyAmbSPnKCQ9_gBDZtIPkkPDP3UPBy2AeSamkr2xQLPFSY4yyn3nM" alt="Image" width="600" height="400" loading="lazy"></p>
<p><strong>Chrome User Experience Report</strong></p>
<p>The Chrome User Experience Report is also called the Core Web Vitals metrics. This is an aggregate of user experience metrics that is compiled from actual users that visit your website over the last 28 days.</p>
<p><img src="https://lh4.googleusercontent.com/sKvUxNDEkANprvlnLFYG1LeLDuYXP-Iov-dP27xyhzTdiu4oSRGQGd0Ix5aZW7uxd8Du0Em60Y4PuLjCVz9YTFRe4HLnk2BOb7zuOoiqWPdoaqb82PaUZ4TFjpo_Aao-cLV18FjiH0Z8yNmhO7uwdAk" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This data is not comprehensive, however. These users are limited to people that have opted to sync their browser history with Chrome, and the data is made available by PageSpeed Insights, Google’s BigQuery project, and Data Studio. While it is helpful information when optimizing your website for speed and performance, it is not representative of everyone’s experience with your site.</p>
<h3 id="heading-google-search-console">Google Search Console</h3>
<p>The Page Experience report in Google’s Search Console provides you with a summary of their measurement for your visitors' user experience. Google evaluates these metrics for individual URLs on your website and will use them as a ranking signal in search results.</p>
<p>This report covers Core Web Vitals, mobile usability, and HTTPS usage for every page that you have in Google’s index. In order for a page to be counted in this report's data, it must also have data in the Core Web Vitals report simultaneously.</p>
<h3 id="heading-other-performance-testing-tools">Other Performance Testing Tools</h3>
<p>We should mention other tools as well because this is by no means an exhaustive list.</p>
<p>In short, there are a ton of professional tools that you can use to measure your website’s performance, such as <a target="_blank" href="https://gtmetrix.com/">GTMetrix</a>, <a target="_blank" href="https://www.webpagetest.org/">Pingdom</a>, <a target="_blank" href="https://www.webpagetest.org/">WebPageTest</a>, and more.</p>
<p>Any tool you use will guide you with things that need to be done to improve your website speed.</p>
<h2 id="heading-why-are-my-scores-always-different">Why Are My Scores Always Different?</h2>
<p>There are many factors that will impact the score you see on these tests. These variables can range from your location related to the website, activity on your server, network routes, and even the activity on your local computer.</p>
<p>Because of these and many other factors, no two tests will show the exact same results.</p>
<p>However, with a little persistence, you can minimize the impact that your server and website bring into the equation. Simply follow the suggestions, learn about them and implement best practices. This will increase the likelihood that your visitors will have a good user experience.View <a target="_blank" href="https://github.com/GoogleChrome/lighthouse/blob/main/docs/variability.md">Lighthouse’s Score Variability</a> documentation for a table containing several common sources of metric variability, the impact they have on results, and the extent to which they are likely to occur in different environments.</p>
<h2 id="heading-speed-and-performance-indicators">Speed and Performance Indicators</h2>
<p>When testing your website’s performance and putting together your plan of attack, the tool you use will dictate the metrics used in the audit. Here are the top performance indicators to pay attention to. We recommend focusing on achieving passing (green) scores on Core Web Vitals before you move onto the other performance metrics.</p>
<h3 id="heading-core-web-vitals">Core Web Vitals</h3>
<p>The key to success for your website is to focus on the user experience. Google’s Core Web Vitals are a set of metrics that measure real-world user experience for loading performance, interactivity, and visual stability of the page. These metrics are designed to help you understand how good the user experience is on your site compared to other sites on the web.</p>
<p><a target="_blank" href="https://www.inmotionhosting.com/blog/core-web-vitals/">Core Web Vitals</a> are broken down into a subset of page experience signals that apply to all websites and should be measured by website owners. The metrics that make up Core Web Vitals are subject to evolve over time as these signals are not set in stone, and are intended to change as time passes to continue improving the overall user experience on the web.</p>
<p>Page Experience Signals and Core Web Vitals are the best signals that developers have to measure and improve the quality of user experience, and they are broken down into Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS). Below, we will outline what each signal is, and share some best practices and steps to take to ensure you improve your website's performance in relation to each metric.</p>
<p>Tools that measure Core Web Vitals consider a page to be passing if it meets the recommended target of 75th percentile for all 3 metrics.</p>
<h3 id="heading-largest-contentful-paint-lcp">Largest Contentful Paint (LCP)</h3>
<p>LCP measures your website's loading performance. In order to provide a good user experience for your visitors, your LCP should occur within 2.5 seconds of the initial page loading.</p>
<p>The types of elements that are considered for largest contentful paint are usually images or videos. It is important to understand that an element can only be considered the LCP once it is rendered, and the user can see it.</p>
<p>This metric is also tied to First Contentful Paint (FCP), which measures how long it takes for the initial DOM content to render, but FCP does not account for how long it takes the largest and usually more important content on page to render.</p>
<ul>
<li><strong>What LCP represents:</strong> A user’s perception of loading experience.</li>
<li><strong>Lighthouse Performance score weighting:</strong> 25%</li>
<li><strong>What it measures:</strong> The point in the page load timeline when the page’s largest image or text block is visible within the viewport.</li>
<li><strong>How it’s measured:</strong> Lighthouse extracts LCP data from <a target="_blank" href="https://www.chromium.org/developers/how-tos/trace-event-profiling-tool">Chrome’s tracing tool</a>.</li>
<li><strong>Is Largest Contentful Paint a Web Core Vital?</strong> Yes</li>
</ul>
<h4 id="heading-lcp-scoring">LCP Scoring</h4>
<table><colgroup><col><col></colgroup><tbody><tr><td><br><div><table><colgroup><col><col></colgroup><tbody><tr><td><p><span>LCP Time (seconds)</span></p></td><td><p><span>Color-Coding Score</span></p></td></tr><tr><td><p><span>0 - 2.5 seconds</span></p></td><td><p><span>Green (Fast / Good)</span></p></td></tr><tr><td><p><span>2.5 - 4.0 seconds</span></p></td><td><p><span>Orange (Moderate /&nbsp;</span></p><p><span>Needs Improvement)</span></p></td></tr><tr><td><p><span>Over 4.0 seconds</span></p></td><td><p><span>Red (Slow / Poor)</span></p></td></tr></tbody></table></div><br></td><td><p><span><span><img src="https://lh3.googleusercontent.com/Zrn9zJr3HveL4HQ3nEiBosGrgeLyaZ_OBPijlhiDmxeJLa8jYf3eTBP4Cz-NoXliT5AoPtb8laF7msE0flDJ0ZYCZkVMwdYaQs5HduWrFCGoeLdpNwLRhB8-CBMZrTic93AVkwAZ6BLrMeoKFHIULM8" width="600" height="400" alt="Zrn9zJr3HveL4HQ3nEiBosGrgeLyaZ_OBPijlhiDmxeJLa8jYf3eTBP4Cz-NoXliT5AoPtb8laF7msE0flDJ0ZYCZkVMwdYaQs5HduWrFCGoeLdpNwLRhB8-CBMZrTic93AVkwAZ6BLrMeoKFHIULM8" loading="lazy"></span></span></p></td></tr></tbody></table>

<h4 id="heading-what-elements-are-part-of-lcp">What Elements are Part of LCP?</h4>
<ul>
<li><img width="600" height="400" alt="" loading="lazy"> elements</li>
<li> elements inside an  element</li>
<li> elements (the poster image is used)</li>
<li>An element with a background image loaded via the url() function (as opposed to a CSS gradient)</li>
<li>Block-level elements containing text nodes or other inline-level text elements children.</li>
</ul>
<h4 id="heading-how-to-define-lcp-using-chrome-devtools">How To Define LCP Using Chrome Devtools</h4>
<ol>
<li>Open the page in Chrome.</li>
<li>Navigate to the <strong>Performance</strong> panel of Dev Tools (Command + Option + I on Mac or Control + Shift + I on Windows and Linux).</li>
<li>Hover over the LCP marker in the <strong>Timings</strong> section.</li>
<li>The element(s) that correspond to LCP is detailed in the <strong>Related Node</strong> field.</li>
</ol>
<h4 id="heading-what-causes-poor-lcp">What Causes Poor LCP?</h4>
<p>Poor LCP typically comes from four issues:</p>
<ul>
<li>Slow server response times.</li>
<li>Render-blocking JavaScript and CSS.</li>
<li>Resource load times.</li>
<li>Client-side rendering.</li>
</ul>
<h4 id="heading-how-to-improve-lcp">How to Improve LCP</h4>
<p>The usual suspects of a poor LCP can be caused by many things. Some of the causes can be slow response times from the server, render blocking JavaScript and CSS, slow resource load times and even client rendering.</p>
<p>Slow server response times is the first thing you should tackle when optimizing for performance. A faster server response will directly impact and improve every page loading measurement, including LCP.</p>
<p>If the cause is <strong>slow server response time</strong>:</p>
<ul>
<li>Optimize your server.</li>
<li>Route users to a nearby CDN.</li>
<li>Cache assets.</li>
<li>Serve HTML page cache-first.</li>
<li>Establish third-party connections early.  </li>
</ul>
<p>If the cause is <strong>render-blocking JavaScript and CSS</strong>:</p>
<ul>
<li>Minify CSS.</li>
<li>Defer non-critical CSS.</li>
<li>Inline critical CSS.</li>
<li>Minify and compress JavaScript files.</li>
<li>Defer unused JavaScript.</li>
<li>Minimize unused polyfills.  </li>
</ul>
<p>If the cause is <strong>resource load times</strong>:</p>
<ul>
<li>Optimize and compress images.</li>
<li>Preload important resources.</li>
<li>Compress text files.</li>
<li>Deliver different assets based on the network connection (adaptive serving).</li>
<li>Cache assets using a service worker.  </li>
</ul>
<p>If the cause is <strong>client-side rendering</strong>:</p>
<ul>
<li>Minimize critical JavaScript.</li>
<li>Use another <a target="_blank" href="https://www.searchenginejournal.com/rendering-seo-introduction/330399/">rendering strategy</a>.</li>
</ul>
<h3 id="heading-first-input-delay-fid">First Input Delay (FID)</h3>
<p>First Input Delay (FID) measures a website's interactivity and focuses on input events from discrete actions like clicks, taps, and key presses. When a website does not respond in a certain amount of time after a user interaction, users experience this as lag, or slowdown. To provide a good user experience your web pages should have a FID of 100 milliseconds or less.</p>
<ul>
<li><strong>What it represents:</strong> Your user's first impression of your site's interactivity and responsiveness.</li>
<li><strong>Lighthouse Performance score weighting:</strong> N/A</li>
<li><strong>What it measures:</strong> Measures the time from when a user first interacts with your site (when they click a link, tap a button, or use a custom, JavaScript-powered control) to the time when the browser is actually able to respond to that interaction.</li>
<li><strong>How it’s measured:</strong> FID requires a real user and thus cannot be measured in the lab. However, the Total Blocking Time (TBT) metric is lab-measurable and can be used as a proxy as it correlates well with FID in the field, and also captures issues that affect interactivity. Optimizations that improve TBT should also improve FID in the field.</li>
<li><strong>Is Largest Contentful Paint a Web Core Vital?</strong> Yes</li>
</ul>
<h4 id="heading-fid-scoring">FID Scoring</h4>
<table><colgroup><col><col></colgroup><tbody><tr><td><br><div><table><colgroup><col><col></colgroup><tbody><tr><td><p><span>FID Time (milliseconds)</span></p></td><td><p><span>Color-Coding Score</span></p></td></tr><tr><td><p><span>0 - 100 milliseconds</span></p></td><td><p><span>Green (Fast / Good)</span></p></td></tr><tr><td><p><span>101 - 300 milliseconds</span></p></td><td><p><span>Orange (Moderate /&nbsp;</span></p><p><span>Needs Improvement)</span></p></td></tr><tr><td><p><span>Over 300 milliseconds</span></p></td><td><p><span>Red (Slow / Poor)</span></p></td></tr></tbody></table></div><br></td><td><p><span><span><img src="https://lh5.googleusercontent.com/tFvhn1l5YD1M--V4OzvEbuuDeDGAHDyFJfNhz3TYjoJ4HKB_9YKXqPGVI1Gt-PFnHDrXRtn5CzrQ1X7PkcpKIeLO1aJMjyFrVanfSAI8ThY3MrMdfTUP0tWuTAih95OIKkCODlBLOI3QIR67wYYe6-c" width="600" height="400" alt="tFvhn1l5YD1M--V4OzvEbuuDeDGAHDyFJfNhz3TYjoJ4HKB_9YKXqPGVI1Gt-PFnHDrXRtn5CzrQ1X7PkcpKIeLO1aJMjyFrVanfSAI8ThY3MrMdfTUP0tWuTAih95OIKkCODlBLOI3QIR67wYYe6-c" loading="lazy"></span></span></p></td></tr></tbody></table>

<h4 id="heading-what-causes-poor-fid">What Causes Poor FID?</h4>
<p>The main cause of a poor FID is heavy JavaScript execution. Optimizing how JavaScript parses, compiles, and executes on your web page will directly reduce FID.</p>
<h4 id="heading-how-to-improve-fid">How to Improve FID</h4>
<ul>
<li>Reduce the impact of third-party script execution</li>
<li>Reduce JavaScript execution time</li>
<li>Defer unused JavaScript</li>
<li>Minimize unused polyfills</li>
<li>Break up Long Tasks</li>
<li>Optimize your page for interaction readiness</li>
<li>Use a web worker</li>
<li>Minimize main thread work</li>
<li>Keep request counts low and transfer sizes small</li>
</ul>
<h3 id="heading-cumulative-layout-shift-cls">Cumulative Layout Shift (CLS)</h3>
<p>CLS measures visual stability. A good user experience is measured as having a CLS of 0.1 or less. This allows the experience to avoid any surprises for the user but isn’t particularly helpful for page speed, it's more a measurement that your website is following best practices and is a necessary piece for achieving a high performance score for your page.</p>
<p>These best practices include following common UX patterns that are optimized for CLS. When your page is loading, you should always be sure to set size attributes or reserve space. This will help ensure your page does not jitter and move for the customer while they are trying to interact with it.</p>
<p>Your website should never insert content above existing content unless a user interacts and expects the behavior, and you should always use transform animations when transforming the layout during said interactions.</p>
<ul>
<li><strong>What it represents:</strong> The visual stability of a page. Instability is defined as unexpected movement of page content as the user is trying to interact with the page.</li>
<li><strong>Lighthouse Performance score weighting:</strong> 15%</li>
<li><strong>What it measures:</strong> CLS measures the largest burst of layout shift scores for every unexpected layout shift that occurs during the entire lifespan of a page. A layout shift occurs any time a visible element changes its position from one rendered frame to the next.</li>
<li><strong>How it’s measured:</strong> To calculate the layout shift score, the browser looks at the viewport size and the movement of unstable elements in the viewport between two rendered frames. The layout shift score is a product of two measures of that movement: the impact fraction and the distance fraction</li>
<li><strong>Is Cumulative Layout Shift a Web Core Vital?</strong> Yes</li>
</ul>
<h4 id="heading-cls-scoring">CLS Scoring</h4>
<table><colgroup><col><col></colgroup><tbody><tr><td><br><div><table><colgroup><col><col><col></colgroup><tbody><tr><td><p><span>CLS Scores</span></p></td><td><p><span>Color-Coding Score</span></p></td></tr><tr><td><p><span>0.1</span></p></td><td><p><span>Green (Fast / Good)</span></p></td></tr><tr><td><p><span>0.1 - 0.25</span></p></td><td><p><span>Orange (Moderate / Needs Improvement)</span></p></td></tr><tr><td><p><span>Over 0.25</span></p></td><td><p><span>Red (Slow / Poor)</span></p></td></tr></tbody></table></div><br></td><td><br><span><img src="https://lh3.googleusercontent.com/8uAS80qGoXOOqddjTCiiCoumNr2Kc5VZgJAoklpLdkV_DNAQFb9lERlOfJp3kY14BG43udgu0N-ftfVAC3QioC0li1fqqJUiTb_ZEVQIZeUfumzbiGT1EMwHT-bF-Za5c1Krgq5kTnaeuzcNnvsUBzU" width="600" height="400" alt="8uAS80qGoXOOqddjTCiiCoumNr2Kc5VZgJAoklpLdkV_DNAQFb9lERlOfJp3kY14BG43udgu0N-ftfVAC3QioC0li1fqqJUiTb_ZEVQIZeUfumzbiGT1EMwHT-bF-Za5c1Krgq5kTnaeuzcNnvsUBzU" loading="lazy"></span></td></tr></tbody></table>




<h4 id="heading-how-to-see-cls-using-chrome-devtools">How To See CLS Using Chrome DevTools</h4>
<p>Use DevTools to help debug layout shifts by leveraging the <strong>Experience</strong> pane under the <strong>Performance</strong> panel.</p>
<p>The <strong>Summary</strong> view for a Layout Shift record includes the Cumulative Layout Shift score as well as a rectangle overlay showing the affected regions.</p>
<p><img src="https://lh4.googleusercontent.com/wya-5Stb54NHzdqExb7phNnYkcukIZRGiQxgSTl5oWVNWM31uf-QwOFsRT9MTusyv2tQkAJit8O0m5yApq_NMIVI5PVCbE3U87S8jY4vVe1kcqkM30fCAEPXxjhC68bzQ-FDLheXKPelL7VC4nz83XI" alt="Image" width="600" height="400" loading="lazy"></p>
<h4 id="heading-what-causes-poor-layout-shifts">What Causes Poor Layout Shifts?</h4>
<ul>
<li>Changes to the position of a DOM element</li>
<li>This is often the result of:</li>
<li>Stylesheets that are loaded late or overwrite previously declared style.</li>
<li>Delays in animation and transition effects.</li>
<li>Changes to the dimensions of a DOM element</li>
<li>This often the result of:</li>
<li>Images, ads, embeds, and iframes without dimensions</li>
<li>Insertion or removal of a DOM element</li>
<li>Animations that trigger layout</li>
<li>This is often the result of:</li>
<li>Insertion of ads and other third-party embeds.</li>
<li>Insertion of banners, alerts, and modals.</li>
<li>Infinite scroll and other UX patterns that load additional content above existing content.</li>
<li>Actions waiting for a network response before updating DOM</li>
</ul>
<h4 id="heading-how-to-improve-cls">How to Improve CLS</h4>
<ul>
<li>Always set size attributes to images and video elements, or allocate the correct amount of space for that element while it is loading.</li>
<li>Never insert content above existing content, except during an intentional user interaction.</li>
<li>Prefer transform animations to animations of properties that trigger layout changes.</li>
<li>Preload fonts using &lt;<strong>link</strong> rel=preload&gt; on the key web fonts, and combine &lt;<strong>link</strong> rel=preload&gt; with font-display: optional</li>
</ul>
<h4 id="heading-additional-resources">Additional Resources</h4>
<ul>
<li><a target="_blank" href="https://web.dev/cls/">Cumulative Layout Shift (CLS)</a> - web.dev</li>
<li><a target="_blank" href="https://web.dev/optimize-cls/">Optimize Cumulative Layout Shift</a> - web.dev</li>
<li><a target="_blank" href="https://web.dev/debug-layout-shifts/">Debug Layout Shifts</a> - web.dev  </li>
</ul>
<h2 id="heading-other-performance-opportunities">Other Performance Opportunities</h2>
<h3 id="heading-first-contentful-paint-fcp">First Contentful Paint (FCP)</h3>
<p>Measures time to render the first piece of DOM content.  </p>
<ul>
<li><strong>What it represents:</strong> The amount of time it takes the browser to render the first piece of DOM content after a user navigates to your page. Images, non-white &lt;<strong>canvas</strong>&gt; elements, and SVGs on your page are considered DOM content.</li>
<li><strong>Lighthouse Performance score weighting:</strong> 10%</li>
<li><strong>What it measures:</strong> FCP is a user-centric metric for measuring perceived load speed because it marks the first point in the page load timeline where the user can see anything on the screen.</li>
<li><strong>How it’s measured:</strong> The FCP score is a comparison of your page's FCP time and FCP times for real websites, based on data from the HTTP Archive.</li>
<li><strong>Is Largest Contentful Paint a Web Core Vital?</strong> No  </li>
</ul>
<h4 id="heading-fcp-scoring">FCP Scoring</h4>
<table><colgroup><col><col></colgroup><tbody><tr><td><br><div><table><colgroup><col><col><col></colgroup><tbody><tr><td><p><span>FCP Time (seconds)</span></p></td><td><p><span>Color-Coding Score</span></p></td></tr><tr><td><p><span>0 - 1.8 seconds</span></p></td><td><p><span>Green (Fast / Good)</span></p></td></tr><tr><td><p><span>1.8 - 3 seconds</span></p></td><td><p><span>Orange (Moderate / Needs Improvement)</span></p></td></tr><tr><td><p><span>Over 3 seconds</span></p></td><td><p><span>Red (Slow / Poor)</span></p></td></tr></tbody></table></div><br></td><td><br><span><img src="https://lh4.googleusercontent.com/cUC3oP-0AqRZCBVMbks4tvNqECBdbQoQdZKud8rnJ69Ix6-7p1TOYgBQ0M_AjjS2v_9Ea5GTRUm2D_QjDSMYbmqEnLjwDigNAyjB1MFV4feXcSY4vqEtOCP70tdOcWJKzKPV4M11-5Bvj-1kBrCJa6s" width="600" height="400" alt="cUC3oP-0AqRZCBVMbks4tvNqECBdbQoQdZKud8rnJ69Ix6-7p1TOYgBQ0M_AjjS2v_9Ea5GTRUm2D_QjDSMYbmqEnLjwDigNAyjB1MFV4feXcSY4vqEtOCP70tdOcWJKzKPV4M11-5Bvj-1kBrCJa6s" loading="lazy"></span></td></tr></tbody></table>

<h4 id="heading-how-to-improve-fcp">How to Improve FCP</h4>
<ul>
<li>Eliminate render-blocking resources</li>
<li>Minify CSS</li>
<li>Remove unused CSS</li>
<li>Preconnect to required origins</li>
<li>Reduce server response times (TTFB)</li>
<li>Avoid multiple page redirects</li>
<li>Preload key requests</li>
<li>Avoid enormous network payloads</li>
<li>Serve static assets with an efficient cache policy</li>
<li>Avoid an excessive DOM size</li>
<li>Minimize critical request depth</li>
<li>Ensure text remains visible during webfont load</li>
<li>Keep request counts low and transfer sizes small</li>
</ul>
<h4 id="heading-additional-resources-1">Additional Resources</h4>
<ul>
<li><a target="_blank" href="https://web.dev/fcp/">First Contentful Paint (FCP)</a> - web.dev</li>
</ul>
<h3 id="heading-speed-index-si">Speed Index (SI)</h3>
<ul>
<li><strong>What it represents:</strong> The average time at which visible parts of the page are displayed.</li>
<li><strong>Lighthouse Performance score weighting:</strong> 10%</li>
<li><strong>What it measures:</strong> Speed Index measures how quickly content is visually displayed during page load. Lighthouse first captures a video of the page loading in the browser and computes the visual progression between frames.</li>
<li><strong>How it’s measured:</strong> The Speed Index score is a comparison of your page's speed index and the speed indices of real websites, based on data from the HTTP Archive.</li>
<li><strong>Is Largest Contentful Paint a Web Core Vital?</strong> No</li>
</ul>
<h4 id="heading-speed-index-scoring">Speed Index Scoring</h4>
<table><colgroup><col><col></colgroup><tbody><tr><td><p><span>Speed Index (seconds)</span></p></td><td><p><span>Color-Coding Score</span></p></td></tr><tr><td><p><span>0 - 3.4 seconds</span></p></td><td><p><span>Green (Fast / Good)</span></p></td></tr><tr><td><p><span>3.4 - 5.8 seconds</span></p></td><td><p><span>Orange (Moderate /&nbsp;</span></p><p><span>Needs Improvement)</span></p></td></tr><tr><td><p><span>Over 5.8 seconds</span></p></td><td><p><span>Red (Slow / Poor)</span></p></td></tr></tbody></table>

<h4 id="heading-how-to-improve-speed-index">How to Improve Speed Index</h4>
<ul>
<li>Minimize main thread work</li>
<li>Reduce JavaScript execution time</li>
<li>Ensure text remains visible during webfont load</li>
<li>Eliminate render-blocking resources</li>
</ul>
<h4 id="heading-additional-resources-2">Additional Resources</h4>
<ul>
<li><a target="_blank" href="https://web.dev/speed-index/">Speed Index</a> - web.dev</li>
<li><a target="_blank" href="https://github.com/WPO-Foundation/webpagetest-docs/blob/main/src/metrics/SpeedIndex.md">WebPagetest Speed Index</a>  </li>
</ul>
<h3 id="heading-total-blocking-time-tbt">Total Blocking Time (TBT)</h3>
<ul>
<li><strong>What it represents:</strong> The total amount of time that a page is blocked from responding to user input, such as mouse clicks, screen taps, or keyboard presses.</li>
<li><strong>Lighthouse Performance score weighting:</strong> 30%</li>
<li><strong>What it measures:</strong> TBT measures the time between First Contentful Paint and Time to Interactive. TBT is the lab equivalent of First Input Delay (FID) – the field data used in the Chrome User Experience Report and Google’s Page Experience ranking signal.</li>
<li><strong>How it’s measured:</strong> The total time in which the main thread is occupied by tasks taking more than 50ms to complete. If a task takes 80ms to run, 30ms of that time will be counted toward TBT. If a task takes 45ms to run, 0ms will be added to TBT.</li>
<li><strong>Is Total Blocking Time a Web Core Vital?</strong> Yes! It’s the lab data equivalent of First Input Delay (FID).</li>
</ul>
<h4 id="heading-tbt-scoring">TBT Scoring</h4>
<table><colgroup><col><col></colgroup><tbody><tr><td><p><span>TBT Time (milliseconds)</span></p></td><td><p><span>Color-Coding Score</span></p></td></tr><tr><td><p><span>0 - 200ms</span></p></td><td><p><span>Green (Fast / Good)</span></p></td></tr><tr><td><p><span>200 - 600ms</span></p></td><td><p><span>Orange (Moderate / Needs Improvement)</span></p></td></tr><tr><td><p><span>Over 600ms</span></p></td><td><p><span>Red (Slow / Poor)</span></p></td></tr></tbody></table>




<h4 id="heading-long-tasks-and-total-blocking-time">Long Tasks and Total Blocking Time</h4>
<p>TBT measures long tasks – those taking longer than 50ms.</p>
<p>When a browser loads your site, there is essentially a single line queue of scripts waiting to be executed.</p>
<p>Any input from the user has to go into that same queue.</p>
<p>When the browser can’t respond to user input because other tasks are executing, the user perceives this as lag.</p>
<p>Essentially, long tasks are like that person at your favorite coffee shop who takes far too long to order a drink.</p>
<p>Like someone ordering a 2% venti four-pump vanilla, five-pump mocha whole-fat froth, long tasks are a major source of bad experiences.</p>
<p><img src="https://lh3.googleusercontent.com/39Zmo8-vgVxoAhVxCtXmkuwyC9KspUXKGQzDnaEFXzu70HCuuAtabgAS_jka-Qzp3ElAsjRGWUCbBhOnRsqOvTl_cOSxag0Mj12pejXQG_FnjTQqiFuRshiKKzWhlavRrctgGaK9vFrL9ofqusRilpA" alt="Short tasks vs. long tasks" width="600" height="400" loading="lazy"></p>
<h4 id="heading-what-causes-high-tbt-on-your-page">What Causes High TBT on your Page?</h4>
<ul>
<li>Heavy JavaScript</li>
<li>Heavy CSS</li>
</ul>
<p>That’s it.</p>
<h4 id="heading-how-to-see-tbt-using-chrome-devtools">How To See TBT Using Chrome DevTools</h4>
<p><img src="https://lh3.googleusercontent.com/bq3y2cnbChfVik2dXdKO01UTU6oQMMHUtogHcHjkv0N7R6qyBKe5aZr-BbIVuEnRw-JoVwrGQ5lRtVz6G4st6u8p7YalWEdgVGxDrJAXGl28SDbcMZkLiA9Ho5HIWcMo96w7NnscuvfzzX7BGPfB8YI" alt="A Technical SEO Guide To Lighthouse Performance Metrics" width="600" height="400" loading="lazy"></p>
<h4 id="heading-how-to-improve-tbt">How to Improve TBT</h4>
<ul>
<li>Break up Long Tasks.</li>
<li>Optimize your page for interaction readiness.</li>
<li>Use a web worker.</li>
<li>Reduce JavaScript execution time.</li>
</ul>
<h4 id="heading-additional-resources-3">Additional Resources</h4>
<ul>
<li><a target="_blank" href="https://web.dev/fid/">First Input Delay (FID)</a> - web.dev</li>
<li><a target="_blank" href="https://web.dev/tbt/">Total Blocking Time (TBT)</a> - web.dev</li>
<li><a target="_blank" href="https://web.dev/optimize-fid/">Optimize First Input Delay</a> - web.dev</li>
<li><a target="_blank" href="https://web.dev/lighthouse-total-blocking-time/">Lighthouse: Total Blocking Time</a> - web.dev</li>
</ul>
<h3 id="heading-time-to-first-byte-ttfb">Time to First Byte (TTFB)</h3>
<p>Time to First Byte (TTFB) is a foundational metric for measuring the time between the request for a resource and when the first byte of a response begins to arrive. It helps identify when a web server is too slow to respond to requests.</p>
<p>TTFB is the sum of the following request phases:</p>
<ul>
<li>Redirect time</li>
<li>Service worker startup time (if applicable)</li>
<li>DNS lookup</li>
<li>Connection and TLS negotiation</li>
<li>Request, up until the point at which the first byte of the response has arrived</li>
</ul>
<h4 id="heading-ttfb-scoring">TTFB Scoring</h4>
<table><colgroup><col><col></colgroup><tbody><tr><td><p><span>TTFB Time (milliseconds)</span></p></td><td><p><span>Color-Coding Score</span></p></td></tr><tr><td><p><span>0 - 800ms</span></p></td><td><p><span>Green (Fast / Good)</span></p></td></tr><tr><td><p><span>800 - 1,800ms</span></p></td><td><p><span>Orange (Moderate / </span><span><br></span><span>Needs Improvement)</span></p></td></tr><tr><td><p><span>Over 1,800ms</span></p></td><td><p><span>Red (Slow / Poor)</span></p></td></tr></tbody></table>

<h4 id="heading-how-to-improve-ttfb">How to Improve TTFB</h4>
<ul>
<li>Hosting services with inadequate infrastructure to handle high traffic loads</li>
<li>Web servers with insufficient memory that can lead to thrashing</li>
<li>Unoptimized database tables</li>
<li>Suboptimal database server configuration</li>
<li>Avoid multiple page redirects</li>
<li>Preconnect to required origins for cross-origin resources</li>
<li>Submit your origin to the HSTS preload list to eliminate HTTP-to-HTTPS redirect latency</li>
<li>Use HTTP/2 or HTTP/3</li>
<li>Use server-side generation (SSG) for markup instead of SSR where possible and appropriate</li>
</ul>
<p>Minimizing TTFB starts with choosing a suitable hosting provider with infrastructure to ensure high uptime and responsiveness. This in combination with a CDN can help significantly.</p>
<h1 id="heading-understanding-a-website-request">Understanding a Website Request</h1>
<p>In this section, we'll discuss how the speed of a request to a website impacts overall website performance.</p>
<p>When a user makes a request to load a website, a series of processes happen behind the scenes to deliver the requested content to the user's browser. The process can be broken down into the following steps:</p>
<ol>
<li>DNS Lookup: The Domain Name System (DNS) is a distributed database that maps domain names to IP addresses. When a user types a URL into their browser, the browser first sends a request to a DNS server to look up the IP address of the domain name.</li>
</ol>
<p><img src="https://lh6.googleusercontent.com/J17zWmjYv-1IbpwhezADAW1QDSpul1SHbJgCnLRP6z8MqzD8FHZsMIowumwFd7PM7la1mGjir1ZBvh2eETXCXvNoiTIEeztVRAgENi0plBq6dV8KN67YatEzyvG_sFCCjIWzKaqTHxKmgPxuxGzYxL8" alt="Image" width="600" height="400" loading="lazy"></p>
<ol>
<li>Connection: Once the browser has the IP address of the website, it establishes a connection to the server hosting the website using the Hypertext Transfer Protocol (HTTP) or the more secure HTTPS protocol.</li>
<li>Request: After establishing the connection, the browser sends an HTTP request to the server requesting the specific web page or resource that the user wants to access.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/VJPrjrVfJXvw8jzXvup91y4sHRq3uMGJNxUyAtsFpdLM8bjZJow-EIRk8nHKx1e-iEHLLquM52oO-lw8iaBVKBBitIVECRv8NWjRqtfcLCbkX00Agbg7w82TCZM-E4hzkcclEjFtbKHpY3sLCYzhm0M" alt="Image" width="600" height="400" loading="lazy"></p>
<ol>
<li>Processing: The server receives the request and begins to process it. This may involve executing scripts, querying databases, and retrieving files from the file system.</li>
<li>Response: Once the server has processed the request, it sends an HTTP response back to the browser. This response includes the requested content, such as the HTML, CSS, JavaScript, and any images or other resources required to display the web page.</li>
<li>Rendering: The browser receives the response from the server and begins to render the web page. This involves parsing the HTML and rendering the layout, styling the page with CSS, executing JavaScript, and loading any images or other resources required to display the page.</li>
<li>User Interaction: Finally, the user can interact with the web page, clicking on links, filling out forms, and performing other actions.</li>
</ol>
<p>These steps happen very quickly, often in a matter of milliseconds, but any delay or bottleneck in any of these steps can cause the page to load slowly or not at all, leading to a poor user experience. To optimize website performance, it's important to identify and address any performance issues at each stage of this process.</p>
<p><img src="https://lh4.googleusercontent.com/SuNvaLxNYi2YgK8v-n2Cpu6x9pdmEtP0Sha4EezZ63RM-hLLoM8felyEutg96VKJxdrZIpqFXidNK4zO-MAjEIoRTliZpdDOaNMRBimFpSk2LY_CNIDn1Vg5vyOEFlaOWmSmkm9nDjTQ_Il1_WMFTPU" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-server-configuration-amp-tuning-for-wordpress">Server Configuration &amp; Tuning for WordPress</h2>
<p>These tips explain what measures can be taken with Redis, MySQL, Opcache, and other technologies to achieve a high performance server. There are many opportunities to improve performance. We focus on fast storage and emphasize tuning the cache. Accessing files from NVMe storage, storing PHP scripts in Opcache, and compressing responses with Brotli are all part of a high performance server. Read on to find out how to analyze your server performance and make incremental improvements.</p>
<h2 id="heading-install-and-configure-redis">Install and Configure Redis</h2>
<p>Services like Redis and Memcached can significantly improve WordPress performance by caching data in memory and reducing the number of database calls required to serve content. They act as key-value stores that temporarily hold frequently accessed or computationally expensive data, resulting in faster response times and reduced server load. WordPress can be configured to use Redis as an object store by employing specific plugins, such as Redis Object Cache or W3 Total Cache.</p>
<p>Once Redis is installed and configured, you can check the following items to ensure Redis is optimized and operating at its full capacity.</p>
<h3 id="heading-memory-usage">Memory Usage</h3>
<p>Check Redis memory usage with the following command (some output has been omitted):</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>[root@localhost ~]</span><span># redis-cli info memory</span><span><br></span><span>used_memory:12654264</span><span><br></span><span>used_memory_rss:18878464</span><span><br></span><span>used_memory_peak:66619048</span><span><br></span><span>total_system_memory:19327352832</span><span><br></span><span>used_memory_lua:37888</span><span><br></span><span>maxmemory:67108864</span><span><br></span><span>maxmemory_policy:allkeys-lru</span><span><br></span><span>mem_fragmentation_ratio:1.49</span><span><br></span><span>mem_allocator:jemalloc-3.6.0</span></p></td></tr></tbody></table>

<p>When used_memory_peak is close to maxmemory, Redis may not have enough resources to operate to its full capacity. In addition, Redis may be actively evicting keys from the cache to make room for new ones. This is not ideal, and key eviction should be avoided if possible. Increase the maxmemory variable in your Redis configuration to resolve this issue.</p>
<h3 id="heading-key-eviction">Key Eviction</h3>
<p>Key eviction is the process of removing old and unused data from the cache to make room for new data. This can be especially problematic for high-traffic websites that rely on Redis caching to improve performance. If your system resources allow for it and the evicted_keys count is high, it is again recommended to increase maxmemory. The following command will provide information about the number of keys and how many have been evicted.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span># redis-cli info stats | grep evicted_keys</span><span><br></span><span>evicted_keys:5463</span><span><br></span><span><br></span><span># redis-cli info keyspace</span><span><br></span><span>db0:keys=773,expires=738,avg_ttl=137198</span></p></td></tr></tbody></table>

<p>By examining these aspects and making appropriate adjustments, you can optimize Redis to significantly enhance your WordPress site's performance</p>
<h2 id="heading-optimize-the-database">Optimize the Database</h2>
<p>If object caching like Redis is not available for the WordPress site, requests for database content go straight to the database. First, the database checks its cache to serve the result directly, if possible, and stores it for future use. If caching is unavailable or not allowed, the query proceeds to the database. The database combines cached and uncached information, requesting data from the Operating System. The speed of retrieving the data depends on available RAM and the storage type, with NVMe being the fastest and HDD being the slowest. Simple queries return data immediately to the PHP call, while complex queries requiring temp tables demand more processing time and can slow down the website or cause server issues under high traffic.</p>
<p>Several tuning techniques can improve performance.</p>
<h3 id="heading-set-the-buffer-pool-size">Set the buffer pool size</h3>
<p>The buffer pool is the area of memory that MariaDB uses to cache data and indexes. It is important to configure the buffer pool size appropriately based on the amount of available memory and the size of the database. A good rule of thumb is to set the buffer pool size to about 40% of available memory, but keep in mind this percentage is typically applicable only on stand-alone database servers. The buffer pool size can be controlled using the innodb_buffer_pool_size variable. See <a target="_blank" href="https://mariadb.com/kb/en/innodb-buffer-pool/">https://mariadb.com/kb/en/innodb-buffer-pool/</a> for more information.</p>
<p>One way to analyze buffer pool performance is by observing the innodb_buffer_pool_wait_free status variable. If it is increasing, then you don't have enough buffer pool (or your flushing isn't occurring frequently enough). In this case, you should set the innodb_buffer_pool_size variable higher if your system resources allow for it.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>SHOW STATUS LIKE </span><span>"Innodb_buffer_pool_wait_free"</span><span>;</span><span><br></span><span>+------------------------------+-------+</span><span><br></span><span>| Variable_name&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Value |</span><span><br></span><span>+------------------------------+-------+</span><span><br></span><span>| Innodb_buffer_pool_wait_free | 5464&nbsp; |</span><span><br></span><span>+------------------------------+-------+</span><span><br></span><span>1 row </span><span>in</span><span> </span><span>set</span><span> (0.001 sec)</span></p></td></tr></tbody></table>

<h3 id="heading-enable-query-cache">Enable query cache</h3>
<p>Query cache is a feature that stores the results of frequently executed queries in memory, which can significantly improve query performance. It is recommended to enable query cache, but it's important to note that it may not be effective for all workloads. The query cache can be enabled or disabled using the query_cache_type variable. See <a target="_blank" href="https://mariadb.com/kb/en/query-cache/">https://mariadb.com/kb/en/query-cache/</a> for more information.</p>
<p>The SQL server stores stats about the Query Cache.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>SHOW STATUS LIKE </span><span>'Qcache%'</span><span>;</span><span><br></span><span>+-------------------------+----------+</span><span><br></span><span>| Variable_name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Value&nbsp; &nbsp; |</span><span><br></span><span>+-------------------------+----------+</span><span><br></span><span>| Qcache_free_blocks&nbsp; &nbsp; &nbsp; | 1158 &nbsp; &nbsp; |</span><span><br></span><span>| Qcache_free_memory&nbsp; &nbsp; &nbsp; | 3760784&nbsp; |</span><span><br></span><span>| Qcache_hits &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 31943398 |</span><span><br></span><span>| Qcache_inserts&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 42998029 |</span><span><br></span><span>| Qcache_lowmem_prunes&nbsp; &nbsp; | 34695322 |</span><span><br></span><span>| Qcache_not_cached &nbsp; &nbsp; &nbsp; | 652482 &nbsp; |</span><span><br></span><span>| Qcache_queries_in_cache | 4628 &nbsp; &nbsp; |</span><span><br></span><span>| Qcache_total_blocks &nbsp; &nbsp; | 11123&nbsp; &nbsp; |</span><span><br></span><span>+-------------------------+----------+</span></p></td></tr></tbody></table>

<p>Qcache_inserts contains the number of queries added to the query cache, Qcache_hits contains the number of queries that have made use of the query cache, while Qcache_lowmem_prunes contains the number of queries that were dropped from the cache due to lack of memory.</p>
<p>The above example could indicate a poorly performing cache. More queries have been added, and more queries have been dropped, than have actually been used.</p>
<p><strong>Set In-memory Table Size Limits:</strong> As previously mentioned, complex queries will cause the SQL server to create temporary tables. The SQL server will attempt to create tables in memory up to a certain size for performance. It is important to set the max size to an appropriate value to avoid creating on-disk temporary tables. The variables that control this behavior are tmp_table_size and max_heap_table_size. You can compare the number of internal on-disk temporary tables created to the total number of internal temporary tables created by comparing Created_tmp_disk_tables and Created_tmp_tables values. See <a target="_blank" href="https://mariadb.com/kb/en/server-system-variables/#tmp_table_size">server-system-variables/#tmp_table_size</a> and <a target="_blank" href="https://mariadb.com/kb/en/server-system-variables/#max_heap_table_size">server-system-variables/#max_heap_table_size</a> for more information.</p>
<p>You can see if it's necessary to increase by comparing the status variables Created_tmp_disk_tables and Created_tmp_tables to see how many temporary tables out of the total created needed to be converted to disk.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>MariaDB [(none)]&gt; SHOW STATUS LIKE </span><span>"Created_tmp%"</span><span>;</span><span><br></span><span>+-------------------------+-------+</span><span><br></span><span>| Variable_name &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | Value |</span><span><br></span><span>+-------------------------+-------+</span><span><br></span><span>| Created_tmp_disk_tables | 0 &nbsp; &nbsp; |</span><span><br></span><span>| Created_tmp_files &nbsp; &nbsp; &nbsp; | 373 &nbsp; |</span><span><br></span><span>| Created_tmp_tables&nbsp; &nbsp; &nbsp; | 1 &nbsp; &nbsp; |</span><span><br></span><span>+-------------------------+-------+</span><span><br></span><span>3 rows </span><span>in</span><span> </span><span>set</span><span> (0.000 sec)</span></p></td></tr></tbody></table>

<p>In the above example, the SQL server is not having to create temporary tables on disk. This is considered optimal.</p>
<h3 id="heading-prune-wordpress-database">Prune WordPress Database</h3>
<p>Without intervention, WordPress will store junk/unused data in the database. Over time, this can add up causing database bloat and serious performance lags. This includes items such as:</p>
<ul>
<li>Post revisions</li>
<li>Auto-saved drafts</li>
<li>Trashed posts</li>
<li>Trashed comments</li>
<li>Comment spam</li>
<li>Tables for plugins and themes that are no longer active or installed</li>
<li>Transient records</li>
</ul>
<p>In your wp-config.php file, add or edit the following setting to limit the number of post revisions saved to the database.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>define(</span><span>'WP_POST_REVISIONS'</span><span>, </span><span>15</span><span>);</span></p></td></tr></tbody></table>

<p>Many resources exist on the internet for dealing with these items.</p>
<h3 id="heading-monitor-performance">Monitor Performance</h3>
<p>It's important to regularly monitor the performance of MariaDB and adjust the configurations as necessary. This includes monitoring CPU usage, memory usage, disk I/O, and query performance. Use a tool like mysqltuner to gain insights on the performance of the SQL installation, or enable Slowquery logging to identify long running queries.</p>
<h2 id="heading-review-opcache-hit-rates-and-stats">Review Opcache Hit Rates and Stats</h2>
<p>Opcache provides significant benefits when used with PHP-FPM. When a PHP file has been previously requested and there is enough opcache available, the script is already stored in memory. This allows for faster execution as it stands ready to accept data inputs without having to reload the file from disk. It is important to maximize Opcache Hits and minimize misses.</p>
<p>PHP provides several built-in functions to obtain information about OPcache status and configuration like opcache_get_status() and opcache_get_configuration(). Additionally, there are several web-based monitoring tools to visualize OPcache usage and performance. Some popular options include:</p>
<ul>
<li><strong>OPcache GUI</strong> (<a target="_blank" href="https://github.com/amnuts/opcache-gui">https://github.com/amnuts/opcache-gui</a>): A single-file PHP script that provides a simple and clean interface to monitor OPcache usage and performance.</li>
<li><strong>OCP</strong> (<a target="_blank" href="https://github.com/ck-on/ocp">https://github.com/ck-on/ocp</a>): A web-based OPcache control panel that allows you to monitor and manage OPcache settings in real-time.</li>
<li><strong>OPcache Status</strong> (<a target="_blank" href="https://github.com/rlerdorf/opcache-status">https://github.com/rlerdorf/opcache-status</a>): A one-page opcache status page for the PHP 5.5 opcode cache.</li>
<li><strong>CacheTool</strong> (<a target="_blank" href="https://github.com/gordalina/cachetool">https://github.com/gordalina/cachetool</a>) : CacheTool allows you to work with APCu, OPcache, and the file status cache through the CLI. It will connect to a FastCGI server (like PHP-FPM) and operate on its cache.</li>
</ul>
<p>To use these tools, download and install them on your web server, following the instructions provided in their respective repositories. Keep in mind that some of the information displayed by these tools can reveal information about web server files, or other sensitive information about the website. It is best to keep these interfaces secured by IP, or another form of authentication.</p>
<p>When reviewing Opcache Statistics there are a few key items to look for and assess.</p>
<h3 id="heading-opcache-hit-rate">Opcache Hit Rate</h3>
<p>The hit rate is the percentage of requests that are being served using cached opcode instead of parsing and compiling the scripts anew. </p>
<table><colgroup></colgroup><tbody><tr><td><p><span>[opcache_hit_rate] =&gt; 90.64060820636</span></p></td></tr></tbody></table>

<p>The above hit rate suggests opcache requires more memory or resources to perform to its full capacity. A high hit rate close to 100 indicates that the cache is functioning effectively and providing the desired performance benefits. Monitoring the hit rate can help identify if adjustments to OPCache settings are necessary to improve its efficiency. The next section explains how to adjust the memory allocation for opcache.</p>
<h3 id="heading-memory-consumption">Memory Consumption</h3>
<p>Analyzing memory usage involves checking the amount of memory allocated to the OPCache and how much of it is being utilized.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>[cache_full] =&gt; 1</span><span><br></span><span>[used_memory] =&gt; 134217720</span><span><br></span><span>[free_memory] =&gt; 8</span><span><br></span><span>[wasted_memory] =&gt; 0</span><span><br></span><span>[current_wasted_percentage] =&gt; 0</span></p></td></tr></tbody></table>

<p>In the above output, the administrator would want to consider increasing the opcache.memory_consumption to a value higher than 128MB as the “cache_full” boolean is true and free_memory is at 8 bytes. This information helps determine if there is a need to increase or decrease the memory allocation, based on the size and complexity of your PHP scripts. Ensuring an appropriate memory allocation helps prevent cache evictions and promotes a more efficient use of server resources.</p>
<p>Both num_cached_keys and max_cached_keys are metrics that provide insight into the number of cached keys (compiled PHP scripts) currently stored in the OPCache (num_cached_keys) and the maximum number of cached keys allowed (max_cached_keys).</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>[num_cached_scripts] =&gt; 4371</span><span><br></span><span>[num_cached_keys] =&gt; 5597</span><span><br></span><span>[max_cached_keys] =&gt; 65407</span><span><br></span><span>[hits] =&gt; 114693</span><span><br></span><span>[start_time] =&gt; 1683575017</span><span><br></span><span>[last_restart_time] =&gt; 0</span><span><br></span><span>[oom_restarts] =&gt; 0</span><span><br></span><span>[hash_restarts] =&gt; 0</span><span><br></span><span>[manual_restarts] =&gt; 0</span><span><br></span><span>[misses] =&gt; 11843</span><span><br></span><span>[blacklist_misses] =&gt; 0</span><span><br></span><span>[blacklist_miss_ratio] =&gt; 0</span><span><br></span><span>[opcache_hit_rate] =&gt; 90.64060820636</span></p></td></tr></tbody></table>

<p>By comparing these values, you can identify if the cache is nearing its capacity or if adjustments are needed to optimize the cache size. If num_cached_keys frequently approaches max_cached_keys, it may be beneficial to increase the opcache.max_accelerated_files value to accommodate more scripts, reducing cache evictions and further improving performance.</p>
<p>Regularly reviewing these key items can help you optimize the OPCache configuration, leading to improved website performance and reduced server resource usage.</p>
<h2 id="heading-utilize-nvme-storage">Utilize NVMe Storage</h2>
<p>As previously mentioned in the database optimization section, NVMe storage helps database server performance by providing significantly faster data access and reduced latency compared to traditional storage solutions. This results in quicker response times and more efficient query processing, leading to improved overall server performance.</p>
<p>NVMe storage improves server performance for WordPress websites in several ways:</p>
<p><strong>Faster Page Load Times</strong></p>
<p>With its high-speed data transfer and low latency, NVMe storage allows for quicker access to website files and assets, such as images, stylesheets, and scripts. This leads to faster page load times and a better user experience.</p>
<p><strong>Improved Database Performance</strong></p>
<p>The benefits of using NVMe storage when processing database queries can be outlined as follows:</p>
<ol>
<li>When processing queries, the database relies on both cached and uncached MySQL data, requiring interaction with the operating system to retrieve the necessary information.</li>
<li>If the operating system has ample RAM, the files needed for a query might already be stored in RAM rather than only being available on a persistent storage device.</li>
<li>In cases where data must be accessed from a storage device, an NVMe drive provides significantly faster data retrieval compared to a SATA SSD, while traditional HDDs are much slower and typically not used in such scenarios anymore.</li>
</ol>
<p>Overall, using NVMe storage greatly enhances database query performance due to its rapid data access capabilities.</p>
<h2 id="heading-enable-brotli-and-gzip-compression">Enable Brotli and Gzip Compression</h2>
<p>Compressing web server responses with Brotli or Gzip can significantly improve website performance by reducing the amount of data transferred over the network. This provides a final stage of optimization on the response being returned from the Origin Server. On average, Gzip compression can reduce the size of web content by 60-70%, while Brotli tends to provide even better compression rates, often reducing content size by 70-80%.</p>
<p>Enabling Brotli compression within NGINX is accomplished through the use of the <a target="_blank" href="https://github.com/google/ngx_brotli">brotli nginx module</a>. The module can be compiled and installed alongside NGINX and loaded dynamically.</p>
<h3 id="heading-analyze-a-server-response-for-compression">Analyze a Server Response for Compression</h3>
<p>To determine if a request response was compressed with Brotli or Gzip compression, you can use Chrome or Firefox Developer Tools to review the Content-Encoding header – follow these steps:</p>
<ol>
<li><p>Open the developer tools in your browser:</p>
</li>
<li><p>In Chrome, press Ctrl + Shift + I (Windows/Linux) or Cmd + Opt + I (Mac).</p>
</li>
<li>In Firefox, press Ctrl + Shift + I (Windows/Linux) or Cmd + Opt + I (Mac).</li>
<li><p>Or right click on the webpage and select <strong>Inspect</strong>.</p>
</li>
<li><p>Click on the "<strong>Network</strong>" tab in the developer tools.</p>
</li>
<li>Refresh the webpage or initiate the action you want to analyze. This will populate the network panel with a list of requests made by the browser.</li>
<li>Find the request you're interested in, such as the main document request or a specific resource like a CSS or JavaScript file. Click on the request to open the detailed view.</li>
<li>In the detailed view, look for the <strong>Headers</strong> tab (this should be the default tab in both browsers). Scroll down to the <strong>Response Headers</strong> section.</li>
<li>Check the value of the <strong>Content-Encoding</strong> header. If the response is compressed with Gzip, it will display gzip, and if it's compressed with Brotli, it will display br. If the header is absent or has a different value, the response is not compressed using either of these algorithms.</li>
</ol>
<p><img src="https://lh5.googleusercontent.com/wuxtQhiksUozSaQ2u0SpDTsW27wj1w2sFZfFmABhsJL1buQVsY81FbyYbwWbvsnfMFAqANpEKfhBwfEw8NlL2-Oq9muspGvqbdqijL0GGEOutqAw7wvCrLxqJPKCIR_n6eadSreKbfEsxiXx5_5XfpM" alt="Image" width="600" height="400" loading="lazy"></p>
<p>By examining the <strong>Content-Encoding</strong> header in the developer tools, you can quickly determine if a request response was compressed with Brotli or Gzip.</p>
<h2 id="heading-nginx-proxy-caching">NGINX Proxy Caching</h2>
<p>Serving requests from the Nginx cache can result in significant performance improvements, as it eliminates the need for the request to traverse the entire stack and access the backend services. This can lead to reduced processing times and improved response times, resulting in a better user experience.</p>
<p>According to benchmarks, serving requests from the Nginx cache can result in a 90% reduction in response times compared to requests that traverse the entire stack. This is due to the caching mechanism's ability to serve requests directly from memory or disk, reducing the time taken to process the request.</p>
<p>Furthermore, serving requests from the Nginx cache can significantly reduce server load and improve scalability. By reducing the number of requests that must be handled by backend services like PHP-FPM or MySQL, the server can handle more requests concurrently, leading to improved performance and faster response times. This is essential for a high traffic website.</p>
<p>Our UltraStack NGINX configuration adds an X-Proxy-Cache HTTP header to responses and the Upstream Cache Status to nginx access log entries. The following three techniques explain how to identify whether the page being received is a cached version served by Nginx:</p>
<ol>
<li><strong>Using cURL:</strong> make a simple GET request to the URL in question, and use grep to check the X-Proxy-Cache header.</li>
</ol>
<table><colgroup></colgroup><tbody><tr><td><p><span>$</span><span> curl -is https://gonintesto.com/ | grep X-Proxy-Cache</span><span><br></span><span>X-Proxy-Cache: HIT</span></p></td></tr></tbody></table>

<ol>
<li><strong>Using Chrome DevTools:</strong> Headers can also be easily inspected using the Chrome DevTools. Use F12 or Ctrl+Shift+I to bring up the DevTools window, then click the Network tab. Tick the box that says “Disable cache”, which will bypass Chrome's internal cache, then reload the page to capture all of the network information (not disabling Chrome's cache will allow you to see 304 Not Modified responses for static assets, which shows how the client-side cache is working).</li>
</ol>
<table><colgroup><col><col></colgroup><tbody><tr><td><p><span><span><img src="https://lh6.googleusercontent.com/JkElkgcW7VIQ0_LGNhK6JUyI5CVV1445HVSjRSBW6eGmXp_2a2I1k1Fvvb6tjpnqDHaT-noPpyQYVDdjpyk03v_F0TpDHe5nTZXqp80IL6iIpV-YhQC7_qJX9qYnJqjx9Enu-4rt1-Uvnd-ooVP0NzQ" width="600" height="400" alt="JkElkgcW7VIQ0_LGNhK6JUyI5CVV1445HVSjRSBW6eGmXp_2a2I1k1Fvvb6tjpnqDHaT-noPpyQYVDdjpyk03v_F0TpDHe5nTZXqp80IL6iIpV-YhQC7_qJX9qYnJqjx9Enu-4rt1-Uvnd-ooVP0NzQ" loading="lazy"></span></span></p></td><td><p><span>The following are the possible values for </span><a href="https://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_cache_status"><span>$upstream_cache_status</span></a><span>:</span></p><ul><li><p><span>MISS – The response was not found in the cache and so was fetched from an origin server. The response might then have been cached.</span></p></li><li><p><span>BYPASS – The response was fetched from the origin server instead of served from the cache because the request matched a proxy_cache_bypass directive.</span></p></li><li><p><span>EXPIRED – The entry in the cache has expired. The response contains fresh content from the origin server.</span></p></li><li><p><span>STALE – The content is stale because the origin server is not responding correctly, and proxy_cache_use_stale was configured.</span></p></li><li><p><span>UPDATING – The content is stale because the entry is currently being updated in response to a previous request, and proxy_cache_use_stale updating is configured.</span></p></li><li><p><span>REVALIDATED – The </span><a href="https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_cache_revalidate"><span>proxy_cache_revalidate</span></a><span> directive was enabled and NGINX verified that the current cached content was still valid (If-Modified-Since or If-None-Match).</span></p></li><li><p><span>HIT – The response contains valid, fresh content direct from the cache.</span></p></li></ul></td></tr></tbody></table>

<ol>
<li><strong>Using NGINX access log</strong>: Connect to the server using SSH and read the access log with a tail or cat.</li>
</ol>
<table><colgroup></colgroup><tbody><tr><td><p><span>[root@vps87640 ~]</span><span># tail -f /var/log/nginx/access.log</span><span><br></span><span>173.231.218.25 - - [16/Mar/2023:21:50:43 -0400] </span><span>"GET / HTTP/2.0"</span><span> 200 8205 </span><span>"-"</span><span> </span><span>"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36"</span><span> [rt=0.000] [proto=HTTP/2.0:h2] [args=-] [ucs=HIT] [xpc=HIT] [uct=-] [gz=-] [tls=TLSv1.3] [cipher=TLS_AES_256_GCM_SHA384] [scheme=https] gonintesto.com gonintesto.com vps87640.inmotionhosting.com 1638</span></p></td></tr></tbody></table>

<p>The value assigned to ucs= (HIT in the above example) or the “Upstream Cache Status” will be one of the above cache statuses.</p>
<p>Using Central’s Manage Server tools, here is how you would enable NGINX proxy cache on your site:</p>
<p><img src="https://lh3.googleusercontent.com/BRe1P9qntdKojYtwRvwzvbsHsma-m0nX4mVIJA8Fv6w4M3uNRLRcaXurVhtKdRypVjazhArw9T33rmvVki-FtXDjVeDWdmwBkt1sCQn6512DOJgyT0TofTo_cVHgmvo99IUpsVlhJ_pEvFdfUe7yXyk" alt="Image" width="600" height="400" loading="lazy"></p>
<p>With NGINX proxy cache configured, you may use our <a target="_blank" href="https://www.inmotionhosting.com/support/product-guides/wordpress-hosting/central/servers/ultrastack-utilities/">Ultrastack Utilities</a> to determine the cache HIT rates for all requests to NGINX.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>CT-92204 /</span><span># usutil </span><span><br></span><span>INFO: Parsing </span><span>log</span><span> </span><span>'/var/log/nginx/access.log'</span><span> (15.4 MiB)...</span><span><br></span><span><br></span><span>CACHE STATUS</span><span><br></span><span>+----------------+--------------+-----------------+</span><span><br></span><span>| HIT (Dynamic)&nbsp; | HIT (Static) | DISABLED+BYPASS |</span><span><br></span><span>+----------------+--------------+-----------------+</span><span><br></span><span>| 146323 (51.8%) | &nbsp; 0 (0.0%) &nbsp; | &nbsp; 4096 (1.4%) &nbsp; |</span><span><br></span><span>+----------------+--------------+-----------------+</span><span><br></span><span>+----------------+----------------+-------------+-------------+----------+</span><span><br></span><span>|&nbsp; &nbsp; &nbsp; HIT &nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; &nbsp; MISS&nbsp; &nbsp; &nbsp; |&nbsp; &nbsp; BYPASS &nbsp; | &nbsp; EXPIRED &nbsp; | UPDATING |</span><span><br></span><span>+----------------+----------------+-------------+-------------+----------+</span><span><br></span><span>| 146323 (51.0%) | 110858 (38.7%) | 4096 (1.4%) | 3095 (1.1%) | 9 (0.0%) |</span><span><br></span><span>+----------------+----------------+-------------+-------------+----------+</span><span><br></span><span>+-------------+-------------+----------+-----------------+</span><span><br></span><span>| STATIC/TYPE | STATIC/PATH | DISABLED |&nbsp; &nbsp; &nbsp; TOTAL&nbsp; &nbsp; &nbsp; |</span><span><br></span><span>+-------------+-------------+----------+-----------------+</span><span><br></span><span>| &nbsp; 0 (0.0%)&nbsp; | &nbsp; 0 (0.0%)&nbsp; | 0 (0.0%) | 286663 (100.0%) |</span><span><br></span><span>+-------------+-------------+----------+-----------------+</span></p></td></tr></tbody></table>

<p>While this is a tool specific to InMotion Hosting, the information can be retrieved using the third party NGINX module, <a target="_blank" href="https://github.com/vozlt/nginx-module-vts">nginx-module-vts</a>.</p>
<p>In summary, using NGINX proxy cache will help drive performance for high traffic websites.</p>
<h2 id="heading-use-tlsv13-and-http2">Use TLSv1.3 and HTTP/2</h2>
<p>TLS (Transport Layer Security) is a cryptographic protocol that provides secure communication between web clients and servers. TLS 1.3 is the latest version of the TLS protocol and is designed to provide faster and more secure communication compared to previous versions.</p>
<p>TLS 1.3 also introduces several new features that improve website performance, such as 0-RTT (Zero Round Trip Time) handshakes, which allows returning visitors to establish a secure connection more quickly. Additionally, TLS 1.3 reduces the number of round trips required to establish a secure connection, which reduces latency and improves website performance.</p>
<p>Here are two ways to determine if an nginx web server is using TLS 1.3:</p>
<ol>
<li><strong>Using the nginx access log:</strong> In the nginx access log, look for requests that were made over HTTPS (port 443) and check the TLS protocol version used by the client. If the client and server are using TLS 1.3, the access log will show the protocol version as "TLSv1.3". For example, a log entry for a request using TLS 1.3 might look like this:   </li>
</ol>
<table><colgroup></colgroup><tbody><tr><td><p><span>1.2.3.4 - - [27/Mar/2023:11:12:13 +0000] </span><span>"GET / HTTP/1.1"</span><span> 200 1234 </span><span>"-"</span><span> </span><span>"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.4.5.6 Safari/537.36"</span><span> </span><span>"TLSv1.3"</span><span>.</span></p></td></tr></tbody></table>

<p><a target="_blank" href="https://nginx.org/en/docs/http/ngx_http_ssl_module.html#variables">https://nginx.org/en/docs/http/ngx_http_ssl_module.html#variables</a></p>
<p><strong>2. Using an SSL/TLS checker:</strong> To determine if an nginx server is using TLS 1.3 using an SSL/TLS checker, run a test on the server using the checker tool, such as SSL Labs' SSL Server Test or Qualys SSL Labs SSL Server Test. The tool will analyze the server's SSL/TLS configuration and provide information about the TLS protocol being used, including whether TLS 1.3 is enabled. The report generated by the tool will also provide details about the server's SSL/TLS configuration, including any issues or vulnerabilities that were found.</p>
<p><strong>Configure NGINX:</strong> To set the ssl_protocols parameter in the nginx configuration, open the /etc/nginx/nginx.conf file and locate the ssl_protocols parameter in the http block, then set the desired SSL/TLS protocols (e.g., ssl_protocols TLSv1.2 TLSv1.3;) and save the file. Finally, test the configuration using nginx -t and reload the nginx service using systemctl reload nginx.</p>
<p><a target="_blank" href="https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_protocols">https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_protocols</a></p>
<p>HTTP/2 is the latest version of the HTTP protocol that powers the web. It is designed to improve website performance by reducing latency and enabling faster page load times. HTTP/2 achieves this by introducing several new features, including multiplexing, header compression, and server push.</p>
<p>There are a few ways to determine if an nginx web server is using HTTP/2:</p>
<ol>
<li><p><strong>Check the response headers:</strong> When a client makes a request to an nginx server, the server responds with headers that include information about the protocol being used. If HTTP/2 is being used, the response headers will include the string "HTTP/2" in the "server" field. For example, the "server" field may read "nginx/1.20.1 (Ubuntu) HTTP/2".  </p>
</li>
<li><p><strong>Use a browser developer tool:</strong> Another way to determine if an nginx server is using HTTP/2 is to use a browser developer tool, such as Chrome DevTools or Firefox Developer Tools. When the tool is open and a page is loaded from the nginx server, the "protocol" column in the network tab will show "h2" if HTTP/2 is being used. If HTTP/1.x is being used, the protocol column will show "http/1.1".  </p>
</li>
</ol>
<p><strong>Configure NGINX:</strong> To configure nginx to use HTTP/2, you need to ensure that your nginx version supports HTTP/2 and then enable it by adding the http2 parameter to the listen directive in the server configuration file, and also include an SSL certificate. For example, the directive listen 443 ssl http2; would enable HTTP/2 over SSL on port 443.</p>
<p><a target="_blank" href="http://nginx.org/en/docs/http/ngx_http_v2_module.html">http://nginx.org/en/docs/http/ngx_http_v2_module.html</a></p>
<h2 id="heading-increase-server-resources">Increase Server Resources</h2>
<p>While the exact amount depends on the specific workload of the website, a minimum of 4GB and 2 vCPU cores is recommended when benchmarking your resource needs on a high traffic website. In a high-performance server running MySQL, Redis, PHP-FPM, Apache, and Nginx, having enough RAM is critical to allow each service's caching techniques to work at their full potential.</p>
<p>These services use RAM to cache frequently accessed data and reduce the time taken to retrieve it from disk or other storage devices. If the server does not have enough RAM, the caching will not be as effective, leading to longer processing times and slower website performance.</p>
<p>For instance, MySQL uses the InnoDB buffer pool to cache frequently accessed data from the database, and Redis uses memory to store frequently accessed data in key-value pairs. PHP-FPM uses opcache to cache PHP scripts, and Nginx uses RAM to cache frequently requested web pages and assets.</p>
<p>If the server does not have sufficient RAM, these caching techniques will not be as effective, and the server may resort to swapping data in and out of slower storage devices, leading to slower response times and reduced server capacity.</p>
<h3 id="heading-swap-usage">Swap Usage</h3>
<p>To determine if a Linux server is swapping, you can use the free command to view the system's memory usage. If the "Swap" value is greater than zero, it indicates that the server is currently using swap space to store data in memory. </p>
<table><colgroup></colgroup><tbody><tr><td><p><span># free</span><span><br></span><span>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; total&nbsp; &nbsp; &nbsp; &nbsp; used&nbsp; &nbsp; &nbsp; &nbsp; free&nbsp; &nbsp; &nbsp; shared&nbsp; buff/cache &nbsp; available</span><span><br></span><span>Mem:&nbsp; &nbsp; &nbsp; &nbsp; 3145728&nbsp; &nbsp; &nbsp; 258388 &nbsp; &nbsp; 1784700 &nbsp; &nbsp; &nbsp; 36848 &nbsp; &nbsp; 1102640 &nbsp; &nbsp; 2850492</span><span><br></span><span>Swap: &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 0</span></p></td></tr></tbody></table>

<p>Additionally, you can use the vmstat command to monitor the amount of swapping activity occurring on the server, with the "si" and "so" values indicating the amount of memory being swapped in and out, respectively.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span># vmstat</span><span><br></span><span>procs -----------memory---------- &nbsp; ---swap-- -----io---- -system-- ------cpu-----</span><span><br></span><span> r&nbsp; b &nbsp; swpd &nbsp; free &nbsp; buff&nbsp; cache &nbsp; si &nbsp; so&nbsp; &nbsp; bi&nbsp; &nbsp; bo &nbsp; </span><span>in</span><span> &nbsp; cs us sy id wa st</span><span><br></span><span> 1&nbsp; 0&nbsp; &nbsp; &nbsp; 0 1782348&nbsp; &nbsp; &nbsp; 0 1102660&nbsp; &nbsp; 0&nbsp; &nbsp; 0&nbsp; &nbsp; 16&nbsp; &nbsp; 14&nbsp; &nbsp; 0&nbsp; &nbsp; 0&nbsp; 4&nbsp; 3 93&nbsp; 0&nbsp; 0</span></p></td></tr></tbody></table>

<p>The above server does not use Swap and is not swapping.</p>
<h3 id="heading-oom-kills">OOM Kills</h3>
<p>To determine if a Linux server is experiencing OOM (Out of Memory) kills, you can check the system logs for messages related to OOM events. On most Linux distributions, the system log file is located at /var/log/messages or /var/log/syslog.</p>
<p>To view OOM-related messages, you can search for the keyword "OOM" using the grep command:</p>
<table><colgroup></colgroup><tbody><tr><td><p><span># grep -i "OOM" /var/log/messages</span><span><br></span><span>May&nbsp; 8 01:22:35 vps53534 kernel: mysqld invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=-1000</span></p></td></tr></tbody></table>

<p>If OOM events are occurring, you will see log entries that indicate which process or application was killed by the OOM killer. Additionally, you can use tools like dmesg and journalctl to view kernel messages related to OOM events.</p>
<p>By having enough RAM on the server, each service can utilize caching techniques to their fullest extent, resulting in faster processing times, reduced disk usage, and an overall better user experience.</p>
<h2 id="heading-caching-explained-with-implementation-techniques">Caching Explained with Implementation Techniques</h2>
<h3 id="heading-etags">ETags</h3>
<p>The ETag (or entity tag) HTTP response header that web servers and browsers use to determine whether a resource in the browser’s local cache matches the one on the origin server.</p>
<p>When a user revisits a site, one of two things happen:</p>
<ul>
<li>Display content to the user in the browser it if is within the allowable cache freshness time - Time to Live (TLL)</li>
<li>If content is out of its cache time (TTL expired) then:</li>
<li>If it has an Etag then it will need to send an Etag to the resolved URL to see if it needs to refresh.</li>
<li>If it gets the matching Etag, then it will keep the content it has (no new downloading of content) and set the existing content’s TTL into the future which makes it a viable cached content for the TTL.</li>
<li>If it gets a different Etag then it will trigger a fresh download of the new content.</li>
<li>If it does not have an Etag then it will send a request out to get the potentially new content and will download that content regardless of if it really is new or not.</li>
</ul>
<p>It is important to note that the Etag request and response is much, much smaller than a download of content. As most websites do not change between TTLs, the TTLs need to be low “just in case” the site does change, therefore the Etag process is much more efficient than TTLs by themselves.</p>
<h4 id="heading-how-to-check-if-your-server-responds-is-using-etags">How to Check if Your Server Responds is Using ETags</h4>
<ol>
<li>Open the developer tools in your browser:</li>
<li>In Chrome, press Ctrl + Shift + I (Windows/Linux) or Cmd + Opt + I (Mac).</li>
<li>In Firefox, press Ctrl + Shift + I (Windows/Linux) or Cmd + Opt + I (Mac).</li>
<li>Or right click on the webpage and select <strong>Inspect</strong>.</li>
<li>Click on the <strong>Network</strong> tab in the developer tools.</li>
<li>Refresh the webpage or initiate the action you want to analyze. This will populate the network panel with a list of requests made by the browser.</li>
<li>Locate a specific resource like a CSS or JavaScript file. Click on the request to open the detailed view.</li>
<li>In the detailed view, look for the <strong>Headers</strong> tab (this should be the default tab in both browsers).</li>
<li>Scroll down to the <strong>Response Headers</strong> section for the selected file and check for the presence of an Etag.</li>
</ol>
<p><img src="https://lh5.googleusercontent.com/Ynyrr_YhIPfRI6kBmx9NdCNqbzgK18vrlmi289r0hQ-8dr38iwni8hyJUq3G0Sd6vRAYDS-JGVq-dWG4IpAdvwn_Cv6yedXM6pmFNVOToui4gCvaH5D6hb1FfmfUIwhNzFJ0DyFPIrsbxslF51i5Yfg" alt="Image" width="600" height="400" loading="lazy"></p>
<p>How to Configure ETags in W3 Total Cache</p>
<ol>
<li>In your WordPress admin dashboard, navigate to <strong>Performance &gt; Browser Cache</strong>.</li>
<li>Scroll down to the <strong>General</strong> section.</li>
<li>Check the box next to the “<strong>Set entity tag (ETag)</strong>” setting.</li>
<li>On the same page, using the method above, you can also enable or disable ETags for specific files types, including: CSS &amp; JS, HTML &amp; XML, Media &amp; Other Files</li>
<li>Press the <strong>Save Settings &amp; Purge Caches</strong> button within each respective settings box to save and apply the caching changes immediately.</li>
</ol>
<p><img src="https://lh3.googleusercontent.com/oVGPcpjE0Dd0RsfplP4Gr2DYCxIcVEUrmznaMxuUeFDpv-ItCe3bdN6ywUQl6vbKhHDXGrU0MBpY89F6_iuX2LlqoiyYtDqLGF42jzVfXCBhYB1-18DmVxw8F_AbkU1_86TdLktWdq7G9_uqkHrySuk" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-time-to-live-ttl">Time To Live (TTL)</h2>
<p>The Time To Live (TTL) value is the time that an object is stored in a caching system before it’s deleted or refreshed. In the context of CDNs, TTL typically refers to content caching, which is the process of storing a copy of your website resources (e.g., images, text, Javascript) on CDN proxies to improve page load speed and reduce origin server bandwidth consumption.</p>
<p>TTLs are used for caching purposes, and the value is stored in seconds. If the TTL value is set to a low number like 3600 seconds, the data will be stored in the cache for one hour. After one hour, a new version of the data needs to be retrieved.</p>
<p>If the TTL value is set to a high number like 86400 seconds, the data will be stored in the cache for 24 hours.</p>
<p>High TTL values cache your data longer, and lessen the frequency for retrieving new data. This gives your website a performance boost by reducing the server's load, which improves the user's experience.</p>
<h4 id="heading-ttl-policies-for-static-and-dynamic-content">TTL Policies for Static and Dynamic Content</h4>
<p>Before you set your cache TTL policies, you need to consider the types of content you have: static and dynamic.</p>
<p>Static files like images and PDFs do not change frequently, so these should have a long TTL policy. This ensures that these files are cached for a longer period of time.</p>
<p>Dynamic content (e.g. CSS, HTML, database driven content) is updated on a frequent basis, so these resources need to be set accordingly. Dynamic content will have varying TTL policies, whether that’s a few minutes, seconds, or none at all.</p>
<h4 id="heading-setting-ttl-policies-in-w3-total-cache">Setting TTL Policies in W3 Total Cache</h4>
<ol>
<li>In your WordPress admin dashboard, navigate to <strong>Performance &gt; Page Cache</strong>.</li>
<li>Scroll down to the <strong>Advanced</strong> section.Locate the “<strong>Maximum lifetime of cache objects:</strong>” setting and set the max-age length.</li>
<li>Scroll down to the bottom and press the Save Settings &amp; Purge Caches button to save and apply the settings immediately.</li>
</ol>
<p><img src="https://lh3.googleusercontent.com/K095w7ZbBQE-q6sgG2rEOiSj7e0j8jmq3PLmdzLWApG6IwYdJBIcboqQQsbEc80-AOgXPkcAFnOo-DXrbTzVcqefGF569tm6blX4Zwmqp3afftwGADtxLIcPFhLvy6Ahh5NVQSCoKdjU7VJHh273WKw" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-http-cache-control-headers">HTTP Cache-Control Headers</h3>
<ul>
<li><strong>Cache-Control: Max-Age</strong></li>
<li>The max-age directive specifies the maximum amount of time that a resource can be cached by a client or a proxy server. After expiring, a browser must refresh its version of the resource by sending another request to a server.</li>
<li>cache-control: max-age=3600 means that the returned resource is valid for one hour, after which the browser has to request a newer version.</li>
<li><strong>Cache-Control: No-Cache</strong></li>
<li>The no-cache directive tells a browser or caching server not to use the cached version of a resource, and to request a new version of the resource from the origin server.</li>
<li><strong>Cache-Control: No-Store</strong></li>
<li>The no-store directive tells browsers to never store a copy of the resource and not to keep it in cache. This setting is usually used for sensitive information like credit card numbers, and ensures PCI compliance by not storing this type of data in the cache.</li>
<li><strong>Cache-Control: Public</strong></li>
<li>The public response directive indicates that a resource can be cached by any cache. This directive is useful for resources that change infrequently, and when the resource is intended for public consumption.</li>
<li><strong>Cache-Control: Private</strong></li>
<li>The private response directive indicates that a resource is user specific - it can still be cached, but only on a client device. For example, a web page response marked as private can be cached by a browser, but not a Content Delivery Network.</li>
<li>This directive can be used in conjunction with the max-age directive to specify how long the resource can be cached before it needs to be revalidated.</li>
</ul>
<h4 id="heading-setting-http-cache-control-headers-in-w3-total-cache">Setting HTTP Cache-Control Headers in W3 Total Cache</h4>
<ol>
<li>In your WordPress admin dashboard, navigate to <strong>Performance &gt; Browser Cache</strong>.</li>
<li>Determine what your Cache-Control policies will be for the following files:  </li>
<li>CSS &amp; JS  </li>
<li>HTML &amp; XML  </li>
<li>Media &amp; Other Files</li>
<li>Locate the <strong>CSS &amp; JS</strong> section.  </li>
<li>Check the box next to the “<strong>Set cache control header</strong>” setting.  </li>
<li>Below that option, select the “Cache Control policy:” from the selections provided.</li>
<li>Repeat step 3 for these sections:  </li>
<li><strong>HTML &amp; XML</strong> section  </li>
<li><strong>Media &amp; Other Files</strong></li>
<li>Scroll down to the bottom and press the <strong>Save Settings &amp; Purge Caches</strong> button to save and apply the settings immediately.</li>
</ol>
<p><img src="https://lh4.googleusercontent.com/niLC--VuoLPAbK_F9odKjqHc4SUDOoHUnbeL2lywXNqyWlDOLDoNUXOIpW3ubO7ZQn8hTwXEzsxAo8VygXhaEBCLl9ctKd_qMK20PBRouWDlCKU3W__50JSofYcYkndUPEQpPLdijvB1i_8275SvEAg" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-cache-busting">Cache Busting</h3>
<p>Cache busting is a technique used to force a browser or caching server to retrieve a new version of a resource, rather than using the cached version. One way to do this is by using a query parameter, such as a timestamp or a version number, in the URL of the resource.</p>
<p>For example, instead of requesting a resource at the URL https://www.example.com/styles.css, a cache-busting URL would look like https://www.example.com/styles.css?v=1234, where v=1234 is the query parameter. This query parameter can be a timestamp or a version number, and it will be ignored by the server, but it will force the browser or caching server to treat the request as a new request, rather than using the cached version of the resource.</p>
<p>This technique is often used for static resources like stylesheets, scripts, images and so on, that are intended to be cached, but that may need to be updated frequently. By appending a query parameter to the URL, a new version of the resource will be retrieved each time the query parameter changes.</p>
<p>This technique is commonly used to ensure that the client gets the latest version of the resources after they are updated on the server side.</p>
<h4 id="heading-enable-cache-busting-in-w3-total-cache">Enable Cache Busting in W3 Total Cache</h4>
<p>Enabling Cache Busting in W3 Total Cache is done by selecting the option “Prevent caching of objects after settings change” under <strong>Performance &gt; Browser Cache</strong>. This adds a random string at the end of static asset URLs.</p>
<p><img src="https://lh6.googleusercontent.com/6-dBvrms8eOPVkl2Xk_hK0M27bk7yXrblhQzVAU2BP_0ifVj145xUJQoNHnPvIoXALz1pCkNQdxACx6AiEfu-1r0wbXCXftLY-cvQUF-Qjvp7c23-YZC58GXCarK239gSlLxuDIpV8UswxyJ92oxOUc" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Whenever a change is made to a static asset, busting cache is done by navigating to the Browser Cache page under performance, and clicking “Update Media Query String” at top. This regenerates a new string that appends to the static asset URL, which will not match the URL of the stored version in your browser so it will show the updated version to the visitor.</p>
<p><img src="https://lh3.googleusercontent.com/dzKEf1iWSU9CC7Vs37Xg3wrKWyhCGPn0xMsGfqlxZFMYr-U0mEu6oZVXADC8sStSVRp5MOiLUz6GBj0mFOT83w-Xm589nCtMFNQiGSiA2-hxtCCbFdXTXARnyPP6NXnVdnyTXrYBvYAwT_TZSafsGsQ" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-proxy-caching-cdns">Proxy Caching / CDNs</h2>
<p>Cache storage is a finite resource, so every bit of storage performance matters. Caching at proxy servers is one of the ways to reduce the response time perceived by World Wide Web users.</p>
<p>Explain choices: Ease of use versus complicated configurations vs your needs</p>
<ul>
<li>CDN level / edge caching</li>
<li>Server (NGINX) Proxy Cache</li>
<li>WordPress Plugins / Application level caching</li>
</ul>
<p>What do you have now? What is your budget? (CDN’s can be expensive) Bunny has a region based solution, with explicit pricing per region we can mention here.</p>
<p>Where is your audience in relation to your server?</p>
<p>What do we want to guide user to do?</p>
<h3 id="heading-cache-eviction-policies">Cache Eviction Policies</h3>
<p>Cache replacement algorithms play a central role in reducing response times by selecting specific website assets for caching, so that a given performance metric is maximized. They do this by deciding which objects can stay and which objects should be evicted the next time the website is accessed.</p>
<ul>
<li><strong>Least Recently Used (LRU):</strong> Replaces the cache line that has been in the cache the longest with no references to it.</li>
<li><strong>First-In First-Out (FICO):</strong> Replaces the cache line that has been in the cache the longest.</li>
<li><strong>Least Frequently Used (LFU):</strong> Replaces the cache line that has experienced the fewest references.</li>
<li><strong>Random:</strong> Pick a line at random from the candidate lines.</li>
</ul>
<h2 id="heading-caching-storage-engines">Caching Storage Engines</h2>
<p>For the different types of caching and storage engines available in the W3TC plugin. The following list outlines those choices for you.</p>
<table><colgroup><col></colgroup><tbody><tr><td><p><span>Note:</span><span> In order for some of these services to be available to your WordPress installation, they must be installed on the server in conjunction with the PHP extension or module needed for the service to function.</span></p></td></tr></tbody></table>

<h4 id="heading-disk-based-methods-with-w3-total-cache">Disk-Based Methods with W3 Total Cache</h4>
<ul>
<li><strong>Disk: Basic</strong> is the option that invokes a PHP script (advanced-cache.php) that does the hard caching job.</li>
<li><strong>Disk: Enhanced</strong> is the more efficient way of caching. This method does not invoke PHP scripts but solves the caching task in a much more elegant way by creating a static version of a web page and serves that instead of the dynamic version of your website via rewrites in the .htaccess file. This approach lets your web server deal with a static (cached) version of your web pages directly. Some tests reveal that the Enhanced method makes a website up to 2.5 times faster when compared to the Basic method.</li>
</ul>
<h4 id="heading-ram-based-methods-with-w3-total-cache">RAM Based Methods with W3 Total Cache</h4>
<ul>
<li><strong>Memcached</strong> is a high-performance, distributed memory object caching system meant to speed up dynamic web applications by alleviating database load. It provides an in-memory key-value store for small chunks of arbitrary data (strings, objects) from the results of database calls, API calls, or page rendering.</li>
<li>Memcached is ideal for relatively small and static data, and as a result may be more efficient than Redis in smaller data sets. It is also multi-threaded, which may be a benefit when using a VPS or Dedicated Server with a large resource pool.</li>
<li><strong>Redis</strong> is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams. Redis data structures resolve very complex programming problems with simple commands executed within the data store, reducing coding effort, increasing throughput, and reducing latency.</li>
</ul>
<h4 id="heading-opcode-based-methods-with-w3-total-cache">OPcode Based Methods with W3 Total Cache</h4>
<ul>
<li><strong>Alternative PHP Cache (APC / APCu)</strong> which provides in-memory Opcode caching and a key-value store for looking up cached items. This is largely deprecated in favor of modern Opcode Caching mechanisms, as APC is not supported in the PHP 7.x branch.</li>
<li><strong>APCu</strong> is similar to APC, though in order to support modern variants of PHP it is stripped of Opcode Caching and only provides the in-memory key-value store mechanisms. When paired with modern Opcode Caching mechanisms it can provide the functionality originally provided by APC, though it should only be used when you require having a limited cache size.</li>
<li><strong>eAccelerator</strong> is an in-memory Opcode caching solution that supports the PHP 4.x and 5.x major versions. This is largely deprecated in favor of modern Opcode Caching mechanisms, as eAccelerator is not supported in the PHP 7.x branch.</li>
<li><strong>XCache</strong> is an in-memory Opcode caching solution that supports up to the PHP 5.6 release. This is largely deprecated in favor of modern Opcode Caching mechanisms, as XCache is not supported in the PHP 7.x branch.</li>
<li><strong>WinCache</strong> (Recommended for Windows-based Environments) is an extension for Microsoft IIS which provides in-memory Opcode caching and currently supports up to IIS 10 as of 04/30/2019. Check the official Microsoft product page for the latest information.</li>
</ul>
<h2 id="heading-page-caching">Page Caching</h2>
<p>Page caching refers to caching the content of a whole page on the server side. Later when the same page is requested again, its content will be served from the cache instead of regenerating it from scratch.</p>
<p>A page from a WordPress website contains dynamic content: PHP scripts, JavaScript, and SQL queries. Executing this dynamic content is very resource heavy and takes a lot of time. Page caching allows for forming a part of the web page into static HTML. With page cache enabled, website content displays faster for a visitor with less load to the server. It’s one of the most efficient ways to improve your website performance.</p>
<table><colgroup><col></colgroup><tbody><tr><td><p><span>Tip:</span><span> The </span><span>Disk: Enhanced</span><span> caching method is the recommended storage engine and the most reliable option for page caching for most types of hosting plans.</span></p></td></tr></tbody></table>

<p>Explain why Disk Enhanced is often recommended, under what scenarios is another type of page cache going to give better performance?</p>
<p>CDN, NGINX Proxy Cache, etc…  </p>
<h2 id="heading-object-caching">Object Caching</h2>
<p>Object caching is the process that involves storing database queries to serve a specific piece of data on the subsequent server request. As a result, there will be fewer queries sent to the database and the result is your website will load much faster.</p>
<h3 id="heading-wordpress-object-cache">WordPress Object Cache</h3>
<p>The idea of an Object Cache is that WordPress Core, themes, and plugins may store some data that is frequently accessed and rarely changed in an object store. This is so these objects will not have to be retrieved and processed on each request.</p>
<p><a target="_blank" href="https://developer.wordpress.org/reference/classes/wp_object_cache/">wp_object_cache</a> is WordPress’ class for caching data, and by default, the object cache is non-persistent. This means that data stored in the cache resides in memory only and only for the duration of the request. Cached data will not be stored persistently across page loads unless you install a persistent caching plugin.</p>
<p>Ultimately, Object Caching will reduce the total number of database queries required for each page load. When the CPU does not have to rebuild these blocks of data, your response time will decrease.</p>
<p><img src="https://lh5.googleusercontent.com/mvUE88n655DRI9aJ7Xtjs9am6jr4g5z5fq_4q6qTeY4MFUFFiYH83tl2dmT2YAtTM7KxOuoxQaNYzDbf5yVA4i9QQwPW0LKkbEHZQpwXVpqE2mutSWRENAQDkAtOQX0H7PlMFb4oUNJXQWAPiRcu7mk" alt="Image" width="600" height="400" loading="lazy"></p>
<table><colgroup><col></colgroup><tbody><tr><td><p><span>Tip:</span><span> The </span><span>Redis</span><span> caching method is the recommended storage engine and the most reliable option for object caching if you have a VPS or Dedicated Server. For shared hosting, Disk may be your only option in some cases.&nbsp;</span></p></td></tr></tbody></table>





<h4 id="heading-store-transients-in-the-database-with-w3-total-cache">Store Transients in the Database with W3 Total Cache</h4>
<p>Transients are the data that exists in memory (in cache) for current WordPress activity. It makes the website faster. However, when the cache is cleared or expires, the heavy numerous database requests should run again to re-fill the cache. In order to avoid these resource-intensive database requests, it’s recommended to save transient data into the database. It results in much less database load when the cache is cleared or expires.</p>
<p>In W3 Total Cache, there is an option to store transients in the database. This setting can be enabled in one of two areas: Object Caching Advanced Settings or by navigating to <strong>Performance &gt; Object Cache</strong>.</p>
<p><img src="https://lh5.googleusercontent.com/BIcHYbzd9wrqXQHqCQz581zbgGusAntNVDfYaTLWUCiljUKj7DihS2f1eA6RphD0MQDPbLF7AVoGLFBxy1BcZNfDV8RAMWsmkYnfkdUo8tMMso0GlepcNHMMEytYkJK8NiGf6IK0OOrmgNGG4lpOZPI" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-database-caching">Database Caching</h2>
<p>Database caching will store the results of MySQL database queries, in theory making it faster to return a response. While this does sound like it would be useful, it is recommended that you disable it, and use <strong>Object Cache</strong> via Redis or Memcache instead.</p>
<table><colgroup><col></colgroup><tbody><tr><td><p><span>Tip:</span><span> Database caching is not recommended if you are hosting on SSD or NVME drives.</span></p></td></tr></tbody></table>

<p>Optimizing the WordPress Application</p>
<p>Once the server and database have been tuned for performance, the next step is to ensure the application is optimized for performance. This can be done by leveraging techniques designed to deliver assets more efficiently, or remove any unnecessary data from them resulting in faster transfers. The following are some of the most effective techniques you can use when it comes to optimizing your WordPress site for speed, but it is not an exhaustive list.   </p>
<h2 id="heading-top-10-techniques-to-improve-core-web-vitals-for-wordpress">Top 10 Techniques to Improve Core Web Vitals for WordPress</h2>
<p>When focusing on page and website performance, there are some essential tasks you can complete to help you achieve the performance results you are looking for. These tasks include configuring caching, following best practices for elements that can introduce layout shifts, and adjusting your assets to ensure they are configured for the fastest possible delivery to your visitors.</p>
<h3 id="heading-1-page-caching">1. Page Caching</h3>
<p>WordPress is a dynamic program by default, so the easiest way to speed things up is to create a static version of your website pages, and use redirects to serve those cached files instead of calculating the result again with PHP and MySQL. This cache can be stored on the disk, in the server's RAM or if you are using a CDN, on a Point of Presence or Edge Server.</p>
<p>If you are storing the page cache on the web server, then it is recommended to use Disk: Enhanced storage, so the web server redirects can serve the cache prior to the request reaching PHP, essentially making the site load faster by using these static files instead of recreating them with queries and calculations.</p>
<p>Storing page cache on a CDN at the edge is a practice known as Full Site Delivery or Acceleration, where the website is served by sending a cached version of the website from a geographic location near the visitor, as opposed to the request reaching out to the origin server where the data lives. This removes location introduced latency from the equation, making websites much faster for all of your visitors.</p>
<h3 id="heading-2-object-caching-with-redis">2. Object Caching with Redis</h3>
<p>By default, the object cache in WordPress is not persistent. This means that data stored in the cache resides in memory for the duration of the request and is removed after the response is delivered. To store these cached objects for reuse, you can use a plugin that connects the WordPress cache to Redis, a RAM based service that is used for persistent object storage.</p>
<p>W3 Total Cache will allow you to use object caching with Redis. Redis stores the data as keys in the web server's memory, which allows for retrieval of the data to happen much faster than the WordPress method, which caches those objects to the options table in the database by default. </p>
<h3 id="heading-3-leveraging-common-ux-patterns">3. Leveraging Common UX Patterns</h3>
<p>When adding elements such as fonts, carousels and banners to your website, you want to ensure you are following best practices. These types of elements can have a negative impact on Core Web Vitals if not implemented correctly.</p>
<p>A great example of this is not explicitly setting proper placeholders or dimensions for images, videos, iframes or other similar embedded content throughout your page. When the content is loaded, this can cause layout shift, and Core Web Vitals has very specific metrics, as a moving page can create a bad user experience for your visitor.</p>
<p>Loading custom fonts on your website is another example where things can go wrong. Adding them incorrectly can delay the text rendering or even cause layout shifts. Typically, your browser will delay displaying text until the font is loaded, which can also impact your FCP or LCP. If the text does load prior to your web font, and they are different sizes, layout shifts will occur and directly impact your CLS score.</p>
<p>Using <a target="_blank" href="https://web.dev/patterns/web-vitals-patterns/">best practices for these and other common UX elements</a> is recommended to avoid negative impacts to your page performance.</p>
<h3 id="heading-4-minification">4. Minification</h3>
<p>When developing a website, most programmers tend to use spacing and comments to make code readable for both themselves and others. Minification is a technique used to reduce load times on a website by removing unnecessary characters and comments from the code for faster delivery and rendering. This technique can be used on HTML, CSS and Javascript files and code, and can dramatically improve your site's performance.</p>
<p>To minify your assets with W3 Total Cache, you will need to enable it in General Settings. There is an automatic mode which attempts to handle the heavy lifting for you, but if you have issues with it you will need to enable manual mode and add the assets you wish to be minified yourself under the minify page.</p>
<p>There is a help wizard for setting up minify, which you can use to specify the template to use when loading the asset, or choose to load the asset globally. Using this method you can create page templates and page specific assets that only load the necessary files for the page being requested to fine tune your application for performance.</p>
<h3 id="heading-5-concatenation">5. Concatenation</h3>
<p>The term concatenation refers to the action of linking things together in a series. In the context of website performance, this means combining multiple CSS and Javascript files into a few files, to deliver the assets the browser needs faster with less requests.</p>
<p>In W3 Total Cache, concatenating files is an option in General Settings, under minify. Checking the box will allow you to combine the asset files into one of 3 different files in the DOM: One in the head, one in the body or one at the footer before the closing of the document.</p>
<h3 id="heading-6-eliminate-render-blocking-resources">6. Eliminate Render Blocking Resources</h3>
<p>Render-blocking resources is essentially code in your website files, usually CSS and JavaScript, that prevents a web page from loading quickly. To ensure your site loads as efficiently as possible, you can specify attributes that tell the browser how to download the code in relation to the other site assets.</p>
<p>When concatenating and minifying files using W3 Total Cache, you will also have the option of embedding them before the close of the document’s &lt;/<strong>head</strong>&gt; tag, or after the &lt;<strong>body</strong>&gt; tag. To improve performance, you have the option of setting “rel” attributes for the assets such as async or defer, which will tell the browser when and how to load the file.</p>
<h4 id="heading-7-using-minify-with-w3-total-cache">7. Using Minify with W3 Total Cache</h4>
<p><a target="_blank" href="https://www.boldgrid.com/support/w3-total-cache/how-to-use-manual-minify-for-css-and-js/">https://www.boldgrid.com/support/w3-total-cache/how-to-use-manual-minify-for-css-and-js/</a></p>
<p><img src="https://lh6.googleusercontent.com/2UFu5etWpFTGn3zroHJpruvWBPej-oddfznvHxELPdMVcE5ZR_zWEXI7qlf_c4zBmVv7LLk0XicDSYF2ThbrszkVQ-8bsf-wdWpzzdaDcvNqGYrHZm_hB9MOWW4-pwRvuE8cetXGN16zjwLzBGeFYiE" alt="Image" width="600" height="400" loading="lazy"></p>
<p>The Minify Help wizard in Total Cache will allow you to specify which JS and CSS files load by template, allowing you to have fine tune control over what assets load when and where. To use the wizard, you must set Minify to Manual Mode in General Settings, then visit the Minify Page to launch the Help Wizard.</p>
<p><img src="https://lh6.googleusercontent.com/eDzBcbl8IRpYa7pemPu5PIkaRiLraeh3C9BsQUr_vlLV7TC_P8cT4j1qKriR56TAIW5XBDZZp8TPYC2oxYwwL01piriceVRg7rwW2VIuvcmmgaG952BMSgiIp0BdV55Efp7qFEyS8Sq49yWfDLcXmQs" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-8-preconnect-amp-prefetch-dns-hints">8. Preconnect &amp; Prefetch DNS Hints</h3>
<p>If your site is using multiple 3rd party scripts, the location those scripts are hosted on will be considered a cross-origin domain. That 3rd party domain will need to resolve to an IP address for the browser to download the file and complete the request.</p>
<p>The time it takes for this DNS resolution to take place can introduce latency into the page load, and using preconnect and prefetch will instruct the browser to handle this prior to fetching the asset. This can help remove the latency introduced by resolving a large number of DNS requests for assets in the background.</p>
<p>Using dns-prefetch and preconnect links will help your page load faster by performing these operations for later use. The dns-prefetch will do a DNS lookup, while preconnect will establish the connection to the server. This connection established will also include a TLS handshake, if served over HTTPS. </p>
<table><colgroup></colgroup><tbody><tr><td><p><span>&lt;</span><span>link</span><span> rel=</span><span>"preconnect"</span><span> href=</span><span>"https://fonts.googleapis.com/"</span><span> crossorigin /&gt;</span><span><br></span><span>&lt;</span><span>link</span><span> rel=</span><span>"dns-prefetch"</span><span> href=</span><span>"https://fonts.googleapis.com/"</span><span> /&gt;</span></p></td></tr></tbody></table>

<p>The preconnect hint should be used sparingly, and only for the most critical assets being used in the viewport during the initial page load. For non critical assets, using only the dns-prefetch hint is recommended.</p>
<h3 id="heading-9-image-optimization">9. Image Optimization</h3>
<p>Image Optimization refers to the practice of a website delivering the highest quality image with the right format, resolution and dimensions for the device and viewport accessing them. This is done with the intent of keeping the file size as small as possible. There are several layers when dealing with optimizing your images, including removing metadata, converting to a different format, resizing and lazy loading.</p>
<h4 id="heading-removing-image-metadata">Removing Image Metadata</h4>
<p>One of the ways to reduce an image's file size is to remove any metadata attached to the file. This data can include information about the camera used to take the picture, GPS coordinates, the files owner, comments, a thumbnail, date, description, keywords and much more.</p>
<p>There are several types of metadata that can be added to images, including EXIF, IPTC, XMP. Removing this data will help to decrease the file size of the image. An added benefit is that removing metadata keeps these details from being publicly shared.</p>
<h4 id="heading-image-formats-webp">Image Formats (WebP)</h4>
<p>WebP is a compression format for images developed by Google. When optimizing your images for speed, using WebP is the recommended format for websites. Most modern browsers now support the WebP image format. There are many WordPress plugins that offer this type of image conversion and most even assist with redirects to automate the process and a fallback option in case the browser does not support the WebP format.</p>
<h4 id="heading-dynamic-image-resizing">Dynamic Image Resizing</h4>
<p>When different devices are used to access your web page, the image size needed will vary depending on the visitors viewport. Dynamic image sizes can be used to make each of these devices load the image with a size tailored specifically to the viewport where the site is being rendered.</p>
<p>A great example of this would be the hero image on your website. While a desktop would likely need the full size version of this image, the narrow viewport of a mobile device may only need an image that is 20% of that size. Providing the browser with the smaller size would reduce the time it needs to download the file, and display it.</p>
<p>There are many WordPress plugins and CDN Providers that offer dynamic resizing for images. The solution you choose should be based on your audience. If your visitors are mostly local and your traffic is not high volume, a CDN’s cost for this service may outweigh the benefits to you, so using a WordPress plugin may be your best option.</p>
<h3 id="heading-10-lazy-loading-images-and-other-embeds">10. Lazy Loading Images and Other Embeds</h3>
<p>Lazy Loading is the practice of identifying non critical assets, and ensuring they only load later as needed to render the page in the browser. In the context of images, lazy loading is usually based on a user interaction such as scrolling, and loads the images needed as a user gets near them.</p>
<p>Lazy Loading allows the first render to happen faster, as it instructs the browser to only load the critical resources needed to display what is being rendered in the viewport. Then, as you scroll, the application can detect when resources (such as images or embeds are needed), and initialize the download.</p>
<p>W3 Total Cache offers lazy loading for images. And upgrading to Pro gives you the ability to lazy load Google maps.</p>
<h3 id="heading-using-image-facades-for-interactive-elements">Using Image Facades for Interactive Elements</h3>
<p>One of the biggest issues authors run across is having multiple video embeds from providers such as Youtube or Vimeo. Loading these videos will force your site to do DNS lookups, make connections to these 3rd party servers in the background, and download the elements needed to render the content.</p>
<p>Providing an image that is served from your site's domain as an interaction point to trigger loading these types of content embeds can save you precious time rendering your web page. It also saves the user from downloading Javascript and CSS for an element they are not going to use, as the video does not render unless the user specifically clicks on the image anchor link to trigger it.</p>
<p>This is also true for other interactive elements such as chat embeds or other interactive elements that are not hosted on your server and are being served to your visitor from a remote service.</p>
<h2 id="heading-individual-page-audits">Individual Page Audits</h2>
<p>After you have optimized your site’s configuration, it is best practice to test your individual pages and disable any assets that are not needed on them. This can be done by using WordPress functions to deregister and dequeue any scripts or styles loaded by plugins not used, or there are some WordPress plugins that will help you do this from within the interface.</p>
<p>To accomplish this, you will need to measure each individual page and use the Network tab within the Inspector to determine what assets are loading per page. Once you have this information, you can determine if the assets are needed, or loading unnecessarily on a page.</p>
<p>This is a common issue with plugins that have front end output, and it can be easily remedied by identifying the pages where the asset is needed for the plugin to function, then using a WordPress function with conditional logic, to ensure those assets are only loaded on an “as needed” basis.</p>
<p>This example is for a plugin that is used on 3 pages - About Us, Contact and Management. Targeting any page that is not one of these by using a ! in front of the is_page conditional, we can use an if else statement to remove the scripts or styles. If this condition is not met, then normal operations would happen and the plugin assets would be included.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>if</span><span> ( !is_page( </span><span>array</span><span>( </span><span>'about-us'</span><span>, </span><span>'contact'</span><span>, </span><span>'management'</span><span> ) ) ) {</span><span><br></span><span>// either in about us, contact, or management, do nothing</span><span><br></span><span>&nbsp; &nbsp; } </span><span>else</span><span> {</span><span><br></span><span>&nbsp; &nbsp; </span><span>// Deregister scripts and styles</span><span><br></span><span>&nbsp; &nbsp; wp_dequeue_style( </span><span>'handle'</span><span> );</span><span><br></span><span>&nbsp; &nbsp; we_dequeue_script( </span><span>'handle'</span><span> );</span><span><br></span><span>}</span></p></td></tr></tbody></table>

<p>You can also disable the entire plugin if it is not one of the pages in the array using the following code snippet that fires on the wp action hook.</p>
<table><colgroup></colgroup><tbody><tr><td><p><span>function</span><span> </span><span>disable_plugin</span><span>() { </span><span><br></span><span>if</span><span> ( !is_page( </span><span>array</span><span> ( </span><span>'about-us'</span><span>, </span><span>'contact'</span><span>, </span><span>'management'</span><span> ) ) ) { </span><span><br></span><span>deactivate_plugins(</span><span>'plugin/main-file-plugin.php'</span><span>); </span><span><br></span><span> &nbsp; &nbsp; } </span><span><br></span><span>} </span><span><br></span><span>add_action(</span><span>'wp'</span><span>, </span><span>'disable_plugin'</span><span>);</span></p></td></tr></tbody></table>


 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use the WordPress Command Line Interface – WP-CLI Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ In the world of website development and content management, efficiency and automation are key. The WordPress Command Line Interface – or WP-CLI – is a powerful tool that can help you streamlines tasks and manage WordPress websites more effectively.  ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-wordpress-cli/</link>
                <guid isPermaLink="false">66bdff6a0b4523e3b8b99099</guid>
                
                    <category>
                        <![CDATA[ command line ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Marco Venturi ]]>
                </dc:creator>
                <pubDate>Fri, 11 Aug 2023 21:37:41 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/pexels-pixabay-207580.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In the world of website development and content management, efficiency and automation are key. The WordPress Command Line Interface – or WP-CLI – is a powerful tool that can help you streamlines tasks and manage WordPress websites more effectively. </p>
<p>This article provides an overview of WP-CLI, focusing on its capabilities to create, modify, and delete users, as well as handle plugins with ease. This article will show you how WP-CLI can significantly elevate your WordPress management experience.</p>
<h2 id="heading-what-is-wp-cli">What is WP-CLI?</h2>
<p>WP-CLI is a command-line tool designed for managing WordPress installations. It empowers developers, administrators, and site owners to interact with their websites directly from the command line, bypassing the need for manual interventions through the web interface. </p>
<p>It's built on PHP, and offers a wide range of commands that you can execute right from the terminal.</p>
<p>By using WP-CLI, you'll be able to manage your WordPress sites much more efficiently. Let's see a few examples of how WP-CLI commands can simplify your workflow:</p>
<h2 id="heading-wp-cli-commands">WP-CLI Commands</h2>
<h3 id="heading-site-information-retrieval">Site Information Retrieval</h3>
<p>The <code>wp site info</code> command provides a quick overview of your WordPress site's important details, including the site's URL, the number of posts and pages, the active theme, and more. </p>
<p>For instance, by running <code>wp site info</code>, you can promptly gather essential information about your site without navigating through the WordPress admin dashboard.</p>
<h3 id="heading-database-management">Database Management</h3>
<p>WP-CLI allows you to manage your WordPress database seamlessly. Use the <code>wp db export</code> command to create a database export file, ensuring a backup of your site's data. </p>
<p>If you need to import data, the <code>wp db import</code> command facilitates this process. For example, if you have a database backup named <code>backup.sql</code>, executing <code>wp db import backup.sql</code> restores the database to a previous state.</p>
<h3 id="heading-theme-manipulation">Theme Manipulation</h3>
<p>Manipulating themes is extremely efficient with WP-CLI. For example, the <code>wp theme install</code> command lets you install a theme directly from the official WordPress theme repository. To install the "Twenty Twenty-One" theme, you can use the command <code>wp theme install twentytwentyone</code>.</p>
<h3 id="heading-post-and-page-creation">Post and Page Creation</h3>
<p>Generating new content is made easier using WP-CLI. The <code>wp post create</code> and <code>wp post generate</code> commands enable you to create and populate posts and pages with content. </p>
<p>For example, <code>wp post create --post_type=post --post_title="New Post"</code> creates a new post with the specified title.</p>
<p>These examples illustrate the versatility and power of WP-CLI in managing various aspects of your WordPress site. By harnessing its capabilities, you can enhance your efficiency, reduce manual tasks, and gain greater control over your website's management.</p>
<h2 id="heading-how-to-install-wp-cli">How to Install WP-CLI</h2>
<p>Before diving into more features of WP-CLI, let's understand the installation process. </p>
<p>You can install WP-CLI globally on your system, making it accessible from any directory. </p>
<p>To install WP-CLI, make sure you have PHP installed, along with a compatible version of WordPress. Download the Phar archive, place it in a directory reachable through your system's PATH, and you're ready to go. </p>
<p>You can verify the installation by typing <code>wp --info</code> in your terminal. <a target="_blank" href="https://wp-cli.org">Here</a> you can find the doc with the URL to download WP-CLI with a wget.</p>
<h2 id="heading-how-to-manage-users-with-wp-cli">How to Manage Users with WP-CLI</h2>
<p>Managing users is a fundamental task when overseeing a WordPress site. WP-CLI simplifies user management with various commands that make creating, modifying, and deleting users much easier.</p>
<h3 id="heading-how-to-create-users">How to Create Users</h3>
<p>The <code>wp user create</code> command lets you quickly create users directly from the command line. </p>
<p>To illustrate, let's create a new user named "Alice" with the email address "alice@example.com" and the role of editor. Simply enter:</p>
<pre><code>wp user create alice alice@example.com --role=editor
</code></pre><h3 id="heading-how-to-modify-users">How to Modify Users</h3>
<p>WP-CLI also streamlines user modifications. Use the <code>wp user update</code> command to adjust a user's details. </p>
<p>For instance, let's change Alice's display name to "Alice Johnson" using the following command:</p>
<pre><code>wp user update <span class="hljs-number">123</span> --display_name=<span class="hljs-string">"Alice Johnson"</span>
</code></pre><p>In this example, "123" is Alice's ID.</p>
<h3 id="heading-how-to-delete-users">How to Delete Users</h3>
<p>When user accounts become obsolete or require removal for security reasons, WP-CLI simplifies the process. </p>
<p>To delete a user, use the <code>wp user delete</code> command. To remove Alice's account, simply execute:</p>
<pre><code>wp user <span class="hljs-keyword">delete</span> <span class="hljs-number">123</span> --reassign=<span class="hljs-number">567</span>
</code></pre><p>In this case, again "123" is Alice's ID and "567" is the ID of the user you want to assign Alice's content to (for example posts, pages, and so on).</p>
<h2 id="heading-how-to-manage-plugins-with-wp-cli">How to Manage Plugins with WP-CLI</h2>
<p>Plugins play a crucial role in enhancing WordPress websites. WP-CLI extends its capabilities to manage plugins, making tasks such as installation, activation, deactivation, and updates incredibly efficient.</p>
<h3 id="heading-how-to-install-plugins">How to Install Plugins</h3>
<p>Use the <code>wp plugin install</code> command to seamlessly install plugins from the WordPress repository. </p>
<p>For instance, let's install the "Akismet" anti-spam plugin:</p>
<pre><code>wp plugin install akismet
</code></pre><h3 id="heading-how-to-activate-and-deactivate-plugins">How to Activate and Deactivate Plugins</h3>
<p>Managing plugin status is quite easy with WP-CLI. Activate or deactivate plugins using the <code>wp plugin activate</code> and <code>wp plugin deactivate</code> commands respectively. </p>
<p>To activate the "Akismet" plugin, type the following command:</p>
<pre><code>wp plugin activate akismet
</code></pre><h3 id="heading-how-to-update-plugins">How to Update Plugins</h3>
<p>Keeping plugins up to date is vital for security and performance. The <code>wp plugin update</code> command makes updates hassle-free. </p>
<p>To update all installed plugins, simply run:</p>
<pre><code>wp plugin update --all
</code></pre><h3 id="heading-how-to-list-installed-plugins">How to List Installed Plugins</h3>
<p>WP-CLI offers an overview of installed plugins with the <code>wp plugin list</code> command. This provides a quick snapshot of each plugin's status, version, and available updates:</p>
<pre><code>wp plugin list
</code></pre><h2 id="heading-conclusion">Conclusion</h2>
<p>WP-CLI is an invaluable asset in the world of WordPress management. Its extensive command set helps you manage users and plugins – and much more – with remarkable ease. This saves you time and minimizes manual interventions. </p>
<p>By harnessing the power of WP-CLI, administrators and developers can streamline workflows, improve security, and ensure their WordPress websites operate seamlessly. </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Optimize Your WordPress Site for Search Engine Visibility ]]>
                </title>
                <description>
                    <![CDATA[ In today's digital landscape, where online presence is key to success, Search Engine Optimization (SEO) plays a pivotal role in driving organic traffic to your website.  Among various content management systems, WordPress is a popular choice due to i... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/wordpress-seo/</link>
                <guid isPermaLink="false">66bb57558884c56d5d5638ac</guid>
                
                    <category>
                        <![CDATA[ search ]]>
                    </category>
                
                    <category>
                        <![CDATA[ SEO ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jim Campbell ]]>
                </dc:creator>
                <pubDate>Thu, 10 Aug 2023 14:55:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/seo-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In today's digital landscape, where online presence is key to success, <a target="_blank" href="https://www.freecodecamp.org/news/tag/seo/">Search Engine Optimization (SEO)</a> plays a pivotal role in driving organic traffic to your website. </p>
<p>Among various content management systems, WordPress is a popular choice due to its user-friendly interface and flexibility. </p>
<p>But having a <a target="_blank" href="https://www.freecodecamp.org/news/what-is-wordpress/">WordPress</a> site is just the beginning. Optimizing it for <a target="_blank" href="https://backlinko.com/hub/seo/visibility">search engine visibility</a> is a crucial step toward ensuring your content reaches the right audience. </p>
<p>In this comprehensive guide, we will delve into the key strategies and plugins that can significantly enhance your WordPress website's SEO, enabling it to rank higher on search engine results pages and attract more organic traffic.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/seo.jpeg" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-1-on-page-seo-optimization">1. On-Page SEO Optimization</h2>
<p><a target="_blank" href="https://www.semrush.com/blog/on-page-seo/">On-Page SEO Optimization</a> holds paramount importance for WordPress sites as it lays the foundation for higher search engine rankings, improved user experience, and increased organic traffic. </p>
<p>By meticulously crafting high-quality content, targeting relevant keywords, and optimizing meta tags, WordPress websites become more discoverable by search engines, ensuring that the right audience finds and engages with the content. </p>
<p>Using the proper heading tags, multimedia elements, and logical site structure not only enhances readability for users but also provides search engines with valuable information about the content's relevance and context. </p>
<p>On-Page SEO is the fundamental step that sets the stage for successful online visibility, enabling WordPress sites to establish their authority, credibility, and competitiveness in an ever-expanding digital landscape.</p>
<h3 id="heading-keyword-research-and-analysis">Keyword Research and Analysis</h3>
<p>Effective SEO begins with thorough keyword research and <a target="_blank" href="https://virtualvalley.io/google-competitors-analysis/">Google competitors analysis</a>. Identify the relevant keywords that resonate with your content and target audience. </p>
<p>Utilize <a target="_blank" href="https://influno.com/best-seo-automation-software/">SEO tools</a> such as <a target="_blank" href="https://ads.google.com/intl/en_us/home/tools/keyword-planner/">Google Keyword Planner</a>, <a target="_blank" href="https://www.semrush.com/">SEMrush</a>, or <a target="_blank" href="https://ahrefs.com/">Ahrefs</a> to uncover high-volume and low-competition keywords. These keywords will serve as the foundation for your content creation and optimization efforts.</p>
<h3 id="heading-high-quality-content-creation">High-Quality Content Creation</h3>
<p>Compelling, informative, and unique content is the cornerstone of SEO success. Craft articles, blog posts, and other content that addresses your audience's needs and interests. Utilize proper heading tags (H1, H2, H3, etc.) to structure your content logically. Engage your readers with multimedia elements like images, videos, and infographics. </p>
<p>At <a target="_blank" href="https://campmedia.com">Camp Media</a>, we use an <a target="_blank" href="https://www.shno.co/products/seo-for-solopreneurs">SEO playbook</a>, which involves all of these factors and allows us to be consistent with the process and outsource our best practices to new members of the team.</p>
<h3 id="heading-optimizing-meta-tags">Optimizing Meta Tags</h3>
<p><a target="_blank" href="https://www.semrush.com/blog/meta-tag/">Meta tags</a> are the first interaction users have with your content in search results. </p>
<p>Write enticing title tags that encapsulate the essence of your content while incorporating target keywords. Craft concise and relevant meta descriptions that encourage users to click through to your website. Also, use meta robots tags to control how search engines crawl and index your pages.</p>
<h2 id="heading-2-technical-seo-enhancement">2. Technical SEO Enhancement</h2>
<p>Technical SEO is a vital aspect for WordPress sites, serving as the backbone that supports optimal performance and user experience while ensuring search engines can effectively crawl, index, and rank the website's content.</p>
<p><a target="_blank" href="https://blog.hubspot.com/marketing/how-to-reduce-your-websites-page-speed">A fast-loading website</a>, facilitated by caching plugins and image optimization, not only keeps users engaged but also aligns with search engines' preference for responsive and swift sites, leading to higher rankings. </p>
<p>Mobile responsiveness is no longer an option but a requirement, as search engines prioritize mobile-friendly websites.</p>
<p>Implementing SSL certificates for HTTPS encryption not only enhances user trust but is also recognized as a ranking factor by search algorithms. </p>
<p>Overall, Technical SEO Enhancement guarantees that the technical infrastructure of a WordPress site is robust, efficient, and aligned with search engine guidelines. This ultimately contributes to improved visibility, higher search rankings, and a seamless user experience. </p>
<p>To make your website error-free, you can opt for a <a target="_blank" href="https://www.intelivita.co.uk/seo-services.php">professional SEO services</a> so that experts with technical SEO knowledge can quickly set your site up for success. </p>
<h3 id="heading-website-speed-and-performance">Website Speed and Performance</h3>
<p>Website loading speed is a critical factor for both user experience and SEO. Use caching plugins such as <a target="_blank" href="https://wordpress.org/plugins/wp-super-cache/">WP Super Cache</a> or <a target="_blank" href="https://wordpress.org/plugins/w3-total-cache/">W3 Total Cache</a> to reduce loading times. Optimize images by compressing them without sacrificing quality. Minimize server response time by choosing a <a target="_blank" href="https://www.wpmyweb.com/hosting/best-web-hosting.html">reliable hosting provider</a>.</p>
<h3 id="heading-mobile-responsiveness">Mobile Responsiveness</h3>
<p><a target="_blank" href="https://www.searchenginejournal.com/ranking-factors/mobile-friendliness/">Mobile-friendliness</a> is no longer optional – it's a necessity. Ensure your WordPress theme is responsive, adapting seamlessly to various screen sizes. </p>
<p>Responsive themes provide an optimal user experience on both desktop and mobile devices. Test your site's mobile usability to identify and fix any issues.</p>
<h3 id="heading-ssl-and-website-security">SSL and Website Security</h3>
<p>Website security is not only important for user trust but also for SEO. Implementing an SSL certificate to enable HTTPS on your site not only encrypts data transmission but is also considered a ranking factor by search engines. </p>
<p>Regularly audit your website's security measures and apply updates to prevent vulnerabilities.</p>
<h2 id="heading-3-user-experience-and-accessibility">3. User Experience and Accessibility</h2>
<p><a target="_blank" href="https://www.codeable.io/blog/wordpress-ux/">User Experience (UX)</a> and Accessibility are of paramount importance for WordPress sites as they directly impact how visitors interact with and perceive the content. </p>
<p>A well-designed and intuitive site structure ensures that users can easily navigate through the website, finding the information they need without frustration. </p>
<p>By implementing <a target="_blank" href="https://www.smashingmagazine.com/2009/03/breadcrumbs-in-web-design-examples-and-best-practices/">breadcrumb trails</a>, clear navigation menus, and logical URLs, WordPress sites create a user-friendly environment that encourages longer visits and reduces bounce rates. Also, optimizing for accessibility through features like descriptive alt text for images and semantic HTML ensures that all users, including those with disabilities, can access and understand the content. </p>
<p>Not only does this demonstrate inclusivity and social responsibility, but it also aligns with search engines' emphasis on providing valuable and accessible content to a wide range of users. </p>
<p>Ultimately, prioritizing User Experience and Accessibility within a WordPress site contributes to improved engagement, better search engine rankings, and a positive online reputation.</p>
<h3 id="heading-intuitive-site-structure">Intuitive Site Structure</h3>
<p>A clear and intuitive site structure improves user experience and SEO. Ensure your navigation is logical and user-friendly. Create a <a target="_blank" href="https://rankmath.com/kb/wordpress-permalinks/">URL structure</a> that reflects the hierarchy of your content. Implement breadcrumbs to help users understand their location within your site and navigate back easily.</p>
<h3 id="heading-accessibility-optimization">Accessibility Optimization</h3>
<p>Design your website with <a target="_blank" href="https://wordpress.org/about/accessibility/">accessibility</a> in mind. Ensure your content is accessible to users with disabilities by using semantic HTML. Provide descriptive alt text for images and multimedia to assist screen readers. </p>
<p>Following accessibility guidelines not only benefits users but also enhances your site's search engine visibility.</p>
<h2 id="heading-4-link-building-and-off-page-seo">4. Link Building and Off-Page SEO</h2>
<p>Link Building and Off-Page SEO play a pivotal role in enhancing the authority, credibility, and visibility of WordPress sites in the vast digital landscape. </p>
<p>By acquiring high-quality backlinks from reputable and relevant sources, these websites garner validation from external sources, signaling to search engines that their content is trustworthy and valuable. </p>
<p>Engaging in <a target="_blank" href="https://marketinglad.io/ethical-link-building-strategies/#:~:text=14.,they%20getting%20some%20new%20links.">ethical link building practices</a>, such as guest posting, influencer collaborations, and industry partnerships, not only establishes connections within the online community but also drives referral traffic and expands the site's reach. </p>
<p><a target="_blank" href="https://wpforms.com/social-media-plugins-wordpress/">Social media integration</a> further amplifies the distribution of content, leading to increased engagement and potentially generating more inbound links. </p>
<p>Recognizing that search algorithms consider external signals as a measure of a site's authority, Link Building and Off-Page SEO contribute to higher search rankings, expanded online visibility, and a broader audience reach for WordPress sites.</p>
<h3 id="heading-creating-high-quality-backlinks">Creating High-Quality Backlinks</h3>
<p>Backlinks from authoritative and relevant sources signal to search engines that your content is valuable and trustworthy. Once acquired, it's also crucial to ensure you <a target="_blank" href="https://digitaltriggers.io/the-definitive-guide-to-getting-backlinks-indexed/">get backlinks indexed</a> for them to contribute effectively to your SEO. </p>
<p>Focus on earning backlinks naturally through strategies like guest posting on reputable websites, collaborating with influencers, and participating in industry forums. Avoid questionable practices like buying links or engaging in link farms, as they can lead to penalties.</p>
<h3 id="heading-social-media-integration">Social Media Integration</h3>
<p>Social media plays a significant role in amplifying your content's reach and engagement. Share your articles, blog posts, and other content on various social media platforms (Twitter, Pinterest, Facebook, LinkedIn, and Facebook's new <a target="_blank" href="https://nikolaroza.com/instagram-threads-statistics-facts/">Threads</a>). </p>
<p>Encourage users to share and engage with your content by adding <a target="_blank" href="https://themeisle.com/blog/add-social-share-buttons-to-wordpress/">social sharing buttons</a> to your site. While social signals are not direct ranking factors, increased engagement can indirectly influence SEO.</p>
<h2 id="heading-5-essential-seo-plugins-for-wordpress">5. Essential SEO Plugins for WordPress</h2>
<p>Essential SEO plugins are a cornerstone for optimizing WordPress sites. They offer an array of tools and functionalities that simplify and streamline the complex process of SEO. </p>
<p>Plugins like Yoast SEO and All in One SEO Pack provide invaluable insights and guidance for on-page optimization, ensuring that content is well-structured, keyword-optimized, and equipped with compelling meta tags.</p>
<p>These plugins facilitate the creation of XML sitemaps and breadcrumbs, enabling search engines to efficiently crawl and index the site's content. </p>
<p>Also, caching plugins like WP Super Cache and W3 Total Cache significantly enhance website speed and performance, critical factors for both user experience and search engine rankings. </p>
<p>By integrating these essential plugins, WordPress sites not only save time and effort but also benefit from a comprehensive approach to SEO that contributes to higher visibility, increased organic traffic, and a more competitive online presence.</p>
<h3 id="heading-yoast-seo">Yoast SEO</h3>
<p><a target="_blank" href="https://yoast.com/wordpress/plugins/seo/">Yoast SEO</a> is a widely-used plugin that offers a comprehensive set of tools for on-page optimization. It helps you optimize content by providing real-time analysis of your focus keyword usage, readability, and meta tags. Configure XML sitemaps and breadcrumbs to enhance search engine crawling and user navigation.</p>
<h3 id="heading-all-in-one-seo-pack">All in One SEO Pack</h3>
<p>Similar to Yoast SEO, the <a target="_blank" href="https://wordpress.org/plugins/all-in-one-seo-pack/">All in One SEO Pack</a> plugin provides features for optimizing your content's meta tags, title tags, and meta descriptions. Configure settings for title templates, meta tags, and more. The plugin also offers advanced features suitable for experienced users who want more control over their SEO settings.</p>
<h3 id="heading-wp-super-cache-and-w3-total-cache">WP Super Cache and W3 Total Cache</h3>
<p>As previously mentioned, these caching plugins are essential for enhancing website speed and performance. They create static versions of your pages, reducing server load and improving loading times. </p>
<p>Set up browser caching and object caching to further enhance speed. Minimizing database queries also contributes to a smoother user experience.</p>
<h2 id="heading-6-monitoring-and-continuous-improvement">6. Monitoring and Continuous Improvement</h2>
<p><a target="_blank" href="https://wp-umbrella.com/blog/monitoring-wordpress-the-ultimate-guide/">Monitoring and continuous improvement</a> are essential practices for maintaining the effectiveness and relevance of WordPress sites in the dynamic online landscape. </p>
<p>Regularly tracking key metrics through tools like Google Analytics provides insights into user behavior, site performance, and traffic sources. This data-driven approach enables webmasters to identify trends, understand user preferences, and refine content strategies accordingly. </p>
<p>Google Search Console offers invaluable information about how search engines index and rank the site, allowing for swift identification and resolution of any issues that might affect visibility. </p>
<p>As search algorithms evolve and user expectations change, the ability to adapt is crucial. By consistently monitoring and analyzing data, WordPress sites can ensure they remain aligned with best practices. Ongoing improvements based on insights gleaned from these tools can lead to enhanced user experience, sustained search engine visibility, and continued success in a competitive digital landscape.</p>
<h3 id="heading-google-analytics-integration">Google Analytics Integration</h3>
<p><a target="_blank" href="https://analytics.google.com/analytics/web/">Google Analytics</a> provides invaluable insights into your website's performance, user behavior, and traffic sources. Monitor key metrics such as page views, bounce rates, and user demographics. Analyze this data to refine your content strategy and identify areas for improvement.</p>
<h3 id="heading-google-search-console">Google Search Console</h3>
<p><a target="_blank" href="https://search.google.com/search-console/about">Google Search Console</a> is a powerful tool for monitoring your website's indexing status and search performance. Submit XML sitemaps to ensure search engines crawl and index your content efficiently. Regularly review the index coverage report to identify potential issues and address crawl errors promptly.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, optimizing your WordPress website for search engine visibility is a multifaceted endeavor. It involves a combination of on-page and technical SEO strategies, user experience enhancements, link building efforts, and the integration of essential plugins. </p>
<p>By implementing these strategies and leveraging the power of SEO plugins, you'll be well-equipped to improve your website's ranking on search engine results pages and attract a steady flow of organic traffic. </p>
<p>Remember that SEO is an ongoing process, requiring continuous monitoring, adaptation, and improvement to stay ahead in the ever-evolving digital landscape.</p>
<p>In the fast-paced and competitive online world, optimizing your WordPress website for search engine visibility is not just a choice – it's a necessity. </p>
<p>This comprehensive guide has explored the key strategies and plugins that can significantly enhance your website's SEO, leading to higher rankings, increased organic traffic, and improved user engagement. </p>
<p>By focusing on on-page optimization, technical enhancements, user experience, link building, and utilizing essential SEO plugins, you're setting your website up for success in the digital realm.</p>
<p>Again, remember that SEO is not a one-time task but an ongoing process. The algorithms that search engines use to rank websites are continually evolving, and staying ahead requires dedication and adaptability. </p>
<p>This means you'll need to regularly monitor your website's performance, analyze user behavior, and stay informed about the latest SEO trends and updates. By consistently fine-tuning your strategies, you can ensure your WordPress website remains competitive and visible in search engine results.</p>
<p>Whether you're a seasoned webmaster or a novice WordPress user, the insights shared in this guide provide a solid foundation for optimizing your website and driving meaningful results. </p>
<p>By implementing the practices outlined here, you're not just enhancing your search engine visibility – you're creating a better online experience for your users, fostering trust, and ultimately achieving your goals in the digital landscape. </p>
<p>So, roll up your sleeves, implement these strategies, and watch as your WordPress website climbs the ranks, attracting more organic traffic and achieving the success it deserves.  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Dynamic Wordpress Site with Advanced Custom Fields and Custom Post Types ]]>
                </title>
                <description>
                    <![CDATA[ Hello, fellow WordPress enthusiasts! Today, I want to share with you an exciting journey I took while building Honeymoons.com. It's a dynamic website that uses Advanced Custom Fields (ACF) and Custom Post Types.  As a travel company specializing in d... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-dynamic-wordpress-website/</link>
                <guid isPermaLink="false">66bb5744965d5c9ed5487b98</guid>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jim Campbell ]]>
                </dc:creator>
                <pubDate>Thu, 03 Aug 2023 20:36:38 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/08/Screenshot-2023-08-03-at-3.50.46-AM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Hello, fellow WordPress enthusiasts! Today, I want to share with you an exciting journey I took while building <a target="_blank" href="https://honeymoons.com">Honeymoons.com</a>. It's a dynamic website that uses <a target="_blank" href="https://www.advancedcustomfields.com/">Advanced Custom Fields (ACF)</a> and <a target="_blank" href="https://developer.wordpress.org/plugins/post-types/registering-custom-post-types/">Custom Post Types</a>. </p>
<p>As a travel company specializing in dreamy honeymoon destinations, it was crucial for us to showcase our hotels and destinations in a user-friendly and visually appealing way. </p>
<p>ACF and CPTs proved to be the perfect solution for achieving our goal of providing an immersive and personalized experience for our users. </p>
<p>Creating a custom post type for both Destinations and Hotels allowed us to easily categorize these specific types of content. Advanced Custom Fields allowed us to enrich the Custom Post Types with specific metadata that can be dynamically displayed throughout the website.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/image-12.png" alt="Image" width="600" height="400" loading="lazy">
<em>Example of <a target="_blank" href="https://honeymoons.com">Honeymoons.com</a> using a Custom Post Type, Custom Template, and ACF to display hotel information.</em></p>
<h2 id="heading-what-are-custom-post-types">What Are Custom Post Types?</h2>
<p>WordPress <a target="_blank" href="https://developer.wordpress.org/plugins/post-types/registering-custom-post-types/">Custom Post Types</a> are a powerful feature that allows you to extend the default functionality of WordPress beyond the standard posts and pages. They enable you to create and manage different types of content, each with its own set of attributes and functionalities. </p>
<p>Custom Post Types are essential for organizing and presenting specific content types, such as products, portfolio items, testimonials, events, recipes, and more in a structured and efficient manner.</p>
<p>By default, WordPress comes with two main post types:</p>
<h3 id="heading-posts">Posts</h3>
<p>These are standard blog posts that are typically displayed in reverse chronological order on the blog page.</p>
<h3 id="heading-pages">Pages</h3>
<p>These are static pages that are typically used for static content like About Us, Contact Us, or a Privacy Policy page.</p>
<p>However, when you need to create content that doesn't fit into the default post or page structure, Custom Post Types come into play.</p>
<p>You can register your custom post types with their own set of attributes, taxonomies, and template files. This allows you to manage and present diverse content in a more organized and user-friendly manner.</p>
<p>For instance, on <a target="_blank" href="https://honeymoons.com">honeymoons.com</a>, we created a Custom Post Type called "Destinations" to showcase honeymoon destinations. </p>
<p>To create Custom Post Types, you can either write custom code using the <code>register_post_type()</code> function or use plugins that make the process more user-friendly, like "<a target="_blank" href="https://wordpress.org/plugins/custom-post-type-ui/">Custom Post Type UI</a>" or "<a target="_blank" href="https://toolset.com/home/types-manage-post-types-taxonomy-and-custom-fields/">Toolset Types</a>." </p>
<p>WordPress comes with functionality to easily configure the post types to your specific needs by updating the functions.php file within your theme.</p>
<p>The specific code we used to create the Destinations post type is here:</p>
<p>    //Destinations
    register_post_type('destination', // Register Custom Post Type
        array(
        'labels' =&gt; array(
            'name' =&gt; <strong>('Destinations', 'destination'), // Rename these to suit
            'singular_name' =&gt; </strong>('Destination', 'html5blank'),
        ),
        'public' =&gt; true,
        'hierarchical' =&gt; true, // Allows your posts to behave like Hierarchy Pages
        'has_archive' =&gt; false,
        'menu_icon' =&gt; 'dashicons-palmtree',
        'show_in_nav_menus'   =&gt; true,
        'supports' =&gt; array(
            'title',
            'editor',
            'excerpt',
            'revisions',
            'page-attributes',
            'thumbnail'
        ), // Go to Dashboard Custom HTML5 Blank post for supports
        'rewrite' =&gt; array (
            'slug' =&gt; '/destinations',
            'with_front' =&gt; false,
            'hierarchical' =&gt; true
        ),
        'can_export' =&gt; true, // Allows export in Tools &gt; Export
        'taxonomies' =&gt; array(
            'experiences',
            'regions'
        ) // Add Category and Post Tags support */
    ));</p>
<p>These Custom Post Types will appear in the wp-admin sidebar with your Posts and Pages:</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/image-11.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Custom Post Types have become an essential tool for developers and content creators, as they offer the flexibility to tailor WordPress websites to specific needs, making it a versatile and robust content management system.</p>
<h2 id="heading-what-are-advanced-custom-fields-for-wordpress">What are Advanced Custom Fields for WordPress?</h2>
<p><a target="_blank" href="https://www.advancedcustomfields.com/">Advanced Custom Fields (ACF)</a> is a popular WordPress plugin that enhances the content creation and management experience by providing a user-friendly interface for adding custom fields to posts, pages, and custom post types. It allows website developers and content creators to easily extend the default WordPress post editor with additional input fields, enabling the creation of more structured and dynamic content.</p>
<p>With ACF, you can define various types of custom fields, such as text fields, image upload fields, select dropdowns, date pickers, repeater fields, and more. These custom fields can be used to add extra information to your content, making it more versatile and tailored to specific requirements.</p>
<p>Key features and benefits of Advanced Custom Fields (ACF) include:</p>
<ol>
<li><strong>Custom Field Creation</strong>: ACF allows you to create custom fields through an intuitive graphical interface within the WordPress admin area. You can choose from various field types and configure their settings to suit your needs.</li>
<li><strong>Field Groups</strong>: You can group related fields together into sets called "Field Groups." These groups can then be assigned to specific post types or pages, providing a modular and organized approach to content management.</li>
<li><strong>Conditionals and Logic</strong>: A powerful feature of ACF is the ability to set conditional logic for fields. You can show or hide specific fields based on the values of other fields, making content creation more efficient and user-friendly.</li>
<li><strong>Repeater Fields</strong>: ACF's repeater field allows you to create sets of sub-fields that can be repeated as needed. This is especially useful for managing dynamic content like lists, galleries, and flexible content sections.</li>
<li><strong>Frontend Integration</strong>: ACF makes it easy to display the custom field data on the frontend of your website. You can use simple template tags or ACF functions to retrieve and display the custom field values within your theme files.</li>
<li><strong>Extensibility</strong>: ACF can be extended through third-party add-ons and custom code, allowing developers to create even more advanced and specialized custom fields and functionalities.</li>
<li><strong>User-Friendly Experience</strong>: ACF simplifies the content creation process for non-technical users. It reduces the need for custom coding and makes it easier for content editors to add and manage content with structured fields.</li>
</ol>
<p>ACF has gained popularity among WordPress developers and designers for its flexibility and ease of use. It enables the creation of dynamic and customized websites without the need for complex custom development, making it a valuable tool for both small-scale websites and large, complex projects.</p>
<h2 id="heading-how-to-create-custom-templates-to-display-acf-content">How to Create Custom Templates to Display ACF Content</h2>
<p>To dynamically show data using Advanced Custom Fields (ACF) and custom templates in WordPress, we'll walk through the steps with an example from Honeymoons.com using a Custom Post Type of Hotels. </p>
<p>We'll create custom fields for metadata such as the number of rooms, average price, and the hotel URL, and then display this data dynamically on the frontend using a custom template.</p>
<h3 id="heading-step-1-install-and-activate-advanced-custom-fields-plugin">Step 1: Install and Activate Advanced Custom Fields Plugin.</h3>
<p>First, ensure that the Advanced Custom Fields plugin is installed and activated on your WordPress website. You can find the plugin in the WordPress Plugin Repository and install it from the admin dashboard.</p>
<h3 id="heading-step-2-create-custom-fields-for-hotel-post-type">Step 2: Create Custom Fields for Hotel Post Type.</h3>
<p>Next, we'll create custom fields for the Hotel post type using ACF.</p>
<ol>
<li><p>Go to "Custom Fields" in the WordPress admin sidebar and click on "Add New."</p>
</li>
<li><p>Create a new field group for Hotels and add the following custom fields:</p>
</li>
<li><p>Hero Image (Image)</p>
</li>
<li>TripAdvisor.com Link (URL)</li>
<li>Number of Rooms (Number)</li>
<li>Number of Rooms (Number)</li>
<li>Price - Low (Number)</li>
<li>Price - High (Number)</li>
<li>Price - Average (Number)</li>
<li>Guest Rating (Number with a maximum value of 10)</li>
<li>Star Rating</li>
<li>Website (URL)</li>
<li>Display URL (Text)</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/image-9.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="3">
<li>Assign Field Group to Hotel Post Type </li>
</ol>
<p>After creating the custom fields, we need to assign the field group to the Hotel post type.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2023/08/image-10.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h3 id="heading-step-3-displaying-the-custom-fields-in-the-custom-template">Step 3: Displaying the Custom Fields in the Custom Template</h3>
<p>Now, we'll create a custom template for the Hotel post type, where we can dynamically retrieve and display the metadata.</p>
<p>Create a new PHP file in your theme folder and name it "single-hotel.php" (assuming you have a custom post type template hierarchy in your theme). Replace "hotel" with whatever your custom post type is named. </p>
<p>In "single-hotel.php," start with the regular template code for the header, footer, and post loop. You can start with a copy of single.php.</p>
<p>Use ACF functions to retrieve the custom field values and display them in the template. Use PHP, HTML and CSS to display the content.</p>
<p>You can retrieve the Advanced Custom Fields like this:</p>
<p>$number_of_rooms = get_field('number_of_rooms');
$average_price = get_field('average_price');
$hotel_url = get_field('hotel_url');</p>
<p>And display the content like this:</p>
<p>echo '</p><p>Number of Rooms: ' . $number_of_rooms . '</p>';
echo '<p>Average Price: $' . $average_price . '</p>';
echo '<p><a href="' . $hotel_url . '">Hotel Website</a></p>';<p></p>
<p>By  capturing metadata with Advanced Custom Fields and displaying that content with Custom Templates and Custom Post Types, you can organize and display data on your WordPress website in a much more dynamic and user-friendly way.</p>
<p>Your WordPress site will not look "out-of-the-box" and your site will provide much more helpful and organized information to the user.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Thanks to ACF and Custom Post Types, Honeymoons.com now boasts a dynamic website that offers personalized experiences to our users. </p>
<p>Our collaboration with ACF and CPTs has empowered us to create stunning hotel and destination pages that captivate visitors and help them plan their dream honeymoon effortlessly. </p>
<p>I hope our case study has inspired you to explore the vast potential of ACF and CPTs for building dynamic WordPress websites tailored to your specific needs. Happy coding!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Choose a WordPress Host ]]>
                </title>
                <description>
                    <![CDATA[ Are you looking for a reliable and secure WordPress hosting provider? With so many options available, it can be hard to know which host is right for your needs. When selecting a hosting provider, several factors need to be taken into consideration. F... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/hosting-a-wordpress-website/</link>
                <guid isPermaLink="false">66bb5747b6e566d0c2aea5eb</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Jim Campbell ]]>
                </dc:creator>
                <pubDate>Thu, 19 Jan 2023 20:44:01 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/01/souvik-banerjee--WPrNEM_6dg-unsplash.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Are you looking for a reliable and secure WordPress hosting provider? With so many options available, it can be hard to know which host is right for your needs.</p>
<p>When selecting a hosting provider, several factors need to be taken into consideration. From the size of your website to the type of server you require to the security measures in place – these all play an important role in determining which host is best suited for you.</p>
<p>In this article, we will discuss seven tips to help you choose a WordPress host that suits your needs. We'll explore topics such as cost-effectiveness, scalability, customer support, and more. </p>
<p>By following these guidelines, you’ll be able to make an informed decision when selecting a web hosting service for your WordPress site.</p>
<h2 id="heading-1-understand-your-needs"><strong>1. Understand Your Needs</strong></h2>
<p>WordPress is a versatile and user-friendly content management system (CMS) that can be used for any business. It's the most popular CMS in the world, powering over <a target="_blank" href="https://kinsta.com/blog/wordpress-statistics/">34% of all websites on the internet</a>. </p>
<p>WordPress is used by beginners and <a target="_blank" href="https://wizve.com/wordpress-certification/">certified WordPress pros</a> alike. Because it is so versatile, many options exist for a hosting provider, which can make it tricky when selecting the best hosting provider.</p>
<p>Consider the size and scope of your website. Will you need a lot of storage space? Will it include large files such as images or videos? Do you expect to have high traffic volumes or need additional security measures in place?</p>
<p>Knowing what your website needs and having a clear idea of the features you require from your WordPress host will help ensure that you select the most suitable one.</p>
<h2 id="heading-2-research-different-hosting-providers"><strong>2. Research Different Hosting Providers</strong></h2>
<p>Once you know what your website needs, take some time to research different hosting providers. Look at their features, support, and pricing. Ask them questions regarding any concerns you have with their services. </p>
<p>Also, read user reviews to get an idea of the experiences others have had using that particular host.</p>
<p>Some of the most popular WordPress hosts are:</p>
<ul>
<li><a target="_blank" href="https://www.siteground.com/">SiteGround</a></li>
<li><a target="_blank" href="https://www.bluehost.com/">Bluehost</a></li>
<li><a target="_blank" href="https://www.ionos.com/">IONOS</a></li>
<li><a target="_blank" href="https://wpengine.com/">WP Engine</a></li>
<li><a target="_blank" href="https://www.dreamhost.com/">DreamHost</a></li>
<li><a target="_blank" href="https://getflywheel.com/">Flywheel</a></li>
<li><a target="_blank" href="https://kinsta.com/">Kinsta</a></li>
<li><a target="_blank" href="https://www.inmotionhosting.com/">InMotion</a></li>
<li><a target="_blank" href="https://www.hostinger.com/">Hostinger</a></li>
<li><a target="_blank" href="https://www.hostgator.com/">HostGator</a></li>
</ul>
<p>Read the full list and reviews at G2 <a target="_blank" href="https://www.g2.com/categories/managed-hosting">here</a>.</p>
<p>There are a lot of WordPress hosting providers, and there are some key things to consider when selecting yours:</p>
<h2 id="heading-3-look-for-reliability-amp-security-features"><strong>3. Look for Reliability &amp; Security Features</strong></h2>
<p>Ensure your host is reliable and secure. Your WordPress host should have a robust server infrastructure with <a target="_blank" href="https://www.wpbeginner.com/plugins/how-to-monitor-server-uptime-in-wordpress/">good uptime</a> and reasonable response times. They should also offer security features such as firewalls and <a target="_blank" href="https://thewpx.com/backup-wordpress/">daily backups</a> to help protect your site from hackers and other malicious attacks.</p>
<p>Reliability and security are paramount when choosing a WordPress host. Having reliable service means that your website will be accessible to visitors more often, which is crucial to running a successful online business. </p>
<p>With secure hosting, you can rest assured that your website and its data will be safe from malicious attacks. </p>
<p>This is especially important if you're going be hosting sensitive data about your users. For example, if you need to store medical information you need a <a target="_blank" href="https://www.12sm.agency/hipaa-hosting/">HIPAA compliant host</a>, and if you need to store financial data you need to be <a target="_blank" href="https://www.ironmountain.com/blogs/2019/what-you-need-to-know-about-storing-financial-data-in-the-cloud">especially careful</a>.</p>
<p>Reliable hosting provides an experience for your visitors and customers that is fast, secure, and hassle-free.</p>
<h2 id="heading-4-check-support-options"><strong>4. Check Support Options</strong></h2>
<p>Make sure you have access to technical support when needed. The best WordPress hosts will provide you with live chat, email support and telephone assistance. Additionally, they should have a knowledge base where you can find answers to frequently asked questions.</p>
<p>It’s important to check the support options before selecting a host, as having access to help in case something goes wrong is invaluable. Good customer service can make or break your online business, so it's worth doing your research and finding a provider that will be there when you need them.</p>
<h2 id="heading-5-think-about-scalability-amp-performance"><strong>5. Think About Scalability &amp; Performance</strong></h2>
<p>Choose a host that can grow with you as your website expands. Look for a host that offers <a target="_blank" href="https://themeisle.com/blog/best-unlimited-hosting-plans/">unlimited data storage, bandwidth, and email accounts</a>. Additionally, the hosting package should include performance-enhancing features like caching and content delivery networks (<a target="_blank" href="https://www.cloudflare.com/learning/cdn/what-is-a-cdn/">CDNs</a>).</p>
<p>These features can help your website load faster, which is essential for keeping visitors on your site and improving search engine rankings. Faster loading times can also lead to higher conversion rates, as customers are more likely to stay on the page if they don’t have to wait too long.</p>
<h2 id="heading-6-consider-maintenance-amp-updates"><strong>6. Consider Maintenance &amp; Updates</strong></h2>
<p>Make sure your host provides automatic software updates and security patches. You should also check if they offer managed WordPress hosting services to <a target="_blank" href="https://elementor.com/blog/wordpress-maintenance-services/">take care of maintenance and security tasks for you</a>.</p>
<p>Having a host that takes care of these tasks for you can be very useful, as it ensures your website is running smoothly and helps to protect it from potential threats.</p>
<h2 id="heading-7-review-pricing-amp-payment-options"><strong>7. Review Pricing &amp; Payment Options</strong></h2>
<p>You should be aware of the various cost factors associated with hosting a WordPress site, including renewal fees and add-on services such as domain registration or website optimization. It’s also helpful to have multiple payment options available so that you can choose the one that best suits your budget.</p>
<p>Watch out for <a target="_blank" href="https://www.demandsage.com/the-hidden-cost-of-website-hosting/">hidden fees</a>. Some hosts may advertise low prices or <a target="_blank" href="https://nikolaroza.com/hosting-trial-no-credit-card/">seemingly generous free trials</a>, but then charge extra for certain features or services.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>By keeping these tips in mind, you can find a WordPress host that meets all of your needs and provides the performance and reliability you need to ensure success for your website. </p>
<p>There are plenty of <a target="_blank" href="https://gfxmaker.com/tips-that-will-make-you-guru-in-hosting-website/">other tips</a> to become a WordPress hosting guru, so be sure to continue to do your research. With the right hosting provider, you can ensure your site runs smoothly with minimal downtime and maximum security.  </p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ WordPress and Elementor Tutorial – How to Easily Create a Blog or Website ]]>
                </title>
                <description>
                    <![CDATA[ WordPress is one of the most popular–and easiest–ways to create a website or blog. People can make all kinds of websites with WordPress. Some popular types include business websites, eCommerce sites, portfolios, and blogs. We just published a course ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/easily-create-a-wordpress-blog-or-website/</link>
                <guid isPermaLink="false">66b2022a25ef0bb2c5a5171b</guid>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                    <category>
                        <![CDATA[ youtube ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Beau Carnes ]]>
                </dc:creator>
                <pubDate>Thu, 17 Nov 2022 15:31:07 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/11/blog.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>WordPress is one of the most popular–and easiest–ways to create a website or blog.</p>
<p>People can make all kinds of websites with WordPress. Some popular types include business websites, eCommerce sites, portfolios, and blogs.</p>
<p>We just published a course on the freeCodeCamp.org YouTube channel that will teach you how to use WordPress to easily create responsive blogs and websites using a drag and drop interface.</p>
<p>I created this course. I've also created many other popular WordPress courses on the freeCodeCamp.org channel. This is the first one that focusses on creating a blog.</p>
<p>You don't need any prior experience to follow along and there is no coding involved.</p>
<p>There are many reasons to make a WordPress blog, but some of the most common reasons include: sharing ideas and thoughts with the world, building a personal brand, promoting a business, and making money through blogging.</p>
<p>The course demonstrates how to use Elementor and a template to make it super quick to make a blog.</p>
<p>Here are the sections in this course:</p>
<ul>
<li>Setting up Hosting and Domain</li>
<li>Installing WordPress</li>
<li>WordPress Dashboard and Initial Settings</li>
<li>Installing WordPress Theme</li>
<li>Overview of Website</li>
<li>Customizing Title</li>
<li>Using Elementor to Edit Page</li>
<li>Adding Images</li>
<li>Customizing Website Elements</li>
<li>Updating Site Menu and Categories</li>
<li>Customizing Blog / Archive</li>
<li>Customizing Single Blog Post</li>
<li>Adding New Blog Post</li>
<li>Customizing About and Contact Page</li>
<li>Setting Up Website Forms Using WPForms</li>
<li>Making URLs Look Better</li>
<li>Updating Site for Responsive Design</li>
<li>Updating Footer</li>
<li>Creating New Pages</li>
<li>Improving SEO (Search Engine Optimization)</li>
</ul>
<p>Watch the full course below or on <a target="_blank" href="https://youtu.be/9VPq1JxMfkA">the freeCodeCamp.org YouTube channel</a> (1.5-hour watch).</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/9VPq1JxMfkA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ From WordPress to Hugo – How I Migrated a 250+ Page Site and the Scripts I Used ]]>
                </title>
                <description>
                    <![CDATA[ I recently decided to switch Boot.dev's blog from WordPress to a static site generator. I decided on Hugo, partly because I’m a huge fan of the Go programming language, but also because it just seemed like the best option from a dev-experience perspe... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/wordpress-to-hugo-scripts/</link>
                <guid isPermaLink="false">66b9e9f3fbdfcf519c5e1a68</guid>
                
                    <category>
                        <![CDATA[ Hugo ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Static Site Generators ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Lane Wagner ]]>
                </dc:creator>
                <pubDate>Tue, 30 Aug 2022 23:25:47 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/08/1__D5sbQUd4XwTy9yt67BCCA-1.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>I recently decided to switch <a target="_blank" href="https://boot.dev">Boot.dev's</a> blog from WordPress to a static site generator.</p>
<p>I decided on <a target="_blank" href="https://gohugo.io/">Hugo</a>, partly because I’m a huge fan of the Go programming language, but also because it just seemed like the best option from a dev-experience perspective. </p>
<p>Here’s why I decided to move away from WordPress:</p>
<ul>
<li>I wanted to write and store all my posts in Markdown.</li>
<li>I wanted to version control all my posts in Git/Github.</li>
<li>I wanted to be able to use ctrl+shift+f to find and edit the content on my blog.</li>
<li>I wanted a less buggy way to do “global blocks”</li>
<li>I didn’t want to spend hours fine-tuning performance. My posts are just text and images, so page speed scores should be 100 by default!</li>
<li>I wanted to use straight CSS for styling, making it easier for my blog and app to have identical styling.</li>
<li>I wanted to host the site for free</li>
</ul>
<p>With all those goals in mind, Hugo was a perfect choice. I’ve been super happy since making the switch, but there were some hiccups along the way. </p>
<p>WordPress takes care of some of the nuances of SEO-tuning for you, and if you forget to redo them yourself, you’ll end up sacrificing rankings.</p>
<h2 id="heading-how-to-export-wordpress-posts-as-markdown">How to Export WordPress Posts as Markdown</h2>
<p>Manually copying and pasting all of your posts out of the WordPress GUI into Markdown files could take a <em>very</em> long time. Especially if you have hundreds of posts like I do. </p>
<p>In order to speed up the process, I used <a target="_blank" href="https://wordpress.org/plugins/wp-gatsby-markdown-exporter/">this Markdown plugin</a> to export all of my posts as markdown at once. It’s called “Gatsby Markdown Exporter”, but it works for Hugo just as well.</p>
<p>I’m not going to go over the basics of getting up and running with Hugo, as I’m going to assume you are already familiar with it. But if you’re not, you can read the <a target="_blank" href="https://gohugo.io/getting-started/quick-start/">quick start guide here</a>.</p>
<h2 id="heading-how-to-use-hugos-built-in-seo-templates">How to Use Hugo’s Built-in SEO Templates</h2>
<p>WordPress and its various SEO plugins take care of a lot of SEO-related hocus-pocus for you. So when you move to a static site generator you often have to do some of that stuff yourself.</p>
<p>As it turns out, Hugo has some turn-key solutions for most of this, so using the right <a target="_blank" href="https://gohugo.io/templates/internal/">internal templates</a> can get you all the open-graph, schema, and Twitter meta tags out of the box.</p>
<p>For me, that meant simply adding these 3 lines to my <code>layouts/partials/header.html</code> file within the <code>&lt;head&gt;</code> tag:</p>
<pre><code class="lang-html">{{ template "_internal/opengraph.html" . }}
{{ template "_internal/twitter_cards.html" . }}
{{ template "_internal/schema.html" . }}
</code></pre>
<p>Now we'll get into the scripts I wrote to help me with this process.</p>
<h2 id="heading-script-1-checking-for-broken-links">Script 1 — Checking for Broken Links</h2>
<p>You can solve a lot of your WordPress woes by installing plugins for various tasks. Well, assuming those plugins don’t break your entire WP installation.</p>
<p>With Hugo, I just write little text-manipulation or HTTP scripts to do my bidding.</p>
<p>This first script is just a simple iterator that crawls the site and reports any broken links. You can see the <a target="_blank" href="https://github.com/bootdotdev/blog/blob/main/scripts/linkcheck/main.go">full source code here</a>. It's small edit of the script the Go team uses to check for broken links on the Go programming language's website.</p>
<h2 id="heading-script-2-minifying-images">Script 2 — Minifying Images</h2>
<p>When working with WordPress, you would typically upload a blog post image, and some SEO plugin would optimize that image’s size for you. </p>
<p>In Hugo, no such optimizations are made for you. It simply serves the exact image you add to your “static” folder.</p>
<p>I wrote a little script to optimize my images. It does the following:</p>
<ul>
<li>Takes an input image of nearly any type (.png, .jpeg, .gif, etc).</li>
<li>Converts it to the <code>.webp</code> format (a performant format).</li>
<li>Shrinks the image to a max image size I've configured if it’s too large.</li>
</ul>
<p>This script is written in Node.js and <a target="_blank" href="https://github.com/bootdotdev/blog/blob/main/scripts/image-min.js">the source code can be found here</a>.</p>
<h2 id="heading-script-3-managing-global-shortcodes">Script 3 — Managing Global Shortcodes</h2>
<p>WordPress had a feature called “global blocks”. They're super useful for things like newsletter signup boxes that show up in the middle of your articles, but that you want to be able to update in a single place. </p>
<p>In Hugo, you can use <a target="_blank" href="https://gohugo.io/content-management/shortcodes/">shortcodes</a> to achieve a similar purpose.</p>
<p>Unfortunately, it’s the inserting and removing of the shortcodes <em>themselves</em> that actually becomes tedious at scale. </p>
<p>For example, let’s say I added my newsletter signup shortcode after the 5th paragraph in all my articles, but now I want it to come after the 7th paragraph. I have to go manually copy/paste the short code!</p>
<p>Well, not anymore. Again, this is the great thing about storing all your blog posts in a text format — we can script some simple solutions. I wrote two scripts, and their source code can be found here:</p>
<ul>
<li><a target="_blank" href="https://github.com/bootdotdev/blog/blob/main/scripts/rmshorts/main.go">rmshorts</a></li>
<li><a target="_blank" href="https://github.com/bootdotdev/blog/blob/main/scripts/addshorts/main.go">addshorts</a></li>
</ul>
<p>These two scripts allow me move my global blocks with ease. For example, to remove all instances of <code>myshortcode</code> from the blog:</p>
<pre><code class="lang-bash">rmshorts myshortcode
</code></pre>
<p>Then to add <code>myshortcode</code> as its own paragraph after the 2nd section of every blog post across the site:</p>
<pre><code class="lang-bash">addshorts myshortcode 2
</code></pre>
<p>This has been a huge time saver.</p>
<h2 id="heading-script-4-converting-docx-to-markdown">Script 4 — Converting .docx to Markdown</h2>
<p>Last but not least, I work with some non-technical writers. My writers aren’t used to writing Markdown. Google docs is their tool of choice. </p>
<p>I have no problem with that, as I want them to be effective. My solution was to write a <a target="_blank" href="https://github.com/bootdotdev/blog/blob/main/scripts/docxmd.sh">little bash script</a> that uses <a target="_blank" href="https://pandoc.org/">pandoc</a> under the hood to convert the Google Docs to Markdown files.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>I hope some of these scripts are valuable to you, and I really can’t recommend enough making the switch to a static site generator. If you’re willing to put in a few hours to get a great working environment up and running for your blog it will save you a lot of time and money in the long run.</p>
<p>Remember, always automate the boring stuff!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
