{
	"version": "https://jsonfeed.org/version/1.1",
	"title": "Alex Zappa",
	"language": "en",
	"home_page_url": "https://alex.zappa.dev/",
	"feed_url": "https://alex.zappa.dev/feed.json",
	"description": "I am writing about my experiences as a naval navel-gazer.",
	"author": {
		"name": "Alex Zappa",
		"url": "https://alex.zappa.dev/about/"
	},
	"items": [
		{
			"id": "https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/",
			"url": "https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/",
			"title": "HubSpot&#39;s Cookie Banner Loads Google Fonts - And Nobody Seems to Care",
			"content_html": "<p>You know what's ironic? A cookie consent banner that violates privacy <em>before</em> you even click &quot;Accept.&quot;</p>\n<p>That's exactly what HubSpot's cookie banner does. It loads Google Fonts, sending your visitor's IP address to Google's servers, the moment the page loads. No consent asked. No opt-in. Just a quiet little request to <code>fonts.googleapis.com</code> that most people never notice.</p>\n<p>I noticed. And it took me down a rabbit hole.</p>\n<h2 id=\"the-problem\" tabindex=\"-1\">The Problem <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#the-problem\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>If you're using HubSpot's embedded tracking script on a non-HubSpot website (which many businesses do for CRM, forms, and analytics), you're also getting their cookie consent banner. Sounds great, right? GDPR compliance out of the box!</p>\n<p>Except the banner itself loads Google Fonts. Before the visitor has given any consent. Before any cookies are set. The very tool meant to protect privacy is leaking personal data to a third party.</p>\n<p>Here's what happens when HubSpot's script loads:</p>\n<ol>\n<li>The <code>hs-script-loader</code> JavaScript file is fetched</li>\n<li>HubSpot injects a cookie consent banner into the DOM</li>\n<li>As part of rendering the banner, it creates <code>&lt;link&gt;</code> elements pointing to <code>fonts.googleapis.com</code></li>\n<li>Google receives the visitor's IP address, browser info, and referrer</li>\n<li>The visitor hasn't consented to anything yet</li>\n</ol>\n<p>This is not a theoretical problem. In January 2022, the <a href=\"https://thehackernews.com/2022/01/german-court-rules-websites-embedding.html\">Munich Regional Court (LG München)</a> ruled that dynamically loading Google Fonts violates GDPR because it transmits the user's IP address to Google without consent. The website operator was fined €100 in damages, and that ruling triggered a <a href=\"https://inplp.com/latest-news/article/the-year-of-google-fonts-warning-letters/\">wave of warning letters across Germany and Austria</a>.</p>\n<p>On top of that, HubSpot injects its own <code>&lt;style&gt;</code> tags (<code>hs-banner-style</code> and <code>hs-banner-modal-style</code>) with default CSS that often conflicts with your site's design. So you get both a privacy violation <em>and</em> visual junk.</p>\n<h2 id=\"the-community-has-been-asking-for-years\" tabindex=\"-1\">The Community Has Been Asking for Years <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#the-community-has-been-asking-for-years\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>I'm not the first person to notice this. The HubSpot community has multiple threads about it, and none of them have a real solution from HubSpot:</p>\n<ul>\n<li><a href=\"https://community.hubspot.com/t5/GDPR/How-to-disable-Google-Fonts/m-p/712488\">How to disable Google Fonts</a> - users asking how to stop Google Fonts from loading, no official fix</li>\n<li><a href=\"https://community.hubspot.com/t5/GDPR/Hubspot-cookie-banner-Google-consent-mode/m-p/664336\">HubSpot cookie banner + Google consent mode</a> - discussion about consent mode integration issues</li>\n<li><a href=\"https://community.hubspot.com/t5/CMS-Development/Disable-Google-Fonts-by-embedded-Video-from-YouTube/m-p/709923\">Disable Google Fonts by embedded Video from YouTube</a> - same problem, different context</li>\n<li><a href=\"https://developers.hubspot.com/docs/api-reference/cookie-banner/cookie-banner-api\">HubSpot Cookie Banner API docs</a> - the API exists, but provides no option to disable font loading</li>\n</ul>\n<p>The answer from HubSpot? Silence. Or &quot;use custom CSS to override the styles.&quot; That doesn't fix the privacy issue -the request to Google still goes out.</p>\n<h2 id=\"the-we-have-a-banner-we-re-fine-problem\" tabindex=\"-1\">The &quot;We Have a Banner, We're Fine&quot; Problem <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#the-we-have-a-banner-we-re-fine-problem\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Here's the thing that really gets me. This Google Fonts issue is just one symptom of a much bigger disease: <strong>cookie banners that do absolutely nothing</strong>.</p>\n<p>I've seen this firsthand. I once told a business owner that their cookie banner was purely cosmetic - it didn't actually block any cookies, didn't gate any third-party scripts, and didn't comply with GDPR in any meaningful way. His response?</p>\n<blockquote>\n<p>&quot;We have a banner. We're compliant.&quot;<br>\n— a Biz owner who doesn't understand how GDPR works</p>\n</blockquote>\n<p>No. Having a banner doesn't make you compliant. That's like putting a &quot;No Trespassing&quot; sign on your front door while leaving it wide open.</p>\n<p>I wrote about this in detail on FreshJuice: <a href=\"https://freshjuice.dev/blog/your-cookie-banner-is-probably-illegal/\">Your cookie banner is probably illegal</a>. The short version: most cookie banners are legal decoration. They sit on websites looking official while cookies fire on page load, third-party scripts track visitors without consent, and Google Fonts leak IP addresses to Mountain View.</p>\n<p>And here's the kicker with HubSpot specifically. They actually have a decent <a href=\"https://developers.hubspot.com/docs/api-reference/cookie-banner/cookie-banner-api\">Cookie Banner API</a>. It gives you:</p>\n<ul>\n<li><code>addPrivacyConsentListener</code> - to conditionally load scripts based on consent</li>\n<li><code>revokeCookieConsent</code> - to reset consent and remove HubSpot cookies</li>\n<li><code>showBanner</code> - to let users change their preferences</li>\n<li>Granular categories: <code>analytics</code>, <code>advertisement</code>, <code>functionality</code></li>\n</ul>\n<p>So the API exists. You <em>can</em> properly gate your third-party scripts behind consent categories:</p>\n<pre class=\"language-javascript\" tabindex=\"0\"><code class=\"language-javascript\"><span class=\"token keyword\">var</span> _hsp <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>window<span class=\"token punctuation\">.</span>_hsp <span class=\"token operator\">=</span> window<span class=\"token punctuation\">.</span>_hsp <span class=\"token operator\">||</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n_hsp<span class=\"token punctuation\">.</span><span class=\"token function\">push</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n  <span class=\"token string\">\"addPrivacyConsentListener\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">consent</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>consent<span class=\"token punctuation\">.</span>categories<span class=\"token punctuation\">.</span>analytics<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// Only now load analytics</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>consent<span class=\"token punctuation\">.</span>categories<span class=\"token punctuation\">.</span>advertisement<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// Only now load ad pixels</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>But none of this matters if the banner itself, the very thing asking for consent, is already leaking data to Google via fonts. The API has no option to disable Google Fonts loading. You can't configure it away. There's no <code>disableGoogleFonts: true</code> flag. The font request goes out before your consent listener even fires.</p>\n<p>It's like building a security system for your house but leaving the back window open.</p>\n<h2 id=\"why-this-matters\" tabindex=\"-1\">Why This Matters <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#why-this-matters\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Let's be clear about what's happening: when a browser fetches a Google Font, Google receives:</p>\n<ul>\n<li>The visitor's <strong>IP address</strong> (personal data under GDPR)</li>\n<li>The <strong>User-Agent</strong> string (browser, OS, device info)</li>\n<li>The <strong>Referer</strong> header (which page they're visiting)</li>\n<li><strong>Timing data</strong> (when they visited)</li>\n</ul>\n<p>After the Munich ruling, this is unambiguously a GDPR violation when done without consent. And a cookie consent banner doing it is... well, peak irony.</p>\n<p>But it's not just about legality. It's also about <strong>performance</strong>. Loading fonts from an external CDN means:</p>\n<ul>\n<li>Extra DNS lookup for <code>fonts.googleapis.com</code></li>\n<li>Extra DNS lookup for <code>fonts.gstatic.com</code></li>\n<li>Render-blocking CSS request</li>\n<li>Font files downloaded from yet another origin</li>\n</ul>\n<p>All for fonts that your website probably already has loaded, or that the user's system already provides.</p>\n<h2 id=\"the-fix-intercept-and-block\" tabindex=\"-1\">The Fix: Intercept and Block <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#the-fix-intercept-and-block\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Since HubSpot won't fix this, I did. The solution is a JavaScript snippet that goes <strong>before</strong> the HubSpot script loader. It uses two techniques:</p>\n<h3 id=\"1-proxy-document-createelement-to-block-google-fonts-at-creation-time\" tabindex=\"-1\">1. Proxy <code>document.createElement</code> to block Google Fonts at creation time <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#1-proxy-document-createelement-to-block-google-fonts-at-creation-time\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<pre class=\"language-javascript\" tabindex=\"0\"><code class=\"language-javascript\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Proxy createElement to kill Google Fonts links before any network request</span>\n  <span class=\"token keyword\">var</span> _create <span class=\"token operator\">=</span> document<span class=\"token punctuation\">.</span><span class=\"token function\">createElement</span><span class=\"token punctuation\">.</span><span class=\"token function\">bind</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  document<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">createElement</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">tag</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">var</span> el <span class=\"token operator\">=</span> <span class=\"token function\">_create</span><span class=\"token punctuation\">(</span>tag<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>tag<span class=\"token punctuation\">.</span><span class=\"token function\">toLowerCase</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">===</span> <span class=\"token string\">\"link\"</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// Override the href property setter</span>\n      <span class=\"token keyword\">var</span> hrefDesc <span class=\"token operator\">=</span> Object<span class=\"token punctuation\">.</span><span class=\"token function\">getOwnPropertyDescriptor</span><span class=\"token punctuation\">(</span>\n        <span class=\"token class-name\">HTMLLinkElement</span><span class=\"token punctuation\">.</span>prototype<span class=\"token punctuation\">,</span>\n        <span class=\"token string\">\"href\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>hrefDesc <span class=\"token operator\">&amp;&amp;</span> hrefDesc<span class=\"token punctuation\">.</span>set<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">var</span> origSet <span class=\"token operator\">=</span> hrefDesc<span class=\"token punctuation\">.</span>set<span class=\"token punctuation\">;</span>\n        Object<span class=\"token punctuation\">.</span><span class=\"token function\">defineProperty</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">,</span> <span class=\"token string\">\"href\"</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n          <span class=\"token function-variable function\">set</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">v</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>\n              <span class=\"token keyword\">typeof</span> v <span class=\"token operator\">===</span> <span class=\"token string\">\"string\"</span> <span class=\"token operator\">&amp;&amp;</span>\n              v<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"fonts.googleapis.com\"</span><span class=\"token punctuation\">)</span>\n            <span class=\"token punctuation\">)</span>\n              <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n            <span class=\"token function\">origSet</span><span class=\"token punctuation\">.</span><span class=\"token function\">call</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">,</span> v<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n          <span class=\"token literal-property property\">get</span><span class=\"token operator\">:</span> hrefDesc<span class=\"token punctuation\">.</span>get\n            <span class=\"token operator\">?</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n                <span class=\"token keyword\">return</span> hrefDesc<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">.</span><span class=\"token function\">call</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n              <span class=\"token punctuation\">}</span>\n            <span class=\"token operator\">:</span> <span class=\"token keyword\">undefined</span><span class=\"token punctuation\">,</span>\n          <span class=\"token literal-property property\">configurable</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span>\n      <span class=\"token comment\">// Also override setAttribute for href</span>\n      <span class=\"token keyword\">var</span> origSetAttr <span class=\"token operator\">=</span> el<span class=\"token punctuation\">.</span><span class=\"token function\">setAttribute</span><span class=\"token punctuation\">.</span><span class=\"token function\">bind</span><span class=\"token punctuation\">(</span>el<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      el<span class=\"token punctuation\">.</span><span class=\"token function-variable function\">setAttribute</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">k<span class=\"token punctuation\">,</span> v</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>\n          k <span class=\"token operator\">===</span> <span class=\"token string\">\"href\"</span> <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token keyword\">typeof</span> v <span class=\"token operator\">===</span> <span class=\"token string\">\"string\"</span> <span class=\"token operator\">&amp;&amp;</span>\n          v<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"fonts.googleapis.com\"</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">)</span>\n          <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">return</span> <span class=\"token function\">origSetAttr</span><span class=\"token punctuation\">(</span>k<span class=\"token punctuation\">,</span> v<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">return</span> el<span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token comment\">// MutationObserver as a safety net -remove anything that slips through</span>\n  <span class=\"token keyword\">new</span> <span class=\"token class-name\">MutationObserver</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">mutations</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">var</span> i <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span> i <span class=\"token operator\">&lt;</span> mutations<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">for</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">var</span> j <span class=\"token operator\">=</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span> j <span class=\"token operator\">&lt;</span> mutations<span class=\"token punctuation\">[</span>i<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>addedNodes<span class=\"token punctuation\">.</span>length<span class=\"token punctuation\">;</span> j<span class=\"token operator\">++</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">var</span> n <span class=\"token operator\">=</span> mutations<span class=\"token punctuation\">[</span>i<span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>addedNodes<span class=\"token punctuation\">[</span>j<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>n<span class=\"token punctuation\">.</span>nodeType <span class=\"token operator\">!==</span> <span class=\"token number\">1</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">continue</span><span class=\"token punctuation\">;</span>\n        <span class=\"token keyword\">var</span> tag <span class=\"token operator\">=</span> n<span class=\"token punctuation\">.</span>tagName<span class=\"token punctuation\">;</span>\n        <span class=\"token comment\">// Remove Google Fonts links</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>\n          tag <span class=\"token operator\">===</span> <span class=\"token string\">\"LINK\"</span> <span class=\"token operator\">&amp;&amp;</span>\n          n<span class=\"token punctuation\">.</span>href <span class=\"token operator\">&amp;&amp;</span>\n          n<span class=\"token punctuation\">.</span>href<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"fonts.googleapis.com\"</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          n<span class=\"token punctuation\">.</span><span class=\"token function\">remove</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n          <span class=\"token keyword\">continue</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token comment\">// Remove HubSpot's default banner styles (optional -if you want to use your own)</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>\n          tag <span class=\"token operator\">===</span> <span class=\"token string\">\"STYLE\"</span> <span class=\"token operator\">&amp;&amp;</span>\n          <span class=\"token punctuation\">(</span>n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> <span class=\"token string\">\"hs-banner-style\"</span> <span class=\"token operator\">||</span>\n            n<span class=\"token punctuation\">.</span>id <span class=\"token operator\">===</span> <span class=\"token string\">\"hs-banner-modal-style\"</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          n<span class=\"token punctuation\">.</span><span class=\"token function\">remove</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">observe</span><span class=\"token punctuation\">(</span>document<span class=\"token punctuation\">.</span>documentElement<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">childList</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">subtree</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<h3 id=\"2-place-it-before-hubspots-script\" tabindex=\"-1\">2. Place it before HubSpot's script <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#2-place-it-before-hubspots-script\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token comment\">&lt;!-- Block Google Fonts and HubSpot default styles --></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span><span class=\"token punctuation\">></span></span><span class=\"token script\"><span class=\"token language-javascript\">\n  <span class=\"token comment\">// ... the script above ...</span>\n</span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span>\n\n<span class=\"token comment\">&lt;!-- HubSpot Embed Code --></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span>\n  <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>text/javascript<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">id</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>hs-script-loader<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">async</span>\n  <span class=\"token attr-name\">defer</span>\n  <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>//js-eu1.hs-scripts.com/YOUR_ID.js<span class=\"token punctuation\">\"</span></span>\n<span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>The order matters. The proxy must be in place before HubSpot's script starts executing and creating DOM elements.</p>\n<h3 id=\"how-it-works\" tabindex=\"-1\">How It Works <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#how-it-works\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p><strong>The <code>createElement</code> proxy</strong> intercepts every <code>&lt;link&gt;</code> element HubSpot tries to create. Before the element can be inserted into the DOM (and trigger a network request), it checks if the <code>href</code> points to <code>fonts.googleapis.com</code>. If it does, the setter silently returns without setting the value. No URL = no network request = no IP leak.</p>\n<p><strong>The <code>MutationObserver</code></strong> is a safety net. It watches the entire document for new nodes. If a Google Fonts link somehow slips through the proxy (maybe via <code>innerHTML</code> or a different code path), the observer catches it and removes it immediately.</p>\n<p><strong>The style removal</strong> (<code>hs-banner-style</code> and <code>hs-banner-modal-style</code>) is optional but recommended. HubSpot injects default CSS that often clashes with your site's design. Removing these lets you style the consent banner with your own CSS that matches your site. You can skip this part if you're fine with HubSpot's default appearance.</p>\n<h2 id=\"the-better-alternatives\" tabindex=\"-1\">The Better Alternatives <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#the-better-alternatives\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Beyond fixing HubSpot's mess, here's what you should be doing with fonts in general:</p>\n<h3 id=\"self-host-your-fonts\" tabindex=\"-1\">Self-Host Your Fonts <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#self-host-your-fonts\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Download the font files and serve them from your own domain. No third-party requests, no IP leaks, better caching control.</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token atrule\"><span class=\"token rule\">@font-face</span></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token property\">font-family</span><span class=\"token punctuation\">:</span> <span class=\"token string\">\"Inter\"</span><span class=\"token punctuation\">;</span>\n  <span class=\"token property\">src</span><span class=\"token punctuation\">:</span> <span class=\"token url\"><span class=\"token function\">url</span><span class=\"token punctuation\">(</span><span class=\"token string url\">\"/fonts/inter-var.woff2\"</span><span class=\"token punctuation\">)</span></span> <span class=\"token function\">format</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"woff2\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token property\">font-display</span><span class=\"token punctuation\">:</span> swap<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h3 id=\"use-bunny-fonts\" tabindex=\"-1\">Use Bunny Fonts <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#use-bunny-fonts\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>If self-hosting feels like too much work, <a href=\"https://fonts.bunny.net\">Bunny Fonts</a> is a drop-in replacement for Google Fonts. Same API, same fonts, but:</p>\n<ul>\n<li><strong>Zero tracking</strong> -no IP logging, no cookies</li>\n<li><strong>EU-based</strong> company and infrastructure</li>\n<li><strong>GDPR compliant</strong> by design</li>\n<li><strong>No account needed</strong>, always free</li>\n</ul>\n<p>The migration is literally a find-and-replace:</p>\n<pre class=\"language-diff\" tabindex=\"0\"><code class=\"language-diff\"><span class=\"token deleted-sign deleted\"><span class=\"token prefix deleted\">-</span> https://fonts.googleapis.com/css2?family=Inter\n</span><span class=\"token inserted-sign inserted\"><span class=\"token prefix inserted\">+</span> https://fonts.bunny.net/css2?family=Inter\n</span></code></pre>\n<p>That's it. Same URL structure, same font files, zero privacy issues.</p>\n<h3 id=\"use-system-fonts\" tabindex=\"-1\">Use System Fonts <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#use-system-fonts\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>The most performant option? Don't load any web fonts at all:</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">body</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token property\">font-family</span><span class=\"token punctuation\">:</span>\n    system-ui<span class=\"token punctuation\">,</span>\n    -apple-system<span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"Segoe UI\"</span><span class=\"token punctuation\">,</span>\n    Roboto<span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"Helvetica Neue\"</span><span class=\"token punctuation\">,</span>\n    Arial<span class=\"token punctuation\">,</span>\n    sans-serif<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>System fonts are already on the user's device. Zero network requests. Instant rendering. And they look native to the platform, which many users actually prefer.</p>\n<h2 id=\"the-bigger-picture\" tabindex=\"-1\">The Bigger Picture <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#the-bigger-picture\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>This isn't just about HubSpot. It's about a mindset problem in the web industry:</p>\n<p><strong>Third-party tools shouldn't load their own fonts.</strong> If a tool injects UI into your website (cookie banners, chat widgets, analytics dashboards), it should use the fonts already available on the page or fall back to system fonts. Loading Google Fonts for a cookie banner that displays two sentences of text is absurd.</p>\n<p><strong>Privacy-first means privacy <em>always</em>.</strong> A consent mechanism that violates privacy before consent is given defeats its own purpose. If HubSpot can build a complex consent management system, they can certainly avoid loading Google Fonts from a third-party CDN.</p>\n<p><strong>Performance matters.</strong> Every external resource is a potential point of failure, an extra DNS lookup, and wasted bandwidth. Cookie banners should be lightweight. They should appear instantly. Loading external fonts for cosmetic reasons is the opposite of lightweight.</p>\n<h2 id=\"tl-dr\" tabindex=\"-1\">TL;DR <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/hubspot-cookie-banner-google-fonts-gdpr/#tl-dr\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<ul>\n<li>HubSpot's cookie consent banner loads Google Fonts before consent, leaking visitor IPs to Google</li>\n<li>This violates GDPR (see: Munich court ruling, €100 fine)</li>\n<li>The HubSpot community has asked about this for years with no official fix</li>\n<li>You can fix it by proxying <code>document.createElement</code> and using a <code>MutationObserver</code> to block Google Fonts requests</li>\n<li>Better yet: self-host your fonts, use <a href=\"https://fonts.bunny.net\">Bunny Fonts</a>, or just use system fonts</li>\n<li>Privacy tools should not violate privacy. Full stop.</li>\n</ul>\n",
			"date_published": "2026-03-10T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/",
			"url": "https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/",
			"title": "Migrating from Cloudflare Pages to Workers (and cleaning up the mess)",
			"content_html": "<p>Cloudflare is <a href=\"https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/\">deprecating Pages</a> in favor of Workers with Static Assets. It's not a sudden death, but the writing is on the wall. Time to migrate.</p>\n<p>I had a setup with two separate projects: an 11ty static site on Pages and an API on Workers. Decided to merge them into one Worker project that handles both static assets and API routes. Clean and simple.</p>\n<p>The migration itself was surprisingly smooth. Cloudflare's docs are solid, and there are some good community guides out there:</p>\n<ul>\n<li><a href=\"https://developers.cloudflare.com/workers/static-assets/migration-guides/migrate-from-pages/\">Official Cloudflare migration guide</a></li>\n<li><a href=\"https://vibecodingwithfred.com/blog/pages-to-workers-migration/\">Vibe Coding with Fred: Pages to Workers Migration</a></li>\n<li><a href=\"https://benwhite.com.au/blog/pages-to-workers/\">Ben White: Pages to Workers</a></li>\n</ul>\n<h2 id=\"the-new-setup\" tabindex=\"-1\">The new setup <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#the-new-setup\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Here's what a combined Worker + Static Assets config looks like:</p>\n<pre class=\"language-json\" tabindex=\"0\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"$schema\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"./node_modules/wrangler/config-schema.json\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"my-website\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"main\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"worker/index.js\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"compatibility_date\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"2025-11-17\"</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// Disable workers.dev subdomain (using custom domain only)</span>\n  <span class=\"token property\">\"workers_dev\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"preview_urls\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// Static assets configuration</span>\n  <span class=\"token comment\">// Static assets are served first EXCEPT for /api/* patterns</span>\n  <span class=\"token property\">\"assets\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"directory\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"./_site\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"binding\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"ASSETS\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"not_found_handling\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"404-page\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"run_worker_first\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"/api/*\"</span><span class=\"token punctuation\">]</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// Custom domain routing</span>\n  <span class=\"token property\">\"routes\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"pattern\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"example.com\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"custom_domain\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// Environment variables are stored in:</span>\n  <span class=\"token comment\">// - .dev.vars (local development, gitignored)</span>\n  <span class=\"token comment\">// - Cloudflare dashboard secrets (production)</span>\n\n  <span class=\"token property\">\"observability\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"enabled\"</span><span class=\"token operator\">:</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"head_sampling_rate\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// KV Namespaces</span>\n  <span class=\"token property\">\"kv_namespaces\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"binding\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"CACHE_KV\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"your-kv-namespace-id\"</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n\n  <span class=\"token comment\">// D1 Database</span>\n  <span class=\"token property\">\"d1_databases\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token property\">\"binding\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"DB\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"database_name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"my_database\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token property\">\"database_id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"your-d1-database-id\"</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>The key is <code>run_worker_first</code> — it routes API requests through the Worker while serving static files directly. Best of both worlds.</p>\n<h2 id=\"the-unexpected-problem\" tabindex=\"-1\">The unexpected problem <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#the-unexpected-problem\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Everything worked great. But when I tried to delete the old Pages project... nope. 😤</p>\n<blockquote>\n<p>&quot;We are very sorry that you did not succeed.&quot; <br>\n— Cloudflare, when you try to delete a Pages project with 500+ deployments</p>\n</blockquote>\n<img src=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/assets/kings-quest-game-over.jpeg\" alt=\"King's Quest Game Over screen - We are very sorry that you did not succeed\" eleventy:widths=\"800\">\n<p>This weekend I was playing the original King's Quest on my Steam Deck (bought the whole Sierra collection of 7 games on sale), and this game over message felt way too familiar. The game brings back warm memories of childhood when our whole family would sit together and play this wonderful adventure. If I remember correctly, it was even translated into Russian back in the day.</p>\n<p>The dashboard just wouldn't let me. Too many deployments.</p>\n<p>Turns out, Cloudflare has a &quot;protection mechanism&quot; to prevent accidental deletion of projects with a high number of deployments. Which is... fine, I guess? But also annoying when you actually want to delete something.</p>\n<h2 id=\"the-official-solution\" tabindex=\"-1\">The official solution <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#the-official-solution\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Cloudflare documents this issue in their <a href=\"https://developers.cloudflare.com/pages/platform/known-issues/#delete-a-project-with-a-high-number-of-deployments\">known issues page</a>. Their solution? Download a <a href=\"https://pub-505c82ba1c844ba788b97b1ed9415e75.r2.dev/delete-all-deployments.zip\">Node.js script</a>, run <code>npm install</code>, set environment variables, and execute it.</p>\n<p>It works, but requires Node.js dependencies (<code>node-fetch</code>, <code>exponential-backoff</code>) and uses environment variables which end up in your shell history. I wanted something simpler.</p>\n<p>I also found <a href=\"https://stackoverflow.com/questions/79606336/mass-delete-cloudflare-pages-deployments\">this StackOverflow question</a> where others had the same problem.</p>\n<h2 id=\"my-solution-a-simple-bash-script\" tabindex=\"-1\">My solution: a simple bash script <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#my-solution-a-simple-bash-script\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>I wrote a quick bash helper that does the same thing. No npm, no extra dependencies. Just <code>curl</code>, <code>jq</code>, and a few minutes of your time.</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token shebang important\">#!/bin/bash</span>\n<span class=\"token comment\"># Delete Cloudflare Pages/Workers deployments via API</span>\n<span class=\"token comment\"># Usage: ./delete-cf-deployments.sh --project=xxx --account=xxx --token=xxx [--limit=N] [--keep=N]</span>\n\n<span class=\"token assign-left variable\">PROJECT</span><span class=\"token operator\">=</span><span class=\"token string\">\"\"</span>\n<span class=\"token assign-left variable\">ACCOUNT_ID</span><span class=\"token operator\">=</span><span class=\"token string\">\"\"</span>\n<span class=\"token assign-left variable\">TOKEN</span><span class=\"token operator\">=</span><span class=\"token string\">\"\"</span>\n<span class=\"token assign-left variable\">LIMIT</span><span class=\"token operator\">=</span><span class=\"token string\">\"\"</span>\n<span class=\"token assign-left variable\">KEEP</span><span class=\"token operator\">=</span><span class=\"token string\">\"\"</span>\n\n<span class=\"token keyword\">for</span> <span class=\"token for-or-select variable\">arg</span> <span class=\"token keyword\">in</span> <span class=\"token string\">\"<span class=\"token variable\">$@</span>\"</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">do</span>\n  <span class=\"token keyword\">case</span> <span class=\"token variable\">$arg</span> <span class=\"token keyword\">in</span>\n    <span class=\"token parameter variable\">--project</span><span class=\"token operator\">=</span>*<span class=\"token punctuation\">)</span> <span class=\"token assign-left variable\">PROJECT</span><span class=\"token operator\">=</span><span class=\"token string\">\"<span class=\"token variable\">${arg<span class=\"token operator\">#</span>*=}</span>\"</span> <span class=\"token punctuation\">;</span><span class=\"token punctuation\">;</span>\n    <span class=\"token parameter variable\">--account</span><span class=\"token operator\">=</span>*<span class=\"token punctuation\">)</span> <span class=\"token assign-left variable\">ACCOUNT_ID</span><span class=\"token operator\">=</span><span class=\"token string\">\"<span class=\"token variable\">${arg<span class=\"token operator\">#</span>*=}</span>\"</span> <span class=\"token punctuation\">;</span><span class=\"token punctuation\">;</span>\n    <span class=\"token parameter variable\">--token</span><span class=\"token operator\">=</span>*<span class=\"token punctuation\">)</span> <span class=\"token assign-left variable\">TOKEN</span><span class=\"token operator\">=</span><span class=\"token string\">\"<span class=\"token variable\">${arg<span class=\"token operator\">#</span>*=}</span>\"</span> <span class=\"token punctuation\">;</span><span class=\"token punctuation\">;</span>\n    <span class=\"token parameter variable\">--limit</span><span class=\"token operator\">=</span>*<span class=\"token punctuation\">)</span> <span class=\"token assign-left variable\">LIMIT</span><span class=\"token operator\">=</span><span class=\"token string\">\"<span class=\"token variable\">${arg<span class=\"token operator\">#</span>*=}</span>\"</span> <span class=\"token punctuation\">;</span><span class=\"token punctuation\">;</span>\n    <span class=\"token parameter variable\">--keep</span><span class=\"token operator\">=</span>*<span class=\"token punctuation\">)</span> <span class=\"token assign-left variable\">KEEP</span><span class=\"token operator\">=</span><span class=\"token string\">\"<span class=\"token variable\">${arg<span class=\"token operator\">#</span>*=}</span>\"</span> <span class=\"token punctuation\">;</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">esac</span>\n<span class=\"token keyword\">done</span>\n\n<span class=\"token keyword\">if</span> <span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-z</span> <span class=\"token string\">\"<span class=\"token variable\">$PROJECT</span>\"</span> <span class=\"token punctuation\">]</span> <span class=\"token operator\">||</span> <span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-z</span> <span class=\"token string\">\"<span class=\"token variable\">$ACCOUNT_ID</span>\"</span> <span class=\"token punctuation\">]</span> <span class=\"token operator\">||</span> <span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-z</span> <span class=\"token string\">\"<span class=\"token variable\">$TOKEN</span>\"</span> <span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">then</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Usage: <span class=\"token variable\">$0</span> --project=&lt;name> --account=&lt;id> --token=&lt;api-token> [options]\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Required:\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  --project=NAME   Cloudflare Pages project name\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  --account=ID     Your Cloudflare account ID\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  --token=TOKEN    Cloudflare API token\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Options:\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  --limit=N        Delete only N deployments (for testing)\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  --keep=N         Keep the last N deployments (cleanup mode)\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Examples:\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  <span class=\"token variable\">$0</span> --project=my-site --account=abc123 --token=xyz789 --limit=3\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  <span class=\"token variable\">$0</span> --project=my-site --account=abc123 --token=xyz789 --keep=10\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  <span class=\"token variable\">$0</span> --project=my-site --account=abc123 --token=xyz789\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Get API token: Cloudflare Dashboard → My Profile → API Tokens\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"               → Create Token → Edit Cloudflare Pages\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Get Account ID: Cloudflare Dashboard → any site → Overview\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"                → right sidebar under 'API'\"</span>\n  <span class=\"token builtin class-name\">exit</span> <span class=\"token number\">1</span>\n<span class=\"token keyword\">fi</span>\n\n<span class=\"token assign-left variable\">API</span><span class=\"token operator\">=</span><span class=\"token string\">\"https://api.cloudflare.com/client/v4/accounts/<span class=\"token variable\">$ACCOUNT_ID</span>/pages/projects/<span class=\"token variable\">$PROJECT</span>\"</span>\n\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Deleting deployments for: <span class=\"token variable\">$PROJECT</span>\"</span>\n<span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-n</span> <span class=\"token string\">\"<span class=\"token variable\">$LIMIT</span>\"</span> <span class=\"token punctuation\">]</span> <span class=\"token operator\">&amp;&amp;</span> <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Limit: <span class=\"token variable\">$LIMIT</span>\"</span>\n<span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-n</span> <span class=\"token string\">\"<span class=\"token variable\">$KEEP</span>\"</span> <span class=\"token punctuation\">]</span> <span class=\"token operator\">&amp;&amp;</span> <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Keeping last: <span class=\"token variable\">$KEEP</span> deployments\"</span>\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n\n<span class=\"token assign-left variable\">COUNT</span><span class=\"token operator\">=</span><span class=\"token number\">0</span>\n<span class=\"token assign-left variable\">PAGE</span><span class=\"token operator\">=</span><span class=\"token number\">1</span>\n\n<span class=\"token comment\"># For --keep mode, we need to skip the first N deployments</span>\n<span class=\"token comment\"># API returns deployments sorted by date (newest first)</span>\n<span class=\"token comment\"># So we paginate past the ones we want to keep</span>\n\n<span class=\"token keyword\">if</span> <span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-n</span> <span class=\"token string\">\"<span class=\"token variable\">$KEEP</span>\"</span> <span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">then</span>\n  <span class=\"token comment\"># Calculate which page to start from</span>\n  <span class=\"token assign-left variable\">PER_PAGE</span><span class=\"token operator\">=</span><span class=\"token number\">25</span>\n  <span class=\"token assign-left variable\">SKIP_PAGES</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$((</span>KEEP <span class=\"token operator\">/</span> PER_PAGE<span class=\"token variable\">))</span></span>\n  <span class=\"token assign-left variable\">SKIP_IN_PAGE</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$((</span>KEEP <span class=\"token operator\">%</span> PER_PAGE<span class=\"token variable\">))</span></span>\n  <span class=\"token assign-left variable\">PAGE</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$((</span>SKIP_PAGES <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token variable\">))</span></span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Skipping first <span class=\"token variable\">$KEEP</span> deployments (starting from page <span class=\"token variable\">$PAGE</span>)...\"</span>\n  <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n<span class=\"token keyword\">fi</span>\n\n<span class=\"token keyword\">while</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">do</span>\n  <span class=\"token comment\"># Fetch deployments with pagination</span>\n  <span class=\"token assign-left variable\">RESPONSE</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> <span class=\"token string\">\"<span class=\"token variable\">$API</span>/deployments?per_page=25&amp;page=<span class=\"token variable\">$PAGE</span>\"</span> <span class=\"token punctuation\">\\</span>\n    <span class=\"token parameter variable\">-H</span> <span class=\"token string\">\"Authorization: Bearer <span class=\"token variable\">$TOKEN</span>\"</span><span class=\"token variable\">)</span></span>\n\n  <span class=\"token assign-left variable\">IDS</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$(</span><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"<span class=\"token variable\">$RESPONSE</span>\"</span> <span class=\"token operator\">|</span> jq <span class=\"token parameter variable\">-r</span> <span class=\"token string\">'.result[].id // empty'</span> <span class=\"token operator\"><span class=\"token file-descriptor important\">2</span>></span>/dev/null<span class=\"token variable\">)</span></span>\n\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-z</span> <span class=\"token string\">\"<span class=\"token variable\">$IDS</span>\"</span> <span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">then</span>\n    <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"No more deployments.\"</span>\n    <span class=\"token builtin class-name\">break</span>\n  <span class=\"token keyword\">fi</span>\n\n  <span class=\"token comment\"># Convert to array</span>\n  <span class=\"token assign-left variable\">IDS_ARRAY</span><span class=\"token operator\">=</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$IDS</span><span class=\"token punctuation\">)</span>\n  <span class=\"token assign-left variable\">START_INDEX</span><span class=\"token operator\">=</span><span class=\"token number\">0</span>\n\n  <span class=\"token comment\"># On the first page in --keep mode, skip partial entries</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-n</span> <span class=\"token string\">\"<span class=\"token variable\">$KEEP</span>\"</span> <span class=\"token punctuation\">]</span> <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">[</span> <span class=\"token string\">\"<span class=\"token variable\">$PAGE</span>\"</span> <span class=\"token parameter variable\">-eq</span> <span class=\"token string\">\"<span class=\"token variable\"><span class=\"token variable\">$((</span>SKIP_PAGES <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token variable\">))</span></span>\"</span> <span class=\"token punctuation\">]</span> <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">[</span> <span class=\"token string\">\"<span class=\"token variable\">$SKIP_IN_PAGE</span>\"</span> <span class=\"token parameter variable\">-gt</span> <span class=\"token number\">0</span> <span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">then</span>\n    <span class=\"token assign-left variable\">START_INDEX</span><span class=\"token operator\">=</span><span class=\"token variable\">$SKIP_IN_PAGE</span>\n    <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Skipping first <span class=\"token variable\">$SKIP_IN_PAGE</span> on this page...\"</span>\n  <span class=\"token keyword\">fi</span>\n\n  <span class=\"token keyword\">for</span> <span class=\"token variable\"><span class=\"token punctuation\">((</span>i<span class=\"token operator\">=</span>START_INDEX<span class=\"token punctuation\">;</span> i<span class=\"token operator\">&lt;</span>${#IDS_ARRAY[@]}<span class=\"token punctuation\">;</span> i<span class=\"token operator\">++</span><span class=\"token punctuation\">))</span></span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">do</span>\n    <span class=\"token assign-left variable\">ID</span><span class=\"token operator\">=</span><span class=\"token string\">\"<span class=\"token variable\">${IDS_ARRAY<span class=\"token punctuation\">[</span>$i<span class=\"token punctuation\">]</span>}</span>\"</span>\n\n    <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Deleting <span class=\"token variable\">$ID</span>...\"</span>\n    <span class=\"token function\">curl</span> <span class=\"token parameter variable\">-s</span> <span class=\"token parameter variable\">-X</span> DELETE <span class=\"token string\">\"<span class=\"token variable\">$API</span>/deployments/<span class=\"token variable\">$ID</span>?force=true\"</span> <span class=\"token punctuation\">\\</span>\n      <span class=\"token parameter variable\">-H</span> <span class=\"token string\">\"Authorization: Bearer <span class=\"token variable\">$TOKEN</span>\"</span> <span class=\"token operator\">></span> /dev/null\n\n    <span class=\"token assign-left variable\">COUNT</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$((</span>COUNT <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token variable\">))</span></span>\n\n    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-n</span> <span class=\"token string\">\"<span class=\"token variable\">$LIMIT</span>\"</span> <span class=\"token punctuation\">]</span> <span class=\"token operator\">&amp;&amp;</span> <span class=\"token punctuation\">[</span> <span class=\"token string\">\"<span class=\"token variable\">$COUNT</span>\"</span> <span class=\"token parameter variable\">-ge</span> <span class=\"token string\">\"<span class=\"token variable\">$LIMIT</span>\"</span> <span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">then</span>\n      <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n      <span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Reached limit of <span class=\"token variable\">$LIMIT</span>. Deleted <span class=\"token variable\">$COUNT</span> deployments.\"</span>\n      <span class=\"token builtin class-name\">exit</span> <span class=\"token number\">0</span>\n    <span class=\"token keyword\">fi</span>\n\n    <span class=\"token function\">sleep</span> <span class=\"token number\">0.3</span>\n  <span class=\"token keyword\">done</span>\n\n  <span class=\"token comment\"># In normal mode (no --keep), always fetch page 1 since we're deleting</span>\n  <span class=\"token comment\"># In --keep mode, move to next page</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">[</span> <span class=\"token parameter variable\">-z</span> <span class=\"token string\">\"<span class=\"token variable\">$KEEP</span>\"</span> <span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span> <span class=\"token keyword\">then</span>\n    <span class=\"token assign-left variable\">PAGE</span><span class=\"token operator\">=</span><span class=\"token number\">1</span>\n  <span class=\"token keyword\">else</span>\n    <span class=\"token assign-left variable\">PAGE</span><span class=\"token operator\">=</span><span class=\"token variable\"><span class=\"token variable\">$((</span>PAGE <span class=\"token operator\">+</span> <span class=\"token number\">1</span><span class=\"token variable\">))</span></span>\n  <span class=\"token keyword\">fi</span>\n<span class=\"token keyword\">done</span>\n\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Done! Deleted <span class=\"token variable\">$COUNT</span> deployments.\"</span>\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"To delete the project entirely, run:\"</span>\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  npx wrangler pages project delete <span class=\"token variable\">$PROJECT</span>\"</span>\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"\"</span>\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"Or delete it via Cloudflare Dashboard:\"</span>\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  Workers &amp; Pages → <span class=\"token variable\">$PROJECT</span> → Settings → Delete project\"</span></code></pre>\n<h2 id=\"how-it-works\" tabindex=\"-1\">How it works <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#how-it-works\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>The script loops through all deployments using the Cloudflare API, deleting them one by one with a small delay to avoid rate limiting. Once done, it prints instructions for deleting the project via Wrangler or Dashboard.</p>\n<h3 id=\"features\" tabindex=\"-1\">Features <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#features\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<ul>\n<li><strong><code>--limit=N</code></strong> - Test mode. Delete only N deployments to make sure everything works before going all in.</li>\n<li><strong><code>--keep=N</code></strong> - Cleanup mode. Keep the last N deployments and delete the rest. Perfect for regular maintenance.</li>\n<li><strong>No dependencies</strong> - Just bash, curl, and jq. That's it.</li>\n</ul>\n<h2 id=\"getting-your-credentials\" tabindex=\"-1\">Getting your credentials <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#getting-your-credentials\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>You'll need two things:</p>\n<ol>\n<li>\n<p><strong>API Token</strong> - Go to Cloudflare Dashboard → My Profile → API Tokens → Create Token → &quot;Edit Cloudflare Pages&quot; template.</p>\n</li>\n<li>\n<p><strong>Account ID</strong> - Open any site in Cloudflare Dashboard → Overview → look at the right sidebar under &quot;API&quot;.</p>\n</li>\n</ol>\n<h2 id=\"example-output\" tabindex=\"-1\">Example output <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#example-output\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\">Deleting deployments for: my-old-project\nLimit: <span class=\"token number\">10</span>\n\nDeleting a1b2c3d4-e5f6-7890-abcd-ef1234567890<span class=\"token punctuation\">..</span>.\nDeleting b2c3d4e5-f6a7-8901-bcde-f12345678901<span class=\"token punctuation\">..</span>.\nDeleting c3d4e5f6-a7b8-9012-cdef-123456789012<span class=\"token punctuation\">..</span>.\nDeleting d4e5f6a7-b8c9-0123-defa-234567890123<span class=\"token punctuation\">..</span>.\nDeleting e5f6a7b8-c9d0-1234-efab-345678901234<span class=\"token punctuation\">..</span>.\nDeleting f6a7b8c9-d0e1-2345-fabc-456789012345<span class=\"token punctuation\">..</span>.\nDeleting a7b8c9d0-e1f2-3456-abcd-567890123456<span class=\"token punctuation\">..</span>.\nDeleting b8c9d0e1-f2a3-4567-bcde-678901234567<span class=\"token punctuation\">..</span>.\nDeleting c9d0e1f2-a3b4-5678-cdef-789012345678<span class=\"token punctuation\">..</span>.\nDeleting d0e1f2a3-b4c5-6789-defa-890123456789<span class=\"token punctuation\">..</span>.\n\nReached limit of <span class=\"token number\">10</span>. Deleted <span class=\"token number\">10</span> deployments.</code></pre>\n<h2 id=\"get-the-script\" tabindex=\"-1\">Get the script <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#get-the-script\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>I've put the script on GitHub Gist for easy access:</p>\n<p>👉 <a href=\"https://gist.github.com/reatlat/0caeaa62996758ac57abebf6124de93f#file-delete-cf-deployments-sh\">delete-cf-deployments.sh</a></p>\n<p>Feel free to use it, fork it, improve it. If you find any bugs or have suggestions, let me know!</p>\n<h2 id=\"why-not-just-use-the-official-script\" tabindex=\"-1\">Why not just use the official script? <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#why-not-just-use-the-official-script\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>The official solution works fine. But it requires Node.js, <code>npm install</code>, and passes credentials via environment variables (which end up in shell history). My bash script:</p>\n<ul>\n<li>Has zero dependencies beyond <code>curl</code> and <code>jq</code></li>\n<li>Passes credentials as arguments (not in env vars)</li>\n<li>Adds <code>--keep=N</code> option to retain recent deployments</li>\n<li>Works for both Pages and Workers projects</li>\n</ul>\n<p>If you prefer Node.js, use theirs. If you want something lighter, use mine. 🤷</p>\n<h2 id=\"tl-dr\" tabindex=\"-1\">TL;DR: <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/cloudflare-pages-to-workers-migration/#tl-dr\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Cloudflare won't let you delete Pages/Workers projects with too many deployments. Their solution needs Node.js. Mine is just bash. <a href=\"https://gist.github.com/reatlat/0caeaa62996758ac57abebf6124de93f\">Grab the script</a> and clean up your old deployments.</p>\n",
			"date_published": "2026-01-11T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/isp-router-replacement/",
			"url": "https://alex.zappa.dev/blog/isp-router-replacement/",
			"title": "How I replaced my ISP router and extracted PPPoE credentials using a bridge sniffer",
			"content_html": "<p>I use Digi España with their standard ZTE H3600 router, but ISP-provided hardware is always limited. You can't properly configure VPN, firewall, or DNS. What I really wanted was full control over my network.</p>\n<p>That's why I chose GL.iNet. Their routers run OpenWRT, which is essentially a well-optimized Linux distribution. I can SSH into the terminal and configure everything through standard Linux config files. That level of control simply isn't possible with ISP hardware.</p>\n<p>For a long time, I was using this setup:</p>\n<pre><code>ONT → Digi Router → Google Wifi Mesh (Router Mode)\n</code></pre>\n<p>Later I replaced the Google Wifi with TP-Link Deco X60 WiFi 6 Mesh routers. And I wouldn't have touched this whole setup if it weren't for TP-Link's greed. 😤</p>\n<p>Imagine this: three years ago you buy a very expensive product advertised as having a firewall, advanced filtering rules, ad blocking, and many other features. Then one sunny Spanish day, you get a firmware update. I'm one of those people who gets excited about new firmware and eagerly installs it. 🤩 My excitement ended the moment I discovered that part of my router's functionality was now behind a paywall! 🤯 They added a subscription wall to built-in features of my router!</p>\n<div class=\"flex flex-col md:flex-row items-center justify-center gap-x-8\">\n  <img src=\"https://alex.zappa.dev/blog/isp-router-replacement/assets/tp-link-paywall-1.png\" alt=\"TP-Link Deco app showing subscription paywall\" eleventy:widths=\"320\" class=\"flex-1 rounded-lg\">\n  <img src=\"https://alex.zappa.dev/blog/isp-router-replacement/assets/tp-link-paywall-2.png\" alt=\"TP-Link Deco app subscription pricing\" eleventy:widths=\"320\" class=\"flex-1 rounded-lg\">\n</div>\n<p>This isn't even a cloud service. This is hardware I bought! It reminds me of BMW's heated seat subscription or Mercedes' audio system paywall. Funny, right? 😂 But facts are facts. I was shocked 😱 and decided it was time to replace the router with something more advanced and open in terms of settings and functionality.</p>\n<p>So I thought: why not replace it with my travel router for testing? Would it handle the load? I was surprised. Yes, it actually does, except for some dead zones in the apartment where the walls seem to be shielded somehow.</p>\n<p>In the end, I decided to keep the TP-Link units but switched them from router mode to access point mode, essentially giving the middle finger to all their subscriptions. 😎</p>\n<p>Two TP-Link units spread across different points in my apartment more than cover the entire area, delivering up to 900 Mbps over WiFi 6 with stable, lag-free internet.</p>\n<p>Because my network topology had become overly complex, I thought: why not remove the Digi router entirely and connect my travel router directly to the ONT? That's when I remembered I didn't know the PPPoE login and password. I could have just opened a support ticket with Digi. They provide credentials without any issues. But where's the fun in that? 😄 I decided to go the hacker route and capture them myself for the experience and entertainment. 🕵️</p>\n<h2 id=\"the-problem-hidden-credentials\" tabindex=\"-1\">The problem: hidden credentials <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#the-problem-hidden-credentials\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>The first thing I tried was the ZTE web interface. The PPPoE password is hidden. Actually, it's not even there! I tried extracting it through DevTools, but the interface is JavaScript-based without direct URLs. Analyzing dashboard requests didn't reveal any vulnerabilities either.</p>\n<p>Attempting to connect via SSH on port 22 failed. The port was closed or the daemon wasn't running.</p>\n<p>I also tried various login combinations for advanced settings:</p>\n<ul>\n<li><code>admin</code> / password from the router sticker</li>\n<li><code>factorymode</code> / <code>Zte521</code></li>\n<li>Hidden URLs like <code>192.168.1.1/manager_dev_config_t.gch</code></li>\n</ul>\n<p>Nothing worked. The Digi firmware is well locked down and likely stripped, with all settings including PPPoE login and password baked into the firmware.</p>\n<p>Then I remembered: PPPoE authentication is transmitted unencrypted. Time to sniff some packets. 😏</p>\n<h2 id=\"the-solution-bridge-sniffer\" tabindex=\"-1\">The solution: bridge sniffer <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#the-solution-bridge-sniffer\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>The idea is simple: place a computer between the ONT and router, pass traffic through transparently, and listen to the PPPoE handshake. PAP credentials are transmitted in plain text.</p>\n<h3 id=\"what-you-need\" tabindex=\"-1\">What you need <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#what-you-need\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<ul>\n<li>Any computer with Linux (even a live USB works)</li>\n<li>Two Ethernet ports (built-in + USB adapter)</li>\n<li>Your new router</li>\n<li>~30 minutes of time</li>\n</ul>\n<p>In my case, I used a Mele Quieter 4C mini PC with Pop!_OS. I keep it around for testing apps on x86_64 since not everything runs smoothly in emulators on Apple Silicon. For the new router, I used my GL.iNet Beryl AX MT3000 travel router as a test. If it works out, I'll probably upgrade to a Flint 2.</p>\n<h3 id=\"connection-diagram\" tabindex=\"-1\">Connection diagram <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#connection-diagram\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<pre><code>ONT → [eth0 Computer eth1] → ZTE Router\n</code></pre>\n<h3 id=\"installing-packages\" tabindex=\"-1\">Installing packages <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#installing-packages\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> <span class=\"token function\">apt</span> update\n<span class=\"token function\">sudo</span> <span class=\"token function\">apt</span> <span class=\"token function\">install</span> bridge-utils tcpdump wireshark</code></pre>\n<h3 id=\"creating-the-bridge\" tabindex=\"-1\">Creating the bridge <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#creating-the-bridge\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token comment\"># Find interface names</span>\n<span class=\"token function\">ip</span> a\n\n<span class=\"token comment\"># Create bridge</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">ip</span> <span class=\"token function\">link</span> <span class=\"token function\">add</span> br0 <span class=\"token builtin class-name\">type</span> bridge\n<span class=\"token function\">sudo</span> <span class=\"token function\">ip</span> <span class=\"token function\">link</span> <span class=\"token builtin class-name\">set</span> enp1s0 master br0           <span class=\"token comment\"># built-in ethernet</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">ip</span> <span class=\"token function\">link</span> <span class=\"token builtin class-name\">set</span> enxc8a36235e23e master br0  <span class=\"token comment\"># USB adapter (name will differ)</span>\n<span class=\"token function\">sudo</span> <span class=\"token function\">ip</span> <span class=\"token function\">link</span> <span class=\"token builtin class-name\">set</span> enp1s0 up\n<span class=\"token function\">sudo</span> <span class=\"token function\">ip</span> <span class=\"token function\">link</span> <span class=\"token builtin class-name\">set</span> enxc8a36235e23e up\n<span class=\"token function\">sudo</span> <span class=\"token function\">ip</span> <span class=\"token function\">link</span> <span class=\"token builtin class-name\">set</span> br0 up</code></pre>\n<h3 id=\"capturing-the-handshake\" tabindex=\"-1\">Capturing the handshake <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#capturing-the-handshake\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>The sequence matters here:</p>\n<ol>\n<li>Power off the ZTE router</li>\n<li>Connect cables through the bridge (ONT → computer → router)</li>\n<li>Start the sniffer:</li>\n</ol>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> tcpdump <span class=\"token parameter variable\">-i</span> br0 <span class=\"token parameter variable\">-vvvs</span> <span class=\"token number\">0</span> <span class=\"token parameter variable\">-w</span> pppoe_capture.pcap</code></pre>\n<ol start=\"4\">\n<li>Power on the ZTE router</li>\n</ol>\n<p>During boot, the router establishes a PPPoE session and sends credentials in plain text.</p>\n<h2 id=\"analyzing-captured-data\" tabindex=\"-1\">Analyzing captured data <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#analyzing-captured-data\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Once the internet LED on the router lit up (indicating a successful connection), I stopped tcpdump (Ctrl+C) and analyzed the capture:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">sudo</span> tcpdump <span class=\"token parameter variable\">-r</span> pppoe_capture.pcap <span class=\"token parameter variable\">-vvv</span> <span class=\"token operator\">|</span> <span class=\"token function\">grep</span> <span class=\"token parameter variable\">-iE</span> <span class=\"token string\">\"pap|chap|user|pass|name\"</span></code></pre>\n<p>The password appeared immediately in the output. 🎉</p>\n<p>I was doing all this connected to a TV, so taking screenshots was inconvenient, but later I opened the capture in Wireshark and took a screenshot.</p>\n<p>Open the capture in Wireshark with filter <code>pap</code>:</p>\n<img src=\"https://alex.zappa.dev/blog/isp-router-replacement/assets/wireshark-pppoe.png\" alt=\"Wireshark showing PAP authentication request with credentials\" eleventy:widths=\"900\">\n<h3 id=\"result\" tabindex=\"-1\">Result <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#result\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>In the logs, I found the PAP Authentication Request:</p>\n<pre><code>PAP, Auth-Req (0x01), id 1, Peer [USERNAME]@digi, Name [PASSWORD]\n</code></pre>\n<p><strong>Important:</strong> PAP transmits credentials in plain text, which is why the capture works.</p>\n<h2 id=\"configuring-the-new-router\" tabindex=\"-1\">Configuring the new router <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#configuring-the-new-router\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<h3 id=\"parameters-for-gl-inet-or-any-other\" tabindex=\"-1\">Parameters for GL.iNet (or any other) <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#parameters-for-gl-inet-or-any-other\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<table>\n<thead>\n<tr>\n<th>Parameter</th>\n<th>Value</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Protocol</td>\n<td>PPPoE</td>\n</tr>\n<tr>\n<td>Username</td>\n<td>[captured username]@digi</td>\n</tr>\n<tr>\n<td>Password</td>\n<td>[captured password]</td>\n</tr>\n<tr>\n<td>VLAN ID</td>\n<td><strong>20</strong></td>\n</tr>\n<tr>\n<td>MTU</td>\n<td>1500</td>\n</tr>\n<tr>\n<td>MAC Clone</td>\n<td>MAC address of old router</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"important-vlan-20\" tabindex=\"-1\">Important: VLAN 20 <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#important-vlan-20\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Initially, the connection wouldn't establish. Logs showed &quot;Timeout waiting for PADO packets&quot;. The problem was solved by adding <strong>VLAN ID 20</strong> to the PPPoE settings.</p>\n<h3 id=\"mac-address\" tabindex=\"-1\">MAC address <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#mac-address\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>You can find the MAC on the ZTE sticker or in its web interface under WAN settings.</p>\n<h2 id=\"troubleshooting\" tabindex=\"-1\">Troubleshooting <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#troubleshooting\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<h3 id=\"timeout-waiting-for-pado-packets\" tabindex=\"-1\">Timeout waiting for PADO packets <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#timeout-waiting-for-pado-packets\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p><strong>Cause:</strong> ONT isn't responding to PPPoE requests.</p>\n<p><strong>Solutions:</strong></p>\n<ol>\n<li>Add VLAN ID 20</li>\n<li>Reboot the ONT (to reset the old session)</li>\n<li>Make sure the ZTE is completely disconnected</li>\n<li>Check cables and ports</li>\n</ol>\n<h3 id=\"mtu-warning\" tabindex=\"-1\">MTU warning <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#mtu-warning\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>The logs showed a warning about MTU 1492. Standard MTU for PPPoE is 1492, but Digi works with 1500 as well.</p>\n<h2 id=\"alternative-method-fake-pppoe-server\" tabindex=\"-1\">Alternative method: fake PPPoE server <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#alternative-method-fake-pppoe-server\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>If you don't have two Ethernet ports, you can set up a fake PPPoE server:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token comment\"># Disconnect ONT from router</span>\n<span class=\"token comment\"># Connect router directly to computer</span>\n\n<span class=\"token function\">sudo</span> pppoe-server <span class=\"token parameter variable\">-I</span> eth0 <span class=\"token parameter variable\">-L</span> <span class=\"token number\">10.0</span>.0.1 <span class=\"token parameter variable\">-R</span> <span class=\"token number\">10.0</span>.0.10 <span class=\"token parameter variable\">-N</span> <span class=\"token number\">1</span> <span class=\"token parameter variable\">-k</span> <span class=\"token parameter variable\">-F</span></code></pre>\n<p>The router will try to connect to the &quot;provider&quot; and send credentials. However, this method is less reliable. Not all routers send credentials to a fake server.</p>\n<h2 id=\"security-hardening\" tabindex=\"-1\">Security hardening <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#security-hardening\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>After setting up my new router (or rather, verifying these settings):</p>\n<ul>\n<li>Disabled UPnP</li>\n<li>Enabled SYN flood protection</li>\n<li>Configured DNS over HTTPS (<a href=\"https://controld.com\">ControlD</a>)</li>\n<li>Disabled remote access</li>\n<li>Installed GL.iNet beta firmware with improved security</li>\n</ul>\n<p>Behind CGNAT (IP 100.x.x.x), you're not directly visible from the internet anyway, but extra protection never hurts.</p>\n<h2 id=\"final-network-topology\" tabindex=\"-1\">Final network topology <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#final-network-topology\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>My new setup is much simpler and more logical:</p>\n<pre><code>ONT → GL.iNet Beryl AX (PPPoE)\n        ↓  ↓  ↓  ↓  ↓  ↓  ↓\nTP-Link Deco X60 (AP Mode, WiFi roaming) 2 units connected via Ethernet backhaul\n+ multiple Ethernet switches to various devices\n</code></pre>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#conclusion\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>The entire process took about an hour, including experimenting with settings. Now I have full control over my home network: proper firewall, VPN, AdGuard, and no ISP firmware limitations. 💪</p>\n<p>This little adventure reminded me of my sysadmin days back in the early 2000s when we were learning how Linux actually works under the hood. That's when I first met Ubuntu. Later came Arch and Fedora. I'm pretty much OS-agnostic at this point, though Linux and macOS are my favorites. Mac is my daily driver for productivity, but Linux is where I go for fun, joy, and tinkering with my homelab. 🛠️ And yes, I use Arch btw. 🐧</p>\n<h2 id=\"tl-dr-for-digi-espana\" tabindex=\"-1\">TL;DR for Digi España <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/isp-router-replacement/#tl-dr-for-digi-espana\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<pre><code>Connection Type: PPPoE\nVLAN ID: 20\nMTU: 1500\nMAC: clone from original router\n</code></pre>\n<blockquote>\n<p><strong>Disclaimer:</strong> <br>\nThis article is for educational and entertainment purposes. It describes obtaining credentials for your own connection. Use this information responsibly.</p>\n</blockquote>\n",
			"date_published": "2026-01-03T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/year-in-review-2025/",
			"url": "https://alex.zappa.dev/blog/year-in-review-2025/",
			"title": "2025 year in review: a year of building, learning, and gratitude",
			"content_html": "<p>If you've noticed my blog has been quiet this year, there's a good reason for that. I've been heads-down, completely immersed in development, research, and building things I'm genuinely proud of.</p>\n<h2 id=\"the-numbers-tell-a-story\" tabindex=\"-1\">The numbers tell a story <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#the-numbers-tell-a-story\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Looking at my GitHub profile, this year brought:</p>\n<img src=\"https://alex.zappa.dev/blog/year-in-review-2025/assets/github-stats-2025.png\" alt=\"GitHub Contributions 2025\" eleventy:widths=\"600\">\n<ul>\n<li><strong>4,738+ contributions</strong> across various projects</li>\n<li><strong>81 repositories</strong> across my <a href=\"https://github.com/reatlat\">personal</a> and <a href=\"https://github.com/freshjuice-dev\">FreshJuice</a> accounts</li>\n<li><strong>7+ Eleventy plugins</strong> published and maintained</li>\n<li>Multiple HubSpot themes and modules</li>\n<li>And countless hours of learning, debugging, and shipping</li>\n</ul>\n<p>But numbers only tell part of the story.</p>\n<h2 id=\"freshjuice-from-side-project-to-passion\" tabindex=\"-1\">FreshJuice: from side project to passion <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#freshjuice-from-side-project-to-passion\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Most of my energy this year went into <a href=\"https://freshjuice.dev/\">FreshJuice</a>, a creative development studio focused on HubSpot CMS and modern web development.</p>\n<p>What started as a way to share HubSpot development knowledge evolved into something bigger:</p>\n<ul>\n<li><strong><a href=\"https://github.com/freshjuice-dev/freshjuice-dev-hubspot-theme\">FreshJuice HubSpot Theme</a></strong> - A developer starter theme with Tailwind CSS and Alpine.js (27 stars, 12 forks)</li>\n<li><strong><a href=\"https://demo.freshjuice.dev/\">Professional HubSpot Modules</a></strong> - 4 premium modules for HubSpot CMS</li>\n<li><strong><a href=\"https://freshjuice.dev/hubspot-devtools/\">HubSpot DevTools Extension</a></strong> - A browser extension I use every single day</li>\n<li><strong><a href=\"https://github.com/freshjuice-dev/freshjuice-11ty-starter\">FreshJuice 11ty Starter</a></strong> - A modern Eleventy starter theme with CloudCannon CMS integration</li>\n<li><strong><a href=\"https://freshjuice.dev/tools/\">Free Online Tools</a></strong> - A collection of 15+ free utilities for developers and marketers</li>\n</ul>\n<h3 id=\"free-tools-for-everyone\" tabindex=\"-1\">Free tools for everyone <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#free-tools-for-everyone\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Speaking of tools, this year I built and launched a whole suite of <a href=\"https://freshjuice.dev/tools/\">free online utilities</a> on FreshJuice:</p>\n<ul>\n<li><strong>SEO Tools</strong>: Broken Link Checker, Keyword Density Checker, Metadata Checker, Robots.txt Analyzer, SEO Analyzer, Readability Score Checker</li>\n<li><strong>AI/LLM Tools</strong>: <a href=\"https://freshjuice.dev/tools/llmstxt-generator/\">llms.txt Generator</a> for creating AI-friendly site documentation</li>\n<li><strong>Development Tools</strong>: CSS Clamp() Font Size Generator, UUID Generator</li>\n<li><strong>Marketing Tools</strong>: <a href=\"https://campaign-url-builder.com/\">Campaign URL Builder</a> for UTM tracking</li>\n</ul>\n<p>All completely free, no sign-up required. Just open and use.</p>\n<h3 id=\"cloudcannon-partnership\" tabindex=\"-1\">CloudCannon partnership <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#cloudcannon-partnership\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>A highlight of the year was partnering with <a href=\"https://cloudcannon.com/\">CloudCannon</a>. The FreshJuice 11ty Starter is now available in their community themes, featuring full visual editing and page builder capabilities. If you're looking for a modern Eleventy starter with a powerful CMS, <a href=\"https://snappy-lemon.cloudvent.net/\">check it out</a>!</p>\n<p>I've also been maintaining and improving several Eleventy plugins:</p>\n<ul>\n<li><a href=\"https://github.com/reatlat/eleventy-plugin-phosphoricons\">eleventy-plugin-phosphoricons</a></li>\n<li><a href=\"https://github.com/reatlat/eleventy-plugin-speculation-rules\">eleventy-plugin-speculation-rules</a></li>\n<li><a href=\"https://github.com/reatlat/eleventy-plugin-hubspot\">eleventy-plugin-hubspot</a></li>\n<li><a href=\"https://github.com/reatlat/eleventy-plugin-vidyard\">eleventy-plugin-vidyard</a></li>\n<li>And a few more...</li>\n</ul>\n<h2 id=\"kandji-to-iru-my-main-gig\" tabindex=\"-1\">Kandji to Iru: my main gig <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#kandji-to-iru-my-main-gig\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>My primary work continues to be with the amazing marketing team at Kandji, which transitioned to <a href=\"https://www.iru.com/\">Iru</a> this year. As part of the team, I build and maintain their HubSpot infrastructure, internal tools, and marketing websites. I even spent six months working from Kandji's London HQ, where I had the chance to meet and collaborate with some truly incredible people in person.</p>\n<p>To the entire team: thank you for your trust, collaboration, and the opportunity to build something meaningful together.</p>\n<h3 id=\"a-special-thank-you-to-sylvia\" tabindex=\"-1\">A special thank you to Sylvia <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#a-special-thank-you-to-sylvia\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>I want to give a special shoutout to <a href=\"https://www.linkedin.com/in/sylvialepoidevin/\">Sylvia LePoidevin</a>, who I had the pleasure of working with for almost 8 years, even before Kandji.</p>\n<p>This year, Sylvia decided to start something new: her own journey in the marketing world. She launched <a href=\"https://www.zerotoonemarketer.com/\">Zero to One Marketer</a>, a blog sharing her insights on marketing, growth, and building from scratch. If you're in marketing or just curious about the field, I highly recommend checking it out. Her experience leading marketing teams and building brands from the ground up makes her perspective incredibly valuable.</p>\n<p>Thank you, Sylvia, for almost 8 years of collaboration and the countless projects we built together. Wishing you all the best in this exciting new chapter!</p>\n<h2 id=\"discovering-linkedin-yes-really\" tabindex=\"-1\">Discovering LinkedIn (yes, really) <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#discovering-linkedin-yes-really\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Here's something unexpected: I started actively posting on LinkedIn in July this year, and I'm genuinely surprised by what I found.</p>\n<p>What inspired me to try? Actually, it was Sylvia. After reading <a href=\"https://www.linkedin.com/posts/sylvialepoidevin_what-i-learned-from-a-post-that-got-458319-activity-7340505273695920129-sfON\">her viral post</a> about lessons from going 0 to 1 as the first marketing hire (458,000+ impressions!), I thought: &quot;Maybe I should give this a real shot too.&quot;</p>\n<p>I expected the usual corporate noise, but instead discovered a warm, supportive community of developers, marketers, and fellow HubSpot enthusiasts who actually engage, share insights, and help each other grow.</p>\n<p>The numbers speak for themselves:</p>\n<img src=\"https://alex.zappa.dev/blog/year-in-review-2025/assets/linkedin-stats-2025.png\" alt=\"LinkedIn Stats 2025\" eleventy:widths=\"600\">\n<ul>\n<li><strong>18,623 impressions</strong> in just 6 months (starting from zero!)</li>\n<li><strong>Nearly 4,000 members reached</strong> with my content</li>\n<li><strong>1,000+ followers</strong> who decided to join the journey</li>\n</ul>\n<p>These might not be viral numbers, but for me they're huge. I've always treated this blog as a personal journal rather than a platform for engagement: no comment sections, no analytics obsession, just me and my thoughts. LinkedIn changed that. For the first time, I have a space to actually connect with people who share my interests, exchange ideas, and learn from each other. Every like, comment, and connection has meant more than you know.</p>\n<h2 id=\"this-website-got-a-refresh-too\" tabindex=\"-1\">This website got a refresh too <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#this-website-got-a-refresh-too\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>And yes, while writing this very post, I updated the design of this website! The navbar now features a liquid glass effect with backdrop blur, a smart sticky header that hides on scroll down and shows on scroll up, and a slick animated mobile menu. I also added a <a href=\"https://alex.zappa.dev/search/\">search functionality</a> powered by <a href=\"https://pagefind.app/\">Pagefind</a>, an amazing static search tool created by the CloudCannon team. Sometimes you just need to practice what you preach and ship something for yourself.</p>\n<p>I've also been diving deep into accessibility. I set up automated tests to ensure this site passes <a href=\"https://www.w3.org/WAI/WCAG21/quickref/\">WCAG 2.1 AA</a> validation, with plans to reach AAA where possible. The WCAG and ADA guidelines have evolved significantly, covering nuances I used to overlook. In the coming year, I'm committed to learning them all and building better web experiences. When design constraints make full compliance tricky, I'll add controls like high-contrast modes to ensure everyone can use my sites comfortably.</p>\n<h2 id=\"gratitude\" tabindex=\"-1\">Gratitude <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#gratitude\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>This year reminded me why I love what I do. It's not just about the code, it's about the people.</p>\n<p>Thank you to:</p>\n<ul>\n<li><strong>The Iru team</strong> (formerly Kandji) for the incredible partnership</li>\n<li><strong><a href=\"https://www.linkedin.com/company/freshjuice\">The FreshJuice community</a></strong> for using, starring, and contributing to our open-source projects</li>\n<li><strong><a href=\"https://www.linkedin.com/in/reatlat/\">My LinkedIn connections</a></strong> for the unexpected warmth and engagement</li>\n<li><strong><a href=\"https://www.11ty.dev/docs/community/\">The Eleventy community</a></strong> for building such an amazing ecosystem</li>\n<li><strong><a href=\"https://developers.hubspot.com/community\">The HubSpot developer community</a></strong> for the constant inspiration</li>\n<li><strong>Everyone who read my posts, opened an issue, or sent a kind message</strong></li>\n</ul>\n<h2 id=\"looking-ahead\" tabindex=\"-1\">Looking Ahead <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/year-in-review-2025/#looking-ahead\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>2026 is around the corner, and I have plans. More open-source tools, more sharing, and hopefully more blog posts here (I promise to write more!).</p>\n<blockquote>\n<p>If you get just 1% better each day, you'll end up 37 times better by the end of the year.</p>\n<p><small>— James Clear, <a href=\"https://jamesclear.com/atomic-habits\">Atomic Habits</a></small></p>\n</blockquote>\n<p>Small steps, big impact. Let's keep pushing for progress and spreading good into the world.</p>\n<p>But for now, I'm taking a moment to appreciate how far we've come. Thank you for being part of this journey.</p>\n<p>Happy Holidays and Happy New Year! 🎉</p>\n",
			"date_published": "2025-12-28T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/aieo-orange-guest/",
			"url": "https://alex.zappa.dev/blog/aieo-orange-guest/",
			"title": "Guest post on Orange Marketing: AIEO is the new SEO",
			"content_html": "<p>The future of search isn't keywords, it's context.\nSeems like no one really <em>Googles</em> anymore. We just ask AI.\nSearch has evolved, and so should the way we create and optimize content.</p>\n<p>In this guest post for <a href=\"https://www.orangemarketing.com\">Orange Marketing</a>, I explored how marketers and modern web developers can rethink their strategies for the age of <em>AI-powered search</em>, where trust, structure, and machine-readable data become the new SEO fundamentals.</p>\n<p>👉 You can read the full article on Orange Marketing’s blog:\n<a href=\"https://blog.orangemarketing.com/aieo-aeo-is-the-new-seo-what-hubspot-marketers-should-know\">AIEO / AEO is the New SEO: What HubSpot Marketers Should Know</a></p>\n<p>Thanks for reading, and stay fresh out there. 🍊</p>\n",
			"date_published": "2025-10-08T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/",
			"url": "https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/",
			"title": "How to manage multiple SSH keys for multiple GitHub accounts on one computer",
			"content_html": "<p>Recently <a href=\"https://zapparov.dev\">my son</a> asked me how to manage multiple SSH keys for multiple GitHub accounts on one computer. He starts his journey as computer science student and he need to work with multiple GitHub accounts for his projects.</p>\n<p>My first attempt was to find an article or ready solution to point him to. But I couldn't find a good one. So I decided to write this article to help him and other developers who’re facing the same issue.</p>\n<img src=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/assets/laptop-keys.png\" alt=\"How to Manage Multiple SSH Keys for Multiple GitHub Accounts on One Computer\" eleventy:widths=\"400\">\n<h2 id=\"step-by-step-guide\" tabindex=\"-1\">Step-by-step guide <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#step-by-step-guide\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<h3 id=\"1-generate-two-ssh-keys\" tabindex=\"-1\">1. Generate two SSH keys <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#1-generate-two-ssh-keys\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>If you haven’t already, <a href=\"https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent\">generate two SSH keys</a> for each GitHub account:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\">ssh-keygen <span class=\"token parameter variable\">-t</span> ed25519 <span class=\"token parameter variable\">-C</span> <span class=\"token string\">\"personal_email_account@example.com\"</span> <span class=\"token parameter variable\">-f</span> ~/.ssh/id_ed25519_personal\nssh-keygen <span class=\"token parameter variable\">-t</span> ed25519 <span class=\"token parameter variable\">-C</span> <span class=\"token string\">\"student_email_account@example.com\"</span> <span class=\"token parameter variable\">-f</span> ~/.ssh/id_ed25519_edu</code></pre>\n<ul>\n<li>The <code>-f</code> flag specifies the filename for the keys (e.g., id_ed25519_personal and id_ed25519_edu).</li>\n</ul>\n<blockquote>\n<p><em><strong>If you are using a legacy system that doesn't support the Ed25519 algorithm, use:</strong></em></p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\">ssh-keygen <span class=\"token parameter variable\">-t</span> rsa <span class=\"token parameter variable\">-b</span> <span class=\"token number\">4096</span> <span class=\"token parameter variable\">-C</span> <span class=\"token string\">\"personal_email_account@example.com\"</span> <span class=\"token parameter variable\">-f</span> ~/.ssh/id_rsa_personal\nssh-keygen <span class=\"token parameter variable\">-t</span> rsa <span class=\"token parameter variable\">-b</span> <span class=\"token number\">4096</span> <span class=\"token parameter variable\">-C</span> <span class=\"token string\">\"student_email_account@example.com\"</span> <span class=\"token parameter variable\">-f</span> ~/.ssh/id_rsa_edu</code></pre>\n</blockquote>\n<h3 id=\"2-add-keys-to-the-ssh-agent\" tabindex=\"-1\">2. Add keys to the SSH agent <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#2-add-keys-to-the-ssh-agent\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Add both keys to your SSH agent:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token builtin class-name\">eval</span> <span class=\"token string\">\"<span class=\"token variable\"><span class=\"token variable\">$(</span>ssh-agent <span class=\"token parameter variable\">-s</span><span class=\"token variable\">)</span></span>\"</span>\nssh-add ~/.ssh/id_ed25519_personal\nssh-add ~/.ssh/id_ed25519_edu</code></pre>\n<h3 id=\"3-update-the-ssh-config-file\" tabindex=\"-1\">3. Update the SSH config file <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#3-update-the-ssh-config-file\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Edit (or create) your ~/.ssh/config file to define configurations for each GitHub account.</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token comment\"># GitHub Personal Account</span>\nHost github.com\n  HostName github.com\n  User <span class=\"token function\">git</span>\n  IdentityFile ~/.ssh/id_ed25519_personal\n\n<span class=\"token comment\"># GitHub Education Account</span>\nHost github.edu\n  HostName github.com\n  User <span class=\"token function\">git</span>\n  IdentityFile ~/.ssh/id_ed25519_edu</code></pre>\n<h3 id=\"4-use-configured-hosts-in-git-urls\" tabindex=\"-1\">4. Use configured hosts in Git URLs <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#4-use-configured-hosts-in-git-urls\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>When cloning or working with Git repositories, use the corresponding host name defined in the SSH config:</p>\n<p>For Personal account:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">git</span> clone git@github.com:username/repo.git</code></pre>\n<p>For Education account:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">git</span> clone git@github.edu:username/repo.git</code></pre>\n<h3 id=\"5-test-your-configuration\" tabindex=\"-1\">5. Test your configuration <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#5-test-your-configuration\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Verify the setup by testing the SSH connection for each account:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">ssh</span> <span class=\"token parameter variable\">-T</span> github.com\n<span class=\"token function\">ssh</span> <span class=\"token parameter variable\">-T</span> github.edu</code></pre>\n<p>If the setup is correct, GitHub will identify each account and display a success message.</p>\n<h2 id=\"tips\" tabindex=\"-1\">Tips <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#tips\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>If you already cloned repositories using the default git@github.com format, update the origin remote URL to use the appropriate host:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">git</span> remote set-url origin git@github.edu:username/repo.git</code></pre>\n<p>Make sure the SSH public keys (id_ed25519_personal.pub and id_ed25519_edu.pub) are added to the respective GitHub accounts in their settings.</p>\n<h2 id=\"setup-git-global-configuration\" tabindex=\"-1\">Setup Git global configuration <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#setup-git-global-configuration\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>To avoid conflicts, set up a global Git configuration for each account:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">git</span> config <span class=\"token parameter variable\">--global</span> user.name <span class=\"token string\">\"Personal Name\"</span>\n<span class=\"token function\">git</span> config <span class=\"token parameter variable\">--global</span> user.email <span class=\"token string\">\"personal_email_account@example.com\"</span></code></pre>\n<p>then you need to update the global configuration for the second account:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">touch</span> ~/.gitconfig_edu\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"[user]\"</span> <span class=\"token operator\">>></span> ~/.gitconfig_edu\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  name = Student Name\"</span> <span class=\"token operator\">>></span> ~/.gitconfig_edu\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  email = student_email_account@example.com\"</span> <span class=\"token operator\">>></span> ~/.gitconfig_edu</code></pre>\n<p>and then you need update the global configuration file <code>~/.gitconfig</code> to include the second configuration file:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"[includeIf <span class=\"token entity\" title=\"\\&quot;\">\\\"</span>gitdir:~/path/to/your/education/**<span class=\"token entity\" title=\"\\&quot;\">\\\"</span>]\"</span> <span class=\"token operator\">>></span> ~/.gitconfig_edu\n<span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"  path = ~/.gitconfig_edu\"</span> <span class=\"token operator\">>></span> ~/.gitconfig_edu</code></pre>\n<blockquote>\n<p><em><strong>Note: for Windows users ruleset <code>includeIf</code> could be different.</strong></em></p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"[includeIf <span class=\"token entity\" title=\"\\&quot;\">\\\"</span>gitdir/i:C:/path/to/your/education/**<span class=\"token entity\" title=\"\\&quot;\">\\\"</span>]\"</span> <span class=\"token operator\">>></span> ~/.gitconfig_edu</code></pre>\n</blockquote>\n<p>This setup allows you to:</p>\n<ul>\n<li>Use the correct name and email for each account.</li>\n<li>Automatically switch between configurations based on the repository path.</li>\n<li>Keep your global configuration clean and organized.</li>\n</ul>\n<h3 id=\"how-it-works\" tabindex=\"-1\">How it works <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#how-it-works\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>When you run a Git command in a repository located in the <code>~/path/to/your/education/</code> directory, Git will use the configuration from the <code>~/.gitconfig_edu</code> file.</p>\n<p>In all other cases, Git will use the default global configuration.</p>\n<h3 id=\"testing-the-configuration\" tabindex=\"-1\">Testing the configuration <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-manage-multiple-ssh-keys-for-multiple-github-accounts-on-one-computer/#testing-the-configuration\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>To confirm the correct profile is being applied in a specific directory:</p>\n<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">git</span> config <span class=\"token parameter variable\">--get</span> user.name\n<span class=\"token function\">git</span> config <span class=\"token parameter variable\">--get</span> user.email</code></pre>\n<blockquote>\n<p><em><strong>Important notes:</strong></em></p>\n<ul>\n<li>The included files (e.g., <code>~/.gitconfig_edu</code>) must be valid Git configuration files.</li>\n<li>Make sure to replace <code>~/path/to/your/education/**</code> with the actual path to your education repositories.</li>\n<li>If a directory doesn’t match any includeIf condition, the global configuration will be used.</li>\n</ul>\n</blockquote>\n<p>That’s it! You’ve successfully set up and managed multiple SSH keys for multiple GitHub accounts on one computer.</p>\n",
			"date_published": "2024-12-06T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/webchronicle/",
			"url": "https://alex.zappa.dev/blog/webchronicle/",
			"title": "webChronicle: your personal Wayback Machine",
			"content_html": "<p>In October 10. 2024 I was looking an archived copy of the website on the <a href=\"https://web.archive.org/\">Wayback Machine</a> and found that the web archive is down.</p>\n<img src=\"https://alex.zappa.dev/blog/webchronicle/assets/wayback-machine-down.png\" alt=\"Wayback Machine is down!\" eleventy:widths=\"500\">\n<p>Shortly I started looking at internet media, what's happened to one of the useful resources in the internet, and found Wayback Machine is down for a reason of DDoS attack.</p>\n<p>Here is a <a href=\"https://www.forbes.com/sites/daveywinder/2024/10/10/internet-hacked-wayback-machine-down-31-million-passwords-stolen/\">Forbes article about this incident</a>.</p>\n<p>This case brings me to the idea of creating a personal web archiving tool that allows you to capture and explore snapshots of webpages over time. Like the Wayback Machine, but as your own personal Time Machine.</p>\n<h2 id=\"meet-the-webchronicle\" tabindex=\"-1\">Meet the webChronicle <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/webchronicle/#meet-the-webchronicle\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>The <a href=\"https://webchronicle.dev/\">webChronicle</a> is a simple tool that allows you to capture and explore snapshots of webpages over time. It's like the Wayback Machine, but as your own personal Time Machine.</p>\n<img src=\"https://alex.zappa.dev/blog/webchronicle/assets/bttf-meme.png\" alt=\"Back To The Future - We have to go back, Marty! To save the World? No, to save the Web!\" eleventy:widths=\"500\">\n<h3 id=\"how-it-works\" tabindex=\"-1\">How it works <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/webchronicle/#how-it-works\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>The webChronicle builds on the <a href=\"https://www.11ty.dev/\">Eleventy</a> static site generator and the <a href=\"https://www.npmjs.com/package/website-scraper\">website-scraper</a> package to capture and store snapshots of webpages.</p>\n<p>As a result you will have a static website that you can host on <a href=\"https://www.netlify.com/\">Netlify</a> or <a href=\"https://vercel.com/\">Vercel</a> to explore snapshots of webpages over time.</p>\n<div class=\"flex flex-wrap gap-6 not-prose\">\n  <a href=\"https://app.netlify.com/start/deploy?repository=https://github.com/reatlat/webchronicle\">\n    <img class=\"text-left\" src=\"https://www.netlify.com/img/deploy/button.svg\" alt=\"Netlify Deploy\" eleventy:widths=\"200\">\n    <span class=\"sr-only\">Netlify Deploy</span>\n  </a>\n  <a href=\"https://vercel.com/import/project?template=https://github.com/reatlat/webchronicle\">\n    <img class=\"text-left\" src=\"https://vercel.com/button\" alt=\"Vercel Deploy\" eleventy:widths=\"200\">\n    <span class=\"sr-only\">Vercel Deploy</span>\n  </a>\n</div>\n<p>You also may deploy this project to other platforms like Heroku, AWS, Cloudflare Pages or Google Cloud.</p>\n<h3 id=\"how-to-use\" tabindex=\"-1\">How to use <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/webchronicle/#how-to-use\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<ol>\n<li>Clone the <a href=\"https://github.com/reatlat/webchronicle/\">webChronicle repository</a>.</li>\n<li>Install dependencies with <code>npm install</code>.</li>\n<li>Update <code>webchronicle.config.js</code> with your configuration:<pre class=\"language-javascript\" tabindex=\"0\"><code class=\"language-javascript\">module<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token operator\">...</span>\n  <span class=\"token literal-property property\">urls</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token string\">'https://example.com'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'https://example.org'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token function-variable function\">urlFilter</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">url</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">return</span> url<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span><span class=\"token string\">'example.com'</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">||</span> url<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span><span class=\"token string\">'example.org'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token operator\">...</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\nFull configuration options are available in the <a href=\"https://github.com/website-scraper/node-website-scraper?tab=readme-ov-file#options\">Options</a> section.</li>\n<li>Run the scraper:<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">npm</span> run scraper</code></pre>\n</li>\n<li>Commit the changes to your repository:<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">git</span> <span class=\"token function\">add</span> ./scrapped-websites\n<span class=\"token function\">git</span> commit <span class=\"token parameter variable\">-m</span> <span class=\"token string\">\"Scrapped websites\"</span>\n<span class=\"token function\">git</span> push</code></pre>\n</li>\n<li>Deploy the project to your preferred platform or run it locally <code>http://localhost:8080</code>:<pre class=\"language-bash\" tabindex=\"0\"><code class=\"language-bash\"><span class=\"token function\">npm</span> run start</code></pre>\n</li>\n<li>Explore the snapshots of the webpages over time.</li>\n<li>Enjoy! 🎉</li>\n</ol>\n<h3 id=\"live-demo\" tabindex=\"-1\">Live demo <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/webchronicle/#live-demo\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>You can explore the live demo of the webChronicle at <a href=\"https://webchronicle.dev/\">webChronicle</a>.</p>\n<h2 id=\"credits\" tabindex=\"-1\">Credits <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/webchronicle/#credits\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Special thanks to <a href=\"https://www.linkedin.com/in/james-dancer/\">James Dancer</a> for the inspiration behind the name. Your idea was spot on!</p>\n<h2 id=\"contributing-and-source-code\" tabindex=\"-1\">Contributing and source code <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/webchronicle/#contributing-and-source-code\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>You can find the source code of the webChronicle on <a href=\"https://github.com/reatlat/webchronicle/\">GitHub</a>.</p>\n<p>If you notice an issue, feel free to <a href=\"https://github.com/reatlat/webchronicle/issues\">open an issue</a>.</p>\n<p>Happy Holidays, and Thanks for reading! 🙏</p>\n",
			"date_published": "2024-12-01T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/upgrading-to-eleventy-v3/",
			"url": "https://alex.zappa.dev/blog/upgrading-to-eleventy-v3/",
			"title": "Upgrading to Eleventy v3",
			"content_html": "<p>This post inspired by Max's blog about <a href=\"https://mxb.dev/blog/eleventy-v3-update/\">Upgrading to Eleventy v3</a></p>\n<img src=\"https://alex.zappa.dev/blog/upgrading-to-eleventy-v3/assets/11ty-possum.jpg\" alt=\"Eleventy Possum\" eleventy:widths=\"300\">\n<p>Right after <a href=\"https://conf.11ty.dev\">11tyConf</a> which was in May of this year, I want to try a new 11ty version and test new image transform plugin.</p>\n<p>Although v3.0.0 is still in alpha, and I'm sure it will be released soon enough that we can use the latest version for <s>testing</s> production, at least for personal websites like mine.</p>\n<h2 id=\"switching-over-to-esm\" tabindex=\"-1\">Switching over to ESM <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/upgrading-to-eleventy-v3/#switching-over-to-esm\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>The biggest change in v3 is that Eleventy switches to use <a href=\"https://nodejs.org/api/esm.html\">ECMAScript Module Syntax</a> (ESM). That aligns it with contemporary standards for JS packages.</p>\n<p>In “<a href=\"https://www.zachleat.com/web/eleventy-v3-esm/\">Lessons learned moving Eleventy from CommonJS to ESM</a>”, Zach explains the motivation for the switch.</p>\n<p>Meantime, on projects where I work and worked usually was a mix of ESM and commonJS, and I never really thought too much about switch until now.</p>\n<h3 id=\"step-1-a-package-type-changes\" tabindex=\"-1\">Step 1: A package type changes <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/upgrading-to-eleventy-v3/#step-1-a-package-type-changes\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>I thought it would be all I had to do for the first time, update the <code>package.json</code> by adding new property <code>type</code> and set value to <code>module</code>.</p>\n<pre class=\"language-json\" tabindex=\"0\"><code class=\"language-json\"><span class=\"token comment\">// package.json</span>\n<span class=\"token punctuation\">{</span>\n  <span class=\"token property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"alex.zappa.dev\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"version\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"7.0.0\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token property\">\"type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"module\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token comment\">// ...</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>Well... it was just a start before realizing there are so many other files and scripts I have to update.</p>\n<h3 id=\"step-2-update-all-js-file\" tabindex=\"-1\">Step 2: update all JS file <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/upgrading-to-eleventy-v3/#step-2-update-all-js-file\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Since all JS files are modules now, they need updating as well.</p>\n<p>Basically we cant use CommonJS syntax like <code>module.exports = thing</code> or <code>require('thing')</code> anymore, and we need to replace it with ESM module syntax instead.</p>\n<p>In an Eleventy v2 project, you’ll typically have your <code>eleventy.config.js</code>, files for filters/shortcodes and global data files that may look something like this:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">const</span> plugin <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'plugin-package'</span><span class=\"token punctuation\">)</span>\n<span class=\"token comment\">// ...</span>\nmodule<span class=\"token punctuation\">.</span>exports <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">something</span><span class=\"token operator\">:</span> <span class=\"token function\">plugin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token keyword\">do</span><span class=\"token operator\">:</span> <span class=\"token string\">'something'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>Using ESM syntax, rewrite these files to look like this:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">import</span> plugin <span class=\"token keyword\">from</span> <span class=\"token string\">'plugin-package'</span>\n<span class=\"token comment\">// ...</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">something</span><span class=\"token operator\">:</span> <span class=\"token function\">plugin</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token keyword\">do</span><span class=\"token operator\">:</span> <span class=\"token string\">'something'</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>It was repetitive work, but once done, it's worth every second.</p>\n<h3 id=\"step-3-postcss-issues\" tabindex=\"-1\">Step 3: postCSS issues <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/upgrading-to-eleventy-v3/#step-3-postcss-issues\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Since I use postCSS with TailwindCSS in my website, I also have to update postCSS and TailwindCSS config files, this is where I found one small issue with <code>tailwindcss/nesting</code> plugin.</p>\n<p>Its not ready to be used yet, and cant be imported like most of other plugins.</p>\n<p>To solve issue, I found one thread on <a href=\"https://github.com/tailwindlabs/tailwindcss/issues/5089\">github issues</a>, the solution was simple, instead of importing tailwindcss as:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">import</span> tailwindNesting <span class=\"token keyword\">from</span> <span class=\"token string\">\"tailwindcss/nesting\"</span><span class=\"token punctuation\">;</span></code></pre>\n<p>you have to specify which file you looking to import</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">import</span> tailwindNesting <span class=\"token keyword\">from</span> <span class=\"token string\">\"tailwindcss/nesting/index.js\"</span><span class=\"token punctuation\">;</span></code></pre>\n<h3 id=\"step-4-image-transform\" tabindex=\"-1\">Step 4: Image Transform <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/upgrading-to-eleventy-v3/#step-4-image-transform\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p><a href=\"https://www.11ty.dev/docs/plugins/image/#eleventy-transform\">Eleventy image plugin</a> got a new feature to optimize any <code>&lt;img&gt;</code> tag on fly using eleventyTransform.</p>\n<p>Implementation is simple, and make you code clean, since you no need to use shortcodes for images anymore</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> eleventyImageTransformPlugin <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"@11ty/eleventy-img\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">eleventyConfig</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  eleventyConfig<span class=\"token punctuation\">.</span><span class=\"token function\">addPlugin</span><span class=\"token punctuation\">(</span>eleventyImageTransformPlugin<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// which file extensions to process</span>\n    <span class=\"token literal-property property\">extensions</span><span class=\"token operator\">:</span> <span class=\"token string\">\"html\"</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">// Add any other Image utility options here:</span>\n\n    <span class=\"token comment\">// optional, output image formats</span>\n    <span class=\"token literal-property property\">formats</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"avif\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"webp\"</span><span class=\"token punctuation\">,</span> <span class=\"token string\">\"auto\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">// optional, output dir and url path for images</span>\n    <span class=\"token literal-property property\">outputDir</span><span class=\"token operator\">:</span> <span class=\"token string\">\"./_site/img/\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">urlPath</span><span class=\"token operator\">:</span> <span class=\"token string\">\"/img/\"</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">// optional, output image widths</span>\n    <span class=\"token literal-property property\">widths</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"auto\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n\n    <span class=\"token comment\">// optional, attributes assigned on &lt;img> override these values.</span>\n    <span class=\"token literal-property property\">defaultAttributes</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token literal-property property\">loading</span><span class=\"token operator\">:</span> <span class=\"token string\">\"lazy\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">decoding</span><span class=\"token operator\">:</span> <span class=\"token string\">\"async\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>This code broke my website, because I forgot to update shortcode implementation first.</p>\n<p>So to solve this problem I have to add an attribute <code>eleventy:ignore</code> to the image shortcode:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">import</span> eleventyImage <span class=\"token keyword\">from</span> <span class=\"token string\">\"@11ty/eleventy-img\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token comment\">// Only one module.exports per configuration file, please!</span>\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">eleventyConfig</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  eleventyConfig<span class=\"token punctuation\">.</span><span class=\"token function\">addShortcode</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"image\"</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">async</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">src<span class=\"token punctuation\">,</span> alt<span class=\"token punctuation\">,</span> sizes</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// ...</span>\n    <span class=\"token keyword\">let</span> imageAttributes <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n      alt<span class=\"token punctuation\">,</span>\n      sizes<span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"eleventy:ignore\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">loading</span><span class=\"token operator\">:</span> <span class=\"token string\">\"lazy\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token literal-property property\">decoding</span><span class=\"token operator\">:</span> <span class=\"token string\">\"async\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// ...</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<p>And as result it works perfectly fine, but I want to replace most of shortcodes to regular <code>&lt;img&gt;</code> tags, and I did it.</p>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/upgrading-to-eleventy-v3/#conclusion\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>If your project is similar than mine then you can prepare your project to migrate to ESM syntax now, before Eleventy v3 will be released.</p>\n<p>Or if you like me, who like to use latest technology in web development, do that a soon as you can.</p>\n",
			"date_published": "2024-06-23T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/custom-user-avatars-for-wordpress/",
			"url": "https://alex.zappa.dev/blog/custom-user-avatars-for-wordpress/",
			"title": "Custom user avatars for WordPress",
			"content_html": "<p>WordPress is a powerful platform that allows you to create and manage a wide variety of websites. One of the key\nfeatures of WordPress is its user management system, which allows you to create user accounts and assign different roles\nand permissions to each user.</p>\n<p>By default, WordPress uses Gravatar to display user avatars, but you may want to add custom avatar functionality to your\nsite to make it more attractive to users, or maybe you want to give users the option to upload their own avatar images.\nOr maybe the author no have access to Gravatar anymore...</p>\n<p>In this blog post, I want to share with you a simple and quick solution to add custom avatar functionality to your WordPress.</p>\n<h2 id=\"advanced-custom-fields\" tabindex=\"-1\">Advanced custom fields <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/custom-user-avatars-for-wordpress/#advanced-custom-fields\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>To add custom avatar functionality to your WordPress site, we will use the Advanced Custom Fields (ACF) plugin. ACF is a powerful plugin that allows you to create custom fields for posts, pages, and users.</p>\n<p>First, you need to install and activate the Advanced Custom Fields plugin on your WordPress site. Once you have installed the plugin, you can add a code snippet to your theme's <code>functions.php</code> file to create a custom field for user avatars. See the code snippet below:</p>\n<pre class=\"language-php\" tabindex=\"0\"><code class=\"language-php\"><span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token function\">class_exists</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'ACF'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token function\">add_action</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'acf/include_fields'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token function\">function_exists</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'acf_add_local_field_group'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n\n        <span class=\"token function\">acf_add_local_field_group</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span>\n            <span class=\"token string single-quoted-string\">'key'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'user_extra_options'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'title'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'User Extra Options'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'fields'</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span>\n                <span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span>\n                    <span class=\"token string single-quoted-string\">'key'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'user_extra_options__custom_gravatar'</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'label'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'Custom Gravatar'</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'name'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'custom_gravatar'</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'aria-label'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'type'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'image'</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'instructions'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'required'</span> <span class=\"token operator\">=></span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'conditional_logic'</span> <span class=\"token operator\">=></span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'wrapper'</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span>\n                        <span class=\"token string single-quoted-string\">'width'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token string single-quoted-string\">'class'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token string single-quoted-string\">'id'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'return_format'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'id'</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'library'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'all'</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'min_width'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'min_height'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'min_size'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'max_width'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'max_height'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'max_size'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'mime_types'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token string single-quoted-string\">'preview_size'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'thumbnail'</span><span class=\"token punctuation\">,</span>\n                <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'location'</span> <span class=\"token operator\">=></span> <span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span>\n                <span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span>\n                    <span class=\"token keyword\">array</span><span class=\"token punctuation\">(</span>\n                        <span class=\"token string single-quoted-string\">'param'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'user_form'</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token string single-quoted-string\">'operator'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'=='</span><span class=\"token punctuation\">,</span>\n                        <span class=\"token string single-quoted-string\">'value'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'all'</span><span class=\"token punctuation\">,</span>\n                    <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n                <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'menu_order'</span> <span class=\"token operator\">=></span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'position'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'normal'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'style'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'default'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'label_placement'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'top'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'instruction_placement'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'label'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'hide_on_screen'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'active'</span> <span class=\"token operator\">=></span> <span class=\"token constant boolean\">true</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'description'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">''</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'show_in_rest'</span> <span class=\"token operator\">=></span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n    <span class=\"token keyword\">function</span> <span class=\"token function-definition function\">sunnypixels_custom_avatar</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$avatar</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$size</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$default</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$alt</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$args</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token variable\">$id</span> <span class=\"token operator\">=</span> <span class=\"token function\">sunnypixels_get_user_id</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token variable\">$id</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">return</span> <span class=\"token variable\">$avatar</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token variable\">$custom_avatar</span> <span class=\"token operator\">=</span> <span class=\"token function\">get_user_meta</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$id</span><span class=\"token punctuation\">,</span> <span class=\"token string single-quoted-string\">'custom_gravatar'</span><span class=\"token punctuation\">,</span> <span class=\"token constant boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token variable\">$custom_avatar</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token variable\">$custom_avatar</span> <span class=\"token operator\">=</span> <span class=\"token function\">wp_get_attachment_image_src</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$custom_avatar</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n            <span class=\"token variable\">$avatar</span> <span class=\"token operator\">=</span> <span class=\"token string double-quoted-string\">\"&lt;img alt='<span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token variable\">$alt</span><span class=\"token punctuation\">}</span></span>' src='<span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token variable\">$custom_avatar</span><span class=\"token punctuation\">}</span></span>' class='avatar avatar-<span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token variable\">$size</span><span class=\"token punctuation\">}</span></span> photo' height='<span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token variable\">$size</span><span class=\"token punctuation\">}</span></span>' width='<span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token variable\">$size</span><span class=\"token punctuation\">}</span></span>' <span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token variable\">$args</span><span class=\"token punctuation\">[</span><span class=\"token string single-quoted-string\">'extra_attr'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">}</span></span> />\"</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n\n        <span class=\"token keyword\">return</span> <span class=\"token variable\">$avatar</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">function</span> <span class=\"token function-definition function\">sunnypixels_custom_avatar_url</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$url</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$args</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token variable\">$id</span> <span class=\"token operator\">=</span> <span class=\"token function\">sunnypixels_get_user_id</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span><span class=\"token variable\">$id</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">return</span> <span class=\"token variable\">$url</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token variable\">$custom_avatar</span> <span class=\"token operator\">=</span> <span class=\"token function\">get_user_meta</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$id</span><span class=\"token punctuation\">,</span> <span class=\"token string single-quoted-string\">'custom_gravatar'</span><span class=\"token punctuation\">,</span> <span class=\"token constant boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token variable\">$custom_avatar</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token variable\">$custom_avatar</span> <span class=\"token operator\">=</span> <span class=\"token function\">wp_get_attachment_image_src</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$custom_avatar</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n            <span class=\"token variable\">$url</span> <span class=\"token operator\">=</span> <span class=\"token variable\">$custom_avatar</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n\n        <span class=\"token keyword\">return</span> <span class=\"token variable\">$url</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token keyword\">function</span> <span class=\"token function-definition function\">sunnypixels_get_user_id</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token function\">is_numeric</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">return</span> <span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token function\">is_object</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">return</span> <span class=\"token variable\">$id_or_email</span><span class=\"token operator\">-></span><span class=\"token property\">user_id</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token function\">is_string</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">return</span> <span class=\"token function\">get_user_by</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'email'</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">?</span> <span class=\"token function\">get_user_by</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'email'</span><span class=\"token punctuation\">,</span> <span class=\"token variable\">$id_or_email</span><span class=\"token punctuation\">)</span><span class=\"token operator\">-></span><span class=\"token constant\">ID</span> <span class=\"token punctuation\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n\n        <span class=\"token keyword\">return</span> <span class=\"token number\">0</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n\n    <span class=\"token function\">add_filter</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'get_avatar'</span><span class=\"token punctuation\">,</span> <span class=\"token string single-quoted-string\">'sunnypixels_custom_avatar'</span><span class=\"token punctuation\">,</span> <span class=\"token number\">100500</span><span class=\"token punctuation\">,</span> <span class=\"token number\">6</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">add_filter</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'get_avatar_url'</span><span class=\"token punctuation\">,</span> <span class=\"token string single-quoted-string\">'sunnypixels_custom_avatar_url'</span><span class=\"token punctuation\">,</span> <span class=\"token number\">100500</span><span class=\"token punctuation\">,</span> <span class=\"token number\">3</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n\n    <span class=\"token function\">add_action</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'admin_notices'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token keyword\">echo</span> <span class=\"token string single-quoted-string\">'&lt;div class=\"notice notice-warning is-dismissible\">&lt;p>Advanced Custom Fields plugin is required for Custom Gravatar functionality.&lt;/p>&lt;/div>'</span><span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token punctuation\">}</span></code></pre>\n<p>You can find copy of <a href=\"https://gist.github.com/reatlat/a84798425b45ad4f18f2b5be9e13a3ff\">this snippet here</a>.</p>\n<p>The result of this code snippet is a new field in the user profile page, where users can upload their custom avatar images. The custom avatar images will be displayed instead of the Gravatar images on the site.</p>\n<img src=\"https://alex.zappa.dev/blog/custom-user-avatars-for-wordpress/assets/wp-custom-gravatar-dashboard.jpeg\" alt=\"Custom Gravatar Field in User Profile\" eleventy:widths=\"320\">\n<h2 id=\"alternative-solutions\" tabindex=\"-1\">Alternative solutions <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/custom-user-avatars-for-wordpress/#alternative-solutions\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>if you don't want to edit your WordPress theme, you can use a plugin variation of this solution, I coded for you. You can find it <a href=\"https://github.com/sunnypixels-io/wp-custom-gravatar\">here</a>.</p>\n<p>I hope this blog post helps you add custom avatar functionality to your WordPress site. If you like this plugin, please consider to give it a star on GitHub.</p>\n",
			"date_published": "2024-04-09T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/",
			"url": "https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/",
			"title": "How to use structured data (schema markup) in HubSpot to improve SEO",
			"content_html": "<p>Structured data, also known as schema markup, is an important tool that can significantly improve your website's search\nengine optimization (SEO). By implementing schema markup in HubSpot, you can provide search engines with valuable\ninformation about your content, helping them to better understand and display your website in search results. In this\nblog post, we will explore the benefits of using structured data and provide you a code snippets which you can use to\nimplement schema markup in HubSpot.</p>\n<h2 id=\"what-is-structured-data\" tabindex=\"-1\">What is structured data? <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#what-is-structured-data\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>There are many different types of schemas available on <a href=\"https://schema.org/\">Schema.org</a>, with over 760 listed.\nSchema.org is a website created by Bing, Google, and Yahoo to provide a common set of schemas for structured data. It\ncan be overwhelming for first-time readers to decide which schema to use. However, Google provides a helpful breakdown\nof specific schemas that can be used for their rich results. These schemas are listed on\ntheir <a href=\"https://developers.google.com/search/docs/appearance/structured-data/search-gallery\">search gallery documentation</a>.\nIn this case, we will focus on the Article structured data type, which is commonly used for news, sports, or blog\narticles. It allows for features like a Top stories carousel, headline text, and larger-than-thumbnail images.</p>\n<h2 id=\"the-benefits-of-using-structured-data\" tabindex=\"-1\">The benefits of using structured data <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#the-benefits-of-using-structured-data\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Using structured data in HubSpot offers several advantages for your website's SEO. First and foremost, it helps search\nengines understand the semantics of your content, enabling them to display rich snippets in search results. These\nsnippets provide users with more detailed and visually appealing information about your website, increasing the\nlikelihood of attracting clicks. Additionally, structured data helps search engines categorize your content more\naccurately, improving its visibility to relevant audiences and increasing organic traffic to your website.</p>\n<h2 id=\"implementing-structured-data-in-hubspot\" tabindex=\"-1\">Implementing structured data in HubSpot <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#implementing-structured-data-in-hubspot\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>To start implementing structured data in HubSpot, you first need to identify the content elements that would benefit\nfrom schema markup. This could include blog posts, product pages, events, and more. Once you have identified the\nrelevant content, you can proceed with adding schema markup to your HubSpot templates. HubSpot provides a user-friendly\ninterface that allows you to easily edit your templates, insert schema markup, and preview the changes. Be sure to\nvalidate your schema markup\nusing <a href=\"https://developers.google.com/search/docs/appearance/structured-data\">Google's Structured Data Testing Tool</a> to\nensure it is implemented correctly.</p>\n<h3 id=\"template-vs-module-implementations-for-structured-data-in-hubspot\" tabindex=\"-1\">Template vs module implementations for structured data in HubSpot <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#template-vs-module-implementations-for-structured-data-in-hubspot\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>When deciding how to implement your structured data in HubSpot, there are two options to consider. It's important to\nchoose the option that suits your needs best.</p>\n<h4 id=\"option-1-adding-code-at-the-template-level\" tabindex=\"-1\">Option 1: adding code at the template level <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#option-1-adding-code-at-the-template-level\">#<span class=\"sr-only\"> Anchor link </span></a></h4>\n<p>This option involves adding the code at the template level. It works well when you have a single schema that applies\nconsistently to your content. For example, if you have a blog that only contains news articles, you can simply include\nthe Article schema in the template. In this case, your content editor doesn't need to worry about adding any additional\ninformation.</p>\n<h4 id=\"option-2-creating-a-module\" tabindex=\"-1\">Option 2: creating a module <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#option-2-creating-a-module\">#<span class=\"sr-only\"> Anchor link </span></a></h4>\n<p>The second option is to create a custom module, either Local or Global, to use on pages or blogs. This method is ideal\nwhen you have multiple schema types (such as Article, Event, JobPosting, etc.) that you want to implement within your\nblog. You can offer options for the content editor to choose from when publishing each piece of content.</p>\n<h2 id=\"lets-do-some-coding\" tabindex=\"-1\">Let's do some coding <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#lets-do-some-coding\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>BlogPosting schema example:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>application/ld+json<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"><span class=\"token language-javascript\">\n<span class=\"token punctuation\">{</span>\n  <span class=\"token string-property property\">\"@context\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://schema.org\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string-property property\">\"@type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"BlogPosting\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string-property property\">\"mainEntityOfPage\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string-property property\">\"@type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"WebPage\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string-property property\">\"@id\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.absolute_url}}\"</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string-property property\">\"headline\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.title}}\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">{</span><span class=\"token operator\">%</span><span class=\"token operator\">-</span> <span class=\"token keyword\">if</span> content<span class=\"token punctuation\">.</span>use_featured_image <span class=\"token operator\">-</span><span class=\"token operator\">%</span><span class=\"token punctuation\">}</span>\n  <span class=\"token string-property property\">\"image\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token string\">\"{{content.featured_image}}\"</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">{</span><span class=\"token operator\">%</span><span class=\"token operator\">-</span> endif <span class=\"token operator\">-</span><span class=\"token operator\">%</span><span class=\"token punctuation\">}</span>\n  <span class=\"token string-property property\">\"datePublished\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.publish_date|datetimeformat('%Y-%m-%dT%H:%M:%S')}}\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string-property property\">\"dateModified\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.updated|datetimeformat('%Y-%m-%dT%H:%M:%S')}}\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string-property property\">\"author\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string-property property\">\"@type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Person\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string-property property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.blog_post_author.full_name}}\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string-property property\">\"url\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.parent_blog.root_url}}/author/{{content.blog_post_author.slug}}\"</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n   <span class=\"token string-property property\">\"publisher\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token string-property property\">\"@type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Organization\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string-property property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{site_settings.company_name or brand_settings.primaryLogo.name or 'Company Name'}}\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string-property property\">\"logo\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token string-property property\">\"@type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"ImageObject\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"url\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{brand_settings.primaryLogo.src}}\"</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string-property property\">\"description\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.meta_description|striptags|safe|truncate(160, True, '')}}\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string-property property\">\"url\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.absolute_url or request.full_url}}\"</span>\n<span class=\"token punctuation\">}</span>\n</span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>BreadcrumbList schema example:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">type</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>application/ld+json<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"><span class=\"token language-javascript\">\n<span class=\"token punctuation\">{</span>\n  <span class=\"token string-property property\">\"@context\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"https://schema.org\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string-property property\">\"@type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"BreadcrumbList\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token string-property property\">\"itemListElement\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token string-property property\">\"@type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"ListItem\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"position\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Home\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"item\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{site_settings.company_url}}\"</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token string-property property\">\"@type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"ListItem\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"position\"</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Blog\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"item\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.parent_blog.root_url}}\"</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">{</span>\n      <span class=\"token string-property property\">\"@type\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"ListItem\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"position\"</span><span class=\"token operator\">:</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"name\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.title}}\"</span><span class=\"token punctuation\">,</span>\n      <span class=\"token string-property property\">\"item\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"{{content.absolute_url}}\"</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">]</span>\n<span class=\"token punctuation\">}</span>\n</span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<h2 id=\"tools-to-help-you-implement-structured-data-in-hubspot\" tabindex=\"-1\">Tools to help you implement structured data in HubSpot <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#tools-to-help-you-implement-structured-data-in-hubspot\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>There are several tools available to help you implement structured data in HubSpot. One of the most popular tools is:</p>\n<ul>\n<li><a href=\"https://www.schemaapp.com/\">Schema App</a>, which offers a free trial and paid plans. Schema App allows you to easily</li>\n<li><a href=\"https://jsonld.com/\">JSON-LD</a>, which is a free tool that allows you to generate JSON-LD code for your website. It\nalso provides a helpful guide on how to implement structured data in HubSpot.</li>\n<li><a href=\"https://developers.google.com/search/docs/appearance/structured-data\">Google's Structured Data Testing Tool</a>, which\nallows you to validate your schema markup and preview how it will appear in search results.</li>\n<li><a href=\"https://search.google.com/test/rich-results\">Google's Rich Results Test</a>, which allows you to test your schema\nmarkup and preview how it will appear in search results.</li>\n<li><a href=\"https://developers.google.com/search/docs/appearance/structured-data/search-gallery\">Google's Search Gallery</a>, which\nprovides a list of schemas that can be used to enhance your website's search results.</li>\n<li><a href=\"https://www.google.com/webmasters/markup-helper/\">Google's Structured Data Markup Helper</a>, which allows you to\ngenerate structured data markup for your website.</li>\n<li><a href=\"https://technicalseo.com/tools/schema-markup-generator/\">TechnicalSEO.com's Schema Markup Generator</a>, which allows\nyou to generate structured data markup for your website.</li>\n<li><a href=\"https://schema.org/\">Schema.org</a>, which provides a list of schemas that can be used to enhance your website's search\nresults.</li>\n</ul>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#conclusion\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>In conclusion, incorporating structured data in HubSpot is a powerful tactic to enhance your website's SEO. By providing\nsearch engines with more information about your content, you can improve its visibility, attract more organic traffic,\nand enhance the user experience. Don't overlook the importance of schema markup in your SEO strategy. Implement it in\nyour HubSpot templates today and reap the benefits of higher search rankings and increased website traffic. Stay Ahead\nof the competition and make the most out of your HubSpot platform by leveraging the power of structured data.</p>\n<h2 id=\"updated-feb-17-2024\" tabindex=\"-1\">Updated (Feb 17, 2024) <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-use-structured-data-schema-markup-in-hubspot-to-improve-seo/#updated-feb-17-2024\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>I just found out that HubSpot has released <a href=\"https://community.hubspot.com/t5/Releases-and-Updates/Now-live-Setting-to-apply-BlogPosting-JSON-LD-schema-to-blog/ba-p/645867\">Structured Data (Beta)</a> and it works really well.\nI'm still think homebrewed solution is better, but it's good to know that HubSpot is moving in the right direction.</p>\n",
			"date_published": "2024-01-07T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/the-best-free-image-placeholder-for-quick-and-easy-content-mockups/",
			"url": "https://alex.zappa.dev/blog/the-best-free-image-placeholder-for-quick-and-easy-content-mockups/",
			"title": "The best free image placeholder for quick and easy content mockups",
			"content_html": "<p>One of the challenges content creators face is finding high-quality, visually appealing images to enhance their articles\nor blog posts. However, it can be time-consuming and expensive to source these images from stock photo sites.\nThankfully, there are free image placeholders available that can quickly and easily serve as temporary replacements\nuntil the final images are obtained. In this blog post, we will explore the best free image placeholders to assist\ncontent creators in their quest for captivating visual content.</p>\n<h2 id=\"the-placehold-co-experience\" tabindex=\"-1\">The Placehold.co experience <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/the-best-free-image-placeholder-for-quick-and-easy-content-mockups/#the-placehold-co-experience\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>One popular option for a free image placeholder is <a href=\"https://placehold.co/\">Placehold.co</a>. This platform offers a simple\nand user-friendly interface that enables users to generate image placeholders of custom sizes simply by modifying the\nURL. With Placehold.co, content creators can specify the width, height, background color, text color, and even add\ncustom text to their placeholders. This versatility makes it a valuable tool for quick and easy content mockups.</p>\n<p>See the example below:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://placehold.co/320x150?text=320x150\\nhttps:/placehold.co/<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">alt</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Placeholder Image<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span></code></pre>\n<img src=\"https://placehold.co/320x150?text=320x150%5Cnhttps%3A%2Fplacehold.co%2F\" alt=\"Placeholder Image\" width=\"320\" height=\"150\" eleventy:ignore=\"\">\n<h2 id=\"lorem-picsum-a-k-a-unsplash-it\" tabindex=\"-1\">Lorem Picsum a.k.a. Unsplash it <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/the-best-free-image-placeholder-for-quick-and-easy-content-mockups/#lorem-picsum-a-k-a-unsplash-it\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Another excellent choice for free image placeholders is <a href=\"https://picsum.photos/\">Lorem Picsum</a>(formerly known as\nUnsplash It). This platform provides high-quality placeholder images sourced from Unsplash, a popular stock photography\nplatform. Users can specify the size, category, and even apply filters to match their desired aesthetic. These\nplaceholders can be easily downloaded, allowing content creators to populate their drafts with visually pleasing images\nbefore acquiring the final ones.</p>\n<p>See the example below:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://unsplash.it/320/150?image=57<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">alt</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Placeholder Image<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span></code></pre>\n<img src=\"https://unsplash.it/320/150?image=57\" alt=\"Placeholder Image\" width=\"320\" height=\"150\" eleventy:ignore=\"\">\n<h2 id=\"unsplash-source-api\" tabindex=\"-1\">Unsplash Source API <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/the-best-free-image-placeholder-for-quick-and-easy-content-mockups/#unsplash-source-api\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p><strong>Updated: Temporary broken or finally deprecated, please check the <a href=\"https://unsplash.com/developers\">Unsplash Source API</a></strong></p>\n<p><a href=\"https://unsplash.com/developers\">Unsplash Source</a> is another free image placeholder that offers a wide selection of\nplaceholder images from <a href=\"https://unsplash.com/\">Unsplash</a>. Users can specify the size, category, and even apply filters\nto match their desired aesthetic. Additionally, Unsplash Source provides options to customize the background color, text\noverlay, and even add a logo. With its comprehensive database and customizability, Unsplash Source is a reliable choice\nfor content creators in need of high-quality placeholder images.</p>\n<p>See the example below:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://source.unsplash.com/320x150/?funny+cat<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">alt</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Placeholder Image<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span></code></pre>\n<h2 id=\"pixabay-fillers\" tabindex=\"-1\">Pixabay fillers <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/the-best-free-image-placeholder-for-quick-and-easy-content-mockups/#pixabay-fillers\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p><a href=\"https://pixabay.com/service/about/api/\">Pixabay Fillers</a> is a free image placeholder that offers a wide selection of\nplaceholder images from <a href=\"https://pixabay.com/\">Pixabay</a>. Users can specify the size, category, and even apply filters\nto match their desired aesthetic. Additionally, Pixabay Fillers provides options to customize the background color, text\noverlay, and even add a logo. With its comprehensive database and customizability, Pixabay Fillers is a reliable choice\nfor content creators in need of high-quality placeholder images.</p>\n<p>See the example below:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://cdn.pixabay.com/video/2015/08/08/125-135736646_small.jpg<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">alt</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>Placeholder Image<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span></code></pre>\n<img src=\"https://cdn.pixabay.com/video/2015/08/08/125-135736646_small.jpg\" alt=\"Placeholder Image\" width=\"320\" height=\"150\" eleventy:ignore=\"\">\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/the-best-free-image-placeholder-for-quick-and-easy-content-mockups/#conclusion\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>As content creators, incorporating captivating visuals into our articles and blog posts is crucial for engaging our\nreaders. However, finding the perfect images can be a time-consuming and expensive process. Fortunately, free image\nplaceholders like Placehold.co, Lorem Picsum, Unsplash, and Pixabay Fillers offer convenient solutions for quick and\neasy content mockups. Whether it's generating customizable image placeholders, accessing high-quality stock photos, or\nadding personal touches, these tools provide the necessary resources to enhance our content creation workflow. By\nutilizing these free image placeholders, content creators can streamline their process and focus on delivering engaging\nand visually stunning content to their audience.</p>\n<p>My favorite is <a href=\"https://unsplash.com/developers\">Unspalsh Source API</a>, what's yours?</p>\n",
			"date_published": "2023-08-20T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/migrating-from-wordpress-to-11ty-enhancing-website-performance-and-control/",
			"url": "https://alex.zappa.dev/blog/migrating-from-wordpress-to-11ty-enhancing-website-performance-and-control/",
			"title": "Migrating from WordPress to 11ty: enhancing website performance and control",
			"content_html": "<p>Hey there, lovely readers! Today, I am absolutely thrilled to share with you my very first blog post on my newly\nmigrated website! After careful consideration and research, I decided to move away from WordPress and embrace the world\nof static website generation with 11ty. This decision was driven by my desire for simplicity, performance, and increased\ncontrol over my website. In this post, I will dive into the reasons behind my migration, the benefits of using 11ty, and\nmy initial thoughts on this exciting new journey. So, grab a cup of coffee and let's get started!</p>\n<h2 id=\"why-i-switched-from-wordpress-to-11ty-enhancing-performance-and-simplifying-maintenance\" tabindex=\"-1\">Why I switched from WordPress to 11ty: enhancing performance and simplifying maintenance <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/migrating-from-wordpress-to-11ty-enhancing-website-performance-and-control/#why-i-switched-from-wordpress-to-11ty-enhancing-performance-and-simplifying-maintenance\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>When I embarked on my blogging journey, I experimented with various platforms including Blogger, WordPress, Jekyll, and\nGhost. Initially, WordPress seemed like the obvious choice with its user-friendly interface, extensive plugin options,\nand vibrant community. However, over time, I began to encounter some limitations. WordPress felt bloated, resulting in\nsluggish website loading times, and the constant plugin updates became tiresome. It was then that I came across 11ty and\nthe concept of static website generation, which intrigued me with its promise of swift loading times and streamlined\nupkeep. The idea of having complete control over my website's codebase and including only what I truly needed greatly\nappealed to me. Thus, the decision to switch to 11ty was born.</p>\n<h2 id=\"the-benefits-of-using-11ty\" tabindex=\"-1\">The benefits of using 11ty <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/migrating-from-wordpress-to-11ty-enhancing-website-performance-and-control/#the-benefits-of-using-11ty\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Now that I have migrated my website, I can already see some major benefits of using 11ty. Firstly, the performance gains\nare remarkable. With static website generation, there is no need for server-side processing or database queries,\nresulting in lightning-fast loading times. This not only enhances the user experience but also improves search engine\noptimization. Secondly, the simplicity of 11ty is a refreshing change. The configuration is straightforward, the\ntemplating language is intuitive, and the documentation is extensive. I feel more confident and in control of my website\nthan ever before. Lastly, the ability to version control my website's codebase using Git is invaluable. I can easily\ntrack changes, collaborate with others, and revert back to a previous version if needed.</p>\n<img src=\"https://alex.zappa.dev/blog/migrating-from-wordpress-to-11ty-enhancing-website-performance-and-control/assets/pagespeed-report.png\" alt=\"Google PageSpeed Insights Report\" eleventy:widths=\"500\">\n<h2 id=\"my-initial-thoughts-and-observations\" tabindex=\"-1\">My initial thoughts and observations <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/migrating-from-wordpress-to-11ty-enhancing-website-performance-and-control/#my-initial-thoughts-and-observations\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>As with any new venture, there is a learning curve that comes with using 11ty. However, I must say that the transition\nhas been relatively smooth. The initial setup was a breeze, thanks to the excellent documentation provided by the 11ty\ncommunity. Migrating my old blog posts to the new platform was a bit time-consuming, but it allowed me to revisit my\ncontent and update it along the way. One of the things that excites me the most about 11ty is the flexibility it offers.\nWhether I want to create a simple blog, a full-fledged e-commerce site, or a documentation portal, 11ty can accommodate\nall my needs. I am eager to dive deeper into its features and explore the endless possibilities it presents.</p>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/migrating-from-wordpress-to-11ty-enhancing-website-performance-and-control/#conclusion\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>In conclusion, the decision to migrate my website from WordPress to 11ty has been one of the best I have made for my\nonline presence. The performance gains, simplicity, and control over my website have exceeded my expectations. Even\nthough there was a learning curve, the transition has been smooth, and I am excited to continue the journey with 11ty. I\nhighly recommend considering static website generation with 11ty if you are looking to enhance your website's\nperformance and take control of your online presence.</p>\n<h2 id=\"future-plans-enhancing-navigation-adding-search-functionality-and-implementing-a-twitter-based-comment-system\" tabindex=\"-1\">Future plans: enhancing navigation, adding search functionality, and implementing a Twitter-based comment system <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/migrating-from-wordpress-to-11ty-enhancing-website-performance-and-control/#future-plans-enhancing-navigation-adding-search-functionality-and-implementing-a-twitter-based-comment-system\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>As I look Ahead to the future, I am excited to outline my plans for further improving my website. I have identified a\nfew key areas that I intend to focus on for future updates:</p>\n<ol>\n<li>Navigation Bar and Footer Navigation: To enhance the user experience and make it easier for visitors to navigate through\nmy website, I plan to update both the main navigation bar and the footer navigation. This will involve streamlining the\nmenu structure, improving accessibility, and ensuring a seamless browsing experience across different devices.</li>\n<li>Search Page: One of my top priorities is to implement a search functionality on my website. By incorporating a search\npage, users will be able to easily find specific content or topics of interest. This will not only save time for users\nbut also improve the overall usability and accessibility of the site.</li>\n<li>Twitter-based Comment System: I am excited to leverage the power of social media and introduce a comment system based on\nTwitter threads. This approach will not only provide a familiar and user-friendly commenting experience but also\nencourage discussions and engagement from a wider audience. By integrating Twitter threads, users will be able to share\ntheir thoughts, ask questions, and interact with others, creating a dynamic and interactive platform.</li>\n</ol>\n<p>These planned updates reflect my commitment to continuously improving my website and providing an exceptional user\nexperience. I believe that by focusing on navigation enhancements, implementing a search page, and incorporating a\nTwitter-based comment system, I will be able to create a more engaging and content-rich environment for my visitors.\nStay tuned for more blog posts where I will be sharing tips, tricks, and insights on using 11ty to its full potential.\nUntil next time, happy coding!</p>\n",
			"date_published": "2023-08-13T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/how-to-change-app-store-preferred-language-2022/",
			"url": "https://alex.zappa.dev/blog/how-to-change-app-store-preferred-language-2022/",
			"title": "How to change App Store preferred Language 2022",
			"content_html": "<p>My wife has issue with AppStore on MacBook, her account, and iPhone was set up in English but for some reason AppStore\non macOS have been in Spanish.</p>\n<img src=\"https://alex.zappa.dev/blog/how-to-change-app-store-preferred-language-2022/assets/appstore-esp.png\" alt=\"App Store in Spanish\" eleventy:widths=\"700\">\n<p>In internet, you can find numerous instructions how to change language of your account and AppStore. Some of them live\non Apple Support pages, but no one solution works for me, and according to google requests, looks like I’m not the only\none who has this issue.</p>\n<p>As AppleCare+ holder I decided to ask Apple advisors about my issue by email first, with no good answer 🙁</p>\n<p>Later I try to contact Apple Support via chat, and there are a couple of funny stories… So far, I would like to say,\nApple Advisors are the most friendly and skilled support ever! But even they, couldn’t help me 🙁</p>\n<p>First I got connected to Super Advisor who tried to help me, but the chat looks like freez.. Or he made it looks like\nfreeze :/</p>\n<p>Anyway, second time I got connection with very friendly guy who try to debug a problem and ask me to try alternatives.</p>\n<p>No one of their solutions don’t want to solve my issue, we have tried to remove VPNs, remove LittleSnitch Firewall,\nreset settings, check Apple ID, brake SMC settings 🙂 Nothing helps, and he decides to schedule a phone call with super\nAdvisor 🙂</p>\n<p>Long story short… after all manipulations I made, and taking short coffee break, I found a simple solution!</p>\n<p>The App Store on macOS its an webpage AppView, and language of AppStore based on geoIP location, so if you based in\nSpain like I am and you log in to appStore, the language will be set to Spanish.</p>\n<p>Even your account set up to English, so based on my discovery I set my VPN to UK location, logout from AppStore, force\nclose it, and open again, first it was in Spanish again, but after I login to my Apple ID, AppStore become to English!!!</p>\n<img src=\"https://alex.zappa.dev/blog/how-to-change-app-store-preferred-language-2022/assets/appstore-eng.png\" alt=\"App Store in English\" eleventy:widths=\"700\">\n<p>Later I turn VPN off and restart my mac to see if AppStore change language, but its not, from now my AppStore are always\nin English.</p>\n<p>This is it, solution was super simple, but nobody, even Apple Support have no idea about this glitch.</p>\n",
			"date_published": "2022-01-21T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/my-favorite-css-hacks/",
			"url": "https://alex.zappa.dev/blog/my-favorite-css-hacks/",
			"title": "My favorite CSS hacks",
			"content_html": "<p>As it is with every coding language, there are several shortcuts or hacks with CSS that allow you to write cleaner code, improve design elements, and save valuable time. Furthermore, you can directly insert these snippets to your site using a code editor. And here is my favorite CSS Hacks.</p>\n<h2 id=\"inherit-box-sizing\" tabindex=\"-1\">Inherit box sizing <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#inherit-box-sizing\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>The border-box tells the browser to account for any border and padding in the values you specify for an element’s width and height.</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">html</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token property\">box-sizing</span><span class=\"token punctuation\">:</span> border-box<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n<span class=\"token selector\">*, *:before, *:after</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token property\">box-sizing</span><span class=\"token punctuation\">:</span> inherit<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p><video class=\"dark:invert mx-auto rounded shadow-lg\" width=\"700\" height=\"380\" autoplay=\"\" muted=\"\" playsinline=\"\" loop=\"\" src=\"https://alex.zappa.dev/video/mdn-css-demo-box-sizing.71b5c688.mp4\"></video></p>\n<p><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing\" rel=\"noreferrer noopener nofollow\">MDN CSS Demo – box-sizing</a></p>\n<h2 id=\"selection-pseudo-class\" tabindex=\"-1\">Selection pseudo class <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#selection-pseudo-class\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Use selection pseudo-class to give a personal touch to text selection on your websites.</p>\n<codepen-embed class=\"codepen-embed select-none relative rounded drop-shadow-lg dark:drop-shadow-none border border-solid dark:border-zinc-700 block\" style=\"min-height:300px\">\n<div class=\"codepen-consent absolute inset-0 flex flex-col items-center justify-center gap-4 bg-stone-100 dark:bg-stone-800 rounded p-4 z-10\">\n<p class=\"text-center text-sm text-stone-600 dark:text-stone-400 mb-4\">Loading this CodePen will set third-party cookies from codepen.io</p>\n<label class=\"flex items-center gap-2 text-sm text-stone-600 dark:text-stone-400 cursor-pointer\"><input type=\"checkbox\" class=\"codepen-remember accent-stone-800 dark:accent-stone-200 w-4 h-4\">Always load CodePen</label>\n<button type=\"button\" class=\"codepen-load-btn inline-flex items-center justify-center px-6 py-3 bg-stone-800 dark:bg-stone-100 text-white dark:text-stone-900 rounded-lg hover:bg-stone-700 dark:hover:bg-stone-200 active:scale-95 transition-all font-semibold shadow-lg hover:shadow-xl border-2 border-stone-900 dark:border-stone-300\">Load CodePen</button>\n<a href=\"https://codepen.io/reatlat/pen/ZEXzqgE\" target=\"_blank\" rel=\"noopener\" class=\"mt-6 text-xs text-stone-600 hover:text-stone-800 dark:text-stone-400 dark:hover:text-stone-200 underline\">Open on CodePen instead</a>\n</div>\n<p class=\"codepen-pending hidden rounded p-4\" data-height=\"300\" data-theme-id=\"1\" data-default-tab=\"css,result\" data-slug-hash=\"ZEXzqgE\" data-user=\"reatlat\" style=\"height:300px\"><span>See the Pen on <a href=\"https://codepen.io/reatlat/pen/ZEXzqgE\">CodePen</a>.</span></p>\n</codepen-embed>\n<h2 id=\"input-caret-color\" tabindex=\"-1\">Input Caret Color <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#input-caret-color\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Set the color of the cursor in input elements.</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">input, textarea</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token property\">caret-color</span><span class=\"token punctuation\">:</span> #ff0000<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<codepen-embed class=\"codepen-embed select-none relative rounded drop-shadow-lg dark:drop-shadow-none border border-solid dark:border-zinc-700 block\" style=\"min-height:300px\">\n<div class=\"codepen-consent absolute inset-0 flex flex-col items-center justify-center gap-4 bg-stone-100 dark:bg-stone-800 rounded p-4 z-10\">\n<p class=\"text-center text-sm text-stone-600 dark:text-stone-400 mb-4\">Loading this CodePen will set third-party cookies from codepen.io</p>\n<label class=\"flex items-center gap-2 text-sm text-stone-600 dark:text-stone-400 cursor-pointer\"><input type=\"checkbox\" class=\"codepen-remember accent-stone-800 dark:accent-stone-200 w-4 h-4\">Always load CodePen</label>\n<button type=\"button\" class=\"codepen-load-btn inline-flex items-center justify-center px-6 py-3 bg-stone-800 dark:bg-stone-100 text-white dark:text-stone-900 rounded-lg hover:bg-stone-700 dark:hover:bg-stone-200 active:scale-95 transition-all font-semibold shadow-lg hover:shadow-xl border-2 border-stone-900 dark:border-stone-300\">Load CodePen</button>\n<a href=\"https://codepen.io/reatlat/pen/poWzQzX\" target=\"_blank\" rel=\"noopener\" class=\"mt-6 text-xs text-stone-600 hover:text-stone-800 dark:text-stone-400 dark:hover:text-stone-200 underline\">Open on CodePen instead</a>\n</div>\n<p class=\"codepen-pending hidden rounded p-4\" data-height=\"300\" data-theme-id=\"1\" data-default-tab=\"css,result\" data-slug-hash=\"poWzQzX\" data-user=\"reatlat\" style=\"height:300px\"><span>See the Pen on <a href=\"https://codepen.io/reatlat/pen/poWzQzX\">CodePen</a>.</span></p>\n</codepen-embed>\n<h2 id=\"no-value-no-problem\" tabindex=\"-1\">No value, No problem <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#no-value-no-problem\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Display links when the element has no text value, but the attribute has a link.</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">a[href^=\"http\"]:empty::before</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">content</span><span class=\"token punctuation\">:</span> <span class=\"token function\">attr</span><span class=\"token punctuation\">(</span>href<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<codepen-embed class=\"codepen-embed select-none relative rounded drop-shadow-lg dark:drop-shadow-none border border-solid dark:border-zinc-700 block\" style=\"min-height:300px\">\n<div class=\"codepen-consent absolute inset-0 flex flex-col items-center justify-center gap-4 bg-stone-100 dark:bg-stone-800 rounded p-4 z-10\">\n<p class=\"text-center text-sm text-stone-600 dark:text-stone-400 mb-4\">Loading this CodePen will set third-party cookies from codepen.io</p>\n<label class=\"flex items-center gap-2 text-sm text-stone-600 dark:text-stone-400 cursor-pointer\"><input type=\"checkbox\" class=\"codepen-remember accent-stone-800 dark:accent-stone-200 w-4 h-4\">Always load CodePen</label>\n<button type=\"button\" class=\"codepen-load-btn inline-flex items-center justify-center px-6 py-3 bg-stone-800 dark:bg-stone-100 text-white dark:text-stone-900 rounded-lg hover:bg-stone-700 dark:hover:bg-stone-200 active:scale-95 transition-all font-semibold shadow-lg hover:shadow-xl border-2 border-stone-900 dark:border-stone-300\">Load CodePen</button>\n<a href=\"https://codepen.io/reatlat/pen/gOxydbR\" target=\"_blank\" rel=\"noopener\" class=\"mt-6 text-xs text-stone-600 hover:text-stone-800 dark:text-stone-400 dark:hover:text-stone-200 underline\">Open on CodePen instead</a>\n</div>\n<p class=\"codepen-pending hidden rounded p-4\" data-height=\"300\" data-theme-id=\"1\" data-default-tab=\"css,result\" data-slug-hash=\"gOxydbR\" data-user=\"reatlat\" style=\"height:300px\"><span>See the Pen on <a href=\"https://codepen.io/reatlat/pen/gOxydbR\">CodePen</a>.</span></p>\n</codepen-embed>\n<h2 id=\"fit-images-to-the-content\" tabindex=\"-1\">Fit images to the content <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#fit-images-to-the-content\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>In this simple hack, you can make sure that your images always fit the visitor’s screen, regardless of the device they’re using. More use cases could be found <a href=\"https://alex.zappa.dev/blog/mobile-friendly-responsive-images-with-css/\">here</a>.</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">img</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">max-width</span><span class=\"token punctuation\">:</span> 100%<span class=\"token punctuation\">;</span>\n    <span class=\"token property\">height</span><span class=\"token punctuation\">:</span> auto<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"detect-dark-system-mode\" tabindex=\"-1\">Detect dark system mode <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#detect-dark-system-mode\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p><a href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/\">When you want a style that applies to users with dark mode turned on</a>, add your style inside media query below. If we want the black background and white text for dark mode users, we will type something like this:</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token atrule\"><span class=\"token rule\">@media</span> <span class=\"token punctuation\">(</span><span class=\"token property\">prefers-color-scheme</span><span class=\"token punctuation\">:</span> dark<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token selector\">body</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">background-color</span><span class=\"token punctuation\">:</span> #111111<span class=\"token punctuation\">;</span>\n        <span class=\"token property\">color</span><span class=\"token punctuation\">:</span> #FFFFFF<span class=\"token punctuation\">;</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"hide-images-on-mobile\" tabindex=\"-1\">Hide images on mobile <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#hide-images-on-mobile\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Sometimes we have icons or images that we just don’t want to be seen on the mobile view.</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token atrule\"><span class=\"token rule\">@media</span> <span class=\"token keyword\">only</span> on screen <span class=\"token keyword\">and</span> <span class=\"token punctuation\">(</span><span class=\"token property\">max-width</span><span class=\"token punctuation\">:</span> 767px<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token selector\">section .user-img</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token property\">display</span><span class=\"token punctuation\">:</span> none<span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"css-vendor-prefixes-by-browsers\" tabindex=\"-1\">CSS vendor prefixes by browsers <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#css-vendor-prefixes-by-browsers\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>CSS vendor prefixes, also sometimes known as or CSS browser prefixes, are a way for browser makers to add support for new CSS features before those features are fully supported in all browsers. This may be done during a sort of testing and experimentation period where the browser manufacturer is determining exactly how these new CSS features will be implemented.</p>\n<p>The CSS browser prefixes that you can use (each of which is specific to a different browser) are:</p>\n<ul>\n<li>Android: <code>-webkit-</code></li>\n<li>Chrome: <code>-webkit-</code></li>\n<li>Safari: <code>-webkit-</code></li>\n<li>iOS: <code>-webkit-</code></li>\n<li>Firefox: <code>-moz-</code></li>\n<li>Internet Explorer: <code>-ms-</code></li>\n<li>Opera: <code>-o-</code></li>\n</ul>\n<h3 id=\"autoprefixer\" tabindex=\"-1\">Autoprefixer <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#autoprefixer\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<blockquote>\n<p>The Autoprefixer uses data on the popularity of browsers and support for vendor prefixes by browsers. Based on this information, it arranges and deletes the prefixes. It can help you get prefixes for: animations, transition, transform, grid, flex, flexbox and others.</p>\n<p><a href=\"https://autoprefixer.github.io/\">https://autoprefixer.github.io/</a></p>\n</blockquote>\n<p>To make sure your CSS works well on the rest of browsers, always use Autoprefixer, here ho is it looks like:</p>\n<img src=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/assets/autoprefixer-css-online.png\" alt=\"Autoprefixer CSS online\" eleventy:widths=\"900\">\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#conclusion\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>There are countless tricks we can use with CSS3. Which is your favorite? <a href=\"https://alex.zappa.dev/blog/my-favorite-css-hacks/#comments\">Comment down below.</a></p>\n",
			"date_published": "2021-11-29T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/",
			"url": "https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/",
			"title": "Detect dark or light system mode",
			"content_html": "<p>As developer, I do prefer dark schema for system and all my apps except Gmail on mobile 🙂 Emails still not so friendly for dark theme mode 🙂</p>\n<img src=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/assets/meme-light-ide.jpeg\" alt=\"Light IDE Meme\" eleventy:widths=\"360\">\n<h2 id=\"detect-with-css-media-query\" tabindex=\"-1\">Detect with CSS media query <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/#detect-with-css-media-query\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>The prefers-color-scheme CSS media feature is used to detect if the user has requested a light or dark color theme.</p>\n<blockquote>\n<p>The user might indicate this preference through an operating system setting (e.g. light or dark mode) or a user agent setting.</p>\n<p><a href=\"https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme\">From MDN Web Docs</a></p>\n</blockquote>\n<h3 id=\"prefers-color-scheme-dark\" tabindex=\"-1\">prefers-color-scheme: dark <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/#prefers-color-scheme-dark\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Indicates that a user has notified the system that they prefer an interface that has a dark theme.</p>\n<p>When you want a style that applies to users with dark mode turned on, add your style inside media query below. If we want the black background and white text for dark mode users, we will type something like this:</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token atrule\"><span class=\"token rule\">@media</span> <span class=\"token punctuation\">(</span><span class=\"token property\">prefers-color-scheme</span><span class=\"token punctuation\">:</span> dark<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token selector\">body</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token property\">background-color</span><span class=\"token punctuation\">:</span> #000000<span class=\"token punctuation\">;</span>\n\t\t<span class=\"token property\">color</span><span class=\"token punctuation\">:</span> #FFFFFF<span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h3 id=\"prefers-color-scheme-light\" tabindex=\"-1\">prefers-color-scheme: light <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/#prefers-color-scheme-light\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Indicates that the user has notified the system that they prefer an interface that has a light theme.</p>\n<p>When you want a style that applies to users with light mode turned on, add your style inside media query below. If we want the white background and black text for light mode users, we will type something like this:</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token atrule\"><span class=\"token rule\">@media</span> <span class=\"token punctuation\">(</span><span class=\"token property\">prefers-color-scheme</span><span class=\"token punctuation\">:</span> light<span class=\"token punctuation\">)</span></span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token selector\">body</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token property\">background-color</span><span class=\"token punctuation\">:</span> #FFFFFF<span class=\"token punctuation\">;</span>\n\t\t<span class=\"token property\">color</span><span class=\"token punctuation\">:</span> #000000<span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"detect-with-js\" tabindex=\"-1\">Detect with JS <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/#detect-with-js\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<h2 id=\"window-matchmedia\" tabindex=\"-1\">window.matchMedia() <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/#window-matchmedia\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<blockquote>\n<p>The Window interface’s matchMedia() method returns a new MediaQueryList object that can then be used to determine if the document matches the media query string, as well as to monitor the document to detect when it matches (or stops matching) that media query.</p>\n<p><a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia\">From MDN Web Docs</a></p>\n</blockquote>\n<p>Here is simple example how to use it:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>window<span class=\"token punctuation\">.</span>matchMedia <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">matchMedia</span><span class=\"token punctuation\">(</span><span class=\"token string\">'(prefers-color-scheme: dark)'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>matches<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// dark mode</span>\n<span class=\"token punctuation\">}</span> <span class=\"token keyword\">else</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token comment\">// light mode or not supported</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>To watch for changes:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\">window<span class=\"token punctuation\">.</span><span class=\"token function\">matchMedia</span><span class=\"token punctuation\">(</span><span class=\"token string\">'(prefers-color-scheme: dark)'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'change'</span><span class=\"token punctuation\">,</span> <span class=\"token parameter\">e</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">const</span> newColorScheme <span class=\"token operator\">=</span> e<span class=\"token punctuation\">.</span>matches <span class=\"token operator\">?</span> <span class=\"token string\">\"dark\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"light\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<h2 id=\"detect-with-gtm-and-track-down-with-ga\" tabindex=\"-1\">Detect with GTM and track down with GA <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/#detect-with-gtm-and-track-down-with-ga\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Google Tag Manager could detect user’s theme color preferences, and after send that data to Google Analytics for example.</p>\n<h3 id=\"define-gtm-datalayer-variable\" tabindex=\"-1\">Define GTM dataLayer variable <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/#define-gtm-datalayer-variable\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Open Google Tag Manager Dashboard, on sidebar select tab Variables and add new User-Defined Variables</p>\n<p>Select Custom JavaScript and copy-paste code from below:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>window<span class=\"token punctuation\">.</span>matchMedia <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">matchMedia</span><span class=\"token punctuation\">(</span><span class=\"token string\">'(prefers-color-scheme: dark)'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>matches<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token keyword\">return</span> <span class=\"token string\">'Dark'</span><span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span>\n\t<span class=\"token keyword\">else</span> <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>window<span class=\"token punctuation\">.</span>matchMedia <span class=\"token operator\">&amp;&amp;</span> window<span class=\"token punctuation\">.</span><span class=\"token function\">matchMedia</span><span class=\"token punctuation\">(</span><span class=\"token string\">'(prefers-color-scheme: light)'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>matches<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token keyword\">return</span> <span class=\"token string\">'Light'</span><span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span>\n\t<span class=\"token keyword\">return</span> <span class=\"token string\">'No Preference'</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>Result should look like a screenshot.</p>\n<img src=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/assets/google-tag-manager-custom-javascript.png\" alt=\"Google Tag Manager Custom JavaScript\" eleventy:widths=\"900\">\n<h3 id=\"tracking-with-ga-universal\" tabindex=\"-1\">Tracking with GA Universal <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/#tracking-with-ga-universal\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>To track user color mode with Google Analytics Universal, we need to create a tag in GTM like screenshot below, and fire it on PageView trigger.</p>\n<img src=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/assets/google-tag-manager-ga-universal-event.png\" alt=\"Google Tag Manager GA Universal Event\" eleventy:widths=\"900\">\n<h3 id=\"tracking-with-gav4\" tabindex=\"-1\">Tracking with GAv4 <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/#tracking-with-gav4\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Not a secret, Google Analytics v4 has new way to collect data, and in this case, we need to create a tag in GTM and also create custom dimension in Google Analytics.</p>\n<img src=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/assets/google-tag-manager-user-color-mode-gav4.png\" alt=\"Google Tag Manager User Color Mode GAv4\" eleventy:widths=\"900\">\n<img src=\"https://alex.zappa.dev/blog/detect-dark-or-light-system-mode/assets/google-analysis-v4-custom-dimension.png\" alt=\"Google Analysis v4 Custom Dimension\" eleventy:widths=\"900\">\n<p>After all set, in 48h, you will start to see User color mode in your Google Analytics reports.</p>\n<p>This is it, hope this article help to learn something new, GTM and GA could help us to collect a lot of different information, to learn how to do that, I strongly recommend checking <a href=\"https://www.analyticsmania.com/\">Analytics Mania</a> where Julius teaching how to use GTM and GA in god mode 😉</p>\n",
			"date_published": "2021-11-21T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/mobile-friendly-responsive-images-with-css/",
			"url": "https://alex.zappa.dev/blog/mobile-friendly-responsive-images-with-css/",
			"title": "Mobile friendly Responsive images with CSS",
			"content_html": "<p>The term <em>“responsive images”</em> has come to mean <em>“responsive images in HTML”</em>, in other words, the <code>srcset</code> and <code>sizes</code>\nattribute for <code>&lt;img&gt;</code> and the <code>&lt;picture&gt;</code> element. But today I want to talk about a common issue, when image go outside\ncontainer.</p>\n<h2 id=\"srcset-in-css\" tabindex=\"-1\">srcset in CSS <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/mobile-friendly-responsive-images-with-css/#srcset-in-css\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>In HTML, srcset is like this:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>img</span> <span class=\"token attr-name\">srcset</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>\n  examples/images/image-384.jpg 1x,\n  examples/images/image-768.jpg 2x\n<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">alt</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>[…]<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span></code></pre>\n<p>And this is good and correct way we know, but what we can do when image goes outside container even they have <code>srcset</code>\nattribute?</p>\n<p>Here is example:</p>\n<img src=\"https://alex.zappa.dev/blog/mobile-friendly-responsive-images-with-css/assets/responsive-images-issue.png\" alt=\"Responsive images issue\" eleventy:widths=\"900\">\n<p><em>On screenshot, you can see classic issue with blogs on WordPress or HubSpot</em></p>\n<h2 id=\"css-and-responsive-images\" tabindex=\"-1\">CSS and responsive images <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/mobile-friendly-responsive-images-with-css/#css-and-responsive-images\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>We must ensure the image is fluid, but up to a limit! Solution: the CSS max-width rule. By this rule, we will indicate\nthe image width in pixels, at the most, 100% of the width of the container. Here is example:</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">img</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token property\">max-width</span><span class=\"token punctuation\">:</span> 100%<span class=\"token punctuation\">;</span>\n\t<span class=\"token property\">height</span><span class=\"token punctuation\">:</span> auto<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"wordpress-and-responsive-images\" tabindex=\"-1\">WordPress and responsive images <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/mobile-friendly-responsive-images-with-css/#wordpress-and-responsive-images\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>For WordPress by adding code below to <code>style.css</code> file in theme directory:</p>\n<pre class=\"language-css\" tabindex=\"0\"><code class=\"language-css\"><span class=\"token selector\">.entry-content img,\n.entry-summary img,\n.comment-content img,\n.widget img,\n.wp-caption</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token property\">max-with</span><span class=\"token punctuation\">:</span> 100%<span class=\"token punctuation\">;</span>\n\t<span class=\"token property\">height</span><span class=\"token punctuation\">:</span> auto<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<h2 id=\"hubspot-and-responsive-images\" tabindex=\"-1\">HubSpot and responsive images <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/mobile-friendly-responsive-images-with-css/#hubspot-and-responsive-images\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>For HubSpot: Open Settings &gt; Website(sidebar) &gt; Pages(sidebar) &gt; Templates(tab) &gt; Site head HTML(section) and paste the\nfinal code to Site head HTML editor:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>style</span><span class=\"token punctuation\">></span></span><span class=\"token style\"><span class=\"token language-css\">\n\t<span class=\"token selector\">.body-wrapper img</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token property\">max-with</span><span class=\"token punctuation\">:</span> 100%<span class=\"token punctuation\">;</span>\n\t\t<span class=\"token property\">height</span><span class=\"token punctuation\">:</span> auto<span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span>\n</span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>style</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>This is it, it should resolve the issue with oversized images. Here is example on CodePen, how its work:</p>\n<codepen-embed class=\"codepen-embed select-none relative rounded drop-shadow-lg dark:drop-shadow-none border border-solid dark:border-zinc-700 block\" style=\"min-height:500px\">\n<div class=\"codepen-consent absolute inset-0 flex flex-col items-center justify-center gap-4 bg-stone-100 dark:bg-stone-800 rounded p-4 z-10\">\n<p class=\"text-center text-sm text-stone-600 dark:text-stone-400 mb-4\">Loading this CodePen will set third-party cookies from codepen.io</p>\n<label class=\"flex items-center gap-2 text-sm text-stone-600 dark:text-stone-400 cursor-pointer\"><input type=\"checkbox\" class=\"codepen-remember accent-stone-800 dark:accent-stone-200 w-4 h-4\">Always load CodePen</label>\n<button type=\"button\" class=\"codepen-load-btn inline-flex items-center justify-center px-6 py-3 bg-stone-800 dark:bg-stone-100 text-white dark:text-stone-900 rounded-lg hover:bg-stone-700 dark:hover:bg-stone-200 active:scale-95 transition-all font-semibold shadow-lg hover:shadow-xl border-2 border-stone-900 dark:border-stone-300\">Load CodePen</button>\n<a href=\"https://codepen.io/reatlat/pen/bGrBJLy\" target=\"_blank\" rel=\"noopener\" class=\"mt-6 text-xs text-stone-600 hover:text-stone-800 dark:text-stone-400 dark:hover:text-stone-200 underline\">Open on CodePen instead</a>\n</div>\n<p class=\"codepen-pending hidden rounded p-4\" data-height=\"500\" data-theme-id=\"1\" data-default-tab=\"result\" data-slug-hash=\"bGrBJLy\" data-user=\"reatlat\" style=\"height:500px\"><span>See the Pen on <a href=\"https://codepen.io/reatlat/pen/bGrBJLy\">CodePen</a>.</span></p>\n</codepen-embed>\n<p>This is it! Hope my post have been helpful, stay safe!</p>\n",
			"date_published": "2021-10-27T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/keep-track-utm-parameters-for-hubspot-forms-like-cookie-monster/",
			"url": "https://alex.zappa.dev/blog/keep-track-utm-parameters-for-hubspot-forms-like-cookie-monster/",
			"title": "Keep Track UTM parameters for HubSpot forms like Cookie Monster",
			"content_html": "<p>About a week ago, I outlined\nstep-by-step <a href=\"https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/\">how to track UTMs across session</a> and\npopulate HubSpot forms even the visitor\nalready left the target page and after checking other website pages decided to finish a form and submit application.</p>\n<p>This time I will explain how we can do the same with cookies and store UTM parameters for a day, or week, or even more.</p>\n<p>The downside of <a href=\"https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/\">sessionStorage</a> solution is when\nvisitor close the browser tab, stored cookies will be gone.</p>\n<h2 id=\"cookies\" tabindex=\"-1\">Cookies <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/keep-track-utm-parameters-for-hubspot-forms-like-cookie-monster/#cookies\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<blockquote>\n<p>An HTTP cookie (web cookie, browser cookie) is a small piece of data that a server sends to a user’s web browser. The\nbrowser may store the cookie and send it back to the same server with later requests. Typically, an HTTP cookie is\nused\nto tell if two requests come from the same browser—keeping a user logged in, for example. It remembers stateful\ninformation for the stateless HTTP protocol.</p>\n<p>From <em><a href=\"https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies\">Web docs | MDN</a></em></p>\n</blockquote>\n<p>I don’t want to <em>“reinvent the wheel”</em>, so we will use <a href=\"https://github.com/js-cookie/js-cookie\">JavaScript Cookie</a>\nlibrary, and the easiest way to start work with this library get it from <a href=\"https://cdnjs.com/\">CDNJS.com</a>. The snippet we\ncan get and install\nto the footer of the website looks like this:</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://cdnjs.cloudflare.com/ajax/libs/js-cookie/2.2.1/js.cookie.min.js<span class=\"token punctuation\">\"</span></span> <span class=\"token attr-name\">referrerpolicy</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>no-referrer<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Or use the latest version with <a href=\"https://unpkg.com/\">UnPKG.com</a></p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://unpkg.com/js-cookie<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<p>Next step let’s get the code from <a href=\"https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/\">previous post</a> and\nset them to use cookies instead of sessionStorage</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">$<span class=\"token punctuation\">,</span> w<span class=\"token punctuation\">,</span> d<span class=\"token punctuation\">,</span> Cookies<span class=\"token punctuation\">,</span> <span class=\"token constant\">GET</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token comment\">// Create object and store UTMs</span>\n\t<span class=\"token keyword\">var</span> utm <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token literal-property property\">source</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_source'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\t\t<span class=\"token literal-property property\">campaign</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_campaign'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\t\t<span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_content'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\t\t<span class=\"token literal-property property\">medium</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_medium'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\t\t<span class=\"token literal-property property\">term</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_term'</span><span class=\"token punctuation\">)</span>\n\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\t<span class=\"token comment\">// Check if one or more UTMs present in URL</span>\n\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>utm<span class=\"token punctuation\">.</span>source <span class=\"token operator\">||</span> utm<span class=\"token punctuation\">.</span>campaign <span class=\"token operator\">||</span> utm<span class=\"token punctuation\">.</span>content <span class=\"token operator\">||</span> utm<span class=\"token punctuation\">.</span>medium <span class=\"token operator\">||</span> utm<span class=\"token punctuation\">.</span>term<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token comment\">// Set Cookie __utm_params with livetime period 7 days</span>\n\t\tCookies<span class=\"token punctuation\">.</span><span class=\"token function\">set</span><span class=\"token punctuation\">(</span><span class=\"token string\">'__utm_params'</span><span class=\"token punctuation\">,</span> utm<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span><span class=\"token literal-property property\">expires</span><span class=\"token operator\">:</span> <span class=\"token number\">7</span><span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">path</span><span class=\"token operator\">:</span> <span class=\"token string\">'/'</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span>\n\t<span class=\"token comment\">// Check if UTM parameters stored in SessionStorage</span>\n\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>Cookies<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'__utm-params'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t<span class=\"token comment\">// Parse UTMs from SessionStorage to JSON</span>\n\t\t<span class=\"token keyword\">var</span> storedUTM <span class=\"token operator\">=</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>Cookies<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'__utm-params'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t<span class=\"token comment\">// Add Event Listener for `onFormReady` event</span>\n\t\tw<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'message'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">.</span>type <span class=\"token operator\">===</span> <span class=\"token string\">'hsFormCallback'</span> <span class=\"token operator\">&amp;&amp;</span> e<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">.</span>eventName <span class=\"token operator\">===</span> <span class=\"token string\">'onFormReady'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t\t\t<span class=\"token comment\">// Find all HubSpot forms on the page</span>\n\t\t\t\t<span class=\"token keyword\">var</span> scope <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'form[data-form-id]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t\t\t<span class=\"token comment\">// Check if UTM parameter exists and populate form hidden input fields</span>\n\t\t\t\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>source<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t\t\t\tscope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_source\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>source<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t\t\t<span class=\"token punctuation\">}</span>\n\t\t\t\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>campaign<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t\t\t\tscope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_campaign\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>campaign<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t\t\t<span class=\"token punctuation\">}</span>\n\t\t\t\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t\t\t\tscope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_content\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t\t\t<span class=\"token punctuation\">}</span>\n\t\t\t\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>medium<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t\t\t\tscope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_medium\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>medium<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t\t\t<span class=\"token punctuation\">}</span>\n\t\t\t\t<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>term<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\t\t\t\tscope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_term\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>term<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t\t\t\t<span class=\"token punctuation\">}</span>\n\t\t\t<span class=\"token punctuation\">}</span>\n\t\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span>jQuery<span class=\"token punctuation\">,</span> window<span class=\"token punctuation\">,</span> document<span class=\"token punctuation\">,</span> Cookies<span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">param<span class=\"token punctuation\">,</span> url</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\turl <span class=\"token operator\">=</span> url <span class=\"token operator\">?</span> url <span class=\"token operator\">:</span> window<span class=\"token punctuation\">.</span>location<span class=\"token punctuation\">.</span>href<span class=\"token punctuation\">;</span>\n\t<span class=\"token keyword\">var</span> vars <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\turl<span class=\"token punctuation\">.</span><span class=\"token function\">replace</span><span class=\"token punctuation\">(</span>location<span class=\"token punctuation\">.</span>hash<span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">replace</span><span class=\"token punctuation\">(</span><span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">[?&amp;]+([^=&amp;]+)=?([^&amp;]*)?</span><span class=\"token regex-delimiter\">/</span><span class=\"token regex-flags\">gi</span></span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">m<span class=\"token punctuation\">,</span> key<span class=\"token punctuation\">,</span> value</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\tvars<span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> value <span class=\"token operator\">!==</span> <span class=\"token keyword\">void</span> <span class=\"token number\">0</span> <span class=\"token operator\">?</span> value <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t<span class=\"token keyword\">return</span> <span class=\"token keyword\">typeof</span> vars<span class=\"token punctuation\">[</span>param<span class=\"token punctuation\">]</span> <span class=\"token operator\">!==</span> <span class=\"token string\">'undefined'</span> <span class=\"token operator\">?</span> vars<span class=\"token punctuation\">[</span>param<span class=\"token punctuation\">]</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre>\n<h2 id=\"installation-to-hubspot-website\" tabindex=\"-1\">Installation to HubSpot website <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/keep-track-utm-parameters-for-hubspot-forms-like-cookie-monster/#installation-to-hubspot-website\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Open Settings &gt; Website(sidebar) &gt; Pages(sidebar) &gt; Templates(tab) &gt; Site footer HTML(section) and paste the final code\nto Site footer HTML editor between script tags</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span> <span class=\"token attr-name\">src</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>https://unpkg.com/js-cookie<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span><span class=\"token script\"></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span><span class=\"token punctuation\">></span></span><span class=\"token script\"><span class=\"token language-javascript\">\n\t<span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n\t  <span class=\"token comment\">// do something</span>\n\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<img src=\"https://alex.zappa.dev/blog/keep-track-utm-parameters-for-hubspot-forms-like-cookie-monster/assets/hubspot-site-footer-html-editor.png\" alt=\"HubSpot Site Footer HTML Editor\" eleventy:widths=\"900\">\n<p><em>Final result should look like screenshot</em></p>\n<p>The same method could be used for any websites(Webflow, WordPress, Wix, Static, etc…) who use HubSpot forms.</p>\n",
			"date_published": "2021-10-22T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/",
			"url": "https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/",
			"title": "Track UTM parameters for HubSpot forms like a BOSS",
			"content_html": "<p>I think a Tracking URL is a good feature for marketing perspectives.</p>\n<blockquote>\n<p>Tracking URLs help you measure the effectiveness of your marketing campaigns by providing information to HubSpot when\nvisitors access your site through the URL.</p>\n<p>Create a tracking URL when you want to track traffic from a campaign to a page with the HubSpot tracking code. Examples\ninclude email blasts, PPC campaigns, and banner ads. You can also create a tracking URL using\nyour <a href=\"https://knowledge.hubspot.com/meetings-tool/create-and-edit-scheduling-pages\">meeting links</a>.</p>\n<p>A tracking URL is a normal URL with parameters attached to it. When visitors come to your site from a tracking URL,\nHubSpot saves the information in those parameters. Learn how\nto <a href=\"https://knowledge.hubspot.com/reports/analyze-your-site-traffic-with-the-traffic-analytics-tool#analyze-your-traffic-using-the-utm-parameters-tab\">analyze traffic data from tracking URLs in the traffic\nanalytics tool</a>.</p>\n<p><em>From <a href=\"https://knowledge.hubspot.com/settings/how-do-i-create-a-tracking-url\">Create Tracking URL’s</a></em></p>\n</blockquote>\n<p>Meantime, it’s good idea to pass those UTM parameters to form hidden fields</p>\n<blockquote>\n<p>HubSpot makes it relatively easy to pass UTM parameters from a URL into hidden fields in a HubSpot form. In this blog\npost, we will outline step-by-step how to do so.</p>\n</blockquote>\n<p><em>From <a href=\"https://align.ly/blog/how-to-pass-utm-parameters-into-a-hubspot-form/\">How to pass UTM parameters into a HubSpot form</a></em></p>\n<p>The downside of the method described in article above it’s work only with landing page, when user arrives to your page\nvia URL with UTM parameters, and if he goes to the next page or check some pages before actually do some actions with\nform on landing page, the UTMs will be lost.</p>\n<p>So basicly we looking to pass UTMs to form fields with property\nnames: <code>utm_source</code>, <code>utm_campaign</code>, <code>utm_content</code>, <code>utm_medium</code>, <code>utm_term</code>.</p>\n<h2 id=\"store-utm-parameters-in-sessionstorage\" tabindex=\"-1\">Store UTM parameters in sessionStorage <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/#store-utm-parameters-in-sessionstorage\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<h3 id=\"what-is-sessionstorage\" tabindex=\"-1\">What is sessionStorage? <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/#what-is-sessionstorage\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<blockquote>\n<p>The read-only <strong>sessionStorage</strong> property accesses a\nsession <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Storage\">Storage</a> object for the\ncurrent <a href=\"https://developer.mozilla.org/en-US/docs/Glossary/Origin\">origin</a>. sessionStorage is\nsimilar to <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage\">localStorage</a>; the difference is\nthat while data in localStorage doesn’t expire, data in sessionStorage is\ncleared when the page session ends.</p>\n<p><em>From <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage\">Web docs | MDN</a></em></p>\n</blockquote>\n<h3 id=\"custom-javascript-module-will-help-store-and-feed-form-fields\" tabindex=\"-1\">Custom JavaScript module will help store and feed form fields <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/#custom-javascript-module-will-help-store-and-feed-form-fields\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>First what we have to learn about JavaScript on systems like HubSpot, always encapsulate your JavaScript using Anonymous\nFunctions, to avoid global issues.</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token comment\">// do something</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>This simple encapsulation example will help you exclude your code from global variables, also will not have to override\nyour or third-party modules on HubSpot.</p>\n<p>Moreover, it can make your code a bit tiny and clean if you pass some global variables to the function, like next\nexample.</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">$<span class=\"token punctuation\">,</span> w<span class=\"token punctuation\">,</span> d</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t<span class=\"token comment\">// do something</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span>jQuery<span class=\"token punctuation\">,</span> window<span class=\"token punctuation\">,</span> document<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>In the example above, we pass <code>jQuery</code>, <code>window</code>, and <code>document</code> as variables to the function which allow us to use <code>$</code>\nas\n<code>jQuery</code> alias, and use a short name for <code>window</code> and <code>document</code>.</p>\n<p>To get the query string component of the URL we need a small helper function like this:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">function</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">param<span class=\"token punctuation\">,</span> url</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\turl <span class=\"token operator\">=</span> url <span class=\"token operator\">?</span> url <span class=\"token operator\">:</span> window<span class=\"token punctuation\">.</span>location<span class=\"token punctuation\">.</span>href<span class=\"token punctuation\">;</span>\n\t<span class=\"token keyword\">var</span> vars <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\turl<span class=\"token punctuation\">.</span><span class=\"token function\">replace</span><span class=\"token punctuation\">(</span>window<span class=\"token punctuation\">.</span>location<span class=\"token punctuation\">.</span>hash<span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">replace</span><span class=\"token punctuation\">(</span><span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">[?&amp;]+([^=&amp;]+)=?([^&amp;]*)?</span><span class=\"token regex-delimiter\">/</span><span class=\"token regex-flags\">gi</span></span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">m<span class=\"token punctuation\">,</span> key<span class=\"token punctuation\">,</span> value</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n\t\tvars<span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> value <span class=\"token operator\">!==</span> <span class=\"token keyword\">void</span> <span class=\"token number\">0</span> <span class=\"token operator\">?</span> value <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span>\n\t<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\t<span class=\"token keyword\">return</span> <span class=\"token keyword\">typeof</span> vars<span class=\"token punctuation\">[</span>param<span class=\"token punctuation\">]</span> <span class=\"token operator\">!==</span> <span class=\"token string\">'undefined'</span> <span class=\"token operator\">?</span> vars<span class=\"token punctuation\">[</span>param<span class=\"token punctuation\">]</span> <span class=\"token operator\">:</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>This small function help us to extract query parameters from current URL. And here is how we could use the new <code>GET</code>\nfunction to extract UTMs from URL</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token keyword\">var</span> utm_source <span class=\"token operator\">=</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_source'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">var</span> utm_campaign <span class=\"token operator\">=</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_campaign'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">var</span> utm_content <span class=\"token operator\">=</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_content'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">var</span> utm_medium <span class=\"token operator\">=</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_medium'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">var</span> utm_term <span class=\"token operator\">=</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_term'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Next we have to add Event Listener to populate forms after they have been rendered on webpage, to achieve that we have\nto check <a href=\"https://legacydocs.hubspot.com/global-form-events\">HubSpot Forms API</a> and check event called <code>onFormReady</code>, here is example how to use it:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\">window<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'message'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">event</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">.</span>type <span class=\"token operator\">===</span> <span class=\"token string\">'hsFormCallback'</span> <span class=\"token operator\">&amp;&amp;</span> event<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">.</span>eventName <span class=\"token operator\">===</span> <span class=\"token string\">'onFormReady'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Form Ready!\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// do something</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>After all, let’s combine all code we have right now to one module:</p>\n<pre class=\"language-js\" tabindex=\"0\"><code class=\"language-js\"><span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">$<span class=\"token punctuation\">,</span> w<span class=\"token punctuation\">,</span> d<span class=\"token punctuation\">,</span> storage<span class=\"token punctuation\">,</span> <span class=\"token constant\">GET</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// Creat object and store UTMs</span>\n  <span class=\"token keyword\">var</span> utm <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">source</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_source'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">campaign</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_campaign'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_content'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">medium</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_medium'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">term</span><span class=\"token operator\">:</span> <span class=\"token constant\">GET</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_term'</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  <span class=\"token comment\">// Check if one or more UTMs present in URL</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>utm<span class=\"token punctuation\">.</span>source <span class=\"token operator\">||</span> utm<span class=\"token punctuation\">.</span>campaign <span class=\"token operator\">||</span> utm<span class=\"token punctuation\">.</span>content <span class=\"token operator\">||</span> utm<span class=\"token punctuation\">.</span>medium <span class=\"token operator\">||</span> utm<span class=\"token punctuation\">.</span>term<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    storage<span class=\"token punctuation\">.</span><span class=\"token function\">setItem</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_params'</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">stringify</span><span class=\"token punctuation\">(</span>utm<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n  <span class=\"token comment\">// Check if UTM parameters stored in SessionStorage</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token keyword\">typeof</span> storage<span class=\"token punctuation\">.</span><span class=\"token function\">getItem</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_params'</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">===</span> <span class=\"token string\">'string'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// Parse UTMs from SessionStorage to JSON</span>\n    <span class=\"token keyword\">var</span> storedUTM <span class=\"token operator\">=</span> <span class=\"token constant\">JSON</span><span class=\"token punctuation\">.</span><span class=\"token function\">parse</span><span class=\"token punctuation\">(</span>storage<span class=\"token punctuation\">.</span><span class=\"token function\">getItem</span><span class=\"token punctuation\">(</span><span class=\"token string\">'utm_params'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// Add Event Listener for `onFormReady` event</span>\n    w<span class=\"token punctuation\">.</span><span class=\"token function\">addEventListener</span><span class=\"token punctuation\">(</span><span class=\"token string\">'message'</span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">e</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>e<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">.</span>type <span class=\"token operator\">===</span> <span class=\"token string\">'hsFormCallback'</span> <span class=\"token operator\">&amp;&amp;</span> e<span class=\"token punctuation\">.</span>data<span class=\"token punctuation\">.</span>eventName <span class=\"token operator\">===</span> <span class=\"token string\">'onFormReady'</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token comment\">// Find all HubSpot forms on the page</span>\n        <span class=\"token keyword\">var</span> scope <span class=\"token operator\">=</span> <span class=\"token function\">$</span><span class=\"token punctuation\">(</span>d<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'form[data-form-id]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token comment\">// Check if UTM parameter exists and populate form hidden input fields</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>source<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          scope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_source\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>source<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>campaign<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          scope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_campaign\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>campaign<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          scope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_content\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>medium<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          scope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_medium\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>medium<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n        <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>term<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n          scope<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'[name=\"utm_term\"]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">val</span><span class=\"token punctuation\">(</span>storedUTM<span class=\"token punctuation\">.</span>term<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">change</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n        <span class=\"token punctuation\">}</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span>jQuery<span class=\"token punctuation\">,</span> window<span class=\"token punctuation\">,</span> document<span class=\"token punctuation\">,</span> sessionStorage<span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">param<span class=\"token punctuation\">,</span> url</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  url <span class=\"token operator\">=</span> url <span class=\"token operator\">?</span> url <span class=\"token operator\">:</span> window<span class=\"token punctuation\">.</span>location<span class=\"token punctuation\">.</span>href<span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">var</span> vars <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n  url<span class=\"token punctuation\">.</span><span class=\"token function\">replace</span><span class=\"token punctuation\">(</span>location<span class=\"token punctuation\">.</span>hash<span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">replace</span><span class=\"token punctuation\">(</span><span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">[?&amp;]+([^=&amp;]+)=?([^&amp;]*)?</span><span class=\"token regex-delimiter\">/</span><span class=\"token regex-flags\">gi</span></span><span class=\"token punctuation\">,</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">m<span class=\"token punctuation\">,</span> key<span class=\"token punctuation\">,</span> value</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    vars<span class=\"token punctuation\">[</span>key<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> value <span class=\"token operator\">!==</span> <span class=\"token keyword\">void</span> <span class=\"token number\">0</span> <span class=\"token operator\">?</span> value <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">return</span> <span class=\"token keyword\">typeof</span> vars<span class=\"token punctuation\">[</span>param<span class=\"token punctuation\">]</span> <span class=\"token operator\">!==</span> <span class=\"token string\">'undefined'</span> <span class=\"token operator\">?</span> vars<span class=\"token punctuation\">[</span>param<span class=\"token punctuation\">]</span> <span class=\"token operator\">:</span> <span class=\"token string\">''</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span></code></pre>\n<h3 id=\"installation-to-hubspot-website\" tabindex=\"-1\">Installation to HubSpot website <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/#installation-to-hubspot-website\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Open Settings &gt; Website(sidebar) &gt; Pages(sidebar) &gt; Templates(tab) &gt; Site footer HTML(section) and paste the final code toSite footer HTML editor between script tags</p>\n<pre class=\"language-html\" tabindex=\"0\"><code class=\"language-html\"><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>script</span><span class=\"token punctuation\">></span></span><span class=\"token script\"><span class=\"token language-javascript\">\n<span class=\"token punctuation\">(</span><span class=\"token keyword\">function</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">{</span>\n  <span class=\"token comment\">// do something</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n</span></span><span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>script</span><span class=\"token punctuation\">></span></span></code></pre>\n<img src=\"https://alex.zappa.dev/blog/track-utm-parameters-for-hubspot-forms-like-a-boss/assets/hubsput-site-footer-html-editor.png\" alt=\"HubSpot Site Footer HTML Editor\" eleventy:widths=\"900\">\n<p><em>Final result should look like screenshot</em></p>\n<p>The same method could be used for any websites(Webflow, WordPress, Wix, Static, etc…) who use HubSpot forms.</p>\n<p>This is it! Next time, I will cover the way <a href=\"https://alex.zappa.dev/blog/keep-track-utm-parameters-for-hubspot-forms-like-cookie-monster/\">how to store UTM parameters in cookie files</a>.</p>\n",
			"date_published": "2021-10-16T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/wp-plugin-elementor-multidomain-support/",
			"url": "https://alex.zappa.dev/blog/wp-plugin-elementor-multidomain-support/",
			"title": "WP plugin Elementor Multidomain Support",
			"content_html": "<p>This plugin will help those who have a Multilanguage website with a multi-domain structure, the plugin will add to\nElementor Page Builder the support for multi-domains structure.</p>\n<p>The source code of plugin can be found here <a href=\"https://github.com/reatlat/wp-elementor-multidomain-support\">https://github.com/reatlat/wp-elementor-multidomain-support</a></p>\n<p>Plugin available in <a href=\"https://wordpress.org/plugins/multidomain-support-for-elementor/\">WordPress repository</a>, and also\nyou can download it from <a href=\"https://github.com/reatlat/wp-multidomain-support-for-elementor/releases/\">GitHub</a></p>\n",
			"date_published": "2019-04-21T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/how-to-block-visitors-by-country-with-the-nginx-geoip-module-debianubuntu/",
			"url": "https://alex.zappa.dev/blog/how-to-block-visitors-by-country-with-the-nginx-geoip-module-debianubuntu/",
			"title": "How to block visitors by country with the NGINX GeoIP Module (Debian/Ubuntu)",
			"content_html": "<p>In the last time, I see a lot of attack from botnet with IPs from eastern europe. Several of my projects\naren’t concerned about visitors from those countries, so we just block all of them 🙂</p>\n<h2 id=\"how-block-visitors-by-country\" tabindex=\"-1\">How block visitors by Country? <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-block-visitors-by-country-with-the-nginx-geoip-module-debianubuntu/#how-block-visitors-by-country\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>This tutorial explains how to use the GeoIP module with NGINX to block visitors by country. This is made possible by the\nGeoIP database which maps users’ IP addresses to countries. NGINX must be version 1.9.11 or higher, and installed the\n<a href=\"http://nginx.org/en/docs/http/ngx_http_geoip_module.html\">HttpGeoipModule</a> to use the GeoIP database.</p>\n<p>Actually, it’s pretty easy with the latest Nginx release. I use nginx v1.15.5, which I think the last stable one 🙂</p>\n<h2 id=\"let-s-start-install-geoip-module-and-database\" tabindex=\"-1\">Let’s start. Install GeoIP module and database. <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-block-visitors-by-country-with-the-nginx-geoip-module-debianubuntu/#let-s-start-install-geoip-module-and-database\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>We need install 3 packages using this command</p>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\"><span class=\"token function\">apt-get</span> <span class=\"token function\">install</span> nginx-module-geoip geoip-database libgeoip1</code></pre>\n<p>Perhaps the last one package(libgeoip1) you already have on your server 🙂</p>\n<p>After that we have to include new module and rules to file</p>\n<pre><code>/etc/nginx/nginx.conf\n</code></pre>\n<p>Add before <em>http {}</em> block open:</p>\n<pre class=\"language-ini\" tabindex=\"0\"><code class=\"language-ini\"><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">...</span><span class=\"token punctuation\">]</span></span>\n    <span class=\"token comment\"># Load GeoIP module</span>\n    load_module \"modules/ngx_http_geoip_module.so\";\n<span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">...</span><span class=\"token punctuation\">]</span></span></code></pre>\n<p>Place next block in the <em>http {}</em> block, before any <em>include</em> lines:</p>\n<pre class=\"language-ini\" tabindex=\"0\"><code class=\"language-ini\"><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">...</span><span class=\"token punctuation\">]</span></span>\n    <span class=\"token comment\"># ISO codes here https://dev.maxmind.com/geoip/legacy/codes/iso3166/</span>\n    geoip_country /usr/share/GeoIP/GeoIP.dat;\n    map $geoip_country_code $allowed_country {\n        default yes;\n        RU no;\n        UA no;\n        BY no;\n    }\n<span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">...</span><span class=\"token punctuation\">]</span></span></code></pre>\n<p>Now, this actually doesn’t block any country, it just sets the <em>$allowed_country</em> variable. To actually block countries,\nyou must open your vhost configuration and place the following code in the <em>server {}</em> container (this can go inside and\nalso outside any <em>location {}</em> block):</p>\n<pre class=\"language-ini\" tabindex=\"0\"><code class=\"language-ini\"><span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">...</span><span class=\"token punctuation\">]</span></span>\n    <span class=\"token key attr-name\">if ($allowed_country</span> <span class=\"token punctuation\">=</span> <span class=\"token value attr-value\">no) {</span>\n        return 444;\n    }\n<span class=\"token section\"><span class=\"token punctuation\">[</span><span class=\"token section-name selector\">...</span><span class=\"token punctuation\">]</span></span></code></pre>\n<p>Definitely, you can have a bit more complicated config structure, but this is just example how it’s work.</p>\n<p>We return <strong>Error 444 connections closed without response.</strong></p>\n<p>A non-standard status code used to instruct nginx to close the connection without sending a response to the client, most\ncommonly used to deny malicious or malformed requests.</p>\n<p>This status code is not seen by the client, it only appears in nginx log files. More information\non <a href=\"http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return\">nginx documentation</a>.</p>\n<h2 id=\"test-nginx-configuration-file\" tabindex=\"-1\">Test NGINX configuration file <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-to-block-visitors-by-country-with-the-nginx-geoip-module-debianubuntu/#test-nginx-configuration-file\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Run command</p>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\">nginx <span class=\"token parameter variable\">-t</span></code></pre>\n<p>You have to see this respond</p>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\">nginx: the configuration <span class=\"token function\">file</span> /etc/nginx/nginx.conf syntax is ok\nnginx: configuration <span class=\"token function\">file</span> /etc/nginx/nginx.conf <span class=\"token builtin class-name\">test</span> is successful</code></pre>\n<p>If your configuration pass the test, restart nginx using <em>systemctl</em></p>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\">systemctl restart nginx</code></pre>\n<p>Admire your great work ? and test how it’s work with VPN service.</p>\n",
			"date_published": "2019-04-14T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/how-remove-dsstore-files-from-a-git-repository/",
			"url": "https://alex.zappa.dev/blog/how-remove-dsstore-files-from-a-git-repository/",
			"title": "How remove .DS_Store files from a Git repository?",
			"content_html": "<p>Mac OS X users can include system .DS_Store files to repository accidentally.</p>\n<p>First, you can check how much .DS_Srore files you have on your work directory. Use fallow command:</p>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\"><span class=\"token function\">find</span> .* <span class=\"token parameter variable\">-name</span> <span class=\"token string\">\".DS_Store\"</span> <span class=\"token parameter variable\">-type</span> f</code></pre>\n<p>To remove all .DS_Store files from git you can use fallowing command:</p>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\"><span class=\"token function\">find</span> .* <span class=\"token parameter variable\">-name</span> .DS_Store <span class=\"token parameter variable\">-print0</span> <span class=\"token operator\">|</span> <span class=\"token function\">xargs</span> <span class=\"token parameter variable\">-0</span> <span class=\"token function\">git</span> <span class=\"token function\">rm</span> <span class=\"token parameter variable\">-f</span> --ignore-unmatch</code></pre>\n<h2 id=\"update-gitignore-file\" tabindex=\"-1\">Update .gitignore file <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-remove-dsstore-files-from-a-git-repository/#update-gitignore-file\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p>Add to the file <code>.gitignore</code>, which can be found at the top level of your repository (or created if it isn’t there already).</p>\n<p>You can do this easily with this command in the top directory:</p>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\"><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"# Apple macOS<span class=\"token entity\" title=\"\\n\">\\n</span>.DS_Store<span class=\"token entity\" title=\"\\n\">\\n</span>.DS_Store?<span class=\"token entity\" title=\"\\n\">\\n</span>*/.DS_Store\"</span> <span class=\"token operator\">>></span> .gitignore</code></pre>\n<p>Then add and commit your new <code>.gitignore</code> file</p>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\"><span class=\"token function\">git</span> <span class=\"token function\">add</span> .gitignore <span class=\"token operator\">&amp;&amp;</span> <span class=\"token function\">git</span> commit <span class=\"token parameter variable\">-m</span> <span class=\"token string\">'.DS_Store banished!'</span></code></pre>\n<h2 id=\"avoid-this-issue-in-future\" tabindex=\"-1\">Avoid this issue in future <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/how-remove-dsstore-files-from-a-git-repository/#avoid-this-issue-in-future\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\"><span class=\"token builtin class-name\">echo</span> <span class=\"token string\">\"# Apple macOS<span class=\"token entity\" title=\"\\n\">\\n</span>.DS_Store<span class=\"token entity\" title=\"\\n\">\\n</span>.DS_Store?<span class=\"token entity\" title=\"\\n\">\\n</span>*/.DS_Store\"</span> <span class=\"token operator\">>></span> ~/.gitignore_global</code></pre>\n<p>Set the global git configuration</p>\n<pre class=\"language-shell\" tabindex=\"0\"><code class=\"language-shell\"><span class=\"token function\">git</span> config <span class=\"token parameter variable\">--global</span> core.excludesfile ~/.gitignore_global</code></pre>\n<p>Admire your great work?</p>\n<p>Also, check <a href=\"https://www.toptal.com/developers/gitignore/\">gitignore.io</a> where you can configure your own <code>.gitignore</code> file by few clicks.</p>\n",
			"date_published": "2019-04-10T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/how-do-i-find-my-bitly-oauth-access-token/",
			"url": "https://alex.zappa.dev/blog/how-do-i-find-my-bitly-oauth-access-token/",
			"title": "How do I find my Bitly OAuth access token?",
			"content_html": "<p>Do you have Bitly account? If not <a href=\"https://bitly.com/a/sign_up\">signup</a> right now.</p>\n<p>If you are looking for start using the Bitly API, you will need your Oauth Access Token. To find your OAuth access token\nnavigate to the hamburger menu button in the top right-hand corner. From the drop down select ‘Settings’ and then\ncontinue to the ‘Advanced Settings’ tab. Look to the bottom under ‘For Developers’ and click on the OAuth hyperlink.</p>\n<img src=\"https://alex.zappa.dev/blog/how-do-i-find-my-bitly-oauth-access-token/assets/api-key-with-arrow.png\" alt=\"Bitly OAuth Access Token\" eleventy:widths=\"900\">\n<p>If you need to generate an access token so you can use our API, you can go to <a href=\"https://bitly.com/a/oauth_apps\">https://bitly.com/a/oauth_apps</a>, click\n“Generic Access Token”,</p>\n<img src=\"https://alex.zappa.dev/blog/how-do-i-find-my-bitly-oauth-access-token/assets/bitly-edit-profile-generic-access-token.png\" alt=\"Bitly Edit Profile Generic Access Token\" eleventy:widths=\"900\">\n<p>Then enter your password to create the token, and then copy that token into your code or configuration.</p>\n<p>Access tokens don’t expire (though you can expire them manually if yours leaks into the wild), so you can use the single\naccess token as long as you need.</p>\n",
			"date_published": "2019-01-19T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/campaign-url-builder-introducing-the-shortcodes/",
			"url": "https://alex.zappa.dev/blog/campaign-url-builder-introducing-the-shortcodes/",
			"title": "Campaign URL Builder Introducing the Shortcodes",
			"content_html": "<p>Today, I’m excited to introduce the first release of shortcodes\nfor <a href=\"https://alex.zappa.dev/blog/wp-plugin-campaign-url-builder/\">Campaign URL Builder</a> plugin.</p>\n<p>Shortcode settings moved to new tab <strong>Shortcode</strong> on top tabs menu.</p>\n<img src=\"https://alex.zappa.dev/blog/campaign-url-builder-introducing-the-shortcodes/assets/campaign-url-builder-shortcode-settings.png\" alt=\"Campaign URL Builder Shortcode Settings\" eleventy:widths=\"900\">\n<p>By default, shortcodes disabled, also if you use bulletin API key shortcodes also will be disabled.</p>\n<p>Please use your API key for Bitly. How to find your Bitly API key, <a href=\"https://alex.zappa.dev/blog/how-do-i-find-my-bitly-oauth-access-token/\">read here</a>.</p>\n<img src=\"https://alex.zappa.dev/blog/campaign-url-builder-introducing-the-shortcodes/assets/campaign-url-builder-introducing-the-shortcodes.png\" alt=\"Campaign URL Builder Shortcode Settings API Key\" eleventy:widths=\"900\">\n<p><em>This is how default shortcode generate a form on front-end</em></p>\n<h2 id=\"how-to-use-shortcode\" tabindex=\"-1\">How to use shortcode <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/campaign-url-builder-introducing-the-shortcodes/#how-to-use-shortcode\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<ol>\n<li>Setup your <a href=\"https://alex.zappa.dev/blog/how-do-i-find-my-bitly-oauth-access-token/\">Bitly API Key</a>.</li>\n<li>Enable Shotcode toggle in plugin settings.</li>\n<li>(optional) Enable shortcode for Anonymous visitor.</li>\n<li>Place shortcode (Campaign-URL-Builder) on target page.</li>\n</ol>\n<h3 id=\"styling\" tabindex=\"-1\">Styling <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/campaign-url-builder-introducing-the-shortcodes/#styling\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>By default, shortcode styles have very basic styles, you can disable it and create your styles.</p>\n<h3 id=\"shortcode-attributes\" tabindex=\"-1\">Shortcode attributes <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/campaign-url-builder-introducing-the-shortcodes/#shortcode-attributes\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Attributes is optional and for your choice.</p>\n<ul>\n<li>wrapper=”anyCssClass additionalClass”</li>\n<li>wrapper-inline-style=”background: #ff0000; padding: 10px”</li>\n<li>form=”anyCssClass additionalClass”</li>\n<li>form-inline-style=”background: #ffff00; padding: 15px”</li>\n<li>input-class=”anyCssClass additionalClass”</li>\n<li>type=”preset”</li>\n<li>campaign_page=”https://alex.zappa.dev/wp-plugin-campaign-url-builder/”</li>\n<li>utm_source=”reatlat_homepage”</li>\n<li>utm_medium=”blogpost”</li>\n<li>utm_campaign=”Introducing shortcodes”</li>\n<li>utm_term=”serach key words”</li>\n<li>utm_content=”some content”</li>\n<li>custom_parameters=”key=value|key2=value|key3=value3″</li>\n<li>hidden=”utm_source,utm_medium,utm_campaign”</li>\n</ul>\n<p>This is stock example, you can replace it like you want.</p>\n<h3 id=\"important-to-know\" tabindex=\"-1\">Important to know. <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/campaign-url-builder-introducing-the-shortcodes/#important-to-know\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>If you use <code>type=”preset”</code> all fields which already have presented attributes will have read only attribute, and front end users can’t replace it.</p>\n<p>The <code>custom_parameters</code>, you can pass only 3 couples. For example <code>my_param=someValue</code>. please separate couples by Vertical Bar.</p>\n<p>The attribute <code>hidden</code> can contain the name of fields which you want to hide from front-end. For example, <code>hidden=”utm_source,utm_medium,utm_campaign”</code> in this case 3 input fields will be hidden for users.</p>\n<p>Very soon, I will prepare the visual shortcode generator.</p>\n<h3 id=\"examples\" tabindex=\"-1\">Examples <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/campaign-url-builder-introducing-the-shortcodes/#examples\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Simple example</p>\n<pre class=\"language-php\" tabindex=\"0\"><code class=\"language-php\"><span class=\"token punctuation\">[</span>Campaign<span class=\"token operator\">-</span><span class=\"token constant\">URL</span><span class=\"token operator\">-</span>Builder<span class=\"token punctuation\">]</span></code></pre>\n<p>Advanced example</p>\n<pre class=\"language-php\" tabindex=\"0\"><code class=\"language-php\"><span class=\"token punctuation\">[</span>Campaign<span class=\"token operator\">-</span><span class=\"token constant\">URL</span><span class=\"token operator\">-</span>Builder wrapper<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"MegaWrapperClass\"</span> wrapper<span class=\"token operator\">-</span>inline<span class=\"token operator\">-</span>style<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"background:#ccc;padding:15px;\"</span> form<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"MegaFormClass\"</span> form<span class=\"token operator\">-</span>inline<span class=\"token operator\">-</span>style<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"padding:10px; background:#c19393\"</span> campaign_page<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"https://alex.zappa.dev\"</span> utm_source<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"\"</span> utm_medium<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"\"</span> utm_campaign<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"\"</span> utm_term<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"\"</span> utm_content<span class=\"token operator\">=</span><span class=\"token string double-quoted-string\">\"\"</span><span class=\"token punctuation\">]</span></code></pre>\n<p>PHP example</p>\n<pre class=\"language-php\" tabindex=\"0\"><code class=\"language-php\"><span class=\"token php language-php\"><span class=\"token delimiter important\">&lt;?php</span> <span class=\"token keyword\">echo</span> <span class=\"token function\">do_shortcode</span><span class=\"token punctuation\">(</span><span class=\"token string single-quoted-string\">'[Campaign-URL-Builder]'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token delimiter important\">?></span></span></code></pre>\n",
			"date_published": "2019-01-19T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/transitioning-google-url-shortener-to-bitly/",
			"url": "https://alex.zappa.dev/blog/transitioning-google-url-shortener-to-bitly/",
			"title": "Transitioning Google URL shortener to Bitly",
			"content_html": "<p>On <a href=\"https://alex.zappa.dev/blog/wp-plugin-campaign-url-builder/\">Campaign URL Builder</a> plugin, I decided finally move to Bitly API endpoint.</p>\n<p>Since March 2019, <a href=\"https://alex.zappa.dev/blog/wp-plugin-campaign-url-builder/\">Campaign URL Builder</a> plugin will be turning down support for\ngoo.gl URL shortener. Previously created links will continue to redirect to their intended destination. Please see this\n<a href=\"https://developers.googleblog.com/2018/03/transitioning-google-url-shortener.html\">Google blog post</a> for more details.</p>\n",
			"date_published": "2019-01-14T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/wp-plugin-campaign-url-builder/",
			"url": "https://alex.zappa.dev/blog/wp-plugin-campaign-url-builder/",
			"title": "WP plugin Campaign URL Builder",
			"content_html": "<p>This plugin allows you to easily add campaign parameters to URLs so you can track Custom Campaigns in Google Analytics.\nAlso, you can easily create short links and easily share it on social networks.</p>\n<h2 id=\"get-and-install-plugin-for-wordpress\" tabindex=\"-1\">Get and Install plugin for WordPress <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/wp-plugin-campaign-url-builder/#get-and-install-plugin-for-wordpress\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<p><em>From WordPress repository</em></p>\n<p>Or alternative repository on GitHub, <a href=\"https://github.com/reatlat/wp-campaign-url-builder/releases\">the latest release</a>.</p>\n<h2 id=\"shotcode\" tabindex=\"-1\">Shotcode <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/wp-plugin-campaign-url-builder/#shotcode\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<h3 id=\"what-is-a-shortcode\" tabindex=\"-1\">What is a shortcode? <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/wp-plugin-campaign-url-builder/#what-is-a-shortcode\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>A shortcode is a WordPress-specific code that lets you do nifty things with very little effort. Shortcodes can embed\nfiles or create objects that would normally require lots of complicated, ugly code in just one line. Shortcode =\nshortcut.</p>\n<p>Campaign URL Builder shortcode allows you to place presented shortlink generator on any page content.</p>\n<h3 id=\"shortcode-generator\" tabindex=\"-1\">Shortcode generator <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/wp-plugin-campaign-url-builder/#shortcode-generator\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<p>Coming a soon as possible… ?</p>\n",
			"date_published": "2019-01-01T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/gitkraken-cross-platform-editor-for-git-repos/",
			"url": "https://alex.zappa.dev/blog/gitkraken-cross-platform-editor-for-git-repos/",
			"title": "GitKraken – cross-platform editor for git repos",
			"content_html": "<p>I did not use the GUI to work with git. When I was just starting to program, there was nothing interesting for Linux,\nbut theoretically, I was immediately taught to the command line, so no interfaces were required.</p>\n<p>Then <a href=\"https://wiki.gnome.org/Apps/Gitg\">gitg</a> and IDEA came along with its integration with git, and this perfectly\ncomplemented my work on the command line.</p>\n<p>However, I still follow different projects, especially if they are written on the technologies of the front. So, I\nstumbled upon GitKraken. Cross-platform git interface.</p>\n<h2 id=\"gitkraken\" tabindex=\"-1\">GitKraken <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/gitkraken-cross-platform-editor-for-git-repos/#gitkraken\">#<span class=\"sr-only\"> Anchor link </span></a></h2>\n<img src=\"https://alex.zappa.dev/blog/gitkraken-cross-platform-editor-for-git-repos/assets/girkraken-interface.png\" alt=\"GitKraken Interface\" eleventy:widths=\"900\">\n<p>GitKraken is written in <a href=\"https://www.electronjs.org\">electron</a> and uses open\nlibraries: <a href=\"https://www.nodegit.org\">NodeGit</a>, <a href=\"https://libgit2.org\">libgit2</a>. This is exactly what allows it to\nsimply support cross-platform.</p>\n<img src=\"https://alex.zappa.dev/blog/gitkraken-cross-platform-editor-for-git-repos/assets/gitkraken-merge.png\" alt=\"GitKraken Merge\" eleventy:widths=\"900\">\n<p>A certain minus of the program is that it is limited free(Freemium). For personal use, with some functional limitations,\nit is completely free, but for professional work you have to take subscription. The cost of a subscription per year is\nnot costly, just $49 per year.</p>\n<p>Recently found an excellent coupon with a $20Off discount for a one-year subscription. Coupon can be obtained if you\nfollow the link <a href=\"https://www.gitkraken.com/switch\">https://www.gitkraken.com/switch</a>, GitKraken thus attracts new subscribers.</p>\n<blockquote>\n<p>By the way, you can immediately use the <strong>switch2018</strong> coupon.</p>\n</blockquote>\n<h3 id=\"gitkraken-pro-features\" tabindex=\"-1\">GitKraken Pro – Features <a class=\"header-anchor\" href=\"https://alex.zappa.dev/blog/gitkraken-cross-platform-editor-for-git-repos/#gitkraken-pro-features\">#<span class=\"sr-only\"> Anchor link </span></a></h3>\n<img src=\"https://alex.zappa.dev/blog/gitkraken-cross-platform-editor-for-git-repos/assets/gk-features.png\" alt=\"GitKraken Pro Features\" eleventy:widths=\"900\">\n<p>There are many goodies, but the most beautiful thing, in my opinion, is that the merge conflict tools, merge a\nconflicting code very difficult on big projects, and often took a lot of time because something could be overwritten and\na whole code branch was lost.</p>\n<p><lite-youtube videoid=\"R1iWJNyRpQE\" class=\"mx-auto rounded drop-shadow-lg\" style=\"background-image: url('https://i.ytimg.com/vi/R1iWJNyRpQE/maxresdefault.jpg');\"></lite-youtube></p>\n<p>With GitKraken, this has become elementary, the code highlighting system for changes in the code (DIFF) and the built-in\neditor allow you to make changes to the files on the fly and the build process becomes effortless.</p>\n<p>This and many other pleasant things make working with Git using GitKraken very fast and comfortable, and therefore\nincreases productivity.</p>\n<p>GitKraken also recently introduced a task-tracking system similar to Trello, called GitKraken Glo. Together with the\nGitHub Issues, the Glo can be an excellent task manager. About GitKraken Glo will write a little later.</p>\n<p>Have fun?</p>\n",
			"date_published": "2018-11-09T00:00:00Z"
		}
		,
		{
			"id": "https://alex.zappa.dev/blog/adding-subscribers-to-a-list-using-mailchimps-api-v3/",
			"url": "https://alex.zappa.dev/blog/adding-subscribers-to-a-list-using-mailchimps-api-v3/",
			"title": "Adding subscribers to a list using Mailchimp’s API v3",
			"content_html": "<p>Based on the <a href=\"https://mailchimp.com/developer/marketing/api/list-members/\">List Members Instance docs</a>, the easiest way\nis to use a PUT request which according to the docs either “adds a new list member or updates the member if the email\nalready exists on the list”.</p>\n<p>Furthermore, API key is definitely not part of\nthe <a href=\"https://us9.api.mailchimp.com/schema/3.0/Lists/Members/Instance.json\">JSON schema</a> and there’s no point in\nincluding it in your JSON\nrequest.</p>\n<p>Also, you can use CURLOPT_USERPWD for basic HTTP auth as illustrated in below.</p>\n<p>I’m using the following function to add and update list members. You may need to include a slightly different set of\nmerge_fields depending on your list parameters.</p>\n<pre class=\"language-php\" tabindex=\"0\"><code class=\"language-php\"><span class=\"token php language-php\"><span class=\"token delimiter important\">&lt;?php</span>\n<span class=\"token comment\">/**\n * Adding subscribers to a list using Mailchimp's API v3\n * Based on the List Members Instance docs,\n * @link http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/\n */</span>\n<span class=\"token variable\">$data</span> <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token string single-quoted-string\">'email'</span>     <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'angelina.jolie@example.com'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string single-quoted-string\">'status'</span>    <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'subscribed'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string single-quoted-string\">'firstname'</span> <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'Angelina'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string single-quoted-string\">'lastname'</span>  <span class=\"token operator\">=></span> <span class=\"token string single-quoted-string\">'Jolie'</span>\n<span class=\"token punctuation\">]</span><span class=\"token punctuation\">;</span>\n<span class=\"token function\">syncMailchimp</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$data</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">function</span> <span class=\"token function-definition function\">syncMailchimp</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$data</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token variable\">$apiKey</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">'your api key'</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$listId</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">'your list id'</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$memberId</span> <span class=\"token operator\">=</span> <span class=\"token function\">md5</span><span class=\"token punctuation\">(</span><span class=\"token function\">strtolower</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$data</span><span class=\"token punctuation\">[</span><span class=\"token string single-quoted-string\">'email'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$dataCenter</span> <span class=\"token operator\">=</span> <span class=\"token function\">substr</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$apiKey</span><span class=\"token punctuation\">,</span><span class=\"token function\">strpos</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$apiKey</span><span class=\"token punctuation\">,</span><span class=\"token string single-quoted-string\">'-'</span><span class=\"token punctuation\">)</span><span class=\"token operator\">+</span><span class=\"token number\">1</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$url</span> <span class=\"token operator\">=</span> <span class=\"token string single-quoted-string\">'https://'</span> <span class=\"token operator\">.</span> <span class=\"token variable\">$dataCenter</span> <span class=\"token operator\">.</span> <span class=\"token string single-quoted-string\">'.api.mailchimp.com/3.0/lists/'</span> <span class=\"token operator\">.</span> <span class=\"token variable\">$listId</span> <span class=\"token operator\">.</span> <span class=\"token string single-quoted-string\">'/members/'</span> <span class=\"token operator\">.</span> <span class=\"token variable\">$memberId</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$json</span> <span class=\"token operator\">=</span> <span class=\"token function\">json_encode</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">[</span>\n        <span class=\"token string single-quoted-string\">'email_address'</span> <span class=\"token operator\">=></span> <span class=\"token variable\">$data</span><span class=\"token punctuation\">[</span><span class=\"token string single-quoted-string\">'email'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string single-quoted-string\">'status'</span>        <span class=\"token operator\">=></span> <span class=\"token variable\">$data</span><span class=\"token punctuation\">[</span><span class=\"token string single-quoted-string\">'status'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// \"subscribed\",\"unsubscribed\",\"cleaned\",\"pending\"</span>\n        <span class=\"token string single-quoted-string\">'merge_fields'</span>  <span class=\"token operator\">=></span> <span class=\"token punctuation\">[</span>\n            <span class=\"token string single-quoted-string\">'FNAME'</span>     <span class=\"token operator\">=></span> <span class=\"token variable\">$data</span><span class=\"token punctuation\">[</span><span class=\"token string single-quoted-string\">'firstname'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string single-quoted-string\">'LNAME'</span>     <span class=\"token operator\">=></span> <span class=\"token variable\">$data</span><span class=\"token punctuation\">[</span><span class=\"token string single-quoted-string\">'lastname'</span><span class=\"token punctuation\">]</span>\n        <span class=\"token punctuation\">]</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$ch</span> <span class=\"token operator\">=</span> <span class=\"token function\">curl_init</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$url</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">curl_setopt</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$ch</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">CURLOPT_USERPWD</span><span class=\"token punctuation\">,</span> <span class=\"token string single-quoted-string\">'user:'</span> <span class=\"token operator\">.</span> <span class=\"token variable\">$apiKey</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">curl_setopt</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$ch</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">CURLOPT_HTTPHEADER</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">[</span><span class=\"token string single-quoted-string\">'Content-Type: application/json'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">curl_setopt</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$ch</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">CURLOPT_RETURNTRANSFER</span><span class=\"token punctuation\">,</span> <span class=\"token constant boolean\">true</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">curl_setopt</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$ch</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">CURLOPT_TIMEOUT</span><span class=\"token punctuation\">,</span> <span class=\"token number\">10</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">curl_setopt</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$ch</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">CURLOPT_CUSTOMREQUEST</span><span class=\"token punctuation\">,</span> <span class=\"token string single-quoted-string\">'PUT'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">curl_setopt</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$ch</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">CURLOPT_SSL_VERIFYPEER</span><span class=\"token punctuation\">,</span> <span class=\"token constant boolean\">false</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$result</span> <span class=\"token operator\">=</span> <span class=\"token function\">curl_exec</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$ch</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token variable\">$httpCode</span> <span class=\"token operator\">=</span> <span class=\"token function\">curl_getinfo</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$ch</span><span class=\"token punctuation\">,</span> <span class=\"token constant\">CURLINFO_HTTP_CODE</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token function\">curl_close</span><span class=\"token punctuation\">(</span><span class=\"token variable\">$ch</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n    <span class=\"token keyword\">return</span> <span class=\"token variable\">$httpCode</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n</span></code></pre>\n",
			"date_published": "2016-11-08T00:00:00Z"
		}
		
	]
}

