Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions .distignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Files and directories excluded from the WordPress.org plugin package (SVN trunk).
#
# Syntax note: .distignore is IGNORE-ONLY — it does not support negation (!) like
# .gitignore. So we cannot "exclude vendor/ except reporting.php". Instead, the
# deploy workflow does NOT run `composer install`, so a fresh checkout's vendor/
# contains only the committed vendor/reporting.php (the dev dependencies are
# git-ignored and therefore absent). That is why vendor/ is intentionally NOT
# listed below: vendor/reporting.php must ship and is the only thing in vendor/.

# Version control & CI
/.git
/.github
/.gitignore
/.gitattributes
/.husky

# Local dev environment & editor tooling
/.wp-env.json
/.editorconfig
/.idea
/node_modules
/.phpunit.result.cache
.DS_Store

# Tests, build sources and scripts (js/build IS shipped; js/src is not)
/tests
/bin
/js/src/blocks

# Composer / npm manifests
/composer.json
/composer.lock
/package.json
/package-lock.json

# Coding standards & test configuration
/phpcs.xml
/phpunit.xml.dist

# Repo docs & release tooling (readme.txt ships; these do not)
/AGENTS.md
/README.md
/SECURITY.md
/CONTRIBUTING.md

# wp.org banners/icons/screenshots — deployed to the SVN /assets dir automatically
# by the action, so they must not also ship inside the plugin trunk.
/.wordpress-org

# This file.
/.distignore
20 changes: 20 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# This file is for unifying the coding style for different editors and IDEs
# It is based on https://core.trac.wordpress.org/browser/trunk/.editorconfig
# WordPress Coding Standards: https://make.wordpress.org/core/handbook/coding-standards/

root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 2

[*.yml]
indent_style = space
indent_size = 2

[*.md]
trim_trailing_whitespace = false
22 changes: 22 additions & 0 deletions .github/workflows/build-zip.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Build release zip

on:
workflow_dispatch:

jobs:
build:
name: Build release zip
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Build plugin
run: |
npm install
npm run build

- name: Generate zip
uses: 10up/action-wordpress-plugin-build-zip@stable
with:
retention-days: 5
38 changes: 38 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Deploy to WordPress.org

on:
release:
types: [released]

permissions:
contents: write

jobs:
deploy:
name: New release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: Check release tag matches version
run: |
v=$(grep -oiP '^Stable tag:\s*\K\S+' readme.txt)
[ "$v" = "$GITHUB_REF_NAME" ] || { echo "::error::Release tag $GITHUB_REF_NAME != Stable tag $v"; exit 1; }

- name: Build
run: |
npm install
npm run build

- name: WordPress plugin deploy
id: deploy
uses: 10up/action-wordpress-plugin-deploy@stable
with:
generate-zip: true
env:
SVN_USERNAME: ${{ secrets.SVN_USERNAME }}
SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }}

- name: Upload release asset
uses: softprops/action-gh-release@v3
with:
files: ${{ steps.deploy.outputs.zip-path }}
59 changes: 59 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: Lint

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
php-compat:
name: PHP compatibility (7.4+)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
coverage: none
tools: composer

- name: Install Composer dependencies
uses: ramsey/composer-install@v4
with:
dependency-versions: highest

# Blocking gate: a failure means shipping code breaks on a supported PHP version.
- name: Check PHP cross-version compatibility
run: composer compat

phpcs:
name: Coding standards (advisory)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.3'
coverage: none
tools: composer

- name: Install Composer dependencies
uses: ramsey/composer-install@v4
with:
dependency-versions: highest

# Advisory while the legacy WPCS backlog is worked down; does not block merges.
- name: Run WordPress coding standards
continue-on-error: true
run: composer lint
68 changes: 68 additions & 0 deletions .github/workflows/phpunit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: PHPUnit

