Skip to content

Add the ability to import and export saved posts.#25509

Open
twstokes wants to merge 6 commits intotrunkfrom
reader-import-export
Open

Add the ability to import and export saved posts.#25509
twstokes wants to merge 6 commits intotrunkfrom
reader-import-export

Conversation

@twstokes
Copy link
Copy Markdown
Contributor

@twstokes twstokes commented Apr 23, 2026

Summary

  • Saved Reader posts are local-only and don't sync across devices. This adds the ability to import and export them as a JSON file, so users can back up their saved posts or transfer them between devices/apps.
  • Accessible from Me → App Settings → Other → Saved Posts
  • Export produces a {AppName}-Saved-Posts-{date}.json file containing post metadata (URL, title, author, site, date, summary, tags, featured image, siteID, postID) along with the app version that exported it.
  • Import parses the JSON, then fetches each post from the WordPress.com API through the normal ReaderPostService pipeline to create fully-populated Core Data objects. Posts are fetched sequentially to avoid race conditions. Deduplication uses permaLink — posts whose URL is already saved are skipped, so importing the same file multiple times or merging lists from different devices is safe.
  • A progress bar is shown during import since each post requires a network round-trip.
  • The result reports imported, skipped (already saved), and failed (API errors) counts.
  • Adds three Tracks events: `reader_saved_posts_settings_shown` (screen appears), `reader_saved_posts_exported` (successful export), and `reader_saved_posts_imported` (with imported/skipped/failed counts).
Reader -> Saved Settings -> Saved Posts Saved Posts
image image image

Test plan

  • Go to Me → App Settings, verify "Saved Posts" row appears in the Other section with a bookmark icon
  • Tap it, verify the Saved Posts screen shows Import and Export buttons with explanatory footer text
  • With no saved posts, tap Export — verify "No saved posts to export" alert
  • Save some Reader posts, then export — verify the share sheet appears with a correctly named JSON file (e.g. `Jetpack-Saved-Posts-2026-04-23.json`)
  • Inspect the exported JSON — verify it contains `appVersion`, `exportDate`, `postCount`, and `posts` array with expected fields including `siteID`, `postID`, and `isFeed`
  • Clear saved posts, then import the exported file — verify progress bar appears, posts are fetched, and result shows correct imported count
  • Verify imported posts appear in the Reader Saved tab and load correctly when tapped
  • Import the same file again — verify all posts are skipped (no duplicates)
  • Try importing an invalid file — verify error message
  • Verify Tracks events fire as expected: `reader_saved_posts_settings_shown` when opening the screen, `reader_saved_posts_exported` after a successful export, and `reader_saved_posts_imported` after import (with non-zero `imported`/`skipped`/`failed` counts as appropriate)
  • Run `ReaderSavedPostsExporterTests` — all 15 tests should pass

🤖 Generated with Claude Code

@dangermattic
Copy link
Copy Markdown
Collaborator

dangermattic commented Apr 23, 2026

1 Warning
⚠️ This PR is larger than 500 lines of changes. Please consider splitting it into smaller PRs for easier and faster reviews.

Generated by 🚫 Danger

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented Apr 23, 2026

App Icon📲 You can test the changes from this Pull Request in WordPress by scanning the QR code below to install the corresponding build.
App NameWordPress
ConfigurationRelease-Alpha
Build Number32156
VersionPR #25509
Bundle IDorg.wordpress.alpha
Commit1209432
Installation URL22p1kqpfvmif0
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented Apr 23, 2026

App Icon📲 You can test the changes from this Pull Request in Jetpack by scanning the QR code below to install the corresponding build.
App NameJetpack
ConfigurationRelease-Alpha
Build Number32156
VersionPR #25509
Bundle IDcom.jetpack.alpha
Commit1209432
Installation URL1bfo3j95c0oc0
Automatticians: You can use our internal self-serve MC tool to give yourself access to those builds if needed.

@twstokes twstokes force-pushed the reader-import-export branch from d2b6618 to 8209a08 Compare April 30, 2026 14:43
@twstokes twstokes marked this pull request as ready for review April 30, 2026 15:10
@twstokes twstokes added this to the 26.9 milestone Apr 30, 2026
@twstokes twstokes force-pushed the reader-import-export branch from 3b1a46f to 06c723d Compare May 5, 2026 18:07
@wpmobilebot
Copy link
Copy Markdown
Contributor

wpmobilebot commented May 5, 2026

🤖 Build Failure Analysis

This build has failures. Claude has analyzed them - check the build annotations for details.

@twstokes twstokes force-pushed the reader-import-export branch from 06c723d to 6f4c403 Compare May 5, 2026 21:27
twstokes added 4 commits May 5, 2026 17:35
Lets the VM be unit-tested without ContextManager.shared, and marks the
alert message strings @published so SwiftUI re-reads them when the
isShowing* flag flips.
Adds three Tracks events:
- reader_saved_posts_settings_shown when the screen appears
- reader_saved_posts_exported on a successful export
- reader_saved_posts_imported with imported/skipped/failed counts
@twstokes twstokes requested review from crazytonyli and jkmassel May 8, 2026 16:31
Comment on lines +49 to +50
let appName = (Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as? String) ?? "WordPress"
let appVersion = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can be force-unwrapped – we'd never ship a release that doesn't have them.

Realistically we should have a helper that does it for you 🤷

import WordPressData

/// Handles exporting and importing saved Reader posts as JSON files.
struct ReaderSavedPostsExporter {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation does not quite follow the patterns used widely in the app. I have added a doc in #25551. I wonder if you can prompt AI to rewrite to follow the updated best practices?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants