There are a couple of ways that I know of to create a theme demo site and I will outline them below.
- Single WordPress Website (Multiple Themes)
- Pro
- Probably only works for themes with builders
- less files and WordPress installs
- all theme templates are available in 1 dashboard
- only 1 set of plugin to configure
- don't have the hassle of setting up multisite
- can add iframe-x header 1 and configure as needed
- less server overheads
- easy to manage
- 1 set of credentials to log in with
- uploaded files are easier to manage
- Con
- cant use divi global headers for each theme
- cant use the inbuilt divi theme menu in div customizer
- Pro
- Multiple WordPress Websites (1 Theme per Website)
- Pro
- Each theme can be fully controlled
- Con
- A lot more inodes and server space is required
- more of a security risk because of the greater attack surface
- harder to manage with all of the updates needed to be applied to every site
- More CPU power needed
- Takes much longer to setup a theme
- many different credentials and databases to manage
- Pro
- WordPress Multisite (same as Multiple Wordpress Sites, but one WordPress instance)
- Pro
- Should work for all WordPress themes
- can use divi global headers for each theme
- only the pages for the defined theme will be in the database
- can configure plugins on a per-theme basis (i think)
- can use the inbuilt Divi theme menu in the Divi Theme customizer
- Con
- extra configuration required to enable multi-site
- all themes are separate and makes them harder to manage
- loads of credentials
- many theme will start to be cumbersome to manage
- Pro
So after outlining the options above I figured out the best way of setting out my themes was to use the Single WordPress Website option. This allows for ease of management and a great base to keep your templates for export when you need them to build client sites.
I will not only use this as my demo site, but i will use this to store my templates which i directly export and use to build my client sites reducing the time it takes to make a site.
You can also add and make modifications to these pages as you go to fix errors, add extra features and general improvements for future project. I find when i use a template for a client, I sometimes design or use a layout I really like so i can then add this back into my theme for future use.
Build the Demo Site (Single WordPress Website)
If you follow these easy instructions below you can quickly build your demo site which allows for easy expansion and management.
Install WordPress
This is straight forward and does not need notes except
- When creating the Database use:
- Use utf8mb4_unicode_ci for database collation
- InnoDB for DB engine
- Extract WordPress into the public_html
- Run the WordPress Wizard
- Setup WordPress using the following details:
- Site Title: WordPress Themes
Configure WordPress and Extensions
These should be straight forward. I am using Divi as my Theme engine, but if you use another it should be fine.
- Themes (Install and Configure)
- Divi
- Manually add API key: xxxxxxxxxxxxxx
- Import Theme options
- Import 'Theme Customizer'
- In options, enable the Divi Gallery (should be done as part of the options import)
- Set Divi to auto update
- Delete widgets
- Delete unwanted themes (i.e. Theme 21)
- Divi
- Plugins (Install and Configure)
- Delete unwanted plugins (i.e. Hello Dolly)
- Wordfence
- (no-reply@qwdemos.com) or what email address you use
- configure/ import settings (via long hash)
- Wordfence --> Login Security --> Settings --> Disable XML-RPC authentication: ticked
- Change file hash scanning because of high I/O (change 'Basic Scan Type Options' to 'Limited Scan' , 'Standard Scan' is normal
- Enable Automatic updates
- Easy WP SMTP (Only needed if no mail() function)
- configure/ import settings
- Manage Notification E-mails
- import settings or configure as:
- Turn off - Automatic WordPress core update e-mail
- Turn off - Automatic WordPress plugin update e-mail
- Turn off - Automatic WordPress theme update e-mail
- Leave the rest same
- import settings or configure as:
- W3 Total Cache
- Either the PHP configuration, web server configuration or a script in the WordPress installation has zlib.output_compression enabled.
- configure/Import settings
- Load options (General Settings --> Import / Export Settings)
- Enable Page Cache (contact forms might fail to work but are not needed on the Demo Sites)
- Save settings and purge
- Now deactivate until you have finished building
- Velvet Blues Update URLs
- This is optional but if you are importing layouts from different URLs you might want this installed so you can change the links.
- You can leave this deactivated when not in use.
- Disable all auto updates
- Easy Updates Manager – WordPress plugin | WordPress.org - Manage all your WordPress updates, including individual updates, automatic updates, logs, and loads more.
- Set all plugins to auto update
- WordPress Settings
- WordPress --> Settings
- General:
- remove tagline
- Reading:
- Set home page
- Discussion:
- 'Attempt to notify any blogs linked to from the post' = off
- 'Allow link notifications from other blogs (pingbacks and trackbacks) on new posts' = off
- 'Allow people to submit comments on new posts' = off
- 'Users must be registered and logged in to comment' = on
- 'Comment must be manually approved' = on
- General:
- delete test comments and posts (might not do this) ??
- WordPress --> Updates
- Updates:
- 'Switch to automatic updates for maintenance and security releases only.'
- Updates all Plugins and Themes
- Updates:
- Delete all Comments, Posts and Pages. Make sure you empty the trash afterwards.
- WordPress --> Settings
- Set Favicon
- Use FTP to upload your favicon.ico to the website root
- WordPress by default blocks the uploading of .ico files
- (Appearance --> Customise --> General Settings --> Site Identity --> Site Icon)
- How to Add a Favicon to Your WordPress Website in 3 Ways | Elegant Themes Blog - This includes using a Wordpress plugin for RealFaviconGenerator which will build all required favicons not jsut the basic favicon.ico
- How To Fix "Sorry, this file type is not permitted for security reasons"
Create a Primary Menu and Homepage
We need to create a default menu and homepage for WordPress for all requests that do not have a proper page then at least we have a proper page that is displayed.
- Create a new menu call 'Primary'
- This should have at least one 'Custom Link' pointing to the 'homepage' of the site https://themes.mydomain.com/ called 'Themes Home'
- Display Location = Primary Menu
- This is so that all default Divi pages have a menu that does not have every page listed.
- Create a homepage
- Goto (Pages --> All Pages)
- Add 'New Page' called 'QWThemes - Home'
- Set the static homepage
- (Settings --> Reading --> Your homepage displays -> Homepage) = 'Themes - Home'
- Fill in content as require. You can leave this blank or add in some company information for example.
Notes
- You could create a menu structure pointing to the
- homepage of each theme (if you don't have a theme toolbar this could be a good option)
- to every themes page (not recommended)
Adding Themes (Pages)
When I refer to a Theme, I actual mean a group of pages that have the same styling such as found on Divi Layouts by Elegant Themes
Each theme will require you to do the following (I will use example of Theme1). You can expand this to have more pages if you require.
- Create Theme Homepage
- Title: Theme1 - Home
- Slug: theme1
- Parent: Main Page (no parent)
- Template = Blank Template
- Use Divi
- Create Theme Content pages
- Services
- Title: Theme1 - Services
- Slug: services
- Parent: Main Page (Theme1 - Home)
- Template = Blank Template
- Use Divi
- Gallery
- Title: Theme1 - Gallery
- Slug: gallery
- Parent: Main Page (Theme1 - Home)
- Template = Blank Template
- Use Divi
- About
- Title: Theme1 - About
- Slug: about
- Parent: Main Page (Theme1 - Home)
- Template = Blank Template
- Use Divi
- Contact
- Title: Theme1 - Contact
- Slug: contact
- Parent: Main Page (Theme1 - Home)
- Template = Blank Template
- Use Divi
- Alt1 (optional)
- Title: Theme1 - Alt1
- Slug: alt1
- Parent: Main Page (Theme1 - Home)
- Template = Blank Template
- Use Divi
- Alt2 (optional)
- Title: Theme1 - Alt2
- Slug: alt2
- Parent: Main Page (Theme1 - Home)
- Template = Blank Template
- Use Divi
- Alt3 (optional)
- Title: Theme1 - Alt3
- Slug: alt3
- Parent: Main Page (Theme1 - Home)
- Template = Blank Template
- Use Divi
- Services
- Change the internal links to now work on your website.
- Run 'Velvet Blues Update URLs' as required.
Adding Menus
Each theme needs its own custom menu and the instructions below show you how this should be done. Again I will use Theme1 as an example.
- Import my Theme Menu Module Layout into Divi Library
- this only needs to be done once
- You might not have a pre-built layout, but it is easy to make one. Just create a layout with a menu module in a section.
- Import my pre-built Divi Menu module layout into the Divi library and call it Themes Header
- Edit the layout and add a logo (optional)
- Create a menu called 'Theme1'
- Select all of the pages for Theme1 and import into the menu
- Put them in the correct order with drag and drop (Home, Services, Gallery, About, Contact, Alt1, Alt2, Alt3)
- Edit menu item's navigation label to read (Home, Services, Gallery, About, Contact, Alt1, Alt2, Alt3)
- Import the 'Themes Header' into each page of the theme
- Edit the page
- Click on the add section button and select Themes Header
- Edit the 'Menu Module' and select the 'Theme1' menu as the menu source
- Move the menu section it to the top as this will be needed there as this is the primary menu.
- Now save the page
Repeat this for each theme you want to add. You can create the layouts on the fly in the demo site but will have to use a plugin (How To Clean Up Your WordPress Media Library | WP Engine / Media Cleaner – Clean & Optimize Space – WordPress plugin | WordPress.org ) to cleanup unwanted images after you finish or you have a separate development site.
Notes
- Divi Selective Sync
- Selective sync only works at module level so you cannot apply this to layout, sections and rows.
- Using Selective Sync In Divi - YouTube - This is a good explanation and help me work out the limitations of Selective Sync otherwise I would of used this and a global menu for my themes.
- Divi Library Global Modules - YouTube
- Divi Global Modules, Rows & Sections | Elegant Themes Documentation
- Selective Sync for Global Modules not working | Divi.Help
- WordPress does not like numbers
- I have to use 'Theme4' instead of 'Theme 4' because WordPress cannot search by just the number '4'.
- I have to use 'theme4' as the home slug because i cannot use just '4', WordPress just changes it to '1-2'.
- The WordPress filter ignores the 's' on the end words so treats 'theme' and 'themes' as the same word
Theme Content
Whether you have built you own layouts or used ones from Elegant themes I recommend reading the following about setting out the actual content.
The blog layouts in the Divi themes can be a good source of a standard clean page.
Use these Contact details
020 7123 456 07747 123456 no-reply@qwdemos.com QuantumWarp House, London SW1A 1AA QuantumWarp House Easy Street Westminster London SW1A 1AA United Kingdom
Import a Divi Layout
- Select the theme you are going to use
- Select a layout for each page of your theme (usually the namesakes are good ones to use, About --> About, Contact --> Contact)
- Import Layout
- You can import via the (Load from Library --> Premade Layouts) or a layout file you have locally.
- Either, 'Do Not Replace Content' as you want to keep the menu in place that you have just added.
Convert a Divi Theme to one you can use for your Clients
Not all clients send enough information and I have found that a lot of Divi Themes look nice but can be a bit impractical to use for my clients so I need to make alterations to them first before I can even use them.
Follow the steps below for each of the Pages/Layouts to make them ready to use for your clients:
- Google Maps (if present)
- The Google map is usually just on the contact page.
- I prefer just to have the map present on the contact page
- Hide the Google Map module for later use. This is just incase you client has specific needs.
- Where the 'Google Map Module' add a 'Code Module' as we are going to add an iframe version which does not require a credit card.
- Add the following Demo iframe code:
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2483.64596804941!2d-0.1440786842302416!3d51.501363979634085!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x48760520cd5b5eb5%3A0xa26abf514d902a7!2sBuckingham%20Palace!5e0!3m2!1sen!2suk!4v1639323812962!5m2!1sen!2suk" width="100%" height="450" style="border:0;display:block;" allowfullscreen="" loading="lazy" ></iframe>
- Map Colour Styling
- Greyscale:
style="border:0;display:block;filter:grayscale(100%);"
- Black and White:
style="border:0;display:block;filter:grayscale(100%) invert(92%) contrast(83%);"
- Greyscale:
- Map Colour Styling
- 'Call Us' / 'Call (451) 350-3922' Buttons
- Rename these all to Contact Us and add the link https://themes.qwdemos.com/theme1/contact/#contact-form
- If you have a button with a phone number on it and the client whats this changing it can take time.
- Phone numbers should stay in the header and footers', and the contact page only
- Contact Form(s)
- Remove all contact forms except the one on the contact page
- This allows you to change the contact email address if every needed
- Reduces the attack surface
- Can apply page caching to more pages.
- On the Contact Page, on the contact form add the CSS ID contact-form to the contact form row. The row is used to allow it to appear on screen better.
- Enable Standard Captcha
- Contact Form --> Advanced --> Custom CSS --> Captcha Field --> margin-left: 5px;
- Contact Form --> Advanced --> Custom CSS --> Captcha Text --> color: #ffffff
- Only if styling is required.
- You don't have to use white
- Make all 'Contact Us' buttons point to https://themes.qwdemos.com/theme1/contact/#contact-form
- Add a success message
- This is the default Divi one: 'Thanks for contacting us'
- No need to add one unless you want to change the default message.
- Add the email address no-reply@qwdemos.com otherwise emails will get sent to the default email account and you will get a lot of SPAM
- Gallery page
- If there is not already a Gallery page on your chosen theme, create one using the following basic layout:
- Grid
- 6-8 images
- No captions or pagination
- If there is not already a Gallery page on your chosen theme, create one using the following basic layout:
- Upload logo for the menu (if needed)
- Make sure all of the text is in Lorem Ipsum.
- Remove all non-free assets
- If you have imported layouts from client websites it is important to remove all of their images and asets
- Examine each page and remove/hide sections that cannot be altered for a generic website. i.e.
- Highly specific graphics
- Cartoons
- Replace images where needed with generic ones (not for copyright reasons though)
Control who can Embed your Demo Site using an iframe
Now you have done all of this hard work you don't want other people stealing your bandwidth so you need to control who can put your site in an iframe and this can be done by several options, some old, some new, but extensively the hosting server tells the client if it can use the website in an iframe. This behaviour all works on the browser or software at the other end respecting these directives.
The options I outline below can usually be managed by decent software such as W3C Total Cache, but there is no harm in doing it manually.
Content Security Policy (CSP)
CSP allows you to control how the browser behaves with your code remotely, and locally. You can tell the browser not to execute scripts on a page or not to embed the content in and iframe. Not allowing your content to be embedded in an iframe is quite obvious, but why would you want to stop your own scripts from running? This feature prevents scripts that have been maliciously implanted from running by only allowing scripts that you want to be run. The rules can be specified a lot more precisely, but this is just a simple example.
Enable restrictions via .htaccess
These are some examples of the .htaccess rules. You only need to specify one.
<IfModule mod_headers.c> ## Allow embedding from sitea.com or siteb.com including sub-domains using any protocol Header set Content-Security-Policy "frame-ancestors 'self' *.sitea.com *.siteb.com" ## Allow embedding from sitea.com or siteb.com including sub-domains using only HTTPS protocol Header set Content-Security-Policy "frame-ancestors 'self' https://*.sitea.com https://*.siteb.com" ## Allow embedding from example.org, example.com, store.example.com using only HTTPS protocol Header set Content-Security-Policy "frame-ancestors 'self' https://example.org https://example.com https://store.example.com;" </IfModule>
- You can use wildcards
- Using frame-ancestors 'self' is similar to using X-Frame-Options: sameorigin
- If you do not need this option, you can just remove 'self'
- When you add multiple Policies, they can be on separate lines to make it easier to read.
- You do not need to add any wrapping conditions like you do when using X-Frame-Options because the conditions are in the statement.
Enable restrictions via W3 Total Cache
- You can add these in WordPress using the W3C Total Cache plugin:
- WP Admin --> Performance --> Browser Cache --> Security Headers --> Content Security Policy: ticked
- WP Admin --> Performance --> Browser Cache --> Security Headers --> frame-ancestors: 'self' *.sitea.com siteb.com;
- WP Admin --> Performance --> Browser Cache --> Security Headers --> X-Frame-Options: unticked
Notes
- Content Security Policy
- Understanding Content Security Policy Headers | Pagely
- Content Security Policy headers are used for restricting the content types and sources that browsers will load. They help to protect your site visitors by instructing their browsers to produce an error and prevent disallowed content from loading on the page.
- Content Security Policy: Embedded Enforcement - This document defines a mechanism by which a web page can embed a nested browsing context if and only if it agrees to enforce a particular set of restrictions upon itself.
- How do I allow a iframe with a content security policy (CSP) - Stack Overflow - I keep getting this error "refused to frame 'url-to-calendly' because it violates the following content security policy directive. This thread offers solutions.
- Content-Security-Policy - HTTP | MDN - The HTTP Content-Security-Policy response header allows web site administrators to control resources the user agent is allowed to load for a given page. With a few exceptions, policies mostly involve specifying server origins and script endpoints. This helps guard against cross-site scripting attacks (Cross-site_scripting).
- Content-Security-Policy PHP Examples | Foundeo - How to add a content security policy header with PHP.
- Understanding Content Security Policy Headers | Pagely
- frame-src
- CSP: frame-src - HTTP | MDN - The HTTP Content-Security-Policy (CSP) frame-src directive specifies valid sources for nested browsing contexts loading using elements such as <frame> and <iframe>.
- Frame Ancestors
- This can be used instead of X-Frame-Options and can be more specific.
- CSP: frame-ancestors - HTTP | MDN
- The HTTP
Content-Security-Policy
(CSP)frame-ancestors
directive specifies valid parents that may embed a page using<frame>
,<iframe>
,<object>
, or<embed>
. - Setting this directive to 'none' is similar to X-Frame-Options: deny (which is also supported in older browsers).
- Note:
frame-ancestors
allows you to specify what parent source may embed a page. This differs fromframe-src
, which allows you to specify where iframes in a page may be loaded from. - Warning: If no URL scheme is specified for a
host-source
and the iframe is loaded from anhttps
URL, the URL for the page loading the iframe must also behttps
, per the Does URL match expression in origin with redirect count? section of the CSP spec.
- The HTTP
- frame-ancestors in CSP ⟶ Allowing / Blocking iframes from Loading | Foundeo - How to use the CSP frame-ancestors directive in a Content-Security-Policy header to allow or block the page from being loaded within frames or iframes.
- Content Security Policy with X-Frame-Options
- Nowadays, X-Frame-Options is only needed for edge cases.
- You cannot do some configurations with CSP if you have X-Frame-Options in place unless you use some wrapping code like my example below.
- CSP frame-ancestors vs. X-Frame-Options for Clickjacking prevention · RapidSec - CSP and Security Headers Made Easy
- CSP frame-ancestors has many advantages over X-Frame-Options options with advanced capabilities. However, both should be used for backward compatibility.
- X-Frame-Options is a graceful degradation for Clickjacking protection - More simply said - it's a fallback for crappy browsers that don't support CSP: ~5% of web traffic as of Nov 2021
- Current best practices to restrict framing in the browser - This article discusses recent changes in framing restriction mechanisms, and provides concrete recommendations to secure modern web applications.
- Frame Ancestors of CSP - Caliber Security Partners - Frame Ancestors "Directive" of Content Security Policy (CSP) - a newer alternative to the X-Frame-Options header.
- http - How does Content-Security-Policy work with X-Frame-Options? - Stack Overflow
- Does Content-Security-Policy ignore X-Frame-Options, returned by a server, or is X-Frame-Options still primary?
- Adding Headers
- Add Content-Security-Policy header with htaccess | Foundeo - Using an Apache CSP header via a htaccess file.
- Read this as it explains all required options quickly
-
Header add Content-Security-Policy "default-src 'self';"
- frame-src - This policy defines what iframes the page can display.
- frame-ancestors - This policy defines what remote sites can display the page in an iframe.
- Adding Security Headers to WordPress Without 3rd-Party Plugins | Pagely
- Add Content-Security-Policy header with htaccess | Foundeo - Using an Apache CSP header via a htaccess file.
X-Frame-Options Header (rules based without using ALLOW-FROM)
You can control the X-Frame-Options headers in either .htaccess or PHP but I will use .htaccess code here because it is easier to implement and is not script dependent.
The Code
The .htaccess code below uses the X-Frame-Options and gives the same effect as using ALLOW-FROM but without using this obsolete command.
# Conditional X-Frame-Options for iframe Embedding Control <If "%{HTTP_REFERER} == 'https://www.content-site.com/' || %{HTTP_REFERER} == 'https://www.sitea.com/' || %{HTTP_REFERER} == 'https://www.siteb.com/'"> <IfModule mod_headers.c> Header always unset X-Frame-Options </IfModule> </If> <Else> <IfModule mod_headers.c> Header always append X-Frame-Options SAMEORIGIN </IfModule> </Else>
- W3C Total Cache adds the X-Frame-Options header to every page if enabled, so if you use this code you should disable this feature in W3C Total Cache
- WP Admin --> Performance --> Browser Cache --> Security Headers --> X-Frame-Options: unticked
- ALLOW-FROM is not used
- Multiple clients can be granted permission to embed iframe content by just adding them to the REFERER list.
- %{HTTP_REFERER} == 'https://www.content-site.com/'
- https://www.content-site.com/ - This is the website which is hosting the content.
- Without this the first page will load in the iframe fine but if we click on any links in the iframe then they will not display
- This is needed because on the intial page load the REFERER is https://www.sitea.com/ or https://www.siteb.com/ but when we click on links in the iframe, the REFERER becomes https://www.content-site.com/
- Effectively the same as SAMEORIGIN
- The <Else> section is optional
- this is useful if you have other code implementing this directive such as W3C Total Cache. But best to keep the code handling this directive all together.
- Some plugins (Joomla 4 / Wordpress W3C Total Cache) will enable 'X-Frame-Options SAMEORIGIN' on all pages so in this case the Else statement is not needed
Header always append X-Frame-Options "SAMEORIGIN"
- The always variable is like !important is in CSS.
- ALLOW-FROM no longer works
- X-Frame-Options - HTTP | MDN
- ALLOW-FROM uri - This is an obsolete directive that no longer works in modern browsers. Don't use it. In supporting legacy browsers, a page can be displayed in a frame only on the specified origin uri. Note that in the legacy Firefox implementation this still suffered from the same problem as SAMEORIGIN did — it doesn't check the frame ancestors to see if they are in the same origin. The Content-Security-Policy HTTP header has a frame-ancestors directive which you can use instead.
- After testing, if you use the following command, iframe blocking sdoes not work at all, not just the exception not working but total failure.
Header always append X-Frame-Options "ALLOW-FROM https://www.sitea.com/"
- X-Frame-Options: ALLOW-FROM in firefox and chrome - Stack Overflow
- ALLOW-FROM is not supported in all browsers as an X-Frame-Options value.
- The solution was to branch based on browser type. For IE, ship X-Frame-Options. For everyone else, ship X-Content-Security-Policy.
- X-Frame-Options - HTTP | MDN
- Apache <If> statement
- You could add other checks into If statements or use other Apache variables, you are not limited to the ones i have used and these statements can be nested.
- Mod_Rewrite Variables Cheatsheet - Mod_Rewrite Variables Cheatsheet
- #htaccess List of all mod_rewrite variables · GitHub - List of Mod_Rewrite Variables with examples
RewriteCond %{HTTP_HOST} = www.askapache.com RewriteCond %{REMOTE_ADDR} = 8.8.8.8
- apache 2.2 - How should I use the directive in .htaccess? - Server Fault
- The <If> directive is only available in Apache 2.4+ and not 2.2 or earlier.
- apache - htaccess if statement - Stack Overflow
<If "%{HTTP_HOST} == 'foo'"> # configuration for foo </If> <Else> # default configuration </Else>
- apache - Conditionally set X-Frame-Option - Stack Overflow
<IfModule mod_headers.c> <If "%{HTTP:X-Requested-From} == 'mobileapp'"> Header unset X-Frame-Options </If> <Else> Header set X-Frame-Options SAMEORIGIN </Else> </IfModule>
- Apache .htaccess statement with multiple matches - Server Fault
- Conditional X-Frame-Options | LiteSpeed Support Forums
- .htaccess If/Else Example
- Code to use env= statement in htaccess.
- If Statement - core - Apache HTTP Server Version 2.4
- apache - htaccess if statement - Stack Overflow
- .htaccess If/Else Example
- apache - Conditionally set X-Frame-Option - Stack Overflow
- .htaccess If/Else Example
- Code to use env= statement in htaccess.
- apache 2.2 - How should I use the directive in .htaccess? - Server Fault
- .htaccess If/Else Example
- Code to use env= statement in htaccess.
- New in httpd 2.4: If, ElseIf, and Else : Apache HTTP Server
Notes
- Joomla
- In Joomla4 there is a plugin called "System - HTTP Headers" that adds the X-Frame-Options headers
- WordPress
- W3C Total Cache adds the X-Frame-Options headers to every page if enabled
- (WP Admin --> Performance --> Browser Cache --> Security Headers --> X-Frame-Options)
- WordPress is hardcoded to add X-Frame-Options SAMEORIGIN onto the admin section and login pages. This can be disabled with a WP function, see notes below.
- W3C Total Cache adds the X-Frame-Options headers to every page if enabled
- Enabling Clickjacking Protection (X-Frame-Options) in WordPress | Pagely
- Embedding a website inside another is one way that attackers may try to steal information. To avoid having your website embedded into another, modern web browsers are equipped to read an X-Frame-Options header to determine if the embed is allowed.
- X-Frame-Options - HTTP | MDN
- How can I add "X-Frame-Options" header for my WordPress site? | cPanel
header('X-Frame-Options: SAMEORIGIN');
- filters - How to remove X-Frame-Options: SAMEORIGIN" from WordPress? - WordPress Development Stack Exchange
- Removing send_frame_options_header from ./wp-includes/default-filters.php
- remove_action('login_init', 'send_frame_options_header');
- Removing @header( ‘X-Frame-Options: SAMEORIGIN’ ); from /wp-includes/functions.php
- Header always unset X-Frame-Options
- php - How does wordpress restrict X-FRAME to sameorigin? - Stack Overflow
- Search · x-frame-options · GitHub
- The send_frame_options_header function handles this. It's an action tied to the login_init hook.
remove_action('login_init', 'send_frame_options_header');
- Enable Wordpress X-Frame Options with .htaccess - Responsive Web Design
# Extra Security Headers <IfModule mod_headers.c> Header set X-XSS-Protection "1; mode=block" Header always append X-Frame-Options SAMEORIGIN Header set X-Content-Type-Options nosniff </IfModule>
- Why isn't my iframe loading? - Responsive Web Design
- A Detailed Guide To Add WordPress Security Headers - Patchstack
<IfModule mod_headers.c> Header always append X-Frame-Options SAMEORIGIN </IfModule> Header always unset X-Frame-Options
- Secure Wordpress with X-Frame-Options & HTTPOnly Cookie
- How to Use the HTTP Headers WordPress Plugin for Better Security – InMotion Hosting Support Center
- php - How to set X-Frame-Options Header in wordpress Site - Stack Overflow
- How to configure frames with X-Frame-Options header
- How to Configure X-Frame-Options in Apache - Fedingo
Combined .htaccess Example
No matter if you use a plugin or manually create the rules in your .htaccess they should look something like this:
<IfModule mod_headers.c> Header always set Strict-Transport-Security "max-age=31536000" Header set X-XSS-Protection "1; mode=block" Header set X-Content-Type-Options "nosniff" Header set Referrer-Policy "no-referrer-when-downgrade" Header set Content-Security-Policy "frame-ancestors 'self' *.sitea.com *.siteb.com" #Header set Content-Security-Policy "frame-ancestors 'self' https://*.sitea.com https://*.siteb.com" #Header set Content-Security-Policy "frame-ancestors 'self' https://example.org https://example.com https://store.example.com;" </IfModule>
Notes
- There are some commented out
Content-Security-Policy
examples for reference. - HSTS is on.
- The live
Content-Security-Policy
does not define the protocol of connections allowed. This means that both HTTP and HTTPS are allowed but because HSTS is on, all incoming HTTP connections must be upgraded to HTTPS.
Final Tasks
These are somes task that might need doing after you have built all of your Theme pages.
- Remove all un-needed images and assets
- Option 1 - Manual
- Full site backup (before anything)
- Delete all images in the gallery (but keep gallery)
- Export all pages
- Empty media library
- Import all pages
- Option 2 - Media Cleaner – Clean & Optimize Space – WordPress plugin | WordPress.org
- Clean your WordPress from unused files, broken media entries. Powerful engine and beautiful UI!
- Ypu will need to buy the Pro version
- Option 1 - Manual
- Activate W3C Total Cache
- It might aswell run quick
Your Theme Demo Site is now finished
You have built all of your Theme Demos, the last thing you have to do is:
- Update QWDemobar (only if you have this plugin on your main business site)
- You need to add the new Theme Pages to be able to show you clients