# Technical documentation — personal_laundry_website

Evidence date: 2026-10-06. Source: `git@bitbucket.org:overdrive/personal_laundry_website.git` at `90e6cd3` (`master`, 2021-03-31).

Secret values are described by location only. They are not copied into this file.

## Architecture

Monolithic WordPress application. PHP renders pages. MySQL stores content. Apache-style rewrite rules live in `.htaccess`. The Wordfence web application firewall is designed to run as a PHP `auto_prepend_file`.

There is no separate API service, queue, or front-end build. Fusion Core and Avada ship their own `package.json` files for the theme vendor's build. This site does not add a Node toolchain.

```text
.htaccess (permalinks, deny wp-config, Options -Indexes)
  .user.ini auto_prepend_file
    wordfence-waf.php
      WordPress bootstrap (wp-config.php -> wp-settings.php)
        Avada child (CSS) -> Avada 4.0.3
        plugins: fusion-core, revslider, contact-form-7, wordpress-seo, wordfence
        MySQL personal_db prefix wp1s_
```

Single site. `wp-config.php` does not define `WP_ALLOW_MULTISITE`, `MULTISITE`, `SUBDOMAIN_INSTALL`, or `DOMAIN_CURRENT_SITE`.

## Repository shape

| Item | Value |
|---|---|
| Remote | `git@bitbucket.org:overdrive/personal_laundry_website.git` |
| Branch | `master` only |
| Tip | `90e6cd3` (full hash `90e6cd30d695169cc30cf07406e43f0f266584e2`) |
| History | 3 commits, all Russel Sauer `russel@overdrive.co.za`, 2021-03-26 to 2021-03-31 |
| Initial tree | 8,946 files |
| Project-authored theme code | `wp-content/themes/Avada-Child-Theme/functions.php` and `style.css` |
| Root gitignore | None |
| CI | No `bitbucket-pipelines.yml` |
| Site tests | None. Avada vendors PHPUnit config inside Redux copies (`wp-content/themes/Avada/phpunit.xml` and Redux `phpunit.xml`). Those are upstream theme tests, not this site's |

The onboarding inventory named `sonar-project.properties` and `sonarqube_scan.bat`. They are not in `90e6cd3`. **Unknown** whether they existed only as untracked files on the scan host.

## Languages and frameworks

| Layer | Version evidence |
|---|---|
| PHP application | WordPress. No `composer.json` at the site root. Avada's bundled Redux has its own `composer.json` |
| WordPress | `$wp_version = '4.7.19'` in `wp-includes/version.php`. Database revision `$wp_db_version = 38590` (4.7 schema). TinyMCE `$tinymce_version = '4506-20170408'` |
| Theme | Avada 4.0.3 (`style.css` header). Child 1.0.0 |
| Plugins | Fusion Core 2.0.3, Slider Revolution 5.2.5, Contact Form 7 4.8, Yoast SEO 4.8, Wordfence 7.5.2 |
| JavaScript | Shipped inside WordPress, Avada, and plugins. No site-level `package.json` |
| CSS | Child theme appends four rules. Avada dynamic CSS is patched in PHP |

No changelog in the repository explains the `4.7.19` string. **Unknown / Requires Confirmation** whether that build is official WordPress or a renamed tree. The database revision and the April 2017 TinyMCE stamp are the stronger schema clues.

## Application structure

Standard WordPress layout:

- `index.php`, `wp-blog-header.php`, `wp-load.php`, `wp-settings.php`, `wp-login.php`, `wp-cron.php`, `wp-mail.php`, `xmlrpc.php`, `wp-signup.php`, `wp-activate.php`, `wp-trackback.php`, `wp-comments-post.php`, `wp-links-opml.php`.
- `wp-admin/` administration.
- `wp-includes/` core libraries.
- `wp-content/themes/Avada/` and `wp-content/themes/Avada-Child-Theme/`.
- `wp-content/plugins/` the five plugins above.
- `wp-content/languages/` `en_GB` catalogues, plus plugin and leftover default-theme catalogues.
- `wp-content/uploads/` media and `avada-styles/avada-global.css`.
- `wp-content/wflogs/` Wordfence state.
- `cgi-bin/php52wrapper.cgi` shell wrapper for `/opt/php52/bin/php-cgi`.
- `license.txt` GNU GPL text shipped with WordPress.
- `readme.4ffec57b37687e87040fe9fdcae8f783.html` stock WordPress readme under a hashed filename. Which tool renamed `readme.html` is **Unknown**.

Child theme `functions.php`:

- `theme_enqueue_styles` hooked to `wp_enqueue_scripts`, enqueue handle `avada-parent-stylesheet`.
- `avada_lang_setup` hooked to `after_setup_theme`, text domain `Avada`, path `get_stylesheet_directory() . '/languages'`. That directory is absent.

