Fork me on GitHub

Simple-Jekyll-Search

Build Status

A JavaScript library to add search functionality to any Jekyll blog.


idea from this blog post


Promotion: check out Pomodoro.cc

Demo

Getting started

  • Place the following code in a file called search.json in the root of your Jekyll blog. This file will be used as a small data source to perform the searches on the client side:
---
---
[
  
    {
      "title"    : "Profiling with Tideways",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/tideways/",
      "date"     : "2018-03-14 21:31:00 +0000"
    } ,
  
    {
      "title"    : "Remote testing",
      "category" : "tests",
      "tags"     : "",
      "url"      : "/docs/tests/remote-testing/",
      "date"     : "2018-01-10 23:15:00 +0000"
    } ,
  
    {
      "title"    : "Moving data between instances",
      "category" : "deployment",
      "tags"     : "",
      "url"      : "/docs/deployment/moving-data/",
      "date"     : "2017-03-26 19:45:00 +0000"
    } ,
  
    {
      "title"    : "Restricting access",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/restricting-access/",
      "date"     : "2017-03-26 19:45:00 +0000"
    } ,
  
    {
      "title"    : "Custom error pages",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/error-pages/",
      "date"     : "2016-08-24 23:11:00 +0000"
    } ,
  
    {
      "title"    : "PHP7 and HHVM",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/php7-hhvm/",
      "date"     : "2016-06-21 19:24:02 +0000"
    } ,
  
    {
      "title"    : "Nginx Web Server",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/nginx/",
      "date"     : "2016-05-17 10:24:02 +0000"
    } ,
  
    {
      "title"    : "Staging instances (Shadows)",
      "category" : "deployment",
      "tags"     : "",
      "url"      : "/docs/deployment/shadows/",
      "date"     : "2016-05-11 07:37:00 +0000"
    } ,
  
    {
      "title"    : "Updating Vagrant Box",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/updating-vagrant-box/",
      "date"     : "2015-10-23 10:53:29 +0000"
    } ,
  
    {
      "title"    : "Seravo plugin - A must-use plugin",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/wppalvelu-plugin/",
      "date"     : "2015-10-15 17:51:38 +0000"
    } ,
  
    {
      "title"    : "Default values",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/defaults/",
      "date"     : "2015-10-13 15:11:50 +0000"
    } ,
  
    {
      "title"    : "Typical workflow",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/local-development/",
      "date"     : "2015-10-13 14:26:53 +0000"
    } ,
  
    {
      "title"    : "How to install Vagrant",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/how-to-install/",
      "date"     : "2015-10-13 14:26:53 +0000"
    } ,
  
    {
      "title"    : "List of commands",
      "category" : "get-started",
      "tags"     : "",
      "url"      : "/docs/get-started/available-commands/",
      "date"     : "2015-10-13 14:25:15 +0000"
    } ,
  
    {
      "title"    : "Configure Vagrant Box",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/configure-vagrant-box/",
      "date"     : "2015-10-12 19:12:17 +0000"
    } ,
  
    {
      "title"    : "Deploy using Git",
      "category" : "deployment",
      "tags"     : "",
      "url"      : "/docs/deployment/deploy-using-git/",
      "date"     : "2015-10-12 18:05:02 +0000"
    } ,
  
    {
      "title"    : "Data locations",
      "category" : "get-started",
      "tags"     : "",
      "url"      : "/docs/get-started/data-locations/",
      "date"     : "2015-10-12 11:29:39 +0000"
    } ,
  
    {
      "title"    : "Using Git hooks",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/using-git-hooks/",
      "date"     : "2015-10-12 11:24:27 +0000"
    } ,
  
    {
      "title"    : "Composer - Plugins & Themes",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/composer/",
      "date"     : "2015-10-11 03:46:06 +0000"
    } ,
  
    {
      "title"    : "Manage with wp-cli",
      "category" : "management",
      "tags"     : "",
      "url"      : "/docs/management/use-wordpress-with-wpcli/",
      "date"     : "2015-10-11 03:39:48 +0000"
    } ,
  
    {
      "title"    : "Vagrant box",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/vagrant-box/",
      "date"     : "2015-10-11 03:32:14 +0000"
    } ,
  
    {
      "title"    : "Compile assets & automate with Gulp",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/gulp/",
      "date"     : "2015-10-11 03:30:52 +0000"
    } ,
  
    {
      "title"    : "Debug mails with MailCatcher",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/mailcatcher/",
      "date"     : "2015-10-11 03:30:42 +0000"
    } ,
  
    {
      "title"    : "Profile runtime with Xdebug & webgrind",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/xdebug/",
      "date"     : "2015-10-11 03:30:24 +0000"
    } ,
  
    {
      "title"    : "Integration tests using Rspec",
      "category" : "tests",
      "tags"     : "",
      "url"      : "/docs/tests/integration-tests/",
      "date"     : "2015-10-11 03:28:22 +0000"
    } ,
  
    {
      "title"    : "Configure SSH",
      "category" : "get-started",
      "tags"     : "",
      "url"      : "/docs/get-started/configure-ssh/",
      "date"     : "2015-10-10 22:20:23 +0000"
    } 
  
]
  • configure the library ( options )

Note that the index generated in search.json does not include the posts’ content since you may not want to load the whole content of your blog in each single page. However, if some of you want to enable full-text search, you can still add the posts’ content to the index, either to the normal search, or on an additional search page with a dedicated second index file. To do this, simply add

"content"  : ""

to search.json after the "date" line to which you must add a comma (,).

Install with bower

bower install simple-jekyll-search

Setup

You need to place the following code within the layout where you want the search to appear.

For example in _layouts/default.html:

<!-- Html Elements for Search -->
<div id="search-container">
<input type="text" id="search-input" placeholder="search...">
<ul id="results-container"></ul>
</div>

<!-- Script pointing to jekyll-search.js -->
<script src="/docs/bower_components/simple-jekyll-search/dest/jekyll-search.js" type="text/javascript"></script>

Options

Customize SimpleJekyllSearch by passing in your configuration options:

SimpleJekyllSearch({
  searchInput: document.getElementById('search-input'),
  resultsContainer: document.getElementById('results-container'),
  json: '/search.json',
})

The above initialization needs to occur after the inclusion of jekyll-search.js.

searchInput (Element) [required]

The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.

resultsContainer (Element) [required]

The container element in which the search results should be rendered in. Typically an <ul>.

json (String|JSON) [required]

You can either pass in an URL to the search.json file, or the results in form of JSON directly, to save one round trip to get the data.

searchResultTemplate

The template of a single rendered search result.

The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.

E.g.

The template

<li><a href="{url}">{title}</a></li>

will render to the following

<li><a href="/jekyll/update/2014/11/01/welcome-to-jekyll.html">Welcome to Jekyll!</a></li>

If the search.json contains this data

[

    {
      "title"    : "Welcome to Jekyll!",
      "category" : "",
      "tags"     : "",
      "url"      : "/jekyll/update/2014/11/01/welcome-to-jekyll.html",
      "date"     : "2014-11-01 21:07:22 +0100"
    }

]

noResultsText

The HTML that will be shown if the query didn’t match anything.

limit

You can limit the number of posts rendered on the page.

fuzzy

Enable fuzzy search to allow less restrictive matching.

exclude

Pass in a list of terms you want to exclude (terms will be matched against a regex, so urls, words are allowed).

Enable full content search of posts and pages

  • Replace ‘search.json’ with the following code:
