Skip to content
Merged
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
4 changes: 4 additions & 0 deletions .distignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ CHANGELOG.md
CONTRIBUTING.md
README.md
.wp-env.json
package.json
package-lock.json
.releaserc.json
scripts
4 changes: 2 additions & 2 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ Fixes #

## Checklist

- [ ] `CHANGELOG.md` has a line under `[Unreleased]`
- [ ] The title is a conventional commit (it becomes the squash commit and the changelog line); a breaking change has a `!` and a `BREAKING CHANGE:` paragraph above
- [ ] README and `readme.txt` updated for any changed setting, event, or hook
- [ ] Commit messages follow conventional commits
- [ ] `CHANGELOG.md` and the version are untouched; the release on merge writes them
73 changes: 25 additions & 48 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,26 +1,38 @@
name: Release

# Every push to main is a release candidate. semantic-release reads the
# conventional commits since the last tag, and when one warrants a release it
# writes the version into linkforty.php and readme.txt, prepends CHANGELOG.md,
# builds the zip, commits `chore(release): x.y.z [skip ci]`, tags vX.Y.Z and
# publishes a GitHub release with the zip attached. Configuration:
# .releaserc.json; version writer: scripts/set-version.sh.

on:
push:
tags:
- 'v*'
branches:
- main

concurrency:
group: release
cancel-in-progress: false

jobs:
release:
name: Build and publish the plugin zip
name: Release
runs-on: ubuntu-latest
if: github.repository == 'LinkForty/wordpress-plugin'
if: github.repository == 'LinkForty/wordpress-plugin' && github.ref == 'refs/heads/main'
timeout-minutes: 15

permissions:
contents: write
contents: write # release commit, tag, GitHub release
issues: write # comments on issues a release fixes
pull-requests: write # comments on released pull requests

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # semantic-release needs every tag and commit
persist-credentials: false

- uses: shivammathur/setup-php@v2
with:
Expand All @@ -34,49 +46,14 @@ jobs:

- run: composer phpcs

- name: Tag matches the plugin version
id: version
run: |
set -e
tag="${GITHUB_REF_NAME#v}"
header=$(grep -E '^\s*\*\s*Version:' linkforty.php | awk '{print $NF}')
stable=$(grep -E '^Stable tag:' readme.txt | awk '{print $NF}')
echo "tag=$tag header=$header stable=$stable"
test "$tag" = "$header"
test "$tag" = "$stable"
grep -q "## \[$tag\]" CHANGELOG.md
echo "version=$tag" >> "$GITHUB_OUTPUT"
if [[ "$tag" == 0.* || "$tag" == *-* ]]; then
echo "prerelease=true" >> "$GITHUB_OUTPUT"
else
echo "prerelease=false" >> "$GITHUB_OUTPUT"
fi

- name: Build the zip
run: |
set -e
composer build
mv build/linkforty.zip "build/linkforty-${{ steps.version.outputs.version }}.zip"
unzip -l "build/linkforty-${{ steps.version.outputs.version }}.zip"
- uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'

- name: Release notes from the changelog
run: |
set -e
awk -v v="${{ steps.version.outputs.version }}" '
$0 ~ "^## \\[" v "\\]" { on = 1; next }
on && /^## \[/ { exit }
on { print }
' CHANGELOG.md | sed -e :a -e '/^\n*$/{$d;N;ba' -e '}' > build/notes.md
printf '\n\nInstall: upload the zip under Plugins → Add New → Upload Plugin, then follow the [setup guide](https://docs.linkforty.com/sdks/wordpress).\n' >> build/notes.md
cat build/notes.md
- run: npm ci

- name: Create the GitHub release
- name: Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -e
args=(--title "v${{ steps.version.outputs.version }}" --notes-file build/notes.md --verify-tag)
if [ "${{ steps.version.outputs.prerelease }}" = "true" ]; then
args+=(--prerelease)
fi
gh release create "$GITHUB_REF_NAME" "build/linkforty-${{ steps.version.outputs.version }}.zip" "${args[@]}"
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release
72 changes: 72 additions & 0 deletions .releaserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
{
"branches": ["main"],
"tagFormat": "v${version}",
"plugins": [
[
"@semantic-release/commit-analyzer",
{
"preset": "conventionalcommits",
"releaseRules": [
{ "type": "feat", "release": "minor" },
{ "type": "fix", "release": "patch" },
{ "type": "perf", "release": "patch" },
{ "type": "revert", "release": "patch" },
{ "type": "docs", "release": "patch" },
{ "type": "refactor", "release": "patch" },
{ "type": "chore", "release": false },
{ "type": "test", "release": false },
{ "type": "build", "release": false },
{ "type": "ci", "release": false },
{ "breaking": true, "release": "minor" }
]
}
],
[
"@semantic-release/release-notes-generator",
{
"preset": "conventionalcommits",
"presetConfig": {
"types": [
{ "type": "feat", "section": "Features" },
{ "type": "fix", "section": "Bug Fixes" },
{ "type": "perf", "section": "Performance Improvements" },
{ "type": "revert", "section": "Reverts" },
{ "type": "docs", "section": "Documentation" },
{ "type": "refactor", "section": "Code Refactoring" },
{ "type": "test", "section": "Tests", "hidden": true },
{ "type": "build", "section": "Build System", "hidden": true },
{ "type": "ci", "section": "CI/CD", "hidden": true }
]
}
}
],
[
"@semantic-release/changelog",
{
"changelogFile": "CHANGELOG.md",
"changelogTitle": "# Changelog"
}
],
[
"@semantic-release/exec",
{
"prepareCmd": "scripts/set-version.sh ${nextRelease.version} && composer build && mv build/linkforty.zip build/linkforty-${nextRelease.version}.zip"
}
],
[
"@semantic-release/git",
{
"assets": ["linkforty.php", "readme.txt", "CHANGELOG.md"],
"message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
}
],
[
"@semantic-release/github",
{
"assets": [{ "path": "build/linkforty-*.zip", "label": "Plugin zip (upload under Plugins → Add New → Upload Plugin)" }],
"failComment": false,
"failTitle": false
}
]
]
}
5 changes: 1 addition & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
# Changelog