on:
push:
branches: [main]
pull_request:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
test:
name: PHP ${{ matrix.php }} / WP ${{ matrix.wp }}${{ matrix.multisite == 1 && ' multisite' || '' }}
runs-on: ubuntu-latest
continue-on-error: ${{ matrix.experimental || false }}
services:
mysql:
image: mysql:8.0
env:
MYSQL_ROOT_PASSWORD: root
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping -proot"
--health-interval=10s
--health-timeout=5s
--health-retries=5
strategy:
fail-fast: false
matrix:
include:
- { php: '7.4', wp: '6.3' }
- { php: '8.0', wp: 'latest' }
- { php: '8.1', wp: 'latest' }
- { php: '8.2', wp: 'latest' }
- { php: '8.3', wp: 'latest' }
- { php: '8.4', wp: 'latest' }
- { php: '8.2', wp: 'latest', multisite: 1 }
- { php: '8.4', wp: 'nightly', experimental: true }
env:
WP_INSTALL_TESTS_SKIP_UPDATE_CHECK: 'true'
steps:
- uses: actions/checkout@v7

- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mysqli
coverage: none
tools: composer

- name: Install Composer dependencies
uses: ramsey/composer-install@v4
with:
dependency-versions: highest

- name: Install WordPress test suite
run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wp }}

- name: Run tests
env:
WP_MULTISITE: ${{ matrix.multisite || 0 }}
run: composer test
22 changes: 13 additions & 9 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
.DS_Store
.idea
.idea/

