This guide is mainly written for people who never had their own WordPress site before and may not have the skills to figure this out by themselves. Feel free to skip ahead. That being said, there are still some parts of interest for veterans in regards to the theme.
First, you need to choose a host for your site, the place where your site "lives". This may very well be the hardest part, because bad choices are annoying to fix and cost money. For that matter, you are encouraged to do your own research — [Online Media Masters](https://onlinemediamasters.com/) is a good place to start. If you feel completely lost, asking for help is entirely justified.
Your choice will ultimately come down to two schools: managed hosting or not. Managed hosting takes away the burden of having to, well, manage your server. Configuration, maintenance, security, and performance issues are covered by the provider — at a price. For example, on [WordPress.com](https://wordpress.com/pricing/) you would need at least the Business plan to use the Fictioneer theme. Non-managed hosting is more affordable and less restrictive, but you need a bit of technical know-how or someone helping you.
If the hosting cost are too much for you alone, there is also the option to share a site with other authors and split the bill. Typically with the administrator holding the contract. Just make sure you trust everyone and write down the obligations and rights of all participants involved. Always prepare for the fallout.
The installation process for WordPress is [documented on the official site](https://wordpress.org/support/article/how-to-install-wordpress/) and in many guides only a quick search away. Nowadays, most hosts offer a one-click installation service as well. Note that the latter often comes with pre-installed plugins that you may want to get rid of, especially analytics plugins which tend to violate data privacy laws.
Fictioneer is best used on a fresh install due to its complexity and possible conflicts with existing plugins or customizations. Which does not mean you cannot switch or migrate, but it would be an ordeal. For example, Fictioneer has custom post types for stories and chapters, so you would need to either [convert existing posts](https://wordpress.org/plugins/post-type-switcher/) or upload them anew (which would disassociate all comments). They also have several additional settings, making automatic conversion scripts risky. Depending on how many posts you have, this may take a while.
### Configuring WordPress
Everything installed? Head to **[Settings](https://wordpress.org/support/article/administration-screens/#general)** in the admin panel to configure your site. You can follow a guide, but this should all be fairly obvious. For the purpose of working with the theme, you are most interested in the **Reading**, **Discussion**, and **Permalinks** submenus.
* **Reading:** If you want a static page like in the demo, you can set this here. Of course, you need to [create the pages](https://wordpress.org/support/article/pages/) for blog and front page first. Best use the "No Title Page" or "Story Page" (for single-story sites) template. Keep the number of blog posts and feed items somewhere between 8 and 20.
* **Discussion:** Most of this is up to you, but the number and order of comments does not necessarily behave as you would expect. Comments are always nested in the theme, regardless of the checkbox, but the depth is honored and should be anywhere up to 5. Break comments into pages with 8 to 50 comments each, the first page being displayed by default, and newer comments at the top. The theme really does not work well with anything else but you are welcome to try.
* **Disallowed Comment Keys:** For simple yet reliable comment spam protection, you are advised to use the [compiled disallow list by slorp](https://github.com/splorp/wordpress-comment-blacklist). Just copy the content of the blacklist into the [Disallowed Comment Key](https://wordpress.org/support/article/comment-moderation/#comment-blocking) field. Check your comment trash occasionally as this can lead to false positives. You can search for less restrictive lists too.
* **Permalinks:** You want the permalink structure set to "Post name". As an off-note, whenever some pages do not show up even though they clearly should, come back here and save to update the permalink structure. You would be surprised how many issues that solves, including the OAuth authentication not working.
* **Open Graph Default Image:** Only used when you enable the SEO features and no (known) SEO plugin is running. This image will be shown in search engine results and social media embeds if no other image is provided by individual posts, such as story cover images. Can be set under **Appearance > Customize > Site Identity**.
* **Author websites:** Technically not a required setting, but authors may want to fill out the website field in their profile. These are added as Open Graph author meta tags used by search engines and social media embeds. If left blank, the generated author page of the site will be used instead, which might be what you want anyway.
You can greatly improve your site security and performance by adding policies to the **.htaccess** file located in the WordPress root directory. Managed hosting plans normally do this for you (if you ask). Make a backup and add the following lines anywhere before `# BEGIN WordPress` or after `# END WordPress`. If something goes wrong wrong, just remove everything again or restore the backup. You can also use a (cache) plugin to do it for you. This is just the basics, far more is possible, but please refer to a proper guide.
There is not much to consider aside from the [data privacy](https://wordpress.com/go/website-building/how-to-write-and-add-a-privacy-policy-to-your-wordpress-site/) issue, which depends on your country of residence and where your host server is located. However, to preempt any legal trouble, you want to assume the strictest laws apply — the [GDPR](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation) and [CCPA](https://en.wikipedia.org/wiki/California_Consumer_Privacy_Act). Fictioneer is compliant with both unless you change things, but you also need to add a [Privacy Policy](PRIVACY.md). And forget about Google Analytics or Fonts.
After you have set up your WordPress site, you can install the theme. Since Fictioneer is not available in the official theme library, you need to do this manually. Either by uploading the *unpacked* theme folder into the `/wp-content/themes/` directory via FTP or by uploading the `.zip` file in the admin panel under **Appearance > Themes > Add New > Upload Theme**.
When you are done, activate the theme under **Appearance > Themes**. If you want to use a [child theme](https://developer.wordpress.org/themes/advanced-topics/child-themes/), which is installed the same way, activate that instead (you need both the main and the child theme). Head to the newly added Fictioneer menu page in the admin sidebar afterwards. Here you need to [configure](#How-to-configure-the-fictioneer-theme) the theme. You may also want to [customize](#How-to-customize-the-fictioneer-theme) the look.
### Updating the Theme
Updating the theme works the same as installing the theme. If done in the admin panel, you will be warned that the theme is already installed and given a quick comparison, prompting you to confirm the overwrite. Make sure you still fulfill all the requirements, namely your WordPress and PHP versions. You can find this information in the info tab on the [site health screen](https://wordpress.org/support/article/site-health-screen/).
Note that any changes made to the theme files will be undone — which you should not have done in the first place. Always use a [child theme](https://developer.wordpress.org/themes/advanced-topics/child-themes/) for modifications to avoid this issue. Your theme options and Customizer settings are preserved, however.
The [plugin ecosystem](https://wordpress.org/plugins/) of WordPress is vast and often confusing. There are plugins for almost everything, in variants, free or premium or "freemium". You often find articles about "must-have" plugins — you are well advised to question those. Too many plugins can slow down your site, open vulnerabilities, or conflict with the theme. Fictioneer is designed as standalone solution and technically works without additional plugins. However, nothing is ever complete, so here are a few plugins of note anyway.
* [Autoptimize](https://wordpress.org/plugins/autoptimize/): Optimization plugin to speed up your site. Best used for its aggregation and deferment of static resources, such as styles and scripts, solving browser cache issues along the way. The other options are nice if not already covered elsewhere.
* [Cloudinary](https://wordpress.org/plugins/cloudinary-image-management-and-manipulation-in-the-cloud-cdn/): Great "plug-and-play" image CDN and optimizer with generous free plan. Offloading your images to a content delivery network improves performance and loading times. Also, your images will be properly sized and compressed.
<details>
<summary>Example settings</summary><br>
<p>Follow the <ahref="https://cloudinary.com/documentation/wordpress_integration">official guide</a> to set up your Cloudinary account and the plugin. You do not need to "register" the CND with other optimization or cache plugins — it will just work.</p>
* [Cloudflare](https://wordpress.org/plugins/cloudflare/): Global content delivery network designed to make your site secure, private, fast, and reliable. Can be used for caching or to enhance a cache plugin further. Unfortunately, the setup is not trivial and you should refer to specific guides or ask for help.
<details>
<summary>Cache considerations</summary><br>
<p>Cloudflare can be problematic if you want to capitalize on the "Cache Everything" option because without a paid plan, you cannot make exceptions for logged-in users. This means visitors might see personalized content of the first user to populate the cache — not good! Imagine your account details being leaked like that. It also does not easily cooperate with on-site caching solutions.</p>
<p>That being said, the free tier can be persuaded! Ditch the official plugin and install <ahref="https://wordpress.org/plugins/wp-cloudflare-page-cache/">Super Page Cache for Cloudflare</a> instead. Same as before, refer to proper guides. Make sure you have the following settings and be prepared that it might still not work! Test this!</p>
<p>Optional: Install <ahref="https://wordpress.org/plugins/wp-super-cache/">WP Super Cache</a> with the extreme settings. Cannot wrongly cache dynamic pages if there are none!</p>
* [WPS Limit Login](https://wordpress.org/plugins/wps-limit-login/): Protects you from brute-force attacks by limiting the number of login attempts within a certain period of time. The sibling plugin [WPS Hide Login](https://wordpress.org/plugins/wps-hide-login/) moves the whole login page to a new URL, if you want to go one step further.
<p>Fictioneer does not have a frontend login form and the login page is not recommended for subscribers, so hiding it serves as additional security layer. Note that the optional OAuth 2.0 authentication system via Discord, Google, etc. is not affected by these plugins.</p>
* [Sucuri Security - Auditing, Malware Scanner and Hardening](https://wordpress.org/plugins/sucuri-scanner/): The free version is meant to complement your security posture and comes with hardening, malware scanner, core file integrity checking, event logging, email alerts for important issues, and more.
<details>
<summary>Notes</summary><br>
<p>There is not much to screw up, but you should refer to a proper guide for your own peace of mind. Because Sucuri has a tendency to be overzealous with scary warnings and until you set up a whitelist, you will see many false positives. Better safe than sorry.</p>
* [UpdraftPlus](https://wordpress.org/plugins/updraftplus/): One of the most popular and convenient backup plugins. If your host does not offer backups or you want to stay in control, this is a good choice to keep your site safe in the event of a disaster.
<p>To quote the plugin’s own premonition: "The day may come when you get hacked, when something goes wrong with an update, your server crashes or your hosting company goes bust — without good backups, you lose everything." The free version is perfectly adequate, allowing you to schedule daily backups saved directly to a remote destination of your choice.</p>
* [EWWW Image Optimizer](https://wordpress.org/plugins/ewww-image-optimizer/): An optimization plugin to properly scale, compress, and (optionally) convert your images. Large file sizes reduce your website’s speed and search rank. Redundant if you use an image CDN like Cloudinary, but they can work together.
<details>
<summary>Example settings</summary><br>
<p>As a matter of fact, you do not need this kind of plugin at all if you pay a modicum of attention to the images you upload. One of the most common yet easy to fix mistakes is uploading over-sized images. Obviously, if your header image is 20 MB, your loading time will go down the drain. Your site will be even faster without the overhead of this plugin if you just pre-optimize your images.</p>
Follow the initial setup guide, then head to <strong>Settings > EWWW Image Optimizer</strong> to review the settings. Also take a look at the <ahref="https://docs.ewww.io/article/4-getting-started">official documentation</a>. Assume missing options are off, empty, or left to default.<br><br>
Technically just another plugin, but one that will make your site significantly faster. [Caching](https://wordpress.org/support/article/optimization-caching/) saves your posts and pages as static files to be served later instead of rendering them anew on each request. Guests see the same content anyway, so why waste resources? Only logged-in users can have individual content that must not be cached, such as their account profile. Following are a few cache plugins that have proven to work well with the theme. Do this after you configured your site.
**Note:** Caches require to be purged occasionally, especially after you updated the theme, settings, or plugins. Your site might show outdated pages otherwise. With *known* plugins, Fictioneer automatically purges post caches when you publish or edit content. Other cache plugins require some custom code or need to be purged manually. Inconvenient, but workable.
**Cacheable Query Vars:** Most cache plugins automatically exclude pages with query vars (`/?foo=bar`), because they tend to have dynamic content. However, there are some query vars that can be safely cached if the plugin recognizes them as separate URLs: `pg` (page), `tab`, and technically `order` as well. You may have even more.
**Minifying CSS/JS/HTML:** While this can bring a *tiny* performance boost, it also often leads to scripts not working, missing fonts, and display issues. Cloudflare is known to break CSS properties with overzealous minification, LiteSpeed tends to mess up relative file paths in the CSS, and purging presumably "redundant" whitespaces from the HTML can cause gaps between elements or words to disappear. You can try it out, but watch the results and more importantly the console for errors.
**Rule of Thumb:** Is something missing or misplaced, purge the cache! Chapter order wrong? Purge the cache! Collections outdated? Purge the cache! Page flashing red? That’s right, call an exorcist and purge the cache!
* [WP Super Cache](https://wordpress.org/plugins/wp-super-cache/): Made by [Automattic](https://automattic.com/), a main contributor to WordPress the *software* and owner of WordPress.com the *service* (do not confuse them), this free cache plugin is a great choice if you want simple and reliable. It is also completely free.
<details>
<summary>Recommended settings</summary><br>
<p>This is the "safest" advanced setup in the regard that you do not need to mess with server files. Expert mode is a tick faster and not actually complicated, but if the terms ".htaccess" and "mod_rewrite" make you feel queasy, you are perfectly fine with simple mode.</p>
<p>This is the most "aggressive" setup meant to carry membership sites on cheaper hosts, e.g. sites with many simultaneous requests by logged-in visitors who would normally not be served supercached files. Generating individual pages in large numbers within a short amount of time can overwhelm a server, leading to timeout errors. An issue you are unlikely to encounter as long as you do not have thousands of daily visitors. But in that case, just extend the recommended settings with the following ones.</p>
Great, now your site is broken for logged-in users! Or rather, they are treated like guests and cannot see their personal content or post comments anymore. To resolve this, head to the <ahref="#general-tab">Fictioneer general settings</a> and activate the following options. Clear the cache afterwards. Yes, the admin bar is now gone. Yes, you can still get into the admin with the <code>…/wp-admin</code> link. No, password protected posts no longer work.<br><br>
* [W3 Total Cache](https://wordpress.org/plugins/w3-total-cache/): Comprehensive suite of caching and performance features with great compatibility regardless of host. But a rather involved setup and requires a subscription to make the most of it. Please refer to a guide for installation.
<details>
<summary>Cache exceptions</summary><br>
<p>As long as you only serve cached pages to unauthenticated users, you can hardly do wrong. To make absolutely sure everything works, please add the following exceptions under <strong>Performance > Page Cache</strong>.</p>
* [LiteSpeed Cache](https://wordpress.org/plugins/litespeed-cache/): The most powerful of the listed cache plugins and also completely free — if you can get it running. As server-side cache, your host must support [LiteSpeed](https://docs.litespeedtech.com/lscache/), which is usually a prominent selling point so you would know.
<details>
<summary>Example settings</summary><br>
<p>LiteSpeed Cache offers you far more than what is covered here, so please refer to more comprehensive guides if you want to take advantage of that. However, combined with the other recommended plugins, you can do without.</p>
[Must-Use Plugins](https://wordpress.org/documentation/article/must-use-plugins/) are not installed but have to be manually copied into the **wp-content/mu-plugins** folder (does not exist by default). They are always loaded, in alphabetical order, and before any other plugin or theme. This behavior can be exploited to boost performance. When you look into the Fictioneer theme folder, you will find an mu-plugins subfolder with a must-use plugin ready to be copied over.
**Fictioneer 001 Fast Requests** accelerates AJAX and REST requests by disabling non-allow-listed plugins during selected theme actions. Depending on the number of plugins you have installed, this can boost your request performance significantly. However, it will prevent the plugins from working during these requests, although that has no effect on the theme’s default functionality. Be not afraid to edit the file and extend the allow list, it will not be overwritten when you update the theme. Or add your own plugin files. This is one of the best speed optimizations you can make.
While search engine optimization plugins such as [Yoast](https://wordpress.org/plugins/wordpress-seo/) and [AIOSEO](https://wordpress.org/plugins/all-in-one-seo-pack/) are usually the way to go, they are not recommended here. Fictioneer already ships with a search engine optimization — not perfect, but tailored to the purpose. Third party plugins do not understand the theme, never mind web fictions. They assume everything to be topic-based articles or products, leading to faulty results unless you teach them and that requires custom code. They also lock essential features behind a subscription that Fictioneer provides for free.
And just to take a step back here and be real: SEO is important. Certainly. Unfortunately. But if you actually try to optimize your *prose* for keywords density, word complexity, sentence and paragraph length, or any other statistical insanity to beseech the great algorithm, you have a poison in your mind.
The theme’s CSS comes already minified and while additional optimizations such as combining files or filtering out *presumably* unused styles can further improve speed, it can also easily break your layout. This has been proven to be an issue with Cloudflare’s auto-minify feature, for example, which removes whitespaces in `clamp()` functions that are required for them to work. An especially insidious case that you might struggle to pinpoint as it happens during the request, not on your own server.
Most of the theme’s configuration is found here, the options being largely self-explanatory. Please note that you will probably not need all the features available, such as Checkmarks or Follows. These are for sites with many authors or stories; publishing a weekly serial is better off saving the server resources. Some changes require you to purge the theme caches after updating under **Fictioneer > Tools**. Options of note:
* **Comment Form CSS Selector:** If you are using a third-party comments plugin, several scripts interacting with the comment form might stop working. You can try changing the selector here. For example, wpDiscuz would need `.wpd-field-comment .ql-editor` (rich editor) or `.wpd-field-comment .wc_comment` (textarea). Purge the theme caches after updating.
* **Enable OAuth 2.0 authentication:** Allows visitors to register with social media accounts, but be aware of the implications! You will need to flush your permalinks after enabling.
* **Enable AJAX user authentication:** If you have trouble with [Nonces](https://developer.wordpress.org/apis/security/nonces/) and/or users not being properly logged-in. Use this as *last resort* to bypass the cache.
* **Disable extended \[story|chapter] list meta queries:** Makes list pages and shortcodes faster, but increases the size of your database by one row for each story/chapter. Fine unless you have *thousands* of posts.
The integrated role manager to add and, edit, and remove roles. Not the most sophisticated compared to dedicated plugins, but it comes with custom capabilities tailored to the theme. Because Fictioneer offers some powerful options and tools you may want to keep away from certain user groups. If the roles have not been properly initialized when you activated the theme, you can do that under the **Tools** tab. For reference, look at the default [WordPress capabilities](https://wordpress.org/documentation/article/roles-and-capabilities/).
This tab is only visible if theme-related plugins are installed and active. Whether the displayed cards are purely informative or hold functions is up to the plugin author. This does not replace the default plugin page of WordPress.
Anything that connects with external service providers goes here, such as the Client ID and Secret for OAuth 2.0 applications. Please refer to respective tutorials on how to set them up and always, *always* keep those credentials confidential.
If you enter a [Discord webhook](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) here, notifications about new comments, stories, and/or chapters will be sent directly into a channel on your server (leave free if you do not want that). Make sure comments are sent to a hidden moderation channel since it will receive excerpts of private comments. Note that webhooks cease to work if used for more than one app (for security reasons).
The OAuth request redirect URI should be akin to `https://your-domain.com/oauth2`, the important part being the `/oauth2` endpoint. Note that the service providers can be picky, such as rejecting an URI that includes "www" if that is not actually part of your website’s address. Use the _exact_ string you see in your browser’s address bar. If the redirect returns 404, you usually need to flush your permalinks under **Settings > Permalinks** (just save).
Allows for some minor translations and changes, such as the cookie notice banner or comment reply notification email. More customization can be achieved with the theme’s [translation filter](FILTERS.md#apply_filters-fictioneer_filter_translations-strings-). But if you want to translate the theme into a new language, you will need to include the proper [translation files](https://developer.wordpress.org/plugins/internationalization/localization/) or use a plugin.
An overview of all installed fonts, with the options to enable/disable them. You can also include Google Fonts here, but be aware that this violates the GDPR. If you want to install custom fonts, take a look at the [Custom Fonts](https://github.com/Tetrakern/fictioneer/blob/main/INSTALLATION.md#custom-fonts) section further down.
Lists all generated ePUBs with statistics, download links, and options to delete them. File names are equal to the story’s `post_name`, which is the slug inside the permalink and *not* the title. They are cleaned of any special characters and are also used to query associated stories. If you change the permalink, they will no longer match and a new ePUB will be generated, leaving the old one orphaned. This is not terrible but takes up space.
**Failed ePUBs:** Indicated by an empty "download" file. The generation of ePUBs can fail due to several circumstances, such as missing writing permissions along the path of `wp-content/uploads/epubs` or non-conform content in the story or chapters. Unfortunately, ePUBs are rather picky regarding allowed HTML and while the converter tries to sanitize the content, this is not fail-proof. Alternatively, you can just upload a file yourself instead of relying on the converter, not limited to the ePUB format.
Only available if you enable the SEO features and no (known) SEO plugin is running. Lists all generated Open Graph meta data and schemas used by search engines and social media embeds, created and cached when a post is first visited until modified or purged. Note that most page templates (besides list templates) and collections do not have schemas, appearing grayed out.
Whether these services actually display the offered data is entirely up to them. You cannot force Google to show your custom description, for example. After all, you could write *anything* in there. This tab is mostly informative, but you can purge the cached meta data or schemas if that should become necessary.
If you want to set up a default Open Graph image for search engine results and embeds, you can do that in the **Customizer** under **Site Identity**. This image will always be used if there is not a more specific one, like the thumbnail for posts.
A collection of actions to add, update, revert, fix, or purge certain items. For example, you can add a proper moderator role if missing or convert tags into genres. Everything is thoroughly explained. But the only action you will most likely need more than once is **Purge Theme Caches**, which should be done whenever you change chapter or story settings.
If the user roles lack permissions, such as authors not being able to add stories and chapters, use the **Initialize Roles** action. This also restores the defaults if you mess something up, although it will not reset capabilities outside the theme’s scope. Most administrative capabilities are left untouched for security reasons.
You can grant logged-in users access to password-protected content via Patreon membership, either by selected tiers or pledge thresholds or both. This requires you to enable and set up the OAuth 2.0 authentication for Patreon, allowing users to log in with their account and import their membership data. The official Patreon plugin for Wordpress would also work, but the integration with the theme is not seamless.
**Fictioneer > General > Feature:**
* Enable OAuth 2.0 authentication
* Enable Patreon content gate
After setting up the [OAuth 2.0 connection](#connections-tab), add a campaign link and import your tiers. This is a unique request limited to administrators and only works for the campaign of your client. No, you cannot have different campaigns for different authors. Changes to tiers on Patreon are **not** automatically synchronized, you have to pull them yourself (but this should rarely be necessary).
Once you are done, you can apply tiers and pledge thresholds in cents (e.g. 350 for $3.50) to individual posts or set them globally. Posts always use the lowest requirements if you do both. Note that you still need to set a post password, because this system hijacks the WordPress password check. Removing a password will also suspend the Patreon gate. This is compatible with cache plugins as well.
**Options:**
* **Tiers (Post/Global):** Comma-separated list of tier IDs, which you can see after pulling them.
* **Threshold (Post/Global):** Pledge amount in cents (e.g. 350 for $3.50) independent of tiers.
* **Lifetime Threshold (Global):** Use the total of all paid pledges, regardless of current status.
Membership data is valid for one week by default, per user, refreshed whenever they log in with Patreon. This can cause users to retain access rights for longer than their membership status allows (up to six days), which is a consequence of the theme not keep a continuous connection to Patreon for security reasons — but if you get hacked, their Patreon accounts will be safe in turn. Security is rarely convenient.
You can increase or reduce the expiration time with the `FICTIONEER_PATREON_EXPIRATION_TIME` constant in a child theme, but it should not be less than three days (which is the maximum login time before you are automatically logged out).
There are two ways to customize the theme. The obvious one is the Customizer of WordPress under **Appearance > Customize**. Here you can upload a header image and logo, set a site title, change the color scheme, and modify the layout to some extend. The interface and live preview make this straightforward. If the color options are too demanding (and they are), you may want to stick to the hue, saturation, and lightness sliders. Also consult the many guides about WordPress customization.
The second way is to directly modify the templates, styles, and scripts. This is indefinitely more powerful but requires some developer skills — and you can easily break your site. The theme’s files can be modified under **Appearance > Theme File Editor**, although you should never actually do this. Always create a [child theme](https://developer.wordpress.org/themes/advanced-topics/child-themes/) because any code changes you make, regardless of quality, will be overwritten again when you update the theme.
As per popular demand, here is a small guide on how to mimic the demo site. Please be aware that the demo is more for showing off features than being a production example. Make sure to look at the available [shortcodes](DOCUMENTATION.md#shortcodes) and their possible configurations. If you are new to WordPress, better read a guide about using the CMS first because the basics are not be covered here.
First, create two new pages with the "No Title Page" template, one called "Home" and the other "Posts" (or whatever you like). Then go to **Settings > Reading > Your homepage displays** and set it to "A static page". Assign the pages you created. Now you can add blocks and shortcodes to your "Home" page; leave the "Posts" page empty. Similar, you can add list pages for Stories, Chapters, etc. with the corresponding templates and assign them under **Fictioneer > General > Page Assignments**. You do not need all of them.
For simplicity, here is the copied content of the demo home page (minus some site-specific things). Put that into the code editor view and adjust it as needed. When you switch back to the visual editor, everything should be properly formatted as blocks.
You can choose between three different header styles: **default**, **top**, and **split** — or **none** at all, if that is what you want. The **default style** is what you see on the screenshots and demo site, optionally with title, tagline, and/or logo. The **top style** puts the site identity above the navigation and removes the header image. And the **split style** is a mix of both, with the identity above but a header image below the navigation.
While the customization options are not as extensive as with multi-purpose themes or page builders, you can achieve quite a lot with some simple [CSS](https://developer.mozilla.org/en-US/docs/Web/CSS) snippets. Easy to learn, hard to master. However, following are several snippets you can use and modify to your needs. Just put them into **Customizer > Additional CSS** or a child theme. This is by far the most powerful way of customization — there are over 500 properties and virtually infinite possible values and combinations that can be assigned to each and every element.
**Developer Tools:** Your very best friend! You can open them by right-clicking anywhere on the site and hitting **Inspect**, directly highlighting the element you are on. Hit **\[Option\] + \[⌘\] + \[J\]** (on macOS) or **\[Shift\] + \[CTRL\] + \[J\]** (on Windows/Linux) if you want to use the keyboard. Here you can see the HTML and applied CSS styles; you can even manipulate them to see what happens. There are many tutorials online on how to use the tools, please consult one first if you are new.
In order to target an element with CSS, you first need to find a valid [selector](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors). This is usually a class, one of the whitespace-separated values as shown in the **Elements Inspector** (prepended with a single dot). They are best in terms of [performance](https://developer.mozilla.org/en-US/docs/Learn/Performance/CSS) and compatibility. You can even chain them for more [specificity](https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity). The **Styles Inspector** lists the currently applied properties and values.
#### Dark/Light Mode & Media Queries
Quite often, you need to apply specific styles depending on the theme mode or screen size. Especially colors are a concern here, as some that pop on a light background might vanish on a dark one. Another issue are the constraints imposed by mobile viewports: there is rarely enough space. Luckily, this can be accounted for.
```css
/* Only applied to viewport sizes 768px and up. */
@media only screen and (min-width: 768px) {
.selector {
property: value;
}
}
/* Only applied to viewport sizes 767px and down. */
@media only screen and (max-width: 767px) {
.selector {
property: value;
}
}
/* Always applied. */
.selector {
property: value;
}
/* Only applied in light mode (chained selector). */
:root[data-mode="light"] .selector {
property: value;
}
/* Only applied in dark mode (chained selector). */
:root[data-mode="dark"] .selector {
property: value;
}
```
#### Overwrite Custom Properties
[Custom properties](https://developer.mozilla.org/en-US/docs/Web/CSS/--*), also known as CSS variables, contain values which can be assigned to style properties using the `var()` function. They are scoped to the selector(s) they are declared on, but typically the `:root` to make them available everywhere. Fictioneer makes liberal use of custom properties (see [here](https://github.com/Tetrakern/fictioneer/blob/main/src/scss/common/_properties.scss)) and you can change a lot just by overwriting them. But be careful, they can cause severe performance issues if made dynamic.
```css
/* Make the *sticky* navigation background 10% transparent (always). */
Assuming you have set the **Header Style** to **top** or **split**, the following snippet makes the navigation background always visible regardless of scroll position and adds a semi-transparent background color to the header. This might come in handy if your site has a background image.
/* Applied to two chained selectors; the first one only affects direct descendants (>) */
.main-navigation__list > .menu-item,
.main-navigation .icon-menu__item {
border-radius: 0 !important; /* The !important enforces the value, even though the selector is too weak */
}
```
#### Background Overlay & Filters
Assuming you have set a background image for your site, this snippet adds an overlay that allows you to tint and filter said image — at a cost of performance. Usually, you are better off using an image already prepared for your needs, but this is one way to apply dynamic adjustments for dark or light mode. A simple semi-transparent color might do, but you can also go nuts with [mix-blend-mode](https://developer.mozilla.org/en-US/docs/Web/CSS/mix-blend-mode) and [backdrop-filter](https://developer.mozilla.org/en-US/docs/Web/CSS/backdrop-filter).
You want the navigation next to your top-aligned header, without changing the HTML? Hacky, but possible. The actual values and result will depend on the size of your header and number of menu items, as this can lead to overlapping elements if you are not careful. Also, depending on your background, you may need to adjust some colors for both light and dark mode.
You want the navigation on top of the header image? Just go to **Appearance > Customize > Layout** and change the Header Style to "Overlay". You may want to adjust the header image, title, tagline, or logo (if any) as well. Additional customizations require some CSS. Note that the following snippets are *examples*; do not mindlessly copy and paste them, adjust them to your needs.
You can change the minimum width of cards and gap spacing under **Appearance > Customize > Layout**, usually in combination with an increased site width. But if you want to have a grid on the list page templates as well, for example Stories and Chapters, you need some custom CSS. Be aware that targeting the `.card-list` class may be convenient to convert all card lists to grids, but can have unintended side effects since the class is used in many places. Better be specific.
Both the header and page style can be set to "Custom CSS", but you will notice there is no interface appearing. That’s because the CSS is supposed to be in the **Additional CSS** section. The option only applies the necessary root classes for the styles to work in the first place. There are many ways to modify the shape of a container, but it usually boils down to a [polygon](https://developer.mozilla.org/en-US/docs/Web/CSS/basic-shape/polygon), [mask image](https://developer.mozilla.org/en-US/docs/Web/CSS/mask-image), or both. Note that this is **not** easy.
A good starting point for masks is [haikai](https://app.haikei.app/), but add `preserveAspectRatio="none"` after the viewBox or the SVG won’t stretch properly. Make sure that your style looks good on both desktop and mobile viewports, which can be difficult to achieve. The following examples use [clamp()](https://developer.mozilla.org/en-US/docs/Web/CSS/clamp) and [calc()](https://developer.mozilla.org/en-US/docs/Web/CSS/calc) functions, but media queries or a fits-all approach work too.
Instead of just uppercasing the string, which would make it uppercase everywhere including search engine results, you can use a little bit of CSS to achieve this clean and proper. You will have to inspect your site to find the right selector, but it should be either one of those: `header__title-link`, `top-header__link`, or `wide-header-identity__title-link`.
You can add an offset to the main container in the Customizer, but that one is static. Maybe you need one that changes with the width of the site or something? There are many ways to achieve this, but you probably want to go with a `clamp()` function. To spare you the high school math, you can use an [online tool to calculate it](https://utopia.fyi/clamp/calculator/). Assign the result to the `--main-offset` custom property in a deeper scope than the root.
```css
/* Example: This interpolates from 32px at 375px width and 48px at 768px width. */
Perhaps you want to make your landing page wider, to show off more or larger cards? But without changing the global site width, because that would look silly for chapters? All you need for that is the ID of your page, which you can find in the address bar of your browser on the edit screen, and the `--site-width` custom property. We will scope the changes to that ID and that ID only; you can repeat the process for other IDs, of course.
WordPress automatically adds a class with the ID to the body, like `.page-id-69`. Using that as scope, you can affect the whole site only for this one instance. However, you may want to limit it to the `.main` container class. Otherwise, you site might display extreme layout flickers when the user visits another page. Obviously, you can do more than just increase the width.
You can remove the drop-shadow from the navigation bar and add a border instead. Mind that the navigation bar gains a background color when you scroll down, which you may want to customize or disable as well. Additional padding might also be necessary for this to look good. If you want the border to only appear when the navigation is sticky, add it to the `.main-navigation__background` instead.
```css
/* Example: Semi-transparent border in black (light mode) and white (dark mode). */
In order to move the title or logo, you need a bit of custom CSS. This can be added directly under **Appearance > Customize > Additional CSS**. Depending on whether you have a logo or not, you will have one of the following HTML/CSS combinations (and then some, but this is the relevant part).
What you are interested in are the `position`, `transform`, and/or `text-align` properties. `transform` changes the origin point (kinda) of the element, which is normally the top-left corner, so that it can be better offset. The `text-align` only works on the title. If you overwrite those values, you can move the element or text around. If you want to offset from the right or bottom, you need to add `top: unset;` or `left: unset;` or both. Make sure the title or logo still fits on mobile. See references for [position](https://developer.mozilla.org/en-US/docs/Web/CSS/position), [transform](https://developer.mozilla.org/en-US/docs/Web/CSS/transform), and [text-align](https://developer.mozilla.org/en-US/docs/Web/CSS/text-align).
The minimum and maximum values found in the Customizer are used to calculate [clamps](https://developer.mozilla.org/en-US/docs/Web/CSS/clamp), which are responsible for the dynamic scaling of the site. Viewport refers to the actual screen dimensions, again with a minimum (fixed) and maximum (site width). Everything is interpolated between those values. Use the built-in responsive display modes at the bottom of the Customizer to review your changes. Do not forget to check "Use custom layout properties" or your settings will be ignored.
Fictioneer comes with two menu locations, **Navigation** and **Footer Menu**, located precisely where you would expect. You can read up on how to create and add menus in the [official documentation](https://codex.wordpress.org/WordPress_Menu_User_Guide). The only thing of note here are the special CSS classes you can assign to menu items for certain effects (whitespace-separated). Make sure to enable the additional menu properties under Screen Options at the top.
On desktop, submenus are rendered as dropdown. On mobile, the **Navigation** shows either the top level items in a scrollable track (overflow) or only the mobile menu button (collapse). You can set that in the **Customizer**. The mobile menu is an unfolded list of all items if not specifically excluded with optional CSS classes.
*`not-in-mobile-menu`: As you can guess, this will hide the menu item in the mobile menu. However, submenu items will still be shown, so you can use this to hide superfluous dropdown parents.
In order to keep the database tidy, Fictioneer does not save or keep "falsy" (`""`, `0`, `null`, `false`, `[]`) meta values. This can cause issues with [meta queries](https://developer.wordpress.org/reference/classes/wp_query/#custom-field-post-meta-parameters) looking for these values, because posts without are excluded from the results. The most common troublemakers here are `fictioneer_story_sticky`, `fictioneer_story_hidden`, and `fictioneer_chapter_hidden`. There are multiple solutions for this.
$allowed[] = 'fictioneer_story_sticky'; // For example
return $allowed;
});
```
You can then append missing meta fields with value `0` under **Fictioneer > Tools**. The filter will also prevent those rows from being deleted when you optimize the database.
**3) Hook into `posts_clauses` (complicated; example from the theme):**
```php
/**
* Filters sticky stories to the top and accounts for missing meta fields
Fictioneer loads the free version of [Font Awesome 6.4.2](https://fontawesome.com/) by default and unless you want to use a different one or encounter compatibility issues (usually when a plugin includes FA as well), no action is required here.
* If you want to include it via plugin (perhaps a Pro Kit) or custom function, disable the theme version under **Fictioneer > General > Compatibility**.
* If you want to change the CDN link and integrity hash, do that by overwriting the `FICTIONEER_FA_CDN` and `FICTIONEER_FA_INTEGRITY` constants in a [child theme](https://developer.wordpress.org/themes/advanced-topics/child-themes/). You can set the integrity to `null` if not needed.
**Note:** The Font Library introduced in WP 6.5 has been disabled due to incompatibilities with the theme, specifically the chapter formatting system allowing to choose fonts. This may change in the future, but for now it should be avoided.
You can add custom fonts, either by uploading a configuration folder to `/themes/your-child-theme/fonts/` or with a CDN like Google Fonts. The latter is far more convenient, though it also violates the GDPR and is therefore not recommended except for testing. Delivering fonts from your server is legally safe, but can affect performance if you do not [leverage browser caching](#securing-wordpress--browser-caching) or use a cache plugin (which you should).
Following is an explanation of both methods on the example of [Noto Sans](https://fonts.google.com/noto/specimen/Noto+Sans?noto.query=noto+sans), which has also great variants for logographic writing systems if you require that. Mind that not all fonts you find on the Internet are free to use.
Purge the theme caches under **Fictioneer > Tools** after adding or removing a font. You may have to force-refresh too. Once everything is in order and refreshed, you can see the font listed under **Fictioneer > Fonts**. With that, you can assign the fonts to specific parts of the theme under **Appearance > Customize > Fonts**. More is possible with custom CSS.
This method requires some preparation. Take a look at the [roboto-serif](https://github.com/Tetrakern/fictioneer/tree/main/fonts/roboto-serif) default font folder; you will find several .woff2 files, one .css file, and one .json file. You can replicate that with relative ease using the [Google Fonts Webhelper](https://gwfh.mranftl.com/fonts/noto-sans) and a text editor of your choice. Search for "Noto Sans", select the charsets and styles you need (typically 300-700), then change the folder prefix to `../fonts/noto-sans/`. Copy the provided CSS into a new font.css file, download and unpack the archive, put everything into a "noto-sans" folder. You can rename the files, remove the comments, and minify the CSS if you got the patience. Just make sure everything is still correct.
The font.json file may seem a bit challenging, but is actually mostly informative. The only name-value pairs of importance right now are **skip**, **chapter**, **remove**, **key**, **name**, and **family**. You are encouraged to fill out the rest regardless, in case it becomes required in the future. Here is a pre-made one for Noto Sans:
"about": "Noto Sans is an unmodulated (“sans serif”) design for texts in the Latin, Cyrillic and Greek scripts, which is also suitable as the complementary choice for other script-specific Noto Sans fonts.",
"note": "",
"preview": "The quick brown fox jumps over the lazy dog.",
You can find a collection of pre-made font folders under [/repo/fonts/](https://github.com/Tetrakern/fictioneer/tree/main/repo/fonts). Currently available:
* [Noto Sans](https://github.com/Tetrakern/fictioneer/tree/main/repo/fonts/noto-sans): The Noto Sans font from Google.
* [Noto Sans JP](https://github.com/Tetrakern/fictioneer/tree/main/repo/fonts/noto-sans-jp): Noto Sans variant for Japanese.
* [Noto Sans KR](https://github.com/Tetrakern/fictioneer/tree/main/repo/fonts/noto-sans-kr): Noto Sans variant for Korean.
* [Noto Sans TC](https://github.com/Tetrakern/fictioneer/tree/main/repo/fonts/noto-sans-tc): Noto Sans variant for Traditional Chinese.
* [Noto Sans SC](https://github.com/Tetrakern/fictioneer/tree/main/repo/fonts/noto-sans-sc): Noto Sans variant for Simplified Chinese.
* [Special Elite](https://github.com/Tetrakern/fictioneer/tree/main/repo/fonts/special-elite): Typewriter-like font good for headings or special sections.
* [Verdana](https://github.com/Tetrakern/fictioneer/tree/main/repo/fonts/verdana): Web safe font and example for adding pre-installed device fonts.
Visit [Google Fonts](https://fonts.google.com/) and browse for a font you like. On the **Specimen** tab, scroll down to **Styles** and select what you need, typically everything from 300 to 700 if you want to cover all cases of the theme. If some styles are missing, you can still use the font — just perhaps not as primary one. On the right, under **Use on the web**, choose the **\<link\>** option and copy the link of the href attribute (nothing else). Make sure only one font is selected, because bundled font links are currently not understood by the theme.
Some options are not available in the settings because tempering with them can break the theme or result in unexpected behavior. Those options are defined via constants in the **function.php**. If you want to change them, you need a [child theme](https://developer.wordpress.org/themes/advanced-topics/child-themes/) or access to your **wp-config.php**. Just override them in the child theme’s own **function.php** or config, but only if you know what you are doing!
| FICTIONEER_TTS_REGEX | string | Splits chapter text into sentences for the text-to-speech feature. Default `'([.!?:"\'\u201C\u201D])\s+(?=[A-Z"\'\u201C\u201D])'`.
| FICTIONEER_ORDER_STORIES_BY_LATEST_CHAPTER | boolean | Whether to order updated stories based on the latest chapter added, excluding stories without chapters. Default `false`.