All notable changes to this plugin are documented here. The format follows
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]
## [0.2.0] - 2026-10-16

### Fixed
- WooCommerce purchases record their revenue: the order total is sent as
Expand Down
28 changes: 20 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ Enhancement suggestions are tracked as GitHub issues. Include the use case, the
2. Make your change, following the standards below
3. Run `composer lint` and `composer phpcs`
4. Test on a real WordPress site (see [Testing](#testing))
5. Add a line under `[Unreleased]` in `CHANGELOG.md`
6. Open a pull request using the template
5. Open a pull request using the template, with a [conventional commit](#commit-messages) title. Don't edit `CHANGELOG.md` or the version; the release on merge writes both

## Development Setup

Expand Down Expand Up @@ -76,7 +75,7 @@ linkforty/
│ └── class-linkforty-woocommerce.php # purchase, begin_checkout, add_to_cart
├── assets/js/linkforty-woocommerce.js # Browser-side add-to-cart listener
├── readme.txt # WordPress.org readme
└── .github/workflows/ # CI and the tag-driven release
└── .github/workflows/ # CI and the release on every merge to main
```

## Coding Standards
Expand Down Expand Up @@ -150,7 +149,9 @@ Follow conventional commits:
type(scope): description
```

Types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`. Scopes that fit this plugin: `pixel`, `woocommerce`, `settings`, `events`, `release`.
Types: `feat`, `fix`, `docs`, `refactor`, `perf`, `test`, `chore`, `ci`, `build`. Scopes that fit this plugin: `pixel`, `woocommerce`, `settings`, `events`, `release`.

Pull requests are squash-merged, so **the pull request title is the commit message** that decides the next version and becomes its changelog line. Write it for a store owner reading the release notes. A breaking change gets a `!` after the type or scope (`fix(woocommerce)!: …`) and a `BREAKING CHANGE:` paragraph in the pull request description saying what to change.

```
fix(woocommerce): report pending orders once they move to processing
Expand All @@ -162,7 +163,7 @@ docs(readme): document the purchase properties

- [ ] `composer lint` and `composer phpcs` pass
- [ ] Tested on a real site; the relevant checklist rows are in the PR description
- [ ] `CHANGELOG.md` has a line under `[Unreleased]`
- [ ] The pull request title is a conventional commit; breaking changes have a `!` and a `BREAKING CHANGE:` note
- [ ] README and `readme.txt` updated if you changed a setting, an event, or a hook
- [ ] No new event names or renamed properties without discussion in an issue first

Expand All @@ -172,13 +173,24 @@ A maintainer reviews every pull request. Expect questions about attribution and

## Versioning and Releases

Maintainers cut releases. The plugin follows [semantic versioning](https://semver.org/):
Every merge to `main` can release. The release workflow runs [semantic-release](https://semantic-release.gitbook.io/), which reads the conventional commits since the last tag and picks the version:

| Commits since the last release | Release |
|---|---|
| Only `chore`, `test`, `ci`, `build` | None |
| Any `fix`, `docs`, `refactor`, `perf`, `revert` | Patch |
| Any `feat` | Minor |
| Any breaking change (`!` or `BREAKING CHANGE:`) | Minor while the plugin is below 1.0, major from 1.0 on |

What counts as a feature or a breaking change:

- **Patch** for fixes
- **Minor** for new settings, hooks, events, or properties
- **Major** for a renamed or removed event, property, setting, or hook
- **Breaking** for a renamed or removed event, property, setting, or hook

When it releases, the workflow writes the version into `linkforty.php` (header and constant) and `readme.txt` (`Stable tag`) with `scripts/set-version.sh`, prepends the release notes to `CHANGELOG.md`, builds the zip, commits `chore(release): x.y.z [skip ci]`, tags `vx.y.z`, and publishes a GitHub release with the zip attached. Nobody edits those files by hand.

To release, the version is bumped in `linkforty.php` (header and constant), `readme.txt` (`Stable tag`) and `CHANGELOG.md` (the `[Unreleased]` section becomes the new version), then a matching tag such as `v0.2.0` is pushed. The release workflow lints, builds the zip, and attaches it to a GitHub release with the changelog section as notes. Versions below 1.0 are marked pre-release.
Below 1.0, a breaking change bumps the minor version, as [semantic versioning allows for 0.x](https://semver.org/#spec-item-4). At 1.0, change the `"breaking": true` rule in `.releaserc.json` from `minor` to `major`.

## Security

Expand Down
4 changes: 2 additions & 2 deletions linkforty.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Plugin Name: LinkForty
* Plugin URI: https://docs.linkforty.com/sdks/wordpress
* Description: Web analytics and conversion tracking for LinkForty links. Adds the LinkForty web pixel to every page and reports WooCommerce purchases as conversions attributed to the link that drove the visit.
* Version: 0.1.0
* Version: 0.2.0
* Requires at least: 6.3
* Requires PHP: 7.4
* Author: LinkForty
Expand All @@ -20,7 +20,7 @@

defined( 'ABSPATH' ) || exit;

define( 'LINKFORTY_VERSION', '0.1.0' );
define( 'LINKFORTY_VERSION', '0.2.0' );
define( 'LINKFORTY_PLUGIN_FILE', __FILE__ );
define( 'LINKFORTY_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'LINKFORTY_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
Expand Down
Loading