Avada `functions.php` registers an autoloader, includes Redux in admin, always includes `multiple_sidebars.php`, `post-link-plus.php`, and multiple featured images, then boots `Avada` and `Avada_Multilingual`.

## Database

From `wp-config.php`:

| Setting | Value |
|---|---|
| `DB_NAME` | `personal_db` |
| `DB_HOST` | `sql47.jnb1.host-h.net` |
| `DB_CHARSET` | `utf8` |
| `DB_COLLATE` | empty |
| `$table_prefix` | `wp1s_` |
| `DB_USER` | Present. The name belongs to the same hosting-account prefix as the QA path `devovvbypb`. The exact username is in `wp-config.php` and is not repeated here |
| `DB_PASSWORD` | Present in Git. Not repeated here |

No dump (`.sql`) is in the repository. Table contents are **Unknown** except for inferences from prefixes and plugins (standard `wp1s_posts`, `wp1s_options`, `wp1s_users`, plus plugin tables created on activation).

`WP_DEBUG` is false. No `WP_CACHE`, `WP_REDIS`, object-cache drop-in, or custom `SUNRISE` constant.

## Authentication

- WordPress cookie authentication. Unique keys and salts are defined in `wp-config.php` (`AUTH_KEY`, `SECURE_AUTH_KEY`, `LOGGED_IN_KEY`, `NONCE_KEY`, and the four matching salts). Values are not copied here.
- Login entry point is core `wp-login.php`.
- No OAuth, SAML, or SSO plugin is present.
- No captcha plugin is present. Contact Form 7 may still have a captcha configured in the database. **Unknown**.
- XML-RPC endpoint `xmlrpc.php` is the stock file. Whether it is blocked at the host is **Unknown**.

## Environment configuration

`wp-config.php` is the environment file, and it is committed. There is no `.env`, no environment split, and no `wp-config-local.php`.

`wp-config-sample.php` is the stock sample and does not contain this site's database name.

`DISALLOW_FILE_EDIT` is defined after `require_once` of `wp-settings.php`. That file returns, so the constant is defined before WordPress finishes the request that included `wp-config.php`. The placement is unusual relative to the WordPress sample, which expects extra constants above the "stop editing" line.

## Hosts recorded in the tree

| Source | Filesystem or host | Notes |
|---|---|---|
| `error_log` | `/home/personallaundryc/public_html/` | cPanel-style. Dates only 14 Mar 2016, 8 Apr 2016, 18 Apr 2016. PHP include path `/opt/alt/php55/` |
| `cgi-bin/php52wrapper.cgi` | `/opt/php52/bin/php-cgi` | Sets `PHP_FCGI_CHILDREN=4`, `PHP_FCGI_MAX_REQUESTS=5000` |
| Wordfence synced config | `/usr/www/users/persotrccj/` | Also server IP `41.203.16.65` and site URL `http://www.personallaundry.co.za` |
| `.user.ini` and `wordfence-waf.php` at `90e6cd3` | `/usr/www/users/devovvbypb/personal_laundry/` | QA, per commit messages |
| `wp-config.php` | `sql47.jnb1.host-h.net` | Database host. Johannesburg host-h.net name. **Inferred** to be xneelo shared hosting |

These cannot all be the current production path. **Unknown / Requires Confirmation** which host serves the public site.

`.user.ini` full behaviour depends on the host allowing per-directory PHP user ini. If it does not, the WAF prepend never runs even when the file is deployed.

## Web server

`.htaccess`:

- `Options -Indexes`.
- `Files wp-config.php` with `order allow,deny` / `deny from all`.
- WordPress permalink block: `RewriteEngine On`, `RewriteBase /`, skip existing files and directories, otherwise `/index.php`.

`wp-content/uploads/.htaccess` is a Wordfence block that turns the PHP engine off for PHP 5 and PHP 7 modules and sets `Options -ExecCGI` after adding a cgi-script handler for a list of extensions.

No nginx config, Docker file, or cloud template is in the repository.

## Background work

- `wp-cron.php` is stock WordPress pseudo-cron, triggered by page views unless the host disables it. No `DISABLE_WP_CRON` or `ALTERNATE_WP_CRON` constant.
- No Action Scheduler, no custom cron event in the child theme, no queue worker.
- Wordfence scan scheduling, if enabled, is stored in the database and in plugin code. The saved schedule is **Unknown**.

## Storage

- Media files are in Git under `wp-content/uploads/`, including generated sizes. About 1,534 files.
- `avada-global.css` is stored as an upload, which is how Avada writes compiled options CSS.
- No S3, CDN, or offload plugin is present. CDN configuration inside Avada options would be in the database. **Unknown**.

## Integrations

| Integration | How it appears | Runtime status |
|---|---|---|
| MySQL on host-h.net | `wp-config.php` | **Unknown** if that server still accepts the committed user |
| Wordfence cloud | API key inside `wp-content/wflogs/config-synced.php`. `isPaid` false. `other_WFNet` true in the serialized config | **Unknown** if the key is still valid |
| Google site verification | Static HTML file at the web root | File present |
| Contact Form 7 mail | PHP `mail` or whatever `wp_mail` is filtered to. No SMTP plugin in `wp-content/plugins/` | **Unknown** |
| Slider Revolution templates | Local `uploads/revslider/templates/` | No evidence of a live ThemePunch subscription |
| Fusion Core updater | The `admin_init` updater action is commented out in `fusion-core.php` | Not hooked |

No analytics, chat, or payment SDK was identified in the child theme. Theme-option header scripts would be invisible here. **Unknown / Requires Confirmation.**

## Security

Implemented controls:

- Wordfence plugin and WAF bootstrap.
- Upload directory PHP execution disabled.
- `wp-config.php` HTTP deny rule.
- `DISALLOW_FILE_EDIT`.
- `WP_DEBUG` false.
- Directory indexes off.

Implemented exposures (values omitted on purpose):

- Database password and WordPress salts are in Git history at `wp-config.php` from the initial commit onward. The QA commits did not remove them.
- Wordfence API key and firewall configuration are in Git at `wp-content/wflogs/config-synced.php` (and related PHP files in that directory).
- `error_log` is committed and records full filesystem paths.
- Stack age: WordPress 4.7-era core, Avada 4.0.3, Slider Revolution 5.2.5, Contact Form 7 4.8, Yoast 4.8, Wordfence 7.5.2. These were already old when the repository was created in 2021. Known-vulnerability status as of 2026 was not re-tested in this documentation pass.
- `xmlrpc.php` is present.
- Local patches edit WordPress core, Avada, and Slider Revolution in place. An update that replaces those files drops the patches.

**Requires Confirmation:** whether the committed password, salts, and Wordfence key have been rotated, and whether `wp-config.php` and `wflogs` should be removed from the tree and from history.

## Local patches

Commit `90e6cd3` (author comments dated 20210329 in the files):

1. `wp-admin/includes/template.php` — `get_settings_errors()` treats an empty `$wp_settings_errors` as "no errors" before calling `count()`.
2. `wp-content/plugins/revslider/includes/framework/base-admin.class.php` — `$arrMetaBoxes` initialised to `array()`; `title` and `location` read only when set.
3. `wp-content/themes/Avada/includes/dynamic_css.php` — parentheses around `intval(side_header_break_point) - 32`.

Earlier commit `2c7e12a` only rewrites the two Wordfence path files.

## Development and testing process

No documented developer workflow. No PHPUnit suite for the site, no linter config at the root, no migration tool, no seed data.

The practical process visible from Git is: copy a live tree into Bitbucket (`315b5fe`), then edit WAF paths and three PHP notices on the QA account (`2c7e12a`, `90e6cd3`).

`error_log` is a captured PHP log, not an application logger. It stops on 18 Apr 2016.

## Monitoring

No application monitoring agent, health endpoint, or uptime config is in the repository. Wordfence is the only security monitor vendored. Whether its alerting email is set is **Unknown** (database and Wordfence account).

## Deployment

No pipeline, git-ftp file, or deploy script is in the repository.

**Inferred** from the QA commits: someone deployed by changing this tree's absolute paths to match a directory on the `devovvbypb` hosting account, subdirectory `personal_laundry`. How files were copied (FTP, git pull, file manager) is **Unknown**.

The permalink `RewriteBase /` does not match a subdirectory install. A subdirectory QA site would also need WordPress `siteurl` / `home` and rewrite base adjusted. Those WordPress options are in the database, not in `wp-config.php` (no `WP_HOME` or `WP_SITEURL` constants). **Requires Confirmation** whether the QA site was actually served from a subfolder.

## Configuration map

| Concern | Where it is | In Git? |
|---|---|---|
| DB host, name, prefix, debug, file editor | `wp-config.php` | Yes, including secrets |
| WAF path | `.user.ini`, `wordfence-waf.php` | Yes, QA path |
| Permalinks | `.htaccess` | Yes |
| Theme choice, plugins active, pages, menus, forms, Yoast, Avada options | MySQL `wp1s_*` | No |
| Compiled Avada CSS | `wp-content/uploads/avada-styles/avada-global.css` | Yes, one snapshot |
| Firewall learned config | `wp-content/wflogs/` | Yes, including secrets |
