WonderCMS - MIT license: wondercms.com/license
WonderCMS repository  https://github.com/robiso/wondercms/wiki
WonderCMS community  https://wondercms.com/forum/
WonderCMS docs  https://github.com/robiso/wondercms/wiki
WonderCMS themes repository  https://github.com/robiso/wondercms-themes
### How to restore a backup in 3 steps
NOTE: This step requires logging into your hosting control panel.
On your computer, unzip the backup you have downloaded through WonderCMS (Security -> Backup).
Log into your hosting provider's file manager (cPanel/FTP/DirectAdmin/admin panel, ...) with login information as provided by your hosting provider.
Upload and overwrite all files from the unzipped backup folder (from your computer) to your hosting provider.

If any errors occur after restoring a backup
set 755 permissions to all folders
set 644 permissions to all files
J:\awww\apl\dev1\fwphp\glomodul\acms\adm\index.php
J:\awww\apl\dev1\zz\mkd\wondercms\index.php ~830 lines
http://sspc1:8083/fwphp/glomodul/acms/adm/php
https://github.com/robiso/wondercms/wiki/Restore-backup#how-to-restore-a-backup-in-3-steps


### Libraries used (6)
Libraries are loaded from Content Delivery Networks (CDNs) and include SRI tags.
3 libraries located in theme.php, always included: 
jquery.min.js (1.12.4), bootstrap.min.js (3.3.7), bootstrap.min.css (3.3.7).
3 libraries located in index.php, included only when logged in: 
autosize.min.js (4.0.0), taboverride.min.js (4.0.3), jquery.taboverride.min.js (4.0.0)

## Security features
1. **Track free**, WonderCMS doesn't track users or store any **cookies**. Your WonderCMS installation is completely detached from WonderCMS **servers**. The one click updates are pushed from GitHub.
1. Supports **HTTPS** out of the box. 
1. See below how to enable a **permanent redirect** on Apache or NGINX.
1. All CSS and JS libraries include **SubResource Integrity (SRI) tags**. This prevents any changes to the libraries being loaded. If any changes are made, the libraries won't load for your and your visitors protection. See below how to add SRI tags to your custom theme. This step isn't necessary if you're using a theme from the official website.
1. WonderCMS encourages you to **change your default login URL. Consider the custom login URL as your private username.** Choosing a good login URL can prevent brute force attacks. Why changing the default login URL is important :
   Changing your default login URL gives attackers less chances at using the brute force attack against your website.
NOTE 1: The login URL is case sensitive.
NOTE 2: Once the default login URL is changed, WonderCMS automatically hides the login link from the footer. This is why it's important that you bookmark your new login URL.
Change default login URL
    1. Login to your WonderCMS website.  
    1. Open the settings panel, Find the login URL field. Change it to anything else.  
    1. Bookmark your new login URL.   
1. WonderCMS returns 404 status on the login page, so search engines shouldn't visit/cache login URL.
1. The** admin password is hashed using PHP's password_hash and password_verify functions**. Even if an attacker guesses your login URL (which should be difficult if you've chosen a good login URL), choosing a strong password prevents them from gaining admin privileges.
1. WonderCMS includes **CSRF verification tokens** for action verification's. It additionally uses the **hash_equals function to prevent CSRF token timing attacks**.
1. Transparent: downloads/updates are sent through GitHub (and not WonderCMS) servers.
1. No known vulnerabilities. 
1. Special thanks to yassineaddi, hypnito and other security researchers.

### Other features
no configuration required, unzip and upload
simple inline click and edit functionality
theme and plugin installer/updater
1 click update and backup
easy to theme
file uploader
lightweight
responsive
clean URLs
custom homepage
menu reordering and visibility 
hiding a page from the menu doesn't hide the page for search engines
highlighted current page in menu
custom 404 page
basic SEO support 
custom title, keywords and description for each page
[optional] functions.php file for loading your custom code 
includes itself when you create it
the location of functions.php file should be inside the current active theme folder (same location as theme.php)

### SRI (Subresource Integrity) - 3 steps for more security
If you're using the default theme, there's no need to make any changes.
In your theme.php, make the following changes (for custom themes)

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
replace the above line with:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ=" crossorigin="anonymous"></script>
replace the above line with:
<script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>

<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
replace the above line with:
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

## .htaccess file on your server

Options -Indexes
ServerSignature Off
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [QSA,L]
RewriteRule database.js - [F]

After applying either of these fixes, all URLs should be working properly.


Why is .htaccess necessary?

.htaccess is a server file that servers multiple purposes:

Prevents access to database.js.
Creates clean URLS. 
example.com/index.php?page=home becomes example.com/home 
Disables server signature.
Disables directory and files listing.


https://github.com/robiso/wondercms/wiki/Always-redirect-to-https-and-www

### Apache

Always redirect to https://www. Copy and paste the code below into your .htaccess file, paste it under the RewriteEngine on 

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Your .htaccess file should look like this