---
layout: null
---
[
  
    {
      "title"    : "Profiling with Tideways",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/tideways/",
      "date"     : "2018-03-14 21:31:00 +0000",
      "content"  : "  Recent PHP version required: To use the Tideways integration, make sure you have PHP 7.2 activated. You want your site to be as fast as possible, right?Xdebug is not for production useWe have provided a pre-installed Xdebug configuration in our Seravo WordPress Vagrant images for a number of years already, but not in our production or staging environments. The reason for this is that the instrumentation Xdebug does is quite heavy and it can be performed only in a separate development environment. For production environments something more lightweight is needed, a tool that does not slow down the site. Also to complement long running in-production tests one needs a good dashboard and tools to extract useful information from the profiling data collected. Therefore we decided to cooperate with Tideways and integrate their profiling tool into our system.Tideways can be safely used in both production and staging all the timeTideways is a service to collect and analyze information about how the code of your WordPress site performs. It helps developers to:  Visualize changes in the site production code performance over time  Drill down into execution logs and find bottle necks in PHP code  Analyze database queries so their performance can be optimized  Alert about PHP errors and analyze stack traces so the code can be improved to avoid the errors  E-mail, Slack, Github and other integrationsThe Tideways profiling agent has a neglible impact on the performance of the site, so it can be active in the backgroud all the time. In our integration we have configured it to sample 1% of production site PHP executions and 10% of executions in the staging shadows, collecting execution traces and profiling data. The Tideways integration also has the Tideways agent pre-configured to work optimally with WordPress. Data from the production and staging shadows is automatically separated in the logs, so developers can easily tell what data came from where.Tideways offers the same timeline and execution path visualizations as XDebug+Webgrind, but in addition it will also store the PHP profiling traces permanently in an online database, which allows you to compare changes over time. Thanks to the team functionality you can share the information between all the development team members. Tideways even has automatic bottle neck detection and it gives improvement suggestions. Analyzing and improving your application could not be easier. Tideways has a ton of features and we strongly recommend you to try it out.  Tideways.com subscription recommended: Note that the free trial version of Tideways does not include all features. For example no traces from your code running in staging environments on Seravo’s servers will be shown on Tideways unless you have at least the Lite plan on Tideways.com.Steps to activate Tideways  Create an account at Tideways. You can start with a free trial and later upgrade to a paid account.  In the Tideways dashboard, create a new application and get the application API key (e.g. A0A0A0A0A0A0A0A0).  Create a file /data/wordpress/.tideways.key in your project and save the application API key in it (e.g. echo 'A0A0A0A0A0A0A0A0' &gt; .tideways.key).  In your production site environment, run wp-restart-php to active the PHP module and the Tideways daemon with your Tideways key.  Double check that you are running PHP 7.2 or newer.  Go back to your Tideways dashboard to see the data start pouring in!Seravo’s customer support is available to help you with the Tideways key activation if the steps above didn’t work for you as expected."
    } ,
  
    {
      "title"    : "Remote testing",
      "category" : "tests",
      "tags"     : "",
      "url"      : "/docs/tests/remote-testing/",
      "date"     : "2018-01-10 23:15:00 +0000",
      "content"  : "By default the local Vagrant is not easy to access by othersWith the default Vagrant box settings it is not easy for someone other than yourself to see the website that is running locally. The exact limitations depend on what kind of network settings your development laptop has and how the Virtualbox machines running on it are exposed. This documentation cannot cover all of those situations, but on the other hand the setup is not Seravo-specific, so any generic Vagrant documentation on this topic can be useful for more information.Sharing the Vagrant box website via Avahi/BonjourThe Seravo Vagrant box has Avahi support out-of-the-box. If you want to make your website available to your local network, you can simply edit the config.yml in your project and set avahi: true. After restarting the Vagrant box it will register the site name to the Avahi service running in your system, which will make it available to the the local network.Normally typing e.g. https://wordpress.local only works on your own computer as it can look up the IP address from the /etc/hosts file. With Avahi anybody in the same local network can type https://wordpress.local and access the site (assuming there are no additional firewalls or restrictions in place).Sharing the Vagrant box website via PageKiteIn theory you could also allow anybody in the world to access your development website running inside your Vagrant box by using a tunneling system like PageKite or localtunnel. We have not tested this setup and it involves so many details regarding your local settings that it is not possible for us to provide generic instructions here. These kind of setups are however very rare. Most developers use the shadow (staging) environments instead when they want to publish their work on a server that can be accessed anywhere from the Internet."
    } ,
  
    {
      "title"    : "Moving data between instances",
      "category" : "deployment",
      "tags"     : "",
      "url"      : "/docs/deployment/moving-data/",
      "date"     : "2017-03-26 19:45:00 +0000",
      "content"  : "  Warning: Unlike some other publishing systems, in WordPress there is a lot of valuable content in the database (user accounts, comments, statistics) and among the files (mainly uploads). Bluntly pushing the database or files from staging to production will most likely destroy some valuable data, so please plan your deployments carefully.Pushing code is easyOur WordPress project template (and many other similar ones, like Bedrock) have been designed with easy deployments in mind. It is preferred to use them so that your deployment to staging is a simple git push staging and after testing to production just git push production, all neatly orchestrated from the lead developers laptop.Pushing a full site with database and files is riskyWordPress does not separate clearly between actual site content, like the user or customer database, and layout related settings and other stuff in the database. Developers are sometimes tempted to push the entire database from staging to production, but be aware of the potential consequences. This approach is typically suitable only for a very static site.However, if you are certain that this is a safe thing to do, you can simply push files from the staging (or any other instance) to production via SSH. Alternatively, you can pull files and the database from production from any remote instance with SSH access.Below are the steps how to do this from production, fetching data from staging.Preparations before moving data from staging to productionThe first step is to run wp-backup to make sure your current database and files are backed up in case of an emergency and a need to revert your actions. The latest database backup can be found at /data/backups/data/db/&lt;sitename&gt;.sql and the WordPress files at /data/backups/data/wordpress/.The second step is to test your SSH credentials and the connection. For that you need to know the SSH port number of your staging instance.example@example_48daaa:/data/home/example$ ssh example@example.seravo.com -p 11111The authenticity of host '[example.seravo.com]:11111' can't be established.ECDSA key fingerprint is aa:aa:aa:aa:48:29:40:e7:a5:9f:ff:09:fc:aa:aa:aa.Are you sure you want to continue connecting (yes/no)? yesWarning: Permanently added '[example.seravo.com]:11111' (ECDSA) to the list of known hosts.example@example.seravo.com's password:example@example_37faaa:~$ exitIf you are familiar with SSH keys, you can generate them in the production environment and install them on the staging instance for easier access from production. For a safe and secure workflow, do not automate the access from staging towards production. The other way around is okay, as production is always persistent and trusted. Also feel free to use .ssh/config in the production instance.Copying files with rsync and SSHThe following commands demonstrate how to use rsync via SSH to fetch new files as quickly as possible (rsync only transfers files and parts of files that are different). The flags stand for:  -av saves the file attributes (owner, time stamp) and prints out a verbose list of all files that changed  --delete-after will delete all the files from production that did not exist in staging, in effect clearing the obsolete files away  --exclude=wp-content/uploads will omit the uploads directory from being transferred from staging, and from being replaced in production  In some cases you might want to use exclude=.git too  The other options define the SSH port and hostname of the staging instance and the path to the wordpress/` directoryrsync -av --delete-after --exclude=wp-content/uploads -e 'ssh -p 11320' example@example.seravo.com:/data/wordpress/ /data/wordpressexample@example.seravo.com's password:receiving file list ... doneAfter the operation above we will rsync the uploads folder, but with different options to make sure that all files that exist in the uploads folder in production will remain intact and we will only add any additional files from staging.rsync -av -e 'ssh -p 11320' example@example.seravo.com:/data/wordpress/htdocs/wp-content/uploads /data/wordpress/htdocs/wp-content/Importing the database with wp-cli and SSHAfter all files have been transferred, the next step is to bring over the database from staging, that is if we really want the production to be a 100% identical to what we have in staging. Do note that this will overwrite all data currently in the production database.First we make a fresh database export in staging directly over SSH and import it with one single command:ssh example@example.seravo.com -p 11111 'wp db export -' | wp db importAfter this step you are done and can proceed to peruse wp-watch-logs and browse the site to make sure everything looks good. If not, repeat the steps above or revert to backups."
    } ,
  
    {
      "title"    : "Restricting access",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/restricting-access/",
      "date"     : "2017-03-26 19:45:00 +0000",
      "content"  : "Restricting access with built-in features of WordPressWordPress offers a multitude of user management and access control related features. We warmly recommend that you use them as your primary means of access management. For instance, you can easily protect individual pages and posts with a password by setting post visibility in WP admin to ‘Password Protected’. You can also activate Maintenance Mode and allow only selected users to access the entire site.For more complex scenarios you can install BuddyPress or use some of the groups plugins.Fiddling with Nginx based access control methods should be your last resort. Using WordPress features and PHP code is always the more flexible, more user and developer friendly option and the preferred method for managing authentication and enforcing access controls.Restricting access with HTTP Basic Authentication  Note: This applies only to static HTML pages. If you want to restrict access to certain WordPress pages or sections, use a WordPress plugin or PHP code to implement it.The HTTP Authentication headers based system is quite old fashioned and not exactly the state-of-the-art in cryptographic security. The list of usernames and passwords needs to be maintained manually using the htpasswd command line utility. First create a file with the -c option and then add more users as you need:htpasswd -bc /data/wordpress/nginx/htpasswd-file-example username1 adminpasswordhtpasswd -b /data/wordpress/nginx/htpasswd-file-example username2 userpasswordOnce you’ve generated a htpasswd file you can activate it for a particular path for example by creating a file /data/wordpress/nginx/htauth.conf like this:location ^~ /restricted-section/ {  auth_basic "Arbitrary realm name";  auth_basic_user_file /data/wordpress/nginx/htpasswd-file-example;}Remember to run wp-restart-nginx to make the new Nginx config file effective.  Warning: Do not activate HTTP Authentication for the entire site. Otherwise you will render the wp-test test unusable, all automatic monitoring of your site will start to fail and Seravo’s admins cannot access your site to check it and do upkeep anymore.Restricting access by IP addressIf you have a section of your site that should only be visible for example to visitors from a certain subnet, typically some sort of intranet or extranet page, you might want to use IP address based access controls. Be warned however that it is really hard to get right. Unlike domain names, IP addresses come and go, and you need to manually keep the IP lists up-to-date. IP addresses should not be used for very sensitive content, as no per-user audit trail whatsoever is formed when using blanket IP access rules.Sometimes your users need to access the page on-the-go, so you should also provide a password authenticated way of access they can resort to. A site should never have hard, IP restrictions that are impossible to bypass.location ^~ /restricted-section/ {  allow 1.2.3.4;  allow 5.6.7.8;  deny all;}  Warning: Do not activate IP address based restrictions for the entire site. Otherwise you will render the wp-test test unusable, all automatic monitoring of your site will start to fail and Seravo’s admins cannot access your site to check it and do upkeep anymore.Use two factor authentication and don’t waste time on implementing IP based restrictionsMany people want IP based restrictions because they are afraid that their users use subpar passwords or they want to increase the barrier for unauthorized access for other reasons. Rather than resort to IP based restrictions, look into WordPress plugins that implement two factor authentication (2FA). The primary plugin to research is the Two Factor plugin, a feature project for WordPress Core. It will most likely become a part of WordPress itself in the future."
    } ,
  
    {
      "title"    : "Custom error pages",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/error-pages/",
      "date"     : "2016-08-24 23:11:00 +0000",
      "content"  : "Custom error pagesIn some maintenance scenarios it might be handy to be able to show custom error pages.Flexible maintenance pageIf there is a need to temporarily divert all traffic to a single static page (for example to show an error message or a maintenance message) the best way to accomplish this is by adding to your /data/wordpress/nginx/custom.conf a line like:rewrite ^(.*)$ /maintenance.html break;The target of the rewrite can actually be any URL and the temporary view shown to visitors can also reside on an entirely different server. This is the recommended way to implement a static maintenance page.Plain static maintenance page (not recommended)If a file named index.html is placed in the /data/wordress/htdocs/ folder, it will take precedence over the existing index.php file that normally loads WordPress. A static file will always work even if PHP is broken for some reason. A static page might also be useful during a DDOS attack as static content can be served at a much higher rate than PHP generated content.Custom database connection error pageIf WordPress is unable to connect to the database, the PHP file /data/wordpress/htdocs/wp-content/db-error.php will be displayed instead. This file may be customized to show any static or dynamic content instead of the default template.Custom WordPress (PHP) error pageIf any WordPress PHP file contains a fatal error and PHP cannot execute, the server will give the error 500 by default and the site will be served from stale cache. If it’s not possible to cache the site due to bad cache/expiry headers or excessive cookie usage, each visitor will see an error page generated by their own browser.To customize this error 500 page, add to the /data/wordpress/nginx/custom.conf lines like:fastcgi_intercept_errors on;error_page 500 /wp-content/wp-error.php;With this change the page wp-error.php will be displayed. This error page is independent of the WordPress stack and will work despite PHP errors in WordPress code.WordPress core maintenance moduleAlso keep in mind that the built-in WordPress drop-in maintenance.php and .maintenance files can be used in the Seravo environment just like anywhere else. For details see wp_maintenance in the WordPress codex."
    } ,
  
    {
      "title"    : "PHP7 and HHVM",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/php7-hhvm/",
      "date"     : "2016-06-21 19:24:02 +0000",
      "content"  : "Alternative PHP EnginesBy default, Seravo.com uses the PHP7 as its PHP driver because it is widely supported in the WordPress community and the vast majority of plugins will work with it. Alternative engines have however also been available and customers can easily change the PHP version in use.PHP versionsThe PHP version can be modified by making a (or modifying an existing) file in /data/wordpress/nginx/*.conf that contains the line:set $mode php7;Currently available options are: php7, php7.2, php7.0, php5.6`. The version PHP7 refers to the most stable PHP version as estimated by Seravo admins, and should be the default for most sites.If for some reason an older PHP version is preferred, just add a line to your nginx conguration in /data/wordpress/nginx/custom.confset $mode php5.6;Remember to reload the Nginx configuration afterwards with wp-restart-nginx.The same instructions work both in our Vagrant box and on the live server. When you make the Nginx configuration part of your development repository, all your development, staging and production environments will use the same PHP back-end across the board.HHVMFor a performance boost we used to offer the option of using the Facebook’s Hip Hop Virtual Machine (HHVM) instead of PHP as the WordPress driver. HHVM was a massive improvement over PHP5 in speed, but sometimes suffered from stability and compatibility issues. Now when PHP7 has been in general availability for over a year, HHVM is not offered for new WordPress instances any more as HHVM has been deprecated in favour of PHP7."
    } ,
  
    {
      "title"    : "Nginx Web Server",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/nginx/",
      "date"     : "2016-05-17 10:24:02 +0000",
      "content"  : "BackgroundTraditionally, most hosting sites have been using Apache bundled with PHP as their web server of choice. However, during the last few years many have migrated from Apache to Nginx due to performance benefits and increased flexibility.Default settingsNginx comes pre-configured to use with WordPress in the Seravo setup. There is no need to peruse any guides online on how to set up Nginx with WordPress.Our default Nginx configuration includes:  Strong HTTPS settings (see example)  A Let’s Encrypt certificate for your public domains  HTTP cache with stale cache configured  Automatic expiration headers for static content  The Pagespeed module  User configurable API  Gzip  And lots more…ConfigurationIn most generic Apache hosting platforms, you have the ability to use .htaccess files to add custom rules to your web server. There are multiple reasons why this is not optimal, one being the inherently slower execution time for all page loads on the site.Instead, we give our users access to their nginx configuration through a directory that contains the .conf filesm which will be read by Nginx on startup. These configuration files can be found in /data/wordpress/nginx/*.conf.  Note: Under the hood, your custom Nginx configuration is included like this:  server {  listen 80 default_server;  server_name your-site.com;  ...  include /data/wordpress/nginx/*.conf;  ...}  How to create your own rulesThe file /data/wordpress/nginx/examples.conf includes a few examples for you to start with, all disabled by comments. We recommend that you do not edit this file directly. Leave it as a reference instead and create your own custom.conf file from scratch.$ cd /data/wordpress/nginx$ nano custom.confTo get started with your configuration you can copy stuff from examples.conf. Remove the comments from the beginning of the line and edit the rules to match the specific needs of your site.Restarting NginxAfter you’ve made changes to your nginx configuration, please reload the configuration by runningwp-restart-nginxIf there should be any errors wp-restart-nginx will warn you about them and refuse to restart before the issue is fixed.ExamplesForcing HTTPSTo force all your users to connect via https, you may redirect them to the https side with a Nginx configuration.The preferred method to force HTTPS is with a custom variable.# Force redirect http -&gt; httpsset $force_https 1;Making exceptions to the default X-Frame-Options ruleDue to security reasons, X-Frame-Options is set for all customers of Seravo by default. Customers can set their own X-Frame-Options and thus override the default values, but it cannot be removed altogether.This can as easily be emitted from PHP code as well with a simple header("X-Frame-Options: ALLOWALL");. To have this emitted for a section of the WordPress site, the functions.php could include something like this, for example:if ( strpos($_SERVER['REQUEST_URI'], '/widget/') !== false ) {  header("X-Frame-Options: ALLOWALL");}If a single page or a section of the site without PHP functionality needs to have a more relaxed rule to allow arbitrary access, it can be done with a rule like this:location /widget/ {  add_header X-Frame-Options ALLOWALL;}Note that ALLOWALL is not an official keyword, but most browsers support it anyway. In the future the whole X-Frame-Options header will be superseded by a new system called frame ancestors. If a site emits any frame-ancestors headers, the browser will follow those rules and ignore whatever was set in the X-Frame-Options headers.RedirectsBasic redirectsRedirects from http://your-site.com/original -&gt; https://example.com/new/url/rewrite ^/original(.*)$ https://example.com/new/url$1 permanent;Rewrite all old *.html files to WordPress pages with pretty URLS:rewrite ^/([0-9a-z-]+)\.html /$1/ permanent;Please use something like Rexexpal to test your regular expressions and be sure to use curl -IL to test your redirects without having to hassle with the cache of a regular browser.Redirecting domainsIf you have multiple domains for your site and want to only use one of them:if ($host ~ "old-subdomain.your-old-site.com") {  return 301 https://your-site.com$request_uri;}Serve two different sites from the same domainSometimes it makes sense to have two separate sites served from the same domain, as it will contribute to a better user experience and improve the search engine ranking for the content of the sites, when compared to having the site split to separate domains or subdomains. For example, the majority of the site example.com could be hosted on WordPress, but the section example.com/store might be on Magento.This can be achieved using Nginx proxying. For example, create a file called /data/wordpress/nginx/store-proxy.conf with the contents:location /store/ {  proxy_ssl_server_name on;  proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;  proxy_pass https://store.example.com/;}The PageSpeed modulePageSpeed sniffs through your html documents and rewrites them to be faster. This process is very site specific, so make sure that you test everything carefully before enabling PageSpeed in production. You can find more about all the filters available in Google documentation.Turn pagespeed onpagespeed on;Add some PageSpeed filters# This does a lot so test which of these you really needpagespeed EnableFilters rewrite_css,sprite_images,combine_css,inline_css,flatten_css_imports,inline_javascript,combine_javascript,inline_google_font_css,canonicalize_javascript_libraries,rewrite_images,recompress_images;Note that with the introduction of HTTP/2, many of the techniques used by PageSpeed have become obsolete. Currently very few of our customers use PageSpeed because of the limited benefits it brings."
    } ,
  
    {
      "title"    : "Staging instances (Shadows)",
      "category" : "deployment",
      "tags"     : "",
      "url"      : "/docs/deployment/shadows/",
      "date"     : "2016-05-11 07:37:00 +0000",
      "content"  : "ShadowsShadows are a unique feature in Seravo that provides you with non-public instances of your website. They are most commonly used as Staging and Development instances.Getting a ShadowEmail us at wordpress@seravo.com and ask us for a Staging instance. You will have one opened up for you in no time.It’s also possible to have your own domain or subdomain for the staging environment. Please note that this feature is still in development so some functionalities are not yet fully implemented and there are known bugs. For example the command wp-shadow-reset and the ‘Exit Staging’ button do not currently work with a staging environment using its own domain.In later revisions of this feature, you will be able to create on-demand shadows via the WordPress admin dashboard and the Seravo plugin.Using a ShadowThe Seravo PluginThe Instance Switcher module in the Seravo plugin adds a simple interface to your WP-admin view, that allows you to easily switch between your Shadow and Production instances.SSH/SFTPYou can SSH into your shadows and work on them via SSH/SFTP or git. When a new shadow is created you will receive the SSH/SFTP credentials to use with it.Your WordPress login will remain unchanged, since the site is a copy of your production site when first created.You can tell that you’re in a shadow by looking at the WP_ENV environment variable. If you’re in a shadow, it will be either staging or development, depending on what’s applicable in your situation. Your production instance will have a WP_ENV value of production.mysite_1a2b3c$ wp-list-env...WP_ENV: stagingReset the Shadow environmentYou can use the command wp-shadow-reset to copy the current production site over the chosen staging instance. The command has to be run on the production server.user@mysite_123abc:~$ wp-shadow-reset No shadow specified, please run "wp-shadow-reset &lt;shadow&gt;" with one of the shadows below:- mysite_1a2b3c- mysite_4d5e6fThe command requires you to choose the shadow environment you want to reset. The system will then ask if it’s okay for you that the database and all files in /data/wordpress will be replaced with the production site.After choosing yes, the shadow will be reset.How does it work?Under the hood, shadows work exactly the same as your production instance does, the only difference being that they have no public domain mapped to them.Shadows have their own full Linux environment and their own database, completely separate from your production instance. You can use SSH to work on your shadow instances in precisely the same way as you can with your production instance.The Shadow CookieTo view your shadow in the browser, a special cookie called wpp_shadow must be set.The value of the wpp_shadow cookie determines which shadow instance will be served to your browser.Example:mysite_123abc (production)mysite_1a2b3c (staging)Setting a cookie wpp_shadow=1a2b3c;path=/ will return the staging instance to your browser.The Seravo plugin handles these cookies easily for you.You can also use GET parameters to set these cookies as described below.Direct link to ShadowYou can set the Shadow cookie easily via a GET parameter in the url. Example:https://mysite.seravo.com/?wpp_shadow=1ab2c3The link above would set the cookie wpp_shadow=1a2b3c;path=/ in your current browser session.Curl to shadowWith curl you can fetch a file from the shadow in the following way:curl -iLs https://example.com/test.php?wpp_shadow=1a2b3c""
    } ,
  
    {
      "title"    : "Updating Vagrant Box",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/updating-vagrant-box/",
      "date"     : "2015-10-23 10:53:29 +0000",
      "content"  : "When to update the Vagrant BoxWhen you’re using Vagrant, it will automatically check for updates. If an update is available you’ll get a message like this:$ vagrant upBringing machine 'default' up with 'virtualbox' provider...==&gt; default: Checking if box 'seravo/wordpress' is up to date...==&gt; default: A newer version of the box 'seravo/wordpress' is available! You currently==&gt; default: have version '20151016.13.2529'. The latest is version '20151022.21.3040'. Run==&gt; default: `vagrant box update` to update....This is an indicator that you don’t have the newest version of the box available locally.Download new box imageRun the following command in your project folder so that you’ll get new version of the box seravo/wordpress:$ vagrant box update  Note: This might take a while. The image is  ~900mb large because it’s designed to have everything included for easier usage.Replace the old box with a newer oneRun the following commands in your project folder:# First make sure that the original box is online for the database dumps to work$ vagrant up# Then just destroy the box# This triggers a database dump in the box which is used when a new box comes online.$ vagrant destroy --force# Then just start it again. This will use newer box image and use the earlier database and ssl certicates$ vagrant up"
    } ,
  
    {
      "title"    : "Seravo plugin - A must-use plugin",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/wppalvelu-plugin/",
      "date"     : "2015-10-15 17:51:38 +0000",
      "content"  : "How to downloadThe plugin is available on Github, so all users can see its open development and even do pull requests for features.You can download the plugin here for testing purposes: Download plugin from GithubList of featuresVersion 1.5.4Notifications from SeravoThese are used only for informing about service outages.Appends all logins to a log file and returns a 401 (unauthorized) http status code after a failed loginAll logins are logged to /data/log/wp-login.log. This enables more relevant logging.Hides “New updates available” naggingAll updates are handled by Seravo so your clients don’t need to worry about them. However,Seravo updates can be manually disabled from the WordPress admin Tools-&gt;Updates page.Uses nocache headers if the site is in development modeMakes development with clients so much easier.Imagine a situation where your client sees the page in development and then doesn’t know how to empty the browser cache later on.Adds a Purge Cache button to the admin barThis feature simplifies emptying your cached pages.Purging the cache is also achievable via command line: $ wp-purge-cache as seen in commands.Makes URLs content relativeThis makes migration and switching the site URL easier when publishing your site.  Note: relative URLs are automatically changed into absolute URLs when using feeds (rss, atom, etc…)Enables login to wp-admin with a secure SSL client certificateThis helps the admins and clients who have multiple sites in Seravo. If you have multiple sites in Seravo, you can request a personal SSL-certificate from our admins.List all domains associated with your accountAdds an admin page where you can view all your domains.Checks that WordPress is configured over SSLNotifies you if you have forgotten to enable SSL in the WordPress siteurl or homeurl. Seravo provides free SSL for its customers and encourages them to ensure the safety of their site.Configuration by using filtersOur plugin contains multiple filters which can be used to turn off the features mentioned above.Add any of the filters below to the functions.php file of your theme:&lt;?php/* * This is a master switch to disable all modules. */add_filter('seravo_disable_modules', '__return_false');/* * Disable: Helpers for hiding useless notifications and small fixes in logging */add_filter('seravo_use_helpers', '__return_false');/* * Remove cache purge button from WP adminbar */add_filter('seravo_use_purge_cache', '__return_false');/* * Remove instance switcher from WP admin bar */add_filter('seravo_show_instance_switcher', '__return_false');/* * Disable: relative URLs in post content */add_filter('seravo_use_relative_urls', '__return_false');/* * Prevent hiding the domain alias from search engines */add_filter('seravo_hide_domain_alias', '__return_false');/* * Disable: Wordpress login log */add_filter('seravo_use_login_log', '__return_false');/* * Disable: Check that HTTPS is enabled in siteurl and homeurl */add_filter('seravo_check_https', '__return_false');/* * Hide admin menu pages, where * {PAGE} is one of: reports, backups, updates or domains */add_filter('seravo_show_{PAGE}_page', '__return_false');/* * Disable: Check that user has changed email address no-reply@seravo */add_filter('seravo_check_default_email', '__return_false');"
    } ,
  
    {
      "title"    : "Default values",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/defaults/",
      "date"     : "2015-10-13 15:11:50 +0000",
      "content"  : "VagrantDefault credentialsWordPress:user:     vagrantpassword: vagrantMariaDB (MySQL):# For rootuser:     rootpassword: root# For WordPress DBuser:     vagrantpassword: vagrantDefault Addresses for the boxThe default address can be changed by editing config.ymlWordpresshttp://wordpress.localMailcatcherhttp://mailcatcher.wordpress.localWebgrindhttp://webgrind.wordpress.localBrowsersynchttp://browsersync.wordpress.local"
    } ,
  
    {
      "title"    : "Typical workflow",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/local-development/",
      "date"     : "2015-10-13 14:26:53 +0000",
      "content"  : "Using gitGit is available on our platform, but there is no git repository by default. This is because most users want to create their own projects, and having a git repository initialized by default might create confusion. An even bigger source of confusion would be a git repository with hundreds of untracked or modified by uncommitted files, a situation we want to avoid. From the server administration point of view the fact that there is a git repository somewhere is a signal that it is there intentionally and any uncommitted changes are real anomalies that need to be addressed.Start a fresh repo from the server contentsLog in to the server via SSH and initialize the project. You can use git add . to add all current files to the project as the default .gitignore file will omit everything that does not belong to be tracked by version control.Example:ssh my-site.seravo.com -p &lt;port&gt;cd /data/wordpress/git config --global user.name "&lt;Full Name&gt;"git config --global user.email &lt;email&gt;git initgit add .git commit -am "Initial commit"Now you can simply clone the remote git repository to your machine and start working.$ git clone ssh://$SSH_USER@$SITE.seravo.com:[$SSH_PORT]/data/wordpress ~/Projects/$SITE --origin productionAlternative: Start by using our project template on GitHubThe method above gives you a fresh new project with no prior history. You may however want to consider using our template as a starting point and have a shared history, which makes it easier to later merge updated versions of our project template to your project. To do that run$ git clone https://github.com/Seravo/wordpress ~/Projects/$SITE$ cd ~/Projects/$SITE$ git remote add production ssh://$SSH_USER@$SITE.seravo.com:[$SSH_PORT]/data/wordpress$ git push -f production masterTip: you can have multiple git remotes:$ git remote add github git@github.com:ottok/example-site.git$ git remote -vgithub	git@github.com:ottok/example-site.git (fetch)github	git@github.com:ottok/example-site.git (push)production ssh://example@example.seravo.com:12345/data/wordpress (fetch)production ssh://example@example.seravo.com:12345/data/wordpress (fetch)upstream	https://github.com/Seravo/wordpress (fetch)upstream	https://github.com/Seravo/wordpress (push)Start up your local copyOnce you have the project on your own machine, starting it using Vagrant is as easy as running vagrant up:# Start vagrant and follow the questions from the installer# It's safe to just push enter to all of them$ vagrant up# You can connect into vagrant$ vagrant ssh# You can pull the production database (not required on new sites)$ wp-pull-production-dbNow you can open http://wordpress.local/ in a browser and edit the files in you project and see the result immediately.When you think your code is good to go, commit it and push to production with:$ git push production masterThe .git/hooks/post-receive will run on the receiving end and run Composer and Gulp if configured to do so. Note that if you created the git repository yourself, there will be no post-receive hook until you have copied it from /usr/share/git-core/templates/hooks/post-receive.When you are done, you can shut down Vagrant with halt. If you completely want to destroy the virtual image (for example to save disk space) execute destroy. Note that even after destroy you will have files under .vagrant and all the Composer installed modules etc under your project. Use git clean to get rid of all traces of vagrant up.vagrant haltvagrant destroygit clean -fdx &amp;&amp; git reset --hardInclude default site database contents in the git repositoryTo provide a seamless vagrant up experience for anybody who starts to develop the site using the git repository as their sole starting point, you should include a file named vagrant-base.sql in the repository that contains a suitable minimal database with some example settings and contents.You can easily create such a database dump file by running inside Vagrant the commandscd /data/wordpresswp db export vagrant-base.sql --path=/data/wordpress/htdocs/wordpress --skip-extended-insert --allow-root --single-transactionCustomize the ‘vagrant up’ runIf Vagrant detects that a file named vagrant-up-customizer.sh is present, it will automatically be run every time vagrant up is invoked. (Feature available in Seravo/WordPress since Jan 29th, 2017)."
    } ,
  
    {
      "title"    : "How to install Vagrant",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/how-to-install/",
      "date"     : "2015-10-13 14:26:53 +0000",
      "content"  : "InstallationLinux (Ubuntu/Debian)To use Virtualbox make sure you have vt-x enabled in your BIOS.sudo apt-get install -y vagrant virtualbox virtualbox-dkmsgit clone https://github.com/Seravo/wordpress ~/wordpress-devcd ~/wordpress-devvagrant plugin install vagrant-hostsupdater vagrant-triggers vagrant-bindfsvagrant up  Optional: If you want to have PHP Composer locally installed run:  $ sudo apt-add-repository -y ppa:duggan/composer$ sudo apt-get update$ sudo apt-get install php5-composer  Ubuntu 16.04 and later need ruby-devIf you see this error message on Ubuntu 16.04 or later:$ vagrant upmkmf.rb can't find header files for ruby at /usr/lib/ruby/include/ruby.hIt means you need to install separately the Ruby development files:sudo apt-get install ruby-devUbuntu 17.04 and laterVirtualBox sets up the vboxnet0 virtual interface routing using the legacy ifconfig and routecommands, instead of the modern ip command. For networking to work properly, you need to runapt install net-tools.Linux (Fedora)Add RPMFusion repositories. See  RpmFusion. Repository isneeded for Virtualbox.Clone the WordPress Git repo and run following commands:sudo yum install vagrant virtualboxsudo yum install ruby-devel # Needed to build native ruby extensionssudo gem update bundlersudo gem install hittimes -v '1.2.2'vagrant plugin install vagrant-hostsupdater vagrant-triggers vagrant-bindfs# Needed to load the kernel module for virtualbox, you may want to load it automatically on boot...sudo modprobe vboxdrvvagrant upLinux (General)If you get errors related to creating host-only network adapters during vagrant up, run sudo vboxreload.It seems that sometimes the virtualbox kernel modules are not working correctly after the machine wakes up from sleep.MacOS X  Install Xcode: xcode-select --install  Install Vagrant  Install Virtualbox  Clone this repo: git clone https://github.com/Seravo/wordpress ~/wordpress-dev  Run the installation in Terminal:    cd ~/wordpress-devvagrant plugin install vagrant-hostsupdater vagrant-triggers vagrant-bindfsvagrant up              Optional: Vagrant Manager for OS X can help you manage multiple Vagrant boxes.      Windows (Cygwin)To use Virtualbox make sure you have vt-x enabled in your BIOS.You might need to disable hyper-v in order to use Virtualbox.  Install Cygwin and via Cygwin openssh and git  Install Vagrant  Install Virtualbox  Clone this repo: git clone https://github.com/Seravo/wordpress ~/wordpress-dev  Run the installation in terminal:    cd ~/wordpress-devvagrant plugin install vagrant-hostsupdater vagrant-triggers vagrant-bindfsvagrant up        In theory, Seravo WordPress should work even without Cygwin installed, but we strongly recommend using Cygwin for doing WordPress development on Windows machines.    Optional: Vagrant Manager for Windows can help you manage multiple Vagrant boxes."
    } ,
  
    {
      "title"    : "List of commands",
      "category" : "get-started",
      "tags"     : "",
      "url"      : "/docs/get-started/available-commands/",
      "date"     : "2015-10-13 14:25:15 +0000",
      "content"  : "Vagrant box contains plenty of helpers for developing your site and migrating data to/from production.Production contains most of these and also a command for purging cache.List of commandsDeveloper helperswp-list-env$ wp-list-env - Prints a list of defined environment variables. Both the Vagrant image and the production server contain ENVs which define ports and credentials for WordPress. With this command you can debug the settings that you have.wp-restart-nginx$ wp-restart-nginx - Restarts the web server and reloads any configuration at  /data/wordpress/nginx/*.confwp-test$ wp-test - Runs Rspec tests from /data/wordpress/tests/rspec/*.rbVagrant commands  Note: These are only available inside the Vagrant box.wp-ssh-production$ wp-ssh-production - If your config.yml is set up with production details you can ssh into your production instance.wp-pull-production-db$ wp-pull-production-db - Copies the production database into your local Vagrant box. Also replaces all production siteurls in the database with your local development siteurl.Vagrant internal commands (good to know, but the developers won’t need to use these.)  Note: These commands are used in vagrantfile by default.wp-vagrant-activation$ wp-vagrant-activation - Restarts nginx and avahi-daemon, generates domains in /etc/hosts and production details to .ssh/configwp-vagrant-dump-db$ wp-vagrant-dump-db - This is run everytime you halt or destroy the vagrant box. So that you have dump file next time.wp-vagrant-import-db$ wp-vagrant-import-db - This is run everytime you up the vagrant box.It tries to import the dump file generated by $ wp-vagrant-dump-db so you can continue development where you left off."
    } ,
  
    {
      "title"    : "Configure Vagrant Box",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/configure-vagrant-box/",
      "date"     : "2015-10-12 19:12:17 +0000",
      "content"  : "Example configuration of config.yml#### Configuration for Vagrant#### This is used for domain mappingname: wordpress# These are used for migrating database and uploads back and forth with production# Comment these out if you don't want this integrationproduction:  domain: example.seravo.com  ssh_port: 12345staging:  domain: example.seravo.com  ssh_port: 23456# Domains are automatically mapped to Vagrant with /etc/hosts modificationsdevelopment:  domains:    - wordpress.local    - example.dev    - www.example.devChanging config.ymlnameChange name in config.yml to change your site name. This is used in quite a few places in the development environment.For example, with the above config.yml mailcatcher is set up in the address: mailcatcher.example.local.productionAdd domain and ssh_port to sync with your production instance.stagingOptional: Add domain and ssh_port to sync with your staging (shadow) instance.developmentAdd new domains under domains before you run vagrant up to use extra domains.See config-sample.yml for more.Using dotenvThe wp-config.php file uses Dotenv by default which enables you to create a file called .env in the root of your project to override default environment variables.Example:$ cat .env.development# Run 'ln -s .env.development .env' in project root to activate thisWP_TEST_URL=https://example.devDOMAIN_CURRENT_SITE=example.devNOBLOGREDIRECT=https://example.devCOOKIE_DOMAIN=.example.dev$ ll .envlrwxrwxrwx 1 otto otto .env -&gt; .env.developmentYou can have template files like .env.development tracked in version control, and then make a location-specific symbolic link from .env to the correct file. By default the .env file is and should be ignored by git via gitignore."
    } ,
  
    {
      "title"    : "Deploy using Git",
      "category" : "deployment",
      "tags"     : "",
      "url"      : "/docs/deployment/deploy-using-git/",
      "date"     : "2015-10-12 18:05:02 +0000",
      "content"  : "Requirements  You need to setup your ssh settings first.  You need to have a git repository initialized on the server and a local copy of it as described in Local development.  You need to be in your project directory: cd ~/Projects/your-site/  You need to have production set as git remote:# Here we are using custom alias 'your-site' in ~/.ssh/config$ git remote -vproduction  your-site:/data/wordpress/.git (fetch)production  your-site:/data/wordpress/.git (push)# This is the output if project was cloned without ssh alias$ git remote -vproduction  ssh://your-site@your-site.seravo.com:12345/data/wordpress (fetch)production  ssh://your-site@your-site.seravo.com:12345/data/wordpress (push)Deploy using gitNote: This doesn’t deploy the database or the contents of uploads. We recommend that you don’t include these in git.$ git push production masterCounting objects: 3, done.Delta compression using up to 8 threads.Compressing objects: 100% (3/3), done.Writing objects: 100% (3/3), 317 bytes | 0 bytes/s, done.Total 3 (delta 2), reused 0 (delta 0)remote: Seravo: composer.json was updated, installing...remote: Loading composer repositories with package informationremote: Installing dependencies from lock fileremote: Nothing to install or updateremote: Generating autoload filesremote: &gt; Wordpress/Installer::symlinkWPContentremote: Seravo: Nginx configs were changed, reloading nginx...remote: testing nginx configuration...remote: nginx: the configuration file /etc/nginx/nginx.conf syntax is okremote: nginx: configuration file /etc/nginx/nginx.conf test is successfulremote: restarting nginx...remote: nginx restarted!To your-site:/data/wordpress/.git   01b9b80..9b3d006  master -&gt; masterTutorialsIf you have a working site in the Vagrant box and you want to deploy itStep 1 - Getting credentialsFirst you need to order a site from seravo.com in order to get ssh credentials, which are described in the Configuring SSH section.Step 2 - Setting credentials# Go to your project folder$ cd Projects/your-site# Add new remote to git$ git remote add production ssh://your-site@your-site.seravo.com:12345/data/wordpress  Note: This is just an example. Use the real credentials for your site.Step 3 - Push into production# First push doesn't share anything with the fresh site so you need to force push it$ git push production master --forceFor deploying the database contents or the contents of the uploads folder you will need to roll your own solution which is safe enough to not overwrite any data created in production.  Note on wp-push- commands:In Seravo Vagrant images created before October 5th, 2016, there used to be the commands wp-push-production-db (deploy database to production) and wp-push-production-uploads (deploy wp-content/uploads into production) but they were deemed as too risky and removed to protect customers from accidentally making too much damage to their site."
    } ,
  
    {
      "title"    : "Data locations",
      "category" : "get-started",
      "tags"     : "",
      "url"      : "/docs/get-started/data-locations/",
      "date"     : "2015-10-12 11:29:39 +0000",
      "content"  : "Base installationSeravo uses https://github.com/Seravo/wordpress as a base installation for all sites. If you have any problems with the template please submit an issue to Github.Data locationsAll of your data is located under the path /data/. During the updates of your site we will wipe away all unnecessary files and only preserve things in the /data/ directory. No need to worry though, because we have moved your home folder into /data/home/$USER/, for instance, and made correct symlinks so you won’t even notice it’s located somewhere else.Web root (htdocs)Your content is served from:/data/wordpress/htdocs/WordPress installation pathWordPress is installed in: /data/wordpress/htdocs/wordpress/WP-contentWP-content is moved outside of the wordpress directory into: /data/wordpress/htdocs/wp-content/WordPress uploadsIt is not recommended to store anything in wp-content/uploads in git. If you have images in your plugin or theme, store those files inside the plugin or theme directories. The uploads folder is intended only for user uploaded files (in production). The real production media files or database should not be tracked in git.When a site is developed in our Seravo Vagrant box, the uploads will automatically be visible via our special uploads asset proxy. It will fetch any media file from the production site not present in the development environment on-the-fly. It requires the Vagrant box to have a working Internet connection and the production server address to be defined in the project config.yml. To use the production database while developing with the Seravo Vagrant box, see the command wp-pull-production-db.Log filesAll logs are saved in: /data/log/Project StructureSeravo uses a custom directory layout which is derived from Bedrock. Bedrock is a WordPress layout which uses Composer for package management. It is not advisable to modify any WP core files, so usually your application consists only of what’s included in the wp-content -directory. When we use version control, it is much better to have your content separated to a folder which is separated from the core installation. Our custom template also includes tests, composer.json, custom Nginx rules and files for local development (Vagrantfile). Let’s take a closer look at the Project directory:/data/wordpress├── config.yml # See about Configuration above├── composer.json # Use composer for package handling├── composer.lock├── gulpfile.js # Example for using gulp├── Vagrantfile # Advanced vagrant environment and scripts packaged in Vagrantfile│├── tests # Here you can include tests for your WordPress instance│   └── rspec│       └── baseline.rb # Our baseline tests use rspec/poltergeist/phantomjs since we have found them very effective.│       └── anything.rb # Your own test suite files can be named anything *.rb.|├── nginx # Here you can have your custom modifications to nginx which are also used in production│   └── examples.conf # Some examples to get started│   └── anything.conf # Your own config files can be named anything *.conf.│├── scripts│   ├── hooks # Git hooks for your project│   │   ├── pre-commit # This is run after every commit│   │   └──│   ││   ├── wordpress│   │   └── Installer.php #Additional composer scripts│   ││   └── run-tests # Bash-script as an interface for your tests in Seravo Production and Dev environment│├── vendor # Composer packages go here└── htdocs # This is the web root of your site    ├── wp-content # wp-content is moved out of core    │   ├── mu-plugins    │   ├── plugins    │   ├── themes    │   └── languages    ├── wp-config.php    ├── index.php    └── wordpress # WordPress Core installed by composer        ├── wp-admin        ├── index.php        ├── wp-load.php        └── ...Migrating from BedrockPlain Bedrock has the following directory structure:/data/wordpress├── config|   ├── environments|   │   ├── production.php|   │   └── ...|   └── application.php├── vendor├── web|   ├── app|   │   ├── mu-plugins|   │   ├── plugins|   │   ├── themes|   │   └── uploads|   ├── index.php|   └── wp-config.php├── composer.json└── ...For this to continue to work, you need to add the following symlinks:ln -s web htdocsln -s app htdocs/wp-contentThe server expects to find the web root in /data/wordpress/htdocs with wp-contents under it containing the site-specific files and wordpress containing the WordPress core files. Alternatively, you can simply modify your composer.json to use the same paths as defined in the Seravo WordPress project template composer.json.Directory layout with Capistrano or other deploy toolsIf you use a deploy tool that deploys multiple versions of the files on the server, and then activates one of them by repointing a symbolic link, you could use a directory layout like this:/data/wordpress├── current -&gt; releases/20170323143417├── htdocs -&gt; releases/20170323143417/web├── nginx├── releases│   ├── 20170322075317│   ├── 20170322112722│   └── 20170323143417│      ├── config│       │   ├── deploy│       │   └── environments│       ├── public -&gt; web│       ├── vendor│       │   ├── composer│       │   └── vlucas│       └── web│           ├── app│           │   ├── languages -&gt; /data/wordpress/shared/web/app/languages│           │   ├── mu-plugins -&gt; /data/wordpress/shared/web/app/mu-plugins│           │   ├── plugins -&gt; /data/wordpress/shared/web/app/plugins│           │   ├── themes│           │   └── uploads -&gt; /data/wordpress/shared/web/app/uploads│           ├── wordpress -&gt; /data/wordpress/htdocs/wp│           ├── wp -&gt; /data/wordpress/shared/web/wp│           └── wp-content -&gt; /data/wordpress/htdocs/app└── shared    ├── config -&gt; releases/20170323143417/config    ├── vendor -&gt; releases/20170323143417/vendor    └── web        ├── app        │   ├── languages        │   ├── mu-plugins        │   ├── plugins        │   └── uploads        └── wp            ├── wp-admin            ├── wp-content            └── wp-includesGit repository locationsIt is intended that customers initialize a git repository in the /data/wordpress directory. For details, see Local development.If we detect that a git repository exists while doing upkeep and editing any project files, we will commit any changes so that it’s less likely that the changes would be lost or overwritten when the customer later does a redeploy."
    } ,
  
    {
      "title"    : "Using Git hooks",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/using-git-hooks/",
      "date"     : "2015-10-12 11:24:27 +0000",
      "content"  : "Git hooksBasically they are scripts which allow you to run custom actions automatically on every git commit.They exists in your repository .git/hooks/ and are not copied when pulling/pushing.Git hooks are explained really well in git documentation. Example hooks can be found on a Linux system at the path /usr/share/git-core/templates/hooks/.What’s included?Our WordPress project template contains one custom git hook: pre-commit.By default it runs your Rspec tests before a new commit is allowed.Server hooksNote that on the server we also have a post-receive hook, but it’s not included in the project template as it’s useless (and potentially even harmful) to have in your local copy. For details see Deploy using git.CustomizingYou can customize the tests by editing scripts/run-tests. It’s in bash but you can use any language you wish. The only important thing is the return value of your script. If it returns true the git commit will continue and a false will reject your commit.Skipping pre-commit hookYou can use -n flag to skip hooks.$ git commit -n -m "commit message""
    } ,
  
    {
      "title"    : "Composer - Plugins &amp; Themes",
      "category" : "configuration",
      "tags"     : "",
      "url"      : "/docs/configuration/composer/",
      "date"     : "2015-10-11 03:46:06 +0000",
      "content"  : "What is it?  Composer is a dependency manager for PHP that has been gaining popularity lately. Your first question is most likely “what is a dependency manager and why do I need one?”. Almost any code you write probably ends up depending on 3rd party libraries. All of these libraries (projects, frameworks, files, etc) become dependencies of your project. Composer lets you declare the dependencies for a project and it will install and manage them.  Source: roots.ioHow to use Composer with WordPressExampleLet’s look at simplified version of our composer.json as an example:{  "repositories": [    {      "type": "composer",      "url": "http://wpackagist.org"    }  ],  "require": {    "php": "&gt;=5.3.2",    "johnpbloch/wordpress": "*",    "wpackagist-plugin/wordpress-seo": "*",    "wpackagist-theme/twentyfifteen": "*"  },  "extra": {    "installer-paths": {      "htdocs/wp-content/plugins/{$name}/": ["type:wordpress-plugin"],      "htdocs/wp-content/mu-plugins/{$name}/": ["type:wordpress-muplugin"],      "htdocs/wp-content/themes/{$name}": ["type:wordpress-theme"]    },    "wordpress-install-dir": "htdocs/wordpress"  }}ExplanationRepositories section:{  "repositories": [    {      "type": "composer",      "url": "http://wpackagist.org"    }  ]}Repositories section tells Composer where to look for your packages. In order for Composer to find your beloved WordPress plugins and themes you’ll need to point it to wpackagist.org, which is a mirror of all the plugins and themes that you can download from wordpress.org. Here you can add any custom repositories you may have, but for WordPress you’ll need to use wpackagist.Require section:{  "require": {    "php": "&gt;=5.3.2",    "johnpbloch/wordpress": "*",    "wpackagist-plugin/wordpress-seo": "*",    "wpackagist-theme/twentyfifteen": "*"  }}Require section tells Composer the minimum PHP version needed and all the packages to install."johnpbloch/wordpress": "*" means newest available version of WordPress."wpackagist-plugin/wordpress-seo": "*" means that we need plugin WordPress Seo"wpackagist-theme/twentyfifteen": "*" means that we need theme TwentyfifteenExtra section:{  "extra": {    "installer-paths": {      "htdocs/wp-content/plugins/{$name}/": ["type:wordpress-plugin"],      "htdocs/wp-content/mu-plugins/{$name}/": ["type:wordpress-muplugin"],      "htdocs/wp-content/themes/{$name}": ["type:wordpress-theme"]    },    "wordpress-install-dir": "htdocs/wordpress"  }}By default Composer installs everything to vendor directory in the root of your project. Luckily for us wpackagist uses a clever plugin composer/installers that allows us to have custom installation paths. In Extra section we can define installation paths for different types of packages.Adding your own plugins and themesThe best way to develop custom plugins and themes is to add them into their own repositories and install them by Composer.You can do this by adding a composer.json file for into your plugin/theme repo:{  "name": "your-name/custom-plugin",  "type": "wordpress-plugin",  "license": "GPLv3",  "description": "Plugin description",  "homepage": "https://github.com/your-name/custom-plugin"}…and then requiring it in your project like this:{  "repositories": [    {        "type": "vcs",        "url": "https://github.com/your-name/custom-plugin.git"    }  ],  "require": {      "your-name/custom-plugin": "*"  }}This way you can use plugins and themes from Github or Bitbucket.Paid WordPress plugins and ComposerBy default Composer only fetches modules that are publicly available on Github. For paid WordPress plugins that are not freely available, there are basically two alternative approaches. Either you can include them in our project repository and distribute them together with the project code, or you can get a paid account from Packagist.com that includes the ability to have private Composer packages.More informationYou can find more documentation on getcomposer.org"
    } ,
  
    {
      "title"    : "Manage with wp-cli",
      "category" : "management",
      "tags"     : "",
      "url"      : "/docs/management/use-wordpress-with-wpcli/",
      "date"     : "2015-10-11 03:39:48 +0000",
      "content"  : "BasicsYou can use wp-cli in Vagrant box and Production. Just run this to see all commands:$ wp --help  Note: You can call wp command anywhere without --path parameter because the environment handles paths for you.More information about wp-cli can be found in wp-cli.orgUseful commandsDatabase export/import (dumping db)# Dumps the database to a provided filename$ wp db export your-dump-filename.sql# Imports the dump file from file$ wp db import your-dump-filename.sqlCreate userThis creates a new administrator user ‘admin’ with password ‘admin’:$ wp user create admin admin@wordpress.dev --user_role=administrator --user_pass=adminSearch-Replace database contentsAfter you have pulled database from production it’s useful to regex replace urls:$ wp search-replace http://original.com http://original.dev"
    } ,
  
    {
      "title"    : "Vagrant box",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/vagrant-box/",
      "date"     : "2015-10-11 03:32:14 +0000",
      "content"  : "Develop locally with VagrantYou can do development for your site locally in your own computer. This is done using Vagrant.All of our sites are pre-configured with a Vagrantfile so you can just clone your site to your computer and start developing locally. We have mimicked the production environment as much as possible and bundled many development tools into the Vagrant image.The virtual machine image is based on Ubuntu and it can be downloaded from Hashicorp Atlas.Contributing to the Vagrant imageOur Vagrant image can be found in Github: Seravo/wp-vagrant.We try to include all widely used dev tools in the box so that developers can use all tools really easily.Please make a pull request if you feel that something important is missing.Requirements  Knowledge of using terminal  Vagrant 1.7.4 or later installed  Virtualbox 4.2 or later installed"
    } ,
  
    {
      "title"    : "Compile assets &amp; automate with Gulp",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/gulp/",
      "date"     : "2015-10-11 03:30:52 +0000",
      "content"  : "Using GulpYou can use Gulp to automatically minify and compile your assets. This includes turning SASS to CSS or CoffeeScript to JavaScript. Gulp can also optimize your images and do a multitude of other things. With Browsersync it can even reload your browser windows across multiple devices automatically.Default Gulp settings require an adaptation to watch for your themeThe Seravo template contains example gulpfile.js. Our example compiles sass files from twentyfifteen theme. It also has Browsersync already configured for the theme twentyfifteen so you can use it as base for your own projects.First, install the dependencies specified in /data/wordpress/package.json:$ cd /data/wordpress/ &amp;&amp; npm installAfter this, Browsersync can be started by running:$ cd /data/wordpress/ &amp;&amp; gulp watchWhen it’s started the internal web server (Nginx) automatically reroutes all traffic through Browsersync so that you can have a nice live reload effect while developing.Example file/* * This is default barebone for gulp, add your own modifications here * It also serves as an example of how to use browser-sync in this environment */var gulp        = require('gulp');var browserSync = require('browser-sync');var sass        = require('gulp-sass');var reload      = browserSync.reload;/* * src array contains the files which the gulp will be watching * Choose your theme over here (twentyfifteen is provided as an example) */var src = {    scss: 'htdocs/wp-content/themes/twentyfifteen/scss/*.scss',    css:  'htdocs/wp-content/themes/twentyfifteen/css/',    php: [        'htdocs/wp-content/themes/*/*.php',        'htdocs/wp-content/plugins/*/*.php',        'htdocs/wp-content/mu-plugins/*/*.php'    ]};// Serve all files through browser-syncgulp.task('serve', ['sass'], function() {    // Initialize browsersync    // Nginx is configured to use any service in port 1337    // as middleware to WordPress in vagrant environment    browserSync.init({        // browsersync with a php server        proxy: "http://localhost:8080",        port: 1337,        ui: {            port: 1338        },        notify: true    });    // Watch sass files and compile them    gulp.watch(src.scss, ['sass']);    // Update the page automatically if php files change    gulp.watch(src.php).on('change', reload);});// Give another name for servegulp.task('watch',['serve'], function() {});// Compile sass into CSSgulp.task('sass', function() {    return gulp.src(src.scss)        .pipe(sass())        .pipe(gulp.dest(src.css))        .pipe(reload({stream: true}));});// Default task just compiles everything// This is run when site is deployed!gulp.task('default', ['sass'], function() {});"
    } ,
  
    {
      "title"    : "Debug mails with MailCatcher",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/mailcatcher/",
      "date"     : "2015-10-11 03:30:42 +0000",
      "content"  : "MailCatcherMailCatcher is a web app which can be used to mimic a real-life mail server. It’s used in Vagrant to prevent WP from sending mail out of the development environment to actual recipients. It simply tells WordPress that mail was sent successfully and saves the contents for the developer to see.You can find MailCatcher at the address: mailcatcher.{sitename}.localBy default it is: mailcatcher.wordpress.local"
    } ,
  
    {
      "title"    : "Profile runtime with Xdebug &amp; webgrind",
      "category" : "development",
      "tags"     : "",
      "url"      : "/docs/development/xdebug/",
      "date"     : "2015-10-11 03:30:24 +0000",
      "content"  : "What is Xdebug?Xdebug is a debugger and profiler for PHP. We mainly use it as profiler and it’s installed in the Vagrant box by default.Profiling pages with Xdebug and webgrindYou can profile any page in Vagrant by visiting them and using the ?XDEBUG_PROFILE paramater in the url.This will generate a new dbkg dump which you can the analyze in your browser using webgrind.Example: Profile WP admin dashboard  Visit: http://wordpress.local/wp-admin/?XDEBUG_PROFILE  Visit http://webgrind.wordpress.local/  Click update button and wait for webgrind to analyze the dump.  You can see the profiling of the admin page and look up slow functions which you can then optimize."
    } ,
  
    {
      "title"    : "Integration tests using Rspec",
      "category" : "tests",
      "tags"     : "",
      "url"      : "/docs/tests/integration-tests/",
      "date"     : "2015-10-11 03:28:22 +0000",
      "content"  : "What are integration tests?Integration tests make sure that certain features of your site work as they should.For example if we have the following use case:  User visits your-site.com/wp-login.php and sees the login form.  When user fills correct password and username he sees the WordPress dashboard including adminbar.When the project is functional we will have the feature described above. Integration tests can be used to make sure that the feature works as described in the use case.Testing with Rspec &amp; CapybaraOur integration tests use a Ruby testing framework called Rspec with the extension Capybara.We use the headless browser PhantomJS with the Ruby driver Poltergeist.Using Ruby for testing a PHP application like WordPress may sound overwhelming but in our opinion it’s quite fun and effective. Our latest WordPress baseline template can be found in Github. It can be used as an example for your own unique tests.  Note: These tests are used in your production system as well (if available).  This way we can figure out if the site is still working after updates so that we can alarm you when something breaks and hand the updating process to be manually by the owner.How to run these testsYou can use this command in Production and Vagrant box:# Runs all tests in /data/wordpress/tests/rspec/*.rb$ wp-testExample testsThe following test suite consists of two describe blocks.The first one tests that the front page is loaded correctly and has CSS styles. Then it clicks a link in the front page and expects the following page to contain text Archives.The second one tests the use case we talked about in the beginning of this page.# Use preconfigured Poltergeist/PhantomJS rules and load WP classrequire_relative 'lib/config.rb'### Begin tests ###describe "WordPress: #{WP.host} - ", :type =&gt; :request, :js =&gt; true do  subject { page }  describe "frontpage" do    before do      visit WP.siteurl('/')    end    it "Healthy status code 200" do      expect(page).to have_status_of [200]    end    it "Page includes stylesheets" do      expect(page).to have_css    end    it "After user clicks archive link, User should see archives" do      click_link('October 2015')      expect(page).to have_content 'Archives'    end  end  describe "admin-panel" do    before do      visit WP.siteurl('/wp-login.php')    end    it "There's a login form" do      expect(page).to have_id "wp-submit"    end    # Only try logging in if we could create a test user    if WP.user?      it "Logged in to WordPress Dashboard" do        within("#loginform") do          fill_in 'log', :with =&gt; WP.user.username          fill_in 'pwd', :with =&gt; WP.user.password        end        click_button 'wp-submit'        # Should obtain cookies and be able to visit /wp-admin        expect(page).to have_id "wpadminbar"      end    end  endendHow to extend the testsAll files located in the path tests/rspec/*.rb will be executed. Instead of editing the existing baseline tests, we recommend creating new files for your own tests. Group the tests that test the same features and try to name the files logically to make it easier for your collaborators to debug or extend the tests later.To try your new test, run it individually with verbose output:rspec -f d new-test.rbRspec also has a profiling option available if you want to measure how long the test takes and potentially detect some execution time anomalies:rspec -f d -p 10 new-test.rbList of Helper functionsWP Helper moduleThese tests use the helper module WP which is included in the project.# Returns url to your site for the following {path}# @return string - url to your siteWP.siteurl(path)WP.url(path)# Returns the hostname/domain which is defined for WordPress# @return string - hostname of WordPressWP.hostname()WP.host()# Check if a testuser was created successfully# @return boolWP.user?# Returns the user object# @return User objectWP.user# User has following attributes:WP.user.username    # Username for the WordPressWP.user.password    # Password for the WordPressWP.user.firstname   # Test user firstname - by default: TestWP.user.lastname    # Test user lastname - by default: SeravoWP.user.email       # Test user email - by default: testbotuser@{your-site}List of Capybara functions# Navigatingvisit('/projects')visit(post_comments_path(post))# Clicking links and buttonsclick_link('id-of-link')click_link('Link Text')click_button('Save')click('Link Text') # Click either a link or a buttonclick('Button Value')# Interacting with formsfill_in('First Name', :with =&gt; 'John')fill_in('Password', :with =&gt; 'Seekrit')fill_in('Description', :with =&gt; 'Really Long Text…')choose('A Radio Button')check('A Checkbox')uncheck('A Checkbox')attach_file('Image', '/path/to/image.jpg')select('Option', :from =&gt; 'Select Box')# Scopingwithin("//li[@id='employee']") do  fill_in 'Name', :with =&gt; 'Jimmy'endwithin(:css, "li#employee") do  fill_in 'Name', :with =&gt; 'Jimmy'endwithin_fieldset('Employee') do  fill_in 'Name', :with =&gt; 'Jimmy'endwithin_table('Employee') do  fill_in 'Name', :with =&gt; 'Jimmy'end# Queryingpage.has_xpath?('//table/tr')page.has_css?('table tr.foo')page.has_content?('foo')page.should have_xpath('//table/tr')page.should have_css('table tr.foo')page.should have_content('foo')page.should have_no_content('foo')find_field('First Name').valuefind_link('Hello').visible?find_button('Send').clickfind('//table/tr').clicklocate("//*[@id='overlay'").find("//h1").clickall('a').each { |a| a[:href] }# Scriptingresult = page.evaluate_script('4 + 4');# Asynchronous JavaScriptclick_link('foo')click_link('bar')page.should have_content('baz')page.should_not have_xpath('//a')page.should have_no_xpath('//a')# XPath and CSSwithin(:css, 'ul li') { ... }find(:css, 'ul li').textlocate(:css, 'input#name').valueCapybara.default_selector = :csswithin('ul li') { ... }find('ul li').textlocate('input#name').value# Source: https://gist.github.com/zhengjia/428105."
    } ,
  
    {
      "title"    : "Configure SSH",
      "category" : "get-started",
      "tags"     : "",
      "url"      : "/docs/get-started/configure-ssh/",
      "date"     : "2015-10-10 22:20:23 +0000",
      "content"  : "Obtaining your CredentialsAfter ordering your instance from Seravo.com you’ll get an email which includes your credentials. It looks something like this:SSH/SFTP:Host: example-site.seravo.comPort: 12345User: example-sitePass: 123456abcdefgh  Important: Use your own credentials instead of these. These are just an example and won't work!Configuring SSHWe advice you to use the ~/.ssh/config file for easier ssh management.Add following lines to your config:Host example-site  HostName example-site.seravo.com  User example-site  Port 12345  ForwardAgent yes  Optional: ForwardAgent yes - allows you to use your ssh credentials in the production machine to access private code from Github or Bitbucket.Using SSH-key authenticationWe advice you to use a ssh key instead of a password for accessing your site. Read more about generating ssh keys.Using Vagrant SSHKeep in mind that when using use the vagrant ssh command to enter your Vagrant box, the SSH ForwardAgent is automatically enabled and your personal keys are used to access the production environment. These are used for wp-ssh-production or wp-pull-production-db. The Vagrant image itself does not contain any private SSH keys.  OS X users: You can install ssh-copy-id with Homebrew:  $ brew install ssh-copy-id    Windows users: Install your ssh key through Putty instead. Cygwin is also a great choice for all your terminal tools (ssh, rsync, git..) under Windows.After the following step you have successfully installed your ssh key into your WP instance:# This will install your ssh-key into your Seravo instance.# Remember we set your credentials in the last step and the name of your site won't be example-site$ ssh-copy-id example-siteThe authenticity of host '[example-site.seravo.com]:12345 ([185.26.50.24]:12345)' cant be established.RSA key fingerprint is xy:xy:xy:xy:xy:xy:xy:xy:xy:xy:xy:xy:xy:xy:xy:xy.Are you sure you want to continue connecting (yes/no)? yesWarning: Permanently added '[example-site.seravo.com]:12345' (RSA) to the list of known hosts.example-site@example-site.seravo.com's password:# After you enter your password you have installed your ssh key.# After this setup you can login to your instance by:$ ssh example-site"
    } 
  
  ,
  
   {
     
        "title"    : "404 - Not found",
        "category" : "",
        "tags"     : "",
        "url"      : "/docs/404/",
        "date"     : "",
        "content"  : "Sorry, the page you tried to open does not exist =(Try using the Search."
     
   } ,
  
   {
     
        "title"    : "WordPress Developer Documentation",
        "category" : "",
        "tags"     : "",
        "url"      : "/docs/",
        "date"     : "",
        "content"  : "  Note: This documentation is primarily intended for Seravo.com customers. You can however use our project structure &amp; Vagrant box for any WordPress development no matter where you decide to deploy, host or maintain it. As stated in LICENSE (GPL), the provided software and documentation is open source and can be used freely anywhere, including also commercial use.This contains guides and tips for developers who might want to enhance their workflow and use the best modern development tools. Feel free to pick the parts that fit your style of development best!All Seravo.com sites are preconfigured for optimal development workflow, but the workflow in general or any part of it is not mandatory. You don’t have to use Git, Composer or the others if you don’t want. Or you can use them, but follow your own workflow. All sites have SFTP/SSH access so all sites support even the most traditional FTP-your-stuff-to-the-server-workflow. But if you like the idea of a really optimized workflow, please keep on reading!This documentation is maintained in a public git repository. If you find any errors or you want to extend the documentation, feel free to contribute!Fast-track guide for developing your site:  Hint: Read the other topics to have better understanding what’s happening over here. The git repository must be initialized as described in Local development.# Clone your site to your computer and name the git remote as 'production'$ git clone ssh://$SSH_USER@$SITE.seravo.com:[$SSH_PORT]/data/wordpress ~/Projects/$SITE --origin production# (Alternatively clone github.com/Seravo/wordpress and use it as your project template)# Start developing your site with Vagrant$ cd ~/Projects/$SITE$ vagrant up# Follow the vagrant installer...# Make changes to your site...# Save your work into git$ git commit -am "Made some superb changes"# See if commit triggered tests are succesful...# Push your changes to production$ git push production masterCounting objects: 3, done.Delta compression using up to 8 threads.Compressing objects: 100% (3/3), done.Writing objects: 100% (3/3), 317 bytes | 0 bytes/s, done.Total 3 (delta 2), reused 0 (delta 0)remote: Seravo: composer.json was updated, installing...remote: Loading composer repositories with package informationremote: Installing dependencies from lock fileremote: Nothing to install or updateremote: Generating autoload filesremote: &gt; Wordpress\Installer::symlinkWPContentremote: Seravo: Nginx configs were changed, reloading nginx...remote: testing nginx configuration...remote: nginx: the configuration file /etc/nginx/nginx.conf syntax is okremote: nginx: configuration file /etc/nginx/nginx.conf test is successfulremote: restarting nginx...remote: nginx restarted!To ssh://example@example.seravo.com:12345/data/wordpress/.git   01b9b80..9b3d006  master -&gt; master"
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
   } ,
  
   {
     
        "title"    : "Simple-Jekyll-Search",
        "category" : "",
        "tags"     : "",
        "url"      : "/docs/bower_components/simple-jekyll-search/",
        "date"     : "",
        "content"  : "Simple-Jekyll-Search====================[![Build Status](https://travis-ci.org/christian-fei/Simple-Jekyll-Search.svg?branch=master)](https://travis-ci.org/christian-fei/Simple-Jekyll-Search)A JavaScript library to add search functionality to any Jekyll blog.---idea from this [blog post](https://alexpearce.me/2012/04/simple-jekyll-searching/#disqus_thread)---### Promotion: check out [Pomodoro.cc](https://pomodoro.cc/)# [Demo](http://christian-fei.github.io/Simple-Jekyll-Search/)# Getting started- Place the following code in a file called `search.json` in the **root** of your Jekyll blog. This file will be used as a small data source to perform the searches on the client side:```------[  {% for post in site.posts %}    {      "title"    : "{{ post.title | escape }}",      "category" : "{{ post.category }}",      "tags"     : "{{ post.tags | join: ', ' }}",      "url"      : "{{ site.baseurl }}{{ post.url }}",      "date"     : "{{ post.date }}"    } {% unless forloop.last %},{% endunless %}  {% endfor %}]```- configure the library ( [options](#options) )### Enabling full-text searchNote that the index generated in `search.json` does not include the posts' content since you may not want to load the whole content of your blog in each single page. However, if some of you want to enable full-text search, you can still add the posts' content to the index, either to the normal search, or on an additional search page with a dedicated second index file. To do this, simply add```"content"  : "{{ post.content | strip_html | strip_newlines }}"```to `search.json` after the `"date"` line to which you must add a comma (`,`).# Install with bower```bower install simple-jekyll-search```# SetupYou need to place the following code within the layout where you want the search to appear.For example in  **_layouts/default.html**:``````# OptionsCustomize SimpleJekyllSearch by passing in your configuration options:```SimpleJekyllSearch({  searchInput: document.getElementById('search-input'),  resultsContainer: document.getElementById('results-container'),  json: '/search.json',})```The above initialization needs to occur after the inclusion of `jekyll-search.js`.### searchInput (Element) [required]The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.### resultsContainer (Element) [required]The container element in which the search results should be rendered in. Typically an ``.### json (String|JSON) [required]You can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data.### searchResultTemplateThe template of a single rendered search result.The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.E.g.The template```{title}```will render to the following```Welcome to Jekyll!```If the `search.json` contains this data```[    {      "title"    : "Welcome to Jekyll!",      "category" : "",      "tags"     : "",      "url"      : "/jekyll/update/2014/11/01/welcome-to-jekyll.html",      "date"     : "2014-11-01 21:07:22 +0100"    }]```### noResultsTextThe HTML that will be shown if the query didn't match anything.### limitYou can limit the number of posts rendered on the page.### fuzzyEnable fuzzy search to allow less restrictive matching.### excludePass in a list of terms you want to exclude (terms will be matched against a regex, so urls, words are allowed).## Enable full content search of posts and pages- Replace 'search.json' with the following code:```---layout: null---[  {% for post in site.posts %}    {      "title"    : "{{ post.title | escape }}",      "category" : "{{ post.category }}",      "tags"     : "{{ post.tags | join: ', ' }}",      "url"      : "{{ site.baseurl }}{{ post.url }}",      "date"     : "{{ post.date }}",      "content"  : "{{ post.content | strip_html | strip_newlines }}"    } {% unless forloop.last %},{% endunless %}  {% endfor %}  ,  {% for page in site.pages %}   {     {% if page.title != nil %}        "title"    : "{{ page.title | escape }}",        "category" : "{{ page.category }}",        "tags"     : "{{ page.tags | join: ', ' }}",        "url"      : "{{ site.baseurl }}{{ page.url }}",        "date"     : "{{ page.date }}",        "content"  : "{{ page.content | strip_html | strip_newlines }}"     {% endif %}   } {% unless forloop.last %},{% endunless %}  {% endfor %}]```### If search isn't working due to invalid JSON- There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use `remove_chars` as a filter.For example: in search.json, replace```"content"  : "{{ page.content | strip_html | strip_newlines }}"```with```"content"  : "{{ page.content | strip_html | strip_newlines | remove_chars | escape }}"```##Browser supportBrowser support should be about IE6+ with this `addEventListener` [shim](https://gist.github.com/eirikbacker/2864711#file-addeventlistener-polyfill-js)# Dev setup- `npm install` the dependencies.- `gulp watch` during development- `npm test` or `npm run test-watch` to run the unit tests#License##MIT licensedPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
     
   } ,
  
   {
     
   } ,
  
   {
     
   } 
  
]

If search isn’t working due to invalid JSON

  • There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use remove_chars as a filter.

For example: in search.json, replace

"content"  : "Simple-Jekyll-Search====================[![Build Status](https://travis-ci.org/christian-fei/Simple-Jekyll-Search.svg?branch=master)](https://travis-ci.org/christian-fei/Simple-Jekyll-Search)A JavaScript library to add search functionality to any Jekyll blog.---idea from this [blog post](https://alexpearce.me/2012/04/simple-jekyll-searching/#disqus_thread)---### Promotion: check out [Pomodoro.cc](https://pomodoro.cc/)# [Demo](http://christian-fei.github.io/Simple-Jekyll-Search/)# Getting started- Place the following code in a file called `search.json` in the **root** of your Jekyll blog. This file will be used as a small data source to perform the searches on the client side:```------[  {% for post in site.posts %}    {      "title"    : "{{ post.title | escape }}",      "category" : "{{ post.category }}",      "tags"     : "{{ post.tags | join: ', ' }}",      "url"      : "{{ site.baseurl }}{{ post.url }}",      "date"     : "{{ post.date }}"    } {% unless forloop.last %},{% endunless %}  {% endfor %}]```- configure the library ( [options](#options) )### Enabling full-text searchNote that the index generated in `search.json` does not include the posts' content since you may not want to load the whole content of your blog in each single page. However, if some of you want to enable full-text search, you can still add the posts' content to the index, either to the normal search, or on an additional search page with a dedicated second index file. To do this, simply add```"content"  : "{{ post.content | strip_html | strip_newlines }}"```to `search.json` after the `"date"` line to which you must add a comma (`,`).# Install with bower```bower install simple-jekyll-search```# SetupYou need to place the following code within the layout where you want the search to appear.For example in  **_layouts/default.html**:``````# OptionsCustomize SimpleJekyllSearch by passing in your configuration options:```SimpleJekyllSearch({  searchInput: document.getElementById('search-input'),  resultsContainer: document.getElementById('results-container'),  json: '/search.json',})```The above initialization needs to occur after the inclusion of `jekyll-search.js`.### searchInput (Element) [required]The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.### resultsContainer (Element) [required]The container element in which the search results should be rendered in. Typically an ``.### json (String|JSON) [required]You can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data.### searchResultTemplateThe template of a single rendered search result.The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.E.g.The template```{title}```will render to the following```Welcome to Jekyll!```If the `search.json` contains this data```[    {      "title"    : "Welcome to Jekyll!",      "category" : "",      "tags"     : "",      "url"      : "/jekyll/update/2014/11/01/welcome-to-jekyll.html",      "date"     : "2014-11-01 21:07:22 +0100"    }]```### noResultsTextThe HTML that will be shown if the query didn't match anything.### limitYou can limit the number of posts rendered on the page.### fuzzyEnable fuzzy search to allow less restrictive matching.### excludePass in a list of terms you want to exclude (terms will be matched against a regex, so urls, words are allowed).## Enable full content search of posts and pages- Replace 'search.json' with the following code:```---layout: null---[  {% for post in site.posts %}    {      "title"    : "{{ post.title | escape }}",      "category" : "{{ post.category }}",      "tags"     : "{{ post.tags | join: ', ' }}",      "url"      : "{{ site.baseurl }}{{ post.url }}",      "date"     : "{{ post.date }}",      "content"  : "{{ post.content | strip_html | strip_newlines }}"    } {% unless forloop.last %},{% endunless %}  {% endfor %}  ,  {% for page in site.pages %}   {     {% if page.title != nil %}        "title"    : "{{ page.title | escape }}",        "category" : "{{ page.category }}",        "tags"     : "{{ page.tags | join: ', ' }}",        "url"      : "{{ site.baseurl }}{{ page.url }}",        "date"     : "{{ page.date }}",        "content"  : "{{ page.content | strip_html | strip_newlines }}"     {% endif %}   } {% unless forloop.last %},{% endunless %}  {% endfor %}]```### If search isn't working due to invalid JSON- There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use `remove_chars` as a filter.For example: in search.json, replace```"content"  : "{{ page.content | strip_html | strip_newlines }}"```with```"content"  : "{{ page.content | strip_html | strip_newlines | remove_chars | escape }}"```##Browser supportBrowser support should be about IE6+ with this `addEventListener` [shim](https://gist.github.com/eirikbacker/2864711#file-addeventlistener-polyfill-js)# Dev setup- `npm install` the dependencies.- `gulp watch` during development- `npm test` or `npm run test-watch` to run the unit tests#License##MIT licensedPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."

with

"content"  : "Simple-Jekyll-Search====================[![Build Status](https://travis-ci.org/christian-fei/Simple-Jekyll-Search.svg?branch=master)](https://travis-ci.org/christian-fei/Simple-Jekyll-Search)A JavaScript library to add search functionality to any Jekyll blog.---idea from this [blog post](https://alexpearce.me/2012/04/simple-jekyll-searching/#disqus_thread)---### Promotion: check out [Pomodoro.cc](https://pomodoro.cc/)# [Demo](http://christian-fei.github.io/Simple-Jekyll-Search/)# Getting started- Place the following code in a file called `search.json` in the **root** of your Jekyll blog. This file will be used as a small data source to perform the searches on the client side:```------[  {% for post in site.posts %}    {      &quot;title&quot;    : &quot;{{ post.title | escape }}&quot;,      &quot;category&quot; : &quot;{{ post.category }}&quot;,      &quot;tags&quot;     : &quot;{{ post.tags | join: &#39;, &#39; }}&quot;,      &quot;url&quot;      : &quot;{{ site.baseurl }}{{ post.url }}&quot;,      &quot;date&quot;     : &quot;{{ post.date }}&quot;    } {% unless forloop.last %},{% endunless %}  {% endfor %}]```- configure the library ( [options](#options) )### Enabling full-text searchNote that the index generated in `search.json` does not include the posts&#39; content since you may not want to load the whole content of your blog in each single page. However, if some of you want to enable full-text search, you can still add the posts&#39; content to the index, either to the normal search, or on an additional search page with a dedicated second index file. To do this, simply add```&quot;content&quot;  : &quot;{{ post.content | strip_html | strip_newlines }}&quot;```to `search.json` after the `&quot;date&quot;` line to which you must add a comma (`,`).# Install with bower```bower install simple-jekyll-search```# SetupYou need to place the following code within the layout where you want the search to appear.For example in  **_layouts/default.html**:``````# OptionsCustomize SimpleJekyllSearch by passing in your configuration options:```SimpleJekyllSearch({  searchInput: document.getElementById(&#39;search-input&#39;),  resultsContainer: document.getElementById(&#39;results-container&#39;),  json: &#39;/search.json&#39;,})```The above initialization needs to occur after the inclusion of `jekyll-search.js`.### searchInput (Element) [required]The input element on which the plugin should listen for keyboard event and trigger the searching and rendering for articles.### resultsContainer (Element) [required]The container element in which the search results should be rendered in. Typically an ``.### json (String|JSON) [required]You can either pass in an URL to the `search.json` file, or the results in form of JSON directly, to save one round trip to get the data.### searchResultTemplateThe template of a single rendered search result.The templating syntax is very simple: You just enclose the properties you want to replace with curly braces.E.g.The template```{title}```will render to the following```Welcome to Jekyll!```If the `search.json` contains this data```[    {      &quot;title&quot;    : &quot;Welcome to Jekyll!&quot;,      &quot;category&quot; : &quot;&quot;,      &quot;tags&quot;     : &quot;&quot;,      &quot;url&quot;      : &quot;/jekyll/update/2014/11/01/welcome-to-jekyll.html&quot;,      &quot;date&quot;     : &quot;2014-11-01 21:07:22 +0100&quot;    }]```### noResultsTextThe HTML that will be shown if the query didn&#39;t match anything.### limitYou can limit the number of posts rendered on the page.### fuzzyEnable fuzzy search to allow less restrictive matching.### excludePass in a list of terms you want to exclude (terms will be matched against a regex, so urls, words are allowed).## Enable full content search of posts and pages- Replace &#39;search.json&#39; with the following code:```---layout: null---[  {% for post in site.posts %}    {      &quot;title&quot;    : &quot;{{ post.title | escape }}&quot;,      &quot;category&quot; : &quot;{{ post.category }}&quot;,      &quot;tags&quot;     : &quot;{{ post.tags | join: &#39;, &#39; }}&quot;,      &quot;url&quot;      : &quot;{{ site.baseurl }}{{ post.url }}&quot;,      &quot;date&quot;     : &quot;{{ post.date }}&quot;,      &quot;content&quot;  : &quot;{{ post.content | strip_html | strip_newlines }}&quot;    } {% unless forloop.last %},{% endunless %}  {% endfor %}  ,  {% for page in site.pages %}   {     {% if page.title != nil %}        &quot;title&quot;    : &quot;{{ page.title | escape }}&quot;,        &quot;category&quot; : &quot;{{ page.category }}&quot;,        &quot;tags&quot;     : &quot;{{ page.tags | join: &#39;, &#39; }}&quot;,        &quot;url&quot;      : &quot;{{ site.baseurl }}{{ page.url }}&quot;,        &quot;date&quot;     : &quot;{{ page.date }}&quot;,        &quot;content&quot;  : &quot;{{ page.content | strip_html | strip_newlines }}&quot;     {% endif %}   } {% unless forloop.last %},{% endunless %}  {% endfor %}]```### If search isn&#39;t working due to invalid JSON- There is a filter plugin in the _plugins folder which should remove most characters that cause invalid JSON. To use it, add the simple_search_filter.rb file to your _plugins folder, and use `remove_chars` as a filter.For example: in search.json, replace```&quot;content&quot;  : &quot;{{ page.content | strip_html | strip_newlines }}&quot;```with```&quot;content&quot;  : &quot;{{ page.content | strip_html | strip_newlines | remove_chars | escape }}&quot;```##Browser supportBrowser support should be about IE6+ with this `addEventListener` [shim](https://gist.github.com/eirikbacker/2864711#file-addeventlistener-polyfill-js)# Dev setup- `npm install` the dependencies.- `gulp watch` during development- `npm test` or `npm run test-watch` to run the unit tests#License##MIT licensedPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the &#39;Software&#39;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.THE SOFTWARE IS PROVIDED &#39;AS IS&#39;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."

##Browser support

Browser support should be about IE6+ with this addEventListener shim

Dev setup

  • npm install the dependencies.

  • gulp watch during development

  • npm test or npm run test-watch to run the unit tests

#License ##MIT licensed Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the ‘Software’), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED ‘AS IS’, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.