What PrizeX is
PrizeX is a PHP-based prize, gaming, and marketplace platform: auctions, lottery, mystery boxes, an arcade game cluster, a multivendor e-commerce shop, and a wallet/coin economy — all in one self-hosted application. It ships as a plugin/theme architecture with an admin panel and 38 payment gateway plugins covering cards, wallets, crypto, and regional processors, plus 3 kernel-seeded manual payment methods.
There is no SaaS lock-in: you install it on your own hosting, own the database, and get lifetime updates on the license. Every vertical (auctions, lottery, mystery boxes, games, shop) can be switched on or off independently from the admin panel — a fresh install can run as a single-vertical product or the full suite.
Core code never hard-depends on a plugin. Every vertical, payment gateway, and social login is a plugin under plugins/ that can be activated, deactivated, or deleted without breaking the rest of the site.
Table prefix tbl_, no ORM, mostly prepared statements. Each plugin owns and migrates its own tables via an idempotent db_delta() installer.
What it runs on
PrizeX runs on standard shared hosting or a VPS — no special server configuration beyond a rewrite-capable web server.
* Several files under database/migrations/ use the MariaDB-only ADD COLUMN IF NOT EXISTS extension. Plain MySQL 8.0/8.4 rejects it — use MariaDB for the database, both in development and production.
Getting a fresh install running
There is no install wizard for a fresh setup — you import the schema directly and configure the environment file.
- Install PHP dependencies:
composer install - Copy the environment template and fill in your database credentials:
cp .env.example .env - Import
database/production.sqlinto the database named in your.env— this creates the full schema. - Replace the seeded admin account (see callout below), then log in at
/admin/.
database/production.sql ships a tbl_admin row (admin@wowcodes.in) whose password hash is identical on every install. Delete it and insert your own before going live:
php -r "echo password_hash('your-password', PASSWORD_BCRYPT), \"\n\";"DELETE FROM tbl_admin;
INSERT INTO tbl_admin (username, email, password, image, status, permission_settings)
VALUES ('yourname', 'you@example.com', '<hash from the command above>', '', 1, 1);For local development, the built-in PHP server works without Apache: php -S localhost:8000 router.php — note that this server ignores .htaccess entirely, so router.php re-implements the same routing rules by hand (see Web server setup).
Environment variables
All environment-specific settings live in .env, loaded via vlucas/phpdotenv. Copy .env.example to .env (git-ignored) and set real values per environment — database credentials, at minimum, before the schema import.
Site-wide settings that aren't environment-specific (app name, currency, active plugins, active theme, and per-vertical toggles) live in the database, in tbl_settings, and are managed from the admin panel rather than in files.
Web server setup
Routing and security rules — pretty URLs, blocking direct access to .env/connection.php/logs, and preventing uploaded content from executing as PHP — are defined in .htaccess files throughout the project. Apache and LiteSpeed/OpenLiteSpeed read these natively.
On nginx, use nginx.conf.example, which mirrors every one of those rules as an nginx server{} block — adjust server_name, root, and the PHP-FPM socket for your environment.
.htaccess (production), router.php (local php -S dev server), and nginx.conf.example (nginx) each re-implement the same routing rules independently. Adding a new pretty-URL route means updating all three.
Request architecture
Every storefront page (index.php, item.php, …) boots through includes/header.php, in this order:
connection.php starts the session, connects via mysqli using the .env credentials, loads tbl_settings into constants like APP_NAME and CURRENCY, and logs in the current user plus a device-fingerprint row. plugins_load() boots every active plugin and fires the plugins_loaded hook — this is the point at which the real, current set of active verticals becomes known, which is why header.php re-checks the legacy settings flags (shop, multivendor, auction, lottery) against actual plugin-active state afterward.
The admin panel doesn't duplicate this bootstrap — admin/includes/connection.php sets admin-specific session/error config and then includes the same root includes/connection.php.
Plugin system
A plugin is plugins/<slug>/plugin.php — header-comment metadata that's parsed without executing the file — plus an optional plugin.json for richer catalog info. Active plugins are stored as a JSON array in tbl_settings.active_plugins.
- Table ownership — each plugin defines its own
includes/schema.php, called on activation, using an idempotentdb_delta()helper (CREATE TABLE IF NOT EXISTS+ additive-onlyALTER TABLE ADD COLUMN). A plugin never touches another plugin's tables. - Registries load first —
add_admin_page,add_route,add_cron_job,add_api_route, andregister_moduleare all defined before any plugin loads, so a plugin's top-level calls never fatal even if the plugin ends up inactive. - Clean removal — deleting a plugin runs its
uninstall.phpand removes its folder; nothing outsideplugins/<slug>/should hard-require its files, so the rest of the site keeps working with the plugin gone.
Theme system
A theme lives at assets/themes/<slug>/ — a manifest.php, theme.css, functions.php for theme hooks, and optional components/. The active theme is stored in tbl_settings.active_theme, with editorial as the fallback if none is set.
Component resolution checks, in order: the active theme's own components/ folder, then a plugin's register_module()-declared components directory, then the shared root components/. In practice this means the shared default lives once in components/, and any theme — or active vertical plugin — can override a specific component path with its own copy.
Database
Table prefix tbl_, raw mysqli, mostly prepared statements. SQL files, in order of authority:
database/core-schema.sql— hand-maintained kernel tables only; vertical/plugin tables are deliberately excluded.database/production.sql— generated (core schema + every plugin's own install routine, dumped from a scratch database). This is what you import for a fresh install.database/sandbox.sql— demo/seed dataset for local development.database/migration.sql— consolidated, idempotent upgrade script for existing installs.database/migrations/<slug>/up.sql(+down.sqlwhere reversible) — one file per individual migration.
Modules
Every module ships in the same installation and is independently toggled from the admin panel.
Auctions
Live bidding with a multivendor seller portal and commission engine. Core plugin: plugins/auction.
Lottery
Ticketed draws with configurable schedules, prizes, and winner notifications. Core plugin: plugins/lottery.
Mystery box
Configurable prize pools with reveal animations — users buy a box and instantly see what they've won. Plugin: plugins/mystery-box.
Games & rewards
An arcade cluster under games/ plus engagement/earn plugins:
Shop & marketplace
A multivendor e-commerce layer with promotions and merchandising tooling. Core plugins: plugins/shop, plugins/multivendor.
Wallet, coins & investing
A platform-wide wallet shared across every module.
Referrals & rewards
Auth, trust & compliance
Utilities
Admin panel
The admin panel lives under admin/ and doesn't duplicate the storefront bootstrap — it sets admin-specific session/error config, then includes the same root includes/connection.php. Pages register through add_admin_page(), which handles the sidebar entry, capability gating, CSRF, and auth chrome; admin-only JSON actions register through add_admin_ajax() and dispatch via admin/ajax.php?action=<slug>.
Items, banners, pages, menus, blog.
Automatic & manual gateway management, manual payment review, payout exports.
User groups, roles, seller details, impersonation.
Transaction/order/user exports, cron logs, error tracking, admin activity logs.
Email campaigns, templates, newsletters, push notifications, notification log.
Activate/deactivate plugins and themes, per-page SEO settings, site-wide settings.
Storefront themes
Five themes ship under assets/themes/, switchable per install from the admin panel. Each theme keeps its own copy of shared components under its own components/ folder.
A simple, modern look with white cards and soft shadows — a safe, versatile choice for almost any kind of shop.
A clean, magazine-style look with warm paper tones and crisp typography, for a polished, trustworthy storefront.
Default fallback themeA bold, luxurious dark theme with gold accents — designed to feel exciting and high-end.
A warm, richly decorated look inspired by traditional marketplaces, with right-to-left language support.
A spooky, festive seasonal look — deep purple backdrops with glowing pumpkin-orange highlights.
Payment gateways
38 automatic gateways are plugin-owned — each lives in its own plugins/gateway-<slug>/ folder and registers itself with the kernel via add_payment_gateway(). Activating one just works; nothing in the checkout dispatcher (payment_processor.php) is hardcoded to a specific gateway.
The 3 manual methods are kernel-seeded, gateway_type = 'manual' rows with no init/verify code to configure — they just display payment instructions or a QR code. The manual-gateway-builder plugin lets an admin add further custom manual payment methods without touching code.
Some gateways (Stripe, Razorpay, Midtrans, Venmo) also register a render hook for checkout flows that need client-side JS — a Stripe Checkout bootstrap, or a Razorpay/Midtrans/Braintree SDK that needs an order ID or token minted server-side first. Every other gateway works with no extra kernel wiring at all.
API & AJAX layers
api/v1/— JWT-authenticated REST API for the mobile app and external consumers.api/v1/middleware/*.phpvalidates theAuthorization: Bearer <token>header. Plugins add their own endpoints viaadd_api_route().ajax/— session-cookie-authenticated internal AJAX for the storefront's own JS (cart, coupons, notifications). No token layer — it relies on the PHP session set up byconnection.php.- Loose top-level
api/— misc non-versioned endpoints such asgeo_location.php,exchange-rate.php, andofferwall_postback.php.
Mobile app
mobile/ is a separate Capacitor + Ionic project — a WebView wrapper around the live site, not a standalone SPA and not solely an api/v1 consumer. Its capacitor.config.ts points server.url at your domain. It has its own package.json and isn't built from the project root:
cd mobile
npm run sync
npm run open:ios
npm run open:androidUpdating & migrations
Take a snapshot before running database/migration.sql or any database/migrations/<slug>/up.sql against a live database:
mysqldump --single-transaction -u<user> -p<pass> <db> > pre-deploy-$(date +%Y%m%d-%H%M%S).sqlMost migrations ship a matching down.sql to reverse just that one change. A few that transform existing data rather than only adding structure ship a down.sql that documents why it's a no-op instead — for those, restore from the pre-deploy dump if you need to roll back.
Security notes
- Rotate the seeded admin credentials immediately after import (see Installation).
.env,connection.php, and log files are blocked from direct HTTP access by the shipped.htaccess/ nginx rules — don't remove those rules.- Uploaded content is served in a way that prevents it from executing as PHP, enforced at the web-server config level, not the application level.
- Payment gateway credentials are configured per-gateway from the admin panel and stored server-side — never exposed to the storefront.
Testing
There is no PHPUnit suite. composer test runs bin/run-probes.php, which aggregates every probe_*.php file under includes/_probes/ and each plugin's own _probes/ folder, running each as a CLI subprocess and checking its exit code.
composer test # run every probe
php plugins/<slug>/_probes/probe_*.php # run a single probe directly
php bin/run-probes.php --all # also run destructive probes (skipped by default)Frequently asked questions
Support & resources
Still stuck, or need something this page doesn't cover?