Skip to content

Conversation

@GaryJones
Copy link
Contributor

Summary

Release 2.2.0 with the following changes:

Note on versioning: This release follows 2.0.1 from the develop branch. A 2.1 branch existed with experimental features but was never formally released. To avoid confusion with that unreleased work and establish a clean baseline, we're releasing as 2.2.0. The 3.0.0 release will incorporate architectural improvements and any valuable features from the experimental branch, bringing all development back to a single, unified codebase.

Fixed

  • fix: defer pull jobs refresh to prevent timeout with many sites by @GaryJones in #185
  • fix: add validation before queuing auto-retry cron jobs by @GaryJones in #186
  • fix: use wp_strip_all_tags for token/password sanitization by @GaryJones in #187
  • fix: format dates as ISO 8601 for WordPress.com REST API by @GaryJones in #188
  • fix: prevent PHP warning when settings are null by @GaryJones in #182
  • fix: prevent syndication loops through unique post identification by @GaryJones in #184
  • security: escape output in admin interfaces by @GaryJones in #181

Added

Maintenance

  • test: add comprehensive unit tests for cron pull time interval by @GaryJones in #183

vaurdan and others added 30 commits July 5, 2021 15:36
…ation into vip/deprecated-mcrypto

� Conflicts:
�	tests/test-encryption.php
Migrating plugin instructions from old VIP Docs site to plugin's READ…
GaryJones and others added 21 commits January 3, 2026 18:07
The original implementation of loop prevention (PR #130) contained several
bugs that prevented it from working correctly:

**REST client issues:**
- Used undefined variables `$key` and `$value` instead of `$meta_key` and
  `$meta_value`, causing PHP notices and failed lookups
- Used `wp_remote_post()` instead of `wp_remote_get()` for retrieving posts
- Missing URL encoding for meta parameters, breaking searches with special
  characters
- Returned WP_Error object instead of boolean false on error
- Included unnecessary Content-Type header for GET request

**XML-RPC client issues:**
- Retrieved all posts without filters, causing performance issues and
  timeouts on sites with many posts
- Only checked first custom field (`[0]`), missing matches in other fields
- Missing fields parameter in `wp.getPosts` call to ensure custom_fields
  are returned

**Server class issues:**
- Missing empty check for `$unique_id` before calling `is_source_site_post()`,
  potentially passing empty values
- Typo in comment: "taget" instead of "target"

These fixes ensure the loop prevention feature works as intended, preventing
posts from being syndicated back to their source site.
The previous implementation incorrectly passed a text domain as the second
parameter to esc_html(), which only accepts a single string parameter. This
commit restructures the code to properly escape the translated output.

Additionally, the code now uses wp_parse_url() instead of parse_url() for
WordPress compatibility, includes a null check for the parsed host to prevent
displaying empty source information, and simplifies the condition with empty()
for better readability. A translator comment has been added to provide context
for the source hostname placeholder.
Adds comprehensive unit test coverage for the is_source_site_post() method
in both REST and XMLRPC clients. These tests validate the loop prevention
logic that detects when a post being syndicated already exists on the target
site, preventing duplicate content creation in circular syndication scenarios.

The REST client test suite (19 tests) covers API interaction, URL encoding,
authentication headers, and response handling. The XMLRPC client test suite
(24 tests) additionally validates custom field iteration and type safety.

Both suites use test doubles to isolate the method logic from WordPress
dependencies whilst preserving the exact implementation for testing.
Addresses timeout issues when adding or editing syndication sites in
installations with many configured syndication sites. The synchronous
refresh_pull_jobs() operation becomes prohibitively expensive at scale,
causing requests to timeout during site administration.

This change introduces deferred background processing via WordPress cron.
When sites or site groups are modified, instead of immediately clearing
and rescheduling all pull jobs, the operation is deferred to a one-time
cron event scheduled 60 seconds in the future. A transient-based debounce
mechanism prevents duplicate scheduling when multiple rapid changes occur.

The solution maintains functional correctness whilst eliminating timeout
issues by moving the expensive operation out of the request lifecycle.

Fixes #86
Previously, when a pull failure occurred, the auto-retry handler would
schedule a cron job without validating the site data. This could cause
problems when:

1. The syn_site post no longer exists (get_post returns null)
2. The post exists but is the wrong post type
3. The site has no valid syndication URL configured

These conditions would cause the cron job to keep requeuing indefinitely
whilst never being able to complete successfully.

The fix adds three validation checks:
- Verify the post exists and is a WP_Post instance
- Verify the post type is syn_site
- Verify the feed URL is a valid URL using filter_var

Also refactored to use early returns for cleaner code flow and changed
date() to gmdate() to address PHPCS timezone warnings.

Fixes #101

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The sanitize_text_field() function converts encoded octets (e.g., %B2)
which can break OAuth tokens and passwords that contain special
characters in encoded form.

This change replaces sanitize_text_field() with wp_strip_all_tags() for
token and password fields. wp_strip_all_tags() removes HTML tags but
does not modify encoded octets, making it safe for credential fields.

Additional improvements:
- Added wp_unslash() for proper magic quotes handling
- Added isset() checks for POST variables
- Used esc_url_raw() for URL fields
- Improved code formatting and inline documentation

Fixes #114

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The WordPress.com REST API expects dates in ISO 8601 format. Previously,
dates were sent in MySQL format (Y-m-d H:i:s) which could cause issues
with scheduled posts.

When a post with status 'future' was pushed to an associated site, the
scheduled date was not being preserved because the date format was not
correctly parsed by the API.

This change adds a format_date_for_api() helper method that converts
MySQL dates to ISO 8601 format using mysql2date('c', ...), ensuring
scheduled posts retain their publish date on target sites.

Fixes #148

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@GaryJones GaryJones requested a review from a team as a code owner January 4, 2026 16:39
@GaryJones GaryJones self-assigned this Jan 4, 2026
@GaryJones GaryJones added the type: release Release-related tasks label Jan 4, 2026
@GaryJones GaryJones added this to the 2.2.0 milestone Jan 4, 2026
@GaryJones GaryJones marked this pull request as draft January 4, 2026 17:02
@GaryJones GaryJones changed the base branch from develop to master January 6, 2026 10:51
@GaryJones GaryJones marked this pull request as ready for review January 6, 2026 10:51
@GaryJones GaryJones merged commit b1eeb01 into master Jan 6, 2026
9 of 10 checks passed
@GaryJones GaryJones deleted the release/2.2.0 branch January 6, 2026 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: release Release-related tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants