Skip to content

Conversation

@GaryJones
Copy link
Contributor

Summary

Prevents posts from being duplicated when syndication forms a loop (e.g., Site A syndicates to Site B, which then syndicates back to Site A).

How it works

  1. When syndication settings are saved, a unique ID (post_uniqueid meta) is generated for the post
  2. Before pushing to a target site, the plugin checks if that site already has a post with this unique ID
  3. If found, the push is skipped, preventing duplicate content

Bug fixes

This PR includes fixes to the original implementation from #130:

  • REST client: Fixed undefined variables ($key/$value$meta_key/$meta_value), changed wp_remote_post to wp_remote_get, added URL encoding, fixed return type
  • XMLRPC client: Fixed inefficient iteration through all posts, properly check all custom_fields (not just index 0), added filter to limit posts returned
  • Server class: Added empty check for unique_id before API call, cleaned up comments

Test plan

  • Create two sites with syndication configured in both directions
  • Create a post on Site A and syndicate to Site B
  • Verify the post appears on Site B with the post_uniqueid meta
  • Configure Site B to syndicate back to Site A
  • Verify the post is NOT duplicated on Site A

Fixes #127
Supersedes #130

Credit to @chetansatasiya for the original implementation.

🤖 Generated with Claude Code

Govind Kumar and others added 3 commits January 3, 2026 20:06
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.
@GaryJones GaryJones requested a review from a team as a code owner January 3, 2026 20:17
@GaryJones GaryJones self-assigned this Jan 3, 2026
@GaryJones GaryJones added the type: bug Something isn't working label Jan 3, 2026
@GaryJones GaryJones added this to the 2.2.0 milestone Jan 3, 2026
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.
@GaryJones GaryJones merged commit e55d365 into develop Jan 3, 2026
8 checks passed
@GaryJones GaryJones deleted the fix/127-syndication-loop-prevention branch January 3, 2026 20:42
@GaryJones GaryJones mentioned this pull request Jan 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Syndication Loops

2 participants