Broken Links¶

Console script that lists internal links pointing to content which no longer exists or has been moved to the trash. Editors keep links to pages that are later renamed, deleted or trashed — the stored link stays behind and only fails when a visitor clicks it. The script walks all content of every Plone site in the instance and reports those links.

Key characteristics:

  • Operates on all Plone sites within the Zope instance

  • Reads only — no content is modified, nothing is committed

  • Checks rich text, link widget fields and JSON schema link fields

  • Reports missing and trashed targets

  • Logs a per-site summary

Usage¶

./bin/broken-links <path-to-zope.conf> [--host HOSTNAME ...]

Arguments:

Argument

Description

zopeconf

Absolute path to the Zope configuration file (zope.conf)

--host

Hostname whose absolute URLs are treated as internal. Repeatable.

Links written as absolute URLs (https://www.example.ch/de/page) are only checked when their host is known. Outside of a running server the instance does not know its public hostnames, so pass every one of them with --host — absolute URLs on any other host count as external and are skipped.

Examples:

# All sites of the instance
./bin/broken-links instance/etc/zope.conf

# Also check absolute URLs written against the live site
./bin/broken-links instance/etc/zope.conf --host www.example.ch --host example.ch

In a container the config file depends on the storage — relstorage.conf, zeo.conf or zope.conf in /app/etc/:

docker compose exec -u plone backend /app/bin/broken-links /app/etc/relstorage.conf

Output¶

Findings are grouped per object. The first line is the path and portal type of the object holding the link, followed by one line per broken link with the field name, the stored link and the reason:

/Plone/gerichte/rechtsprechung/uebersicht (Block)
    text: resolveuid/6f6d6a0834914414bce433f0a962689f -> target does not exist
    text: /themen/wohnen/schlichtungsstelle -> target does not exist
/Plone/verwaltung/kontakt (ContentPage)
    cta_href: resolveuid/1d8d8958263942d297f520d5cc18252c -> target is in the trash
Plone: 3 broken internal link(s).
othersite: 0 broken internal link(s).

Redirect to a file for large sites — a grown site easily produces thousands of lines:

./bin/broken-links instance/etc/zope.conf > broken-links.txt

Reasons¶

Reason

Meaning

target does not exist

The UID is unknown or the path cannot be traversed. The link is dead.

target is in the trash

The target was deleted by an editor and sits in the trash container.

Trashed content is worth its own reason: it stays in the catalog, so the link still resolves internally, but the public site answers with a 404. Such links are fixed either by restoring the target or by repointing the link.

What is checked¶

Field type

Where links come from

Rich text

href of links and src of images in the stored HTML

Text line with the link widget

The stored value, e.g. a call to action link

JSON field

Every value whose JSON schema marks it with "format": "link"

How links are resolved¶

  • resolveuid/<uid> is looked up by UID. Everything after the UID is a view on the target (/@@images/image/preview) and is not checked separately.

  • ${portal_url} and ${navigation_root_url} are replaced by the path they stand for, relative to the object holding the link.

  • Absolute paths are traversed from the Zope root first (/Plone/de/page) and then from the portal, so public frontend paths without the portal id (/de/page) resolve as well.

  • Relative paths are traversed from the container of the object. A link stored in a block is resolved against the container of its page, because that is the URL the block is rendered at.

  • The view part of a path (everything from /@@ or /++) is cut off before traversal. Whether /@@download/file/report.pdf renders says nothing about the existence of the linked content.

Skipped, because they are not internal links: other URL schemes (mailto:, tel:, …), absolute URLs on unknown hosts, and links that carry only a fragment or a query string.

Not checked¶

  • External links — no HTTP request is made, the script never leaves the ZODB.

  • Relations — reference fields (RelationValue) are not link fields and are not inspected.

  • Content in the trash — trashed content is skipped as a source of links; fixing links inside deleted content has no value.

Scheduling with Cron¶

The script is safe to run unattended, for example as a weekly report:

# Every Monday at 3:00 AM
0 3 * * 1 /path/to/bin/broken-links /path/to/instance/etc/zope.conf > /var/log/broken-links.txt

Storage note¶

The script opens the database like any other Zope process. With RelStorage or ZEO it runs next to the live instance without interfering. With a direct FileStorage only one process can hold the storage lock, so the instance has to be stopped, or the script has to be pointed at a copy of Data.fs.

Logging¶

The script logs to the wcs.backend.linkcheck logger at INFO level. Output is written to stdout with the format %(message)s.

7inOne

Navigation

Contents

  • Technical Documentation
    • Audit Log
    • Rename by Title
    • Background Jobs
    • Banner
    • Book and Library
    • Book Group Management
    • Book PDF Customization
    • Broken Links
      • Usage
      • Output
      • Reasons
      • What is checked
      • How links are resolved
      • Not checked
      • Scheduling with Cron
      • Storage note
      • Logging
    • Caching & Cloudflare Invalidation
    • Chatbot
    • Call to Action
    • Site Distributions
    • Document Date
    • Empty Trash
    • Exclude Items by Default
    • External Data Fetchers
    • Field Inheritance
    • ImageReferenceField
    • JSON Schema Widget
    • Keycloak Integration
    • Likes
    • Matomo Stats
    • Multilingual
    • Navigation
    • Notifications
    • OIDC Integration
    • Opening Hours
    • Public PDF API
    • RAG (Retrieval-Augmented Generation)
    • Responsible Unit
    • REST API 404 for Inactive Content
    • Restapi
    • Elasticsearch Integration (RESTAPI)
    • SAML Integration
    • Elasticsearch Search
    • Staging (Working Copies)
    • Subsite
    • Task System
    • Topics and SubTopics
    • Trash (Soft Delete & Restore)
    • Versioning
    • Website Workflow

Related Topics

  • Documentation overview
    • Technical Documentation
      • Previous: Book PDF Customization
      • Next: Caching & Cloudflare Invalidation
©2025, maethu. | Powered by Sphinx 8.0.2 & Alabaster 1.0.0 | Page source