Options -Indexes
ServerSignature Off
RewriteEngine on

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [QSA,L]
RewriteRule database.js - [F]

Your website should now always redirect to https://www.example.com.


Recommended: even more security!

In addition to the above, paste this at the bottom of your .htaccess file

Header always edit Set-Cookie (.*) "$1; HTTPOnly"
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Content-Type-Options: nosniff
Header always append X-Frame-Options SAMEORIGIN
Header set Referrer-Policy: strict-origin-when-cross-origin


THE (final) ULTIMATE htaccess settings

IMPORTANT: please contact your host and make sure your website supports https or the below htaccess MAY BREAK YOUR WEBSITE. Always backup!

Works best if WonderCMS is installed at the root of your website (not in a subfolder).
The .htaccess file with ALL of the above changes included should look like:

Header set Strict-Transport-Security "max-age=31536000" env=HTTPS
Header set Cache-Control "max-age=2628000, public"

Options -Indexes
ServerSignature Off
RewriteEngine on

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?page=$1 [QSA,L]
RewriteRule database.js - [F]

Header always edit Set-Cookie (.*) "$1; HTTPOnly"
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Content-Type-Options: nosniff
Header always append X-Frame-Options SAMEORIGIN
Header set Referrer-Policy: strict-origin-when-cross-origin

Explanation of what the above .htaccess does

turns off directory listing // included in WonderCMS by default Options -Indexes
turns off server signature // included by default ServerSignature Off
denies access to database.js // included by default RewriteRule database.js - [F]
creates clean URLs (example.com/?page=home TO example.com/home) // included by default RewriteEngine on

always redirect to https:// and www on your website
a stricter cookie policy,
additional XSS protection for when the user has it turned off by default (server side),
MIME type sniffing prevention,
iframes to be allowed only from the same origin and a
stricter referrer policy
30 day cache policy

> Note 1: Make sure you have a valid certificate to avoid any errors. You can check this with your hosting provider to really make sure you can use HTTPS correctly.


### NGINX
Check the official nginx website for instructions on enabling https.


## List of hooks
### Creating a plugin is easy
Each plugin has to be in it's own folder (example.com/plugins/pluginFolderName/).
Each plugin can have unlimited number of files.
WonderCMS will automatically include your plugin and plugin files.
### List of available hooks/listeners
Listeners are used for attaching your functions to different parts of WonderCMS.
These hooks can be used inside your plugin PHP files (example.com/plugins/pluginFolderName/myPluginFileName.php).
 wCMS::addListener('page', 'yourFunctionName'); // attach your function to the page
 wCMS::addListener('js', 'yourFunctionName'); // can be used for additional JavaScript
 wCMS::addListener('css', 'yourFunctionName'); // can be used for additional CSS
 wCMS::addListener('settings', 'yourFunctionName');
 wCMS::addListener('menu', 'yourFunctionName');
 wCMS::addListener('getMenuSettings', 'yourFunctionName');
 wCMS::addListener('footer', 'yourFunctionName');
### Simple plugin example: [hits counter plugin](https://github.com/robiso/wondercms-plugins/blob/master/plugins/hits-counter/hits-counter.php) 
    <?php
    /**
     * Hits counter.
     *
     * Simple hits/visits counter. Hits are displayed in the footer once the admin is logged in.
     * Hits will not be incremented if admin is logged in.
     *
     * @author Yassine Addi <yassineaddi.dev@gmail.com> // edit by robiso
     * @version 2.4 // edit by robiso
     */
    if (defined('VERSION') && !defined('version')) {
      define('version', VERSION);
    }

    wCMS::addListener('menu', 'incrementHits');
    wCMS::addListener('footer', 'displayHits');

    function incrementHits ($args) {
      if (wCMS::$loggedIn) return $args;
      $hits = file_exists(__DIR__ . '/hits.txt') ? (int) file_get_contents(__DIR__ . '/hits.txt') : 0;
      if ( ! isset($_SESSION['_wcms_hits_counter'])) {
        $_SESSION['_wcms_hits_counter'] = time();
        $hits++;
      }
      if ((time()-$_SESSION['_wcms_hits_counter'])>600)
        $hits++;
      $_SESSION['_wcms_hits_counter'] = time();
      file_put_contents(__DIR__ . '/hits.txt', $hits);
      return $args;
    }

    function displayHits ($args) {
      if ( ! wCMS::$loggedIn) return $args;
      $hits = file_exists(__DIR__ . '/hits.txt') ? (int) file_get_contents(__DIR__ . '/hits.txt') : 0;
      $args[0] .= ' • Hits: ' . $hits;
      return $args;
    }
    

### How do I make my plugin downloadable by others?
Create a ZIP file of your plugin folder. If your plugin folder is "myAwesomePlugin", create a ZIP file of the "myAwesomePlugin" folder.
Upload ZIP file to GitHub (as a release file).
Anyone with your ZIP link will be able to install your plugin through the WonderCMS Settings panel.

