"gatsby-source-wordpress",
html: {
useGatsbyImage: false,
},
—verbose flag with build commands - debugging tip
----
yarn global add gatsby-cli
yarn global add netlify-cli
npm install --platform=darwin --arch=arm64v8 sharp - fixing sharp error:
https://chatgpt.com/share/6889f0ea-64f0-8007-a8ae-3cfac0df0fa6
netlify api getSite --data '{
"site_id": "xxx"
}'
netlify api updateSite --data '{
"site_id": "xxx",
"body": { "build_timelimit": 1800 }
}'
netlify api getSite --data '{
"site_id": "xxx"
}' | jq '.build_timelimit'
On Bitnami stacks, there are usually two PHP configuration files:
• /opt/bitnami/php/etc/php.ini → loaded for web server (Apache).
• /opt/bitnami/php/etc/php.ini-production → sometimes used for CLI/PHP-FPM or fallback.
To be safe, we can update both files in one SSH command using sed and && chaining. Here’s a one-liner you can paste directly into your Lightsail SSH:
for f in /opt/bitnami/php/etc/php.ini /opt/bitnami/php/etc/php.ini-production; do sudo sed -i "s/upload_max_filesize = .*/upload_max_filesize = 1024M/" $f && sudo sed -i "s/post_max_size = .*/post_max_size = 1024M/" $f && sudo sed -i "s/memory_limit = .*/memory_limit = 2048M/" $f && sudo sed -i "s/max_execution_time = .*/max_execution_time = 3000/" $f && sudo sed -i "s/max_input_time = .*/max_input_time = 3000/" $f; done && sudo /opt/bitnami/ctlscript.sh restart apache && echo "✅ PHP limits updated on Bitnami (including production). Max upload size is now 1GB."
sudo /opt/bitnami/ctlscript.sh restart php-fpm
sudo /opt/bitnami/ctlscript.sh restart apache
# ====================================================
# 🛠️ Fix CORS + CSP for Bitnami WordPress (artopen.co)
# - Allows fonts, PDFs, uploads, iframes
# - Fixes base64 data URI + blob CSP issues
# - Safe & HTTPS-only
# ====================================================
# 1️⃣ Backup configs first
sudo cp /opt/bitnami/apache/conf/vhosts/wordpress-vhost.conf /opt/bitnami/apache/conf/vhosts/wordpress-vhost.conf.bak
sudo cp /opt/bitnami/apache/conf/vhosts/wordpress-https-vhost.conf /opt/bitnami/apache/conf/vhosts/wordpress-https-vhost.conf.bak
# 2️⃣ Append unified CORS + CSP rules to both vhost files
for FILE in /opt/bitnami/apache/conf/vhosts/wordpress-vhost.conf /opt/bitnami/apache/conf/vhosts/wordpress-https-vhost.conf; do
sudo tee -a $FILE > /dev/null <<'EOF'
# ====================================================
# BEGIN: Headless CORS + CSP (artopen.co)
# ====================================================
<IfModule mod_headers.c>
# --- CORS for Frontend Domain ---
<Directory "/opt/bitnami/wordpress/wp-content/uploads">
Header always set Access-Control-Allow-Origin "https://example.com"
Header always set Access-Control-Allow-Methods "GET, OPTIONS"
Header always set Access-Control-Allow-Headers "Range, Content-Type, Accept, Origin"
Header always set Access-Control-Expose-Headers "Content-Length, Content-Range"
</Directory>
<Directory "/opt/bitnami/wordpress/wp-content/themes">
Header always set Access-Control-Allow-Origin "https://example.com"
</Directory>
<Directory "/opt/bitnami/wordpress/wp-content/plugins">
Header always set Access-Control-Allow-Origin "https://example.com"
</Directory>
# --- Global Secure Content Security Policy ---
Header always set Content-Security-Policy "default-src 'self' https:; \
frame-ancestors 'self' https://example.backend.com https://example.com https://other.domain.com https://other.domain.com; \
script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; \
worker-src 'self' blob:; \
style-src 'self' 'unsafe-inline' https:; \
img-src 'self' data: https:; \
connect-src 'self' data: blob: https: https://example.backend.com; \
font-src 'self' https: data:; \
object-src 'none'; \
base-uri 'self'; \
form-action 'self';"
# --- Extra Security Headers ---
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "no-referrer-when-downgrade"
Header always set Permissions-Policy "geolocation=(), microphone=(), camera=(), payment=(), interest-cohort=()"
</IfModule>
# ====================================================
# END: Headless CORS + CSP (artopen.co)
# ====================================================
EOF
done
# 3️⃣ Restart Apache to apply the new headers
sudo /opt/bitnami/ctlscript.sh restart apache
# 4️⃣ Verify headers for a PDF (optional test)
echo "✅ Deployment complete. Now run:"
echo "curl -I https://example.backend.com/wp-content/uploads/2025/11/elektronika-uzytkowa-usb.pdf"
https://repost.aws/knowledge-center/lightsail-upgrade-php
gatsby develop –host 0.0.0.0 – opens ports on lan
netlify dev – for functions testing
1. superfunky – frontend
1.0. General improvements
Time estimation: x days
- Router fallback solution for not built data – incremental builds / cache problem
- Push notifications layer
- Geolocalization for multi-lang
1.1. Additional mutations and data
Time estimation: x days
1.3. Login, user account and registration
Time estimation: x weeks
- Virtual products support with files download
- Login by socials – Google etc.
1.5 Data layer, GTM + Cookies Consent v2 advanced settings ✅
Integrate data layer and gtm ✅ + advanced cookies data ✅
Order matters!
1. before </head> - TCF
<script>
<!-- Enabled tcf support for Google tag -->
window ['gtag_enable_tcf_support'] = true;
</script>
2. before </head> - DCV
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
// Restrictive defaults except analytics
gtag("consent", "default", {
ad_storage: "denied",
ad_user_data: "denied",
ad_personalization: "denied",
analytics_storage: "granted", // ✅ granted by default
functionality_storage: "granted",
personalization_storage: "denied",
security_storage: "granted",
wait_for_update: 2500,
});
gtag("set", "ads_data_redaction", true);
gtag("set", "url_passthrough", true);
// Restore saved preferences if user decided before
(function() {
function getCookie(name) {
const value = ("; " + document.cookie).split("; " + name + "=");
if (value.length === 2) return decodeURIComponent(value.pop().split(";").shift());
}
const saved = getCookie("cookie_v2");
if (saved) {
try {
const consent = JSON.parse(saved);
gtag("consent", "update", consent);
window.dataLayer.push({ event: "consent_update", consent });
} catch(e) {
console.warn("Invalid consent cookie:", e);
}
}
})();
</script>
3. before </head> - GTM
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-XXX');</script>
<!-- End Google Tag Manager -->
4. before </body> - GTMNS
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-XXX"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->
Fix:
Correct permissions:
sudo find /bitnami/wordpress/ -type d -exec chmod 755 {} \;
sudo find /bitnami/wordpress/ -type f -exec chmod 644 {} \;
1.6 Variables list ✅
This post presents all the front-end variables available for mapping broke into smaller chunks.
{
"crossSell": "Promoted products",
"categoryPills": "Product categories",
"allProducts": "All products",
"tagPills": "Product tags",
"latestPosts": "Latest posts",
"blogCategories": "Post categories",
"blogTags": "Post tags",
"featuredCategory": "Check out our drinks",
"featuredPosts": "Featured posts",
"wishlist": "Wishlist",
"wishlistIntro": "Your magically saved products ",
"wishlistEmpty": "There are no products on your list, ",
"wishlistBack": "Back to shop",
"savedPosts": "Saved posts",
"savedPostsIntro": "Here you will find saved posts.",
"savedPostsEmpty": "You haven’t saved any posts, go back to the blog and ",
"savedPostsBack": "save a post.",
"auth": "Customer panel",
"authIntro": "Go through registration or log in to manage your profile and orders.",
"login": "Log in",
"loginText": "Log in to the customer panel to manage your profile and orders",
"loginLabel": "Email or username",
"loginPlaceholder": "enter here...",
"passwordLabel": "Enter password",
"passwordPlaceholder": "enter password...",
"loginButton": "Log in",
"loginRegister": "Don’t have an account? Register.",
"register": "Register",
"registerText": "Register to get access to the customer panel.",
"registerLabel": "Registration",
"registerUser": "Your name",
"registerUserPlaceholder": "enter name",
"registerEmail": "Your email",
"registerEmailPlaceholder": "enter your email",
"registerPassword": "Enter password",
"registerPasswordPlaceholder": "enter password...",
"registerConsent": "I have read and accept the shop’s terms and policies",
"registerTerms": "I declare that I have read and accept the Privacy Policy and information on the processing of my personal data by the Data Administrator",
"registerButton": "Join",
"registerLogin": "Already have an account? Log in",
"forgotPass": "Reset password",
"forgotSubmit": "Magic link sent!",
"forgotButton": "Send magic link",
"forgotText": "Enter your email to receive a reset link.",
"forgotPassword": "Forgot password? Generate a magic link!",
"resetPass": "Reset password",
"resetButton": "Reset",
"resetNew": "New password",
"resetText": "Set a new password for your account.",
"featuredPro": "Featured products",
"shop": "Shop",
"blog": "Blog",
"shopIntro": "Welcome to the shop!",
"shopDesc": "Check out our products.",
"blogIntro": "Welcome to the blog!",
"blogDesc": "Enjoy the reading...",
"cartButtonSimple": "Add to cart 🍄",
"cartButtonExternal": "Subscribe 🍄",
"cartButtonVariable": "Choose an option 🍄",
"viewProduct": "View product 🍄",
"viewCart": "View cart",
"inStock": "in stock",
"outOfStock": "out of stock",
"saveForLater": "Add to list",
"readMore": "Read article →",
"cartIntro": "Cart",
"clearCart": "Clear cart",
"emptyCart": "Your cart is empty",
"continueShopping": "Continue shopping",
"backToShop": "Back to shop",
"cartSummary": "Total value",
"subtotal": "Subtotal:",
"shipping": "Shipping:",
"shippingInfo": "PLN more to <b>free shipping</b>",
"total": "Total:",
"checkout": "Order & pay",
"quantity": "Quantity:",
"item": "Items:",
"proFeatured": "Featured",
"proGallery": "Product gallery",
"proLearnMore": "Learn more",
"proCats": "Product categories",
"proTags": "Product tags",
"optChoose": "Choose an option",
"askForItem": "Ask about product",
"learnMore": "Learn more...",
"upSell": "Check also",
"postWords": "words",
"postRead": "reading time",
"postToc": "Table of contents",
"reviewTxt": "Leave a review",
"reviewName": "Your name",
"reviewEmail": "Your email",
"reviewRating": "Your rating",
"reviewContent": "Your message",
"reviewSubmit": "Leave a comment",
"reviewApproval": "Your review has been submitted and is awaiting approval.",
"noReviews": "No reviews :( Add one!",
"allReviews": "All reviews",
"account": "Your account",
"accountIntro": "Have questions about your account? Contact us!.",
"dashboard": "Dashboard",
"yourData": "Your data",
"hello": "Hello",
"dashText": "In your account panel you can view your recent orders and check your shipping and billing addresses.",
"orders": "Your orders",
"orderSearch": "Search by order ID or product name...",
"subsInfo": "For subscription orders visit the Stripe customer panel by clicking here.",
"noOrders": "No orders found",
"shopNow": "Back to shop",
"order": "Order",
"orderPlaced": "Placed:",
"paymentMethod": "Paid with:",
"allOrders": "All",
"orderTax": "Includes VAT:",
"orderNote": "Note:",
"loadMore": "Load more",
"addresses": "Your addresses",
"billingAddress": "Billing address",
"shippingAddress": "Shipping address",
"accountDetails": "Details",
"firstName": "Your first name",
"lastName": "Last name",
"username": "Username",
"website": "Website",
"yourEmail": "Your email",
"edit": "Edit",
"save": "Save",
"cancel": "Cancel",
"registeredOn": "Joined:",
"updateAvatar": "Change avatar",
"maxFile": "Maximum file size is 690KB",
"cantChange": "Username cannot be changed",
"company": "Company",
"addres1": "Your address",
"addres2": "Address (cont.)",
"addressPlaceholder1": "Street and house / apartment number",
"addressPlaceholder2": "Apartment, building, unit, etc. (optional)",
"city": "City",
"postcode": "Postcode",
"state": "State/Province",
"country": "Country",
"phone": "Phone",
"email": "Email",
"checkoutBilling": "Billing details",
"checkoutDifferent": "Deliver to a different address?",
"checkoutNote": "Order note",
"checkoutOrder": "Your order",
"gotCoupon": "Have a coupon code?",
"couponCode": "enter coupon code...",
"applyCode": "Apply",
"wrongCode": "Invalid code...",
"validCode": "Congratulations, discount applied!",
"createAcc": "Create an account?",
"chooseCountry": "Choose country",
"freeShipping": "Free shipping 🎉",
"discount": "Discount:",
"coupons": "Used coupons",
"noTerms": "Please accept the Terms & Conditions and Privacy Policy.",
"blik0": "Please enter a six-digit BLIK code.",
"blik1": "The BLIK code must have exactly 6 digits.",
"blikCode": "Enter code:",
"blikTimer": "You have <b id='timer'>02:00</b> minutes to complete the payment and enter the 6-digit <b>BLIK</b> code from your banking app.",
"blikBtn": "Order & pay - BLIK",
"checkoutTerms": "I have read and accept the Terms & Conditions",
"checkoutPrivacy": "I declare that I have read and accept the Privacy Policy and information on the processing of my personal data by the Data Administrator, Shroom sp. z o.o. based in Olsztyn, ul. Towarowa 20b, 10-417 Olsztyn",
"checkoutBtn": "Order & pay",
"processingPayment": "Processing payment, please do not close the window...",
"orderSuccess": "Your order has been received",
"orderThankYou": "Thank you for shopping with us!",
"orderPaymentSuccess": "✅ Payment processed successfully!",
"orderPaymentPending": "⏳ Payment is still being processed.",
"orderPaymentFailed": "❌ Payment failed. Redirecting...",
"orderPaymentUnexpected": "⚠️ Unexpected payment status.",
"orderDetails": "Order details",
"orderDetailsText": "Full order summary",
"orderQuestions": "Have questions about your order?",
"contactUs": "Contact us",
"extraCode": "Thank you for shopping with us. <br /> You will receive -5% on your next order with code <code>shroom_bonus</code>.",
"image": "Image:",
"product": "Product:",
"courier": "Courier:",
"pleaseWait": "Order is being processed, please don’t close the window yet",
"logOut": "Log out",
"cookiesIntro": "Manage cookies",
"alwaysOn":"Always on",
"cookiesEssential": "Essential",
"cookiesAnalytics": "Analytics",
"cookiesAds": "Ads",
"cookiesPersonalization": "Personalization",
"cookiesAdvanced": "Advanced",
"cookiesEssentialInfo": "Essential cookies are always enabled to ensure security and basic functionality.",
"cookiesAnalyticsInfo": "Analytics cookies help us understand how visitors interact with the site.",
"cookiesAdsInfo": "Advertising cookies are used to show personalized ads and measure their effectiveness.",
"cookiesPersonalizationInfo": "Personalization cookies allow us to remember your preferences.",
"cookiesAdvancedInfo": "A full list of all cookies stored in your browser.",
"cookieDelete": "Delete",
"cookieSave": "Save choices",
"cookieAllowed": "Allowed",
"cookieBlocked": "Blocked",
"cookieConsent":"I consent to cookies...",
"manageOptions":"Manage",
"acceptAll":"Accept",
"cookiesInfo":"We inform you that we use cookies to ensure the proper functioning of our website, as well as for analytical and advertising purposes. Learn more about how we use cookies on our website.",
"cookiesPolicy":"in the Cookie Policy",
"thankYou":"Thank you!",
"yourMessage":"Your application has been accepted",
"ourTeam":"Our team will contact you shortly :)",
"searchBar": "Type here..."
}
We need to add explanations to each fields so the users fill them properly as well as null checks in the code for handling empty ones.
{
"socialLinks": [
{ "service": "INSTAGRAM", "username": "shroom.drink" },
{ "service": "FACEBOOK", "username": "shroom4you" },
{ "service": "LINKEDIN", "username": "company/shroom4you/" },
{ "service": "YOUTUBE", "username": "@shroom4you" }
],"headers": [
{ "id":0, "text": "Let's connect!" }
]
}
{
"options": {
"slidesPerView": 5,
"spaceBetween": 20,
"loop": true,
"autoplay": {
"delay": 3000,
"disableOnInteraction": false
},
"pagination": { "clickable": true }
},
"images": [
{
"title": "Lion's mane",
"url": "https://v2.shroom4you.com/wp-content/uploads/2023/06/lion-mane-300x300.png",
"width": "100px",
"height": "100px"
},
{
"title": "Ginger",
"url": "https://v2.shroom4you.com/wp-content/uploads/2023/06/ginger-300x300.png",
"width": "100px",
"height": "100px"
},
{
"title": "Ginseng",
"url": "https://v2.shroom4you.com/wp-content/uploads/2025/08/ginseng-root-showcasing-twisted-earthy-form-natural-setting-displays-its-unique-shape-highlighting-intricate-details-349821261.png",
"width": "100px",
"height": "100px"
},
{
"title": "Vitamine C + Zinc",
"url": "https://v2.shroom4you.com/wp-content/uploads/2023/06/vitamin-c-300x300.png",
"width": "100px",
"height": "100px"
},
{
"title": "Hops",
"url": "https://v2.shroom4you.com/wp-content/uploads/2023/06/hops-300x300.png",
"width": "100px",
"height": "100px"
},
{
"title": "L-Theanine",
"url": "https://v2.shroom4you.com/wp-content/uploads/2023/06/zinc-300x300.png",
"width": "100px",
"height": "100px"
}
]
}
{
"buttonText": "Newsletter",
"header": "Join our newsletter",
"intro": "Get updates on new products, promo codes, limited drops and early access.",
"privacy": "I agree to receive emails about products, updates and special offers. I can unsubscribe at any time, learn more in the <a href='/privacy-policy/' class='text-blue-600 hover:underline'>privacy policy</a>.",
"ctaText": "Subscribe"
}
{
"header": "Zapraszamy do kontaktu...",
"intro": "Chciałbyś dowiedzieć się więcej? Porozmawiajmy!",
"phoneText":"Zadzwoń",
"phone": "+48717776660",
"emailText":"Wyślij email",
"email": "info@proart.biz",
"revealText": "kliknij tutaj",
"locationText":"Lokalizacja",
"location": "Polska",
"hoursText":"Godziny",
"hours": "9:00 - 17:00 pon. - pt.",
"nameLabel":"Twoje imię",
"emailLabel":"Twój email",
"companyLabel":"Twoja firma",
"phoneLabel":"Twój telefon",
"textareaLabel":"Wpisz tutaj wiadomość...",
"buttonText":"Wyślij",
"nameError":"Imię jest wymagane...",
"emailError":"Email jest wymagany...",
"emailInvalidError":"Email jest niepoprawny...",
"messageError":"Wiadomość jest wymagana...",
"thankYouMsg":"Dziękujemy!"
}
1.7. Post processing & SEO improvements ✅
Performance works:
- Lightspeed test + perfomance optimisation❗️/ ✅
- Google sheets with app script – REST API ✅
- Set up sheets and automation ✅
- Maps location plugin – GCP required, data migrated ✅
- Sitemap XML – netlify extension sitemap + submit activated ✅ – https://app.netlify.com/projects/shroomv2/configuration/deploys#build-plugins
- Mailgun + domain check
- Redirects for old shop domain ✅
Post processing:
- Baselinker – ✅
- Google for woo – plugin / ❗️✅ + Aga
- Ifirma – rest api ✅
Yoast SEO full-stack implementation ✅
2. Headless mods plugin – functions
Time estimation: x week
3. Headless theme – extra functions
Time estimation: 3 days to 1 week
4. headless-security-plugin ✅ – extra functions
Time estimation: 3 days to 1 week
- Rebuild the admin dashboard for admin experience
- Functions listed in plugin’s readme.
4. Extras
- pass order & user data to stripe – develop stripe endpoints ❗️
- Autoresponders in front-end forms❗️- should be sent from backend
- hreflang for languages in layout helmet❗️
- lang localize errors / msgs properly ❗️
- more parse for html content in componentsData❗️
- Stripe customer portal url mapped in backend ✅ /❗️
- Slack integration – not needed for now❗️
- Translations correction
- Language filtration – next / prev problem for posts and products /❗️- can wait
- author pages language filter
- ?User’s profile pages generated with their data (only public and posts)
- Spotify player with soundtrack ✅ – backend map ❗️
- Click & sounds UX = on / off + file / plugin / theme❗️
- Crypto wallet support for payments (future feature ETH / BTC blockchains) ❗️
- Prism.js syntax highlighting for code fragments (optional future feature) ❗️
- Order options❗️
- add payment / shipping methods display with pricing (added queries for both need to be dynamic select might be better + shipping costs? and update the order data) ❗️ ✅❗️
- multi-currency – after MVP ❗️
- Idea: products without price will have an ask for product button and a form in a pop-up box. ❗️
- IDEA: Plugin specific code – allows to simplify the setup for less functions, possible to query plugins form front-end❗️
Milestones:
- Finish the documentation
- Remove the need for ACF = move to custom graphql endpoints
- Get polylang pro agency license
GLOBAL DISTRIBUTION > 01.01.2027
Around 12 months of production is needed to complete the project with global distribution click to install style. Then for monetisation there are a few options:
- self-distributed (preffered, from the theme website itself)
- agencies & freelancers
- service of implementation
- envato, themeforest etc. marketplaces
