Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Import annotations from wallabag JSON exports - #8928

Open
TowyTowy wants to merge 3 commits into
wallabag:masterfrom
TowyTowy:fix/8643-import-annotations
Open

Import annotations from wallabag JSON exports#8928
TowyTowy wants to merge 3 commits into
wallabag:masterfrom
TowyTowy:fix/8643-import-annotations

Conversation

@TowyTowy

Copy link
Copy Markdown
Q A
Bug fix? yes
New feature? no
BC breaks? no
Deprecations? no
Tests pass? yes
Documentation no
Translation no
CHANGELOG.md no
License MIT

Wallabag JSON exports include an annotations array for every entry, but the wallabag importers only read url, title, tags, etc. and silently dropped the annotations. Re-importing an export therefore lost every highlight/note.

This parses the annotations key in WallabagImport::parseEntry() and recreates each Annotation (text, quote, ranges) attached to the imported entry and the current user, following the same flow as AnnotationController::postAnnotationAction(). Entry::$annotations is now initialized in the constructor (like $tags) so a freshly created entry exposes a proper collection.

Added a unit test (testImportWithAnnotations) with a dedicated fixture (80 tests / 405 assertions pass across tests/unit/Import + EntryTest); the existing wallabag-v2 fixtures (annotations empty) are unaffected. php-cs-fixer clean.

Note: imported annotations currently receive an import-time created_at (the entity has no createdAt setter); happy to preserve original dates if preferred.

Fixes #8643


Disclosure: prepared with AI assistance (Claude); authored/verified by me. Tests and php-cs-fixer run locally and pass.

Wallabag JSON exports include an `annotations` array for each entry, but
the wallabag importers only read `url`, `title`, `tags`, etc. and silently
dropped the annotations. Re-importing an export therefore lost all
highlights/notes.

Parse the `annotations` key in `WallabagImport::parseEntry()` and recreate
each `Annotation` (text, quote, ranges) attached to the imported entry and
the current user. Also initialize `Entry::$annotations` in the constructor
so a freshly created entry exposes a proper collection.

Fixes wallabag#8643

Co-Authored-By: Claude Fable 5 <[email protected]>
@netlify

netlify Bot commented Jul 11, 2026

Copy link
Copy Markdown

Deploy Preview for wallabag-doc ready!

Name Link
🔨 Latest commit 383435f
🔍 Latest deploy log https://app.netlify.com/projects/wallabag-doc/deploys/6a524cdcbc2bef0008868443
😎 Deploy Preview https://deploy-preview-8928--wallabag-doc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

Once the constructor initializes it as an ArrayCollection,
inferPrivatePropertyTypeFromConstructor inferred an empty collection.
Type the property (mirroring $tags) and align getAnnotations() docblock.

Co-Authored-By: Claude <[email protected]>
@TowyTowy

Copy link
Copy Markdown
Author

Fixed the PHPStan failure: typing Entry::$annotations was needed once the constructor initializes it as an ArrayCollection (with inferPrivatePropertyTypeFromConstructor, the untyped property was inferred as an empty collection). Added @var Collection<Annotation> plus a Collection type on the property, mirroring $tags, and aligned getAnnotations()'s return docblock to Collection<Annotation>. bin/phpstan analyse and the import unit tests pass locally.

Comment thread src/Import/WallabagImport.php Outdated
*/
protected function parseAnnotation(Entry $entry, $importedAnnotation): ?Annotation
{
if (!\is_array($importedAnnotation) || empty($importedAnnotation['text'])) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A note can be empty (if we only want to highlight some text)

Suggested change
if (!\is_array($importedAnnotation) || empty($importedAnnotation['text'])) {
if (!\is_array($importedAnnotation) || !\array_key_exists('text', $importedAnnotation)) {

$annotation->setQuote($importedAnnotation['quote'] ?? '');
$annotation->setRanges(\is_array($importedAnnotation['ranges'] ?? null) ? $importedAnnotation['ranges'] : []);

return $annotation;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Also, maybe you can force the created/updated at so it won't be lost after import

Following review:

- an annotation with an empty text is legitimate (a highlight without a
  note), so only skip entries which have no `text` key at all;
- restore `created_at` / `updated_at` from the imported file instead of
  stamping them with the import date. `EntityTimestampsTrait` now only
  fills `updated_at` on insert when it wasn't set, the same way it
  already did for `created_at`, so an explicit date survives the
  `prePersist` callback;
- annotation dates were not part of the JSON export (they carry no
  serialization group), so add them, otherwise there is nothing to
  restore when re-importing a wallabag export.
@TowyTowy

Copy link
Copy Markdown
Author

Good catch on the empty note, applied your suggestion.

For the dates: EntityTimestampsTrait was overwriting updated_at on every insert, so I split the callback — prePersist now only fills the dates when they aren't already set (it already did that for created_at), and preUpdate still always bumps updated_at. Nothing else in the codebase sets updated_at before persisting, so existing behaviour shouldn't change.

One thing I ran into: the annotation dates aren't in the JSON export at all — they have no serialization group, so entries_for_user filters them out and there was nothing to restore on import. I added the groups so the round-trip works, but that does change the export/API payload for annotations, so say the word if you'd rather have that as a separate PR and I'll pull it back out.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Importing a Wallabag export does not import annotations

2 participants