# Manage wordpress/wp-content/plugins/memberful-wp and ignore everything else
# from the wordpress/ folder.
/wordpress/*
!/wordpress/wp-content/
/wordpress/wp-content/*
!/wordpress/wp-content/plugins
/wordpress/wp-content/plugins/*
!/wordpress/wp-content/plugins/memberful-wp
# Dependencies and build output
node_modules/
**/build/**

# Composer dependencies - ignore everything except the hand-vendored
# reporting.php, which is a runtime file that ships with the plugin.
/vendor/*
!/vendor/reporting.php

composer.lock
.phpunit.result.cache
.phpunit.cache

# Claude Code - https://code.claude.com/docs/en/settings
.claude/settings.local.json
Expand Down
6 changes: 6 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
if [ ! -f vendor/bin/phpcs-changed ]; then
echo "memberful-wp: vendor/bin/phpcs-changed not found — run 'composer install' to enable PHP pre-commit linting. Skipping."
exit 0
fi

npx lint-staged
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
18 changes: 18 additions & 0 deletions .wp-env.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://schemas.wp.org/trunk/wp-env.json",
"core": null,
"phpVersion": "8.2",
"plugins": [ "." ],
"themes": [ "https://downloads.wordpress.org/theme/twentytwentyone.zip" ],
"config": {
"WP_DEBUG": true,
"WP_DEBUG_LOG": true,
"SCRIPT_DEBUG": true,
"MEMBERFUL_APPS_HOST": "http://apps.memberful.localhost",
"MEMBERFUL_EMBED_HOST": "http://js.memberful.localhost",
"MEMBERFUL_SSL_VERIFY": false
},
"lifecycleScripts": {
"afterStart": "wp-env run cli wp theme activate twentytwentyone && wp-env run cli wp widget add memberful_wp_profile_widget sidebar-1 1"
}
}
36 changes: 19 additions & 17 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,42 @@

## Project Structure & Module Organization

This repository develops the Memberful WordPress plugin. The plugin source lives in `wordpress/wp-content/plugins/memberful-wp`, with a convenience symlink at `plugin`.
This repository develops the Memberful WordPress plugin.

- `wordpress/wp-content/plugins/memberful-wp/src`: PHP feature modules and integrations.
- `wordpress/wp-content/plugins/memberful-wp/views`: PHP view templates used by admin and frontend output.
- `wordpress/wp-content/plugins/memberful-wp/js/src`: JavaScript sources such as `admin.js` and `editor-scripts.js`.
- `wordpress/wp-content/plugins/memberful-wp/js/build`: generated assets; rebuild locally instead of editing by hand.
- `wordpress/wp-content/plugins/memberful-wp/stylesheets`: plugin CSS sources.
- `assets`: WordPress.org banner, icon, and screenshot assets.
- `src`: PHP feature modules and integrations.
- `views`: PHP view templates used by admin and frontend output.
- `js/src`: JavaScript sources such as `admin.js` and `editor-scripts.js`.
- `js/build`: generated assets; rebuild locally instead of editing by hand.
- `stylesheets`: plugin CSS sources.
- `.wordpress-org`: WordPress.org banner, icon, and screenshot assets.

## Build, Test, and Development Commands

- `docker compose up` or `docker compose up -d`: start the local WordPress stack.
- `./docker-provision.sh`: perform the initial WordPress setup after containers are running.
- `cd wordpress/wp-content/plugins/memberful-wp && npm install`: install JS build dependencies.
- `cd wordpress/wp-content/plugins/memberful-wp && npm run start`: watch and rebuild JS during development.
- `cd wordpress/wp-content/plugins/memberful-wp && npm run build`: create production JS bundles for release checks.
- `docker compose down`: stop and remove the local stack.
The local environment uses [`@wordpress/env`](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/) (Docker required).

- `npm install`: install JS build dependencies and dev tooling.
- `npm run env:start`: start the local WordPress environment. Site at `http://localhost:8888`, wp-admin at `http://localhost:8888/wp-admin` (user `admin`, password `password`).
- `npm run env:stop`: stop it; `npm run env:clean` resets the database; `npm run env:destroy` removes the environment entirely.
- `npm run env:cli -- <args>`: run WP-CLI in the container, e.g. `npm run env:cli -- plugin list`.
- `npm run start`: watch and rebuild JS during development.
- `npm run build`: create production JS bundles for release checks.

## Coding Style & Naming Conventions

Match the surrounding code rather than reformatting broadly. PHP follows the existing WordPress-style conventions used here: 2-space indentation, snake_case functions, uppercase `TRUE`/`FALSE` where already present, and `Memberful_*` class names. Keep filenames consistent with nearby modules, for example `src/private_user_feed.php` or `src/endpoints/webhook.php`. JavaScript is built with `@wordpress/scripts`; keep source files in `js/src` and let Webpack produce `js/build`.

## Testing Guidelines

There is no dedicated PHPUnit or JS test suite in this repository today. Validate changes in the Docker environment, then smoke-test the affected flows in `wp-admin` at `http://wordpress.localhost/wp-admin`. For UI changes, verify both PHP-rendered views and rebuilt JS assets. For integration work, exercise the specific Memberful connection, webhook, or content-protection path you changed.
Validate changes in the local `wp-env` environment, then smoke-test the affected flows in `wp-admin` at `http://localhost:8888/wp-admin`. For UI changes, verify both PHP-rendered views and rebuilt JS assets. For integration work, exercise the specific Memberful connection, webhook, or content-protection path you changed.

## Commit & Pull Request Guidelines

Recent history favors short, imperative commit subjects such as `Fix PHP 8.3 deprecation notice` or `Add filter comment`. Keep commits focused and avoid mixing release prep with feature work. Pull requests should describe the behavior change, link the relevant issue, note any manual test coverage, and include screenshots for admin-facing UI changes. If a change affects plugin behavior or release notes, update `wordpress/wp-content/plugins/memberful-wp/readme.txt`.
Do not run `./release.sh` as part of normal contributor or agent work unless a maintainer explicitly asks for a release.
Recent history favors short, imperative commit subjects such as `Fix PHP 8.3 deprecation notice` or `Add filter comment`. Keep commits focused and avoid mixing release prep with feature work. Pull requests should describe the behavior change, link the relevant issue, note any manual test coverage, and include screenshots for admin-facing UI changes. If a change affects plugin behavior or release notes, update `readme.txt`.
Releases are published by the **Deploy to WordPress.org** GitHub Actions workflow when a GitHub release is created; do not cut a release (or otherwise trigger the deploy) as part of normal contributor or agent work unless a maintainer explicitly asks for one.

## Versioning

The plugin version must match in three places: the `Stable tag` field in `readme.txt`, the `Version` header in `memberful-wp.php`, and the `MEMBERFUL_VERSION` constant in the same file. `release.sh` validates this before publishing. During feature development, use `= unreleased =` as the changelog heading in `readme.txt`. When a release is cut, that heading is replaced with the actual version number and all three locations are updated together. Do not bump the version unless explicitly asked.
The plugin version must match in three places: the `Stable tag` field in `readme.txt`, the `Version` header in `memberful-wp.php`, and the `MEMBERFUL_VERSION` constant in the same file. The deploy workflow verifies the release tag matches the `Stable tag` before publishing to WordPress.org. During feature development, use `= unreleased =` as the changelog heading in `readme.txt`. When a release is cut, that heading is replaced with the actual version number and all three locations are updated together. Do not bump the version unless explicitly asked.

### Changelog updates before a version bump

Expand Down
Loading
Loading