https://github.com/j7-dev/wp-power-course
https://github.com/j7-dev/wp-power-course
Last synced: 3 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/j7-dev/wp-power-course
- Owner: j7-dev
- License: gpl-2.0
- Created: 2024-04-15T02:09:17.000Z (about 2 years ago)
- Default Branch: master
- Last Pushed: 2025-11-20T03:34:03.000Z (7 months ago)
- Last Synced: 2025-11-20T05:26:17.466Z (7 months ago)
- Language: PHP
- Size: 7.47 MB
- Stars: 4
- Watchers: 1
- Forks: 3
- Open Issues: 21
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Power Course — WordPress LMS Plugin
[繁體中文](./README.zh-TW.md) | English
[](https://github.com/j7-dev/wp-power-course/releases)
[](https://www.php.net/)
[](https://wordpress.org/)
[](https://woocommerce.com/)
[](./LICENSE)
> A full-featured LMS plugin for WordPress + WooCommerce — sell and manage online courses with a modern React admin interface.
---
## Overview
Power Course transforms WooCommerce products into online courses with hierarchical chapters, video streaming, progress tracking, and automated email workflows — all managed through a React SPA admin dashboard backed by a RESTful API.
---
## Features
### Course Management
- Create, update, delete, and duplicate courses
- Courses are built on WooCommerce products — pricing, stock, and checkout flow are handled natively
- Filter and search course listings
- Set course visibility and launch schedule (scheduled start date triggers automatic notifications)
### Chapter Management
- Hierarchical chapter / unit structure with unlimited nesting
- Drag-and-drop reordering (sort chapters via API)
- Upload and delete subtitle files (`.srt`) per chapter
- Per-chapter completion toggle tracked per student
### Student Management
- Enroll students into a course manually or in bulk (CSV import)
- Remove student course access
- Update individual student expiry dates
- View student list with search and pagination
- Export student list to CSV
- View per-student activity logs (chapter visits, completions, access events)
### Progress Tracking
- Toggle chapter completion status per student
- Course progress calculated as a percentage (0–100%) based on completed chapters
- Triggers `power_course_course_finished` action when 100% is reached
### Access Control
| Type | Description |
|------|-------------|
| Unlimited | No expiry |
| Fixed duration | N days from enrollment |
| Specific date | Access until a set date |
| Subscription | Follows WooCommerce Subscription lifecycle |
### Bundle Products (Sales Plans)
- Group multiple products into a bundle that grants access to linked courses on purchase
- Display bundle item quantities in the product listing
- Bundles cannot contain other bundles
### Automated Email (PowerEmail)
- Drag-and-drop MJML-based email builder
- 5 trigger events:
| Trigger | When Fired |
|---------|-----------|
| `course_granted` | Student gains course access |
| `course_finish` | Student reaches 100% completion |
| `course_launch` | Scheduled course launch date is reached |
| `chapter_enter` | Student first enters a chapter |
| `chapter_finish` | Student marks a chapter as complete |
- Variable replacement: `{user.display_name}`, `{user.email}`, `{course.title}`, `{chapter.title}`, and more
- Create, update, and delete email templates
- Automatic email send history stored in database
### WooCommerce Integration
- Auto-activate course access when an order reaches the configured status (default: `completed`)
- Prevent guest checkout for course products
- Bind multiple courses to a single WooCommerce product
- Scheduled course start notifications dispatched via Action Scheduler
### Teacher Management
- Assign one or more instructors to a course
- Dedicated teacher management interface in the admin panel
### Analytics & Reports
- Revenue reports per course / date range
- Course completion rate statistics
- Student activity log with filterable event types
### Media & Watermarking
- Upload media files (video, images, PDFs) through the admin
- Dynamic video watermark overlay (user info — display name, email, etc.)
- PDF watermark support
- Configurable watermark count and template text
### Video Playback
- **Bunny Stream** (HLS adaptive streaming) — primary CDN
- **YouTube** embed
- **Vimeo** embed
- Custom embed code support
- Sticky video player and tab navigation on mobile
### Subtitles
- Upload `.srt` subtitle files per chapter
- Delete subtitles
- Default empty subtitle option (no subtitle selected by default)
---
## Requirements
| Dependency | Minimum Version | Source |
|-----------|----------------|--------|
| WordPress | 5.7 | [wordpress.org](https://wordpress.org/) |
| PHP | 8.0 | |
| WooCommerce | 7.6.0 | [wordpress.org/plugins/woocommerce](https://wordpress.org/plugins/woocommerce/) |
| [Powerhouse](https://github.com/j7-dev/wp-powerhouse) | 3.3.41 | GitHub |
**Optional:**
- WooCommerce Subscriptions — required for subscription-based access control
---
## Installation
### Production
1. Download the latest `.zip` from [GitHub Releases](https://github.com/j7-dev/wp-power-course/releases)
2. In WordPress Admin go to **Plugins → Add New → Upload Plugin**
3. Install and activate **WooCommerce** and **Powerhouse** first
4. Install and activate **Power Course**
5. The plugin automatically creates 4 required database tables on activation
### Development
```bash
# PHP dependencies
composer install
# JS dependencies
pnpm install
# Start Vite dev server (port 5174)
pnpm run dev
# Production build
pnpm run build
```
---
## Architecture
### Tech Stack
| Layer | Technology |
|-------|-----------|
| Backend language | PHP 8.0+, `declare(strict_types=1)` |
| Backend framework | WordPress, WooCommerce 7.6.0+, Powerhouse 3.3.41+ |
| PHP namespace | `J7\PowerCourse` (PSR-4: `inc/classes/`, `inc/src/`) |
| Frontend language | TypeScript 5.5 (strict mode) |
| Frontend framework | React 18, Refine.dev 4.x, Ant Design 5.x |
| State management | Jotai (UI state), TanStack Query 4.x (server state) |
| Build tool | Vite + @kucrut/vite-for-wp |
| Video player | VidStack, hls.js, Bunny CDN |
| Email editor | j7-easy-email (MJML-based) |
| Testing | Playwright E2E, PHPUnit |
| PHP quality | PHPCS (WordPress standards) + PHPStan level 9 |
| TS quality | ESLint + Prettier |
### Directory Structure
```
power-course/
├── plugin.php # Plugin entry point (Singleton)
├── inc/ # PHP backend
│ ├── classes/ # PSR-4 autoload
│ │ ├── Api/ # REST API endpoints
│ │ ├── Resources/ # Domain resources (Course, Chapter, Student…)
│ │ ├── BundleProduct/ # Bundle / sales plan logic
│ │ ├── PowerEmail/ # Automated email subsystem
│ │ └── Utils/ # Utility classes
│ ├── src/Domain/ # DDD-style: Product Events
│ └── templates/ # PHP frontend templates
├── js/src/ # React admin SPA
│ ├── pages/admin/ # Admin pages (lazy-loaded)
│ ├── components/ # Reusable components
│ ├── hooks/ # Custom React hooks
│ ├── resources/ # Refine.dev resource definitions
│ └── types/ # TypeScript type definitions
├── tests/e2e/ # Playwright E2E tests
└── specs/ # Business specification documents
```
### Custom Database Tables
| Table | Purpose |
|-------|---------|
| `{prefix}_pc_avl_coursemeta` | User ↔ Course metadata (expiry, progress) |
| `{prefix}_pc_avl_chaptermeta` | User ↔ Chapter progress |
| `{prefix}_pc_email_records` | Automated email send history |
| `{prefix}_pc_student_logs` | Student activity audit trail |
### Custom Post Type
| CPT | Slug | Description |
|-----|------|-------------|
| `pc_chapter` | `classroom` | Course chapters (hierarchical) |
---
## REST API
Base URL: `{site_url}/wp-json/power-course/v2/`
| Endpoint | Methods | Description |
|----------|---------|-------------|
| `courses` | GET, POST, DELETE | List / create / bulk-delete courses |
| `courses/{id}` | GET, POST, DELETE | Get / update / delete a course |
| `courses/add-students` | POST | Enroll students into a course |
| `courses/remove-students` | POST | Revoke student course access |
| `courses/update-students` | POST | Update student expiry dates |
| `courses/student-logs` | GET | Student activity logs |
| `chapters` | GET, POST, DELETE | List / create / bulk-delete chapters |
| `chapters/{id}` | POST | Update a chapter |
| `chapters/sort` | POST | Reorder chapters |
| `chapters/{id}/subtitles` | POST, DELETE | Upload / delete subtitle file |
| `toggle-finish-chapters/{id}` | POST | Toggle chapter completion |
| `products` | GET | List WooCommerce products |
| `bundle-products` | GET, POST | Manage bundle products |
| `teachers` | GET, POST | Manage teacher assignments |
| `options` | GET, POST | Plugin settings |
| `reports/revenue` | GET | Revenue analytics |
| `comments` | GET, POST | Chapter comments |
| `media` | POST | Upload media files |
Full OpenAPI 3.0.3 specification: [`specs/api/api.yml`](./specs/api/api.yml)
---
## WordPress Hooks
### Actions
```php
// After course access is granted to a student
add_action(
'power_course_after_add_student_to_course',
function( int $user_id, int $course_id, int|string $expire_date, ?\WC_Order $order ) {
// send custom notification, award points, etc.
},
10, 4
);
// When a student reaches 100% course completion
add_action(
'power_course_course_finished',
function( int $course_id, int $user_id ) {
// issue certificate, etc.
},
10, 2
);
// Before course / chapter meta is saved via REST API
add_action(
'power_course_before_update_product_meta',
function( \WC_Product $product, array $meta_data ) {
// validate or modify meta data before save
},
10, 2
);
```
### Granting Course Access Programmatically
```php
use J7\PowerCourse\Resources\Course\LifeCycle;
// Always dispatch the action — never call the underlying function directly
do_action(
LifeCycle::ADD_STUDENT_TO_COURSE_ACTION,
$user_id, // int — WordPress user ID
$course_id, // int — WooCommerce product ID
$expire_date, // 0 = unlimited | Unix timestamp | 'subscription_123'
$order // \WC_Order|null
);
```
### Utility Functions
```php
use J7\PowerCourse\Utils\Course as CourseUtils;
CourseUtils::is_course_product( $product ); // bool — is this a course?
CourseUtils::is_avl( $course_id, $user_id ); // bool — does user have access?
CourseUtils::is_course_ready( $product ); // bool — has it launched?
CourseUtils::is_expired( $product, $user_id ); // bool — has access expired?
CourseUtils::get_course_progress( $product, $user_id ); // float 0–100
```
---
## Plugin Settings
Configure at **Power Course → Settings** or via `POST /wp-json/power-course/v2/options`.
| Setting | Default | Description |
|---------|---------|-------------|
| `course_access_trigger` | `completed` | WC order status that grants access |
| `hide_myaccount_courses` | `no` | Hide courses tab in WC My Account |
| `fix_video_and_tabs_mobile` | `no` | Enable sticky video / tabs on mobile |
| `pc_watermark_qty` | `0` | Video watermark count (0 = disabled) |
| `pc_watermark_text` | `用戶 {display_name}...` | Watermark label template |
| `pc_pdf_watermark_qty` | `0` | PDF watermark count |
| `hide_courses_in_main_query` | `no` | Exclude courses from main WP query |
**Bunny Stream CDN** credentials (library ID, CDN hostname, API key) are configured in **Powerhouse → Settings**, not Power Course.
---
## Development
### Commands
```bash
# Development
pnpm run dev # Vite dev server (http://localhost:5174)
pnpm run build # Production JS build
pnpm run build:wp # WordPress-optimized build
# Quality checks
pnpm run lint:php # PHPCS + PHPStan
pnpm run lint:ts # ESLint
pnpm run format # Prettier-ESLint format
composer run phpstan # PHPStan static analysis (level 9)
# Testing
composer run test # PHPUnit
pnpm run test:e2e # All Playwright E2E tests
pnpm run test:e2e:admin # Admin-side E2E
pnpm run test:e2e:frontend # Frontend E2E
pnpm run test:e2e:integration # Integration E2E
# Release
pnpm run release # Bump patch version + build + release
pnpm run release:minor # Bump minor version
pnpm run release:major # Bump major version
pnpm run zip # Create distributable plugin zip
pnpm run sync:version # Sync version: package.json → plugin.php
```
### Code Standards
- **PHP**: WordPress Coding Standards (WPCS), PHPStan level 9 (`phpstan.neon`)
- **TypeScript**: ESLint with strict mode
- **Formatting**: Prettier (tabs, single quotes, no semicolons)
- **Commits**: Conventional Commits (`feat:`, `fix:`, `chore:`, etc.)
---
## Contributing
1. Fork the repository
2. Create a feature branch: `git checkout -b feat/my-feature`
3. Follow the coding standards above
4. Ensure all tests pass: `pnpm run test:e2e` and `composer run test`
5. Open a Pull Request against `master`
---
## License
GPL v2 or later — see [LICENSE](./LICENSE) for details.
---
## Links
- [GitHub Repository](https://github.com/j7-dev/wp-power-course)
- [Author](https://github.com/j7-dev)
- [Powerhouse Plugin](https://github.com/j7-dev/wp-powerhouse)
- [API Specification](./specs/api/api.yml)
- [WordPress Developer Reference](https://developer.wordpress.org/reference/)
- [WooCommerce Code Reference](https://woocommerce.github.io/code-reference/)
- [Refine.dev Documentation](https://refine.dev/